-------------------------------------------------------- Shellcoding.txt by bob from dtors.net -------------------------------------------------------- Introduction ------------ There is no real easy way out when comming to learn how to do shellcode. You have to no a little bit of asm, and how the stack is sorted. The way im going to explain differs from aleph1's method, which i learnt from the guys at netric.org. This paper is based on Linux x86 platforms. Some Simple asm basics ---------------------- Im going to give you some simple asm basics that you will need to know to follow this paper. MOV - This puts some [data] into a register. For example: mov ax,10 - Puts 10 into ax. mov bx,cx - Moves value from cx into bx mov dx, number - Moves the value of number into dx PUSH - Pushes a piece of [data] onto the stack. For example push $data POP - Puts the [data] from the stack into a specified register or variable. For example pop %eax Push a push pop and save some for later: push cx - put cx on the stack pop cx - puts value from the stack into cx XCHG - Exchange two registers INT - calls a bios function which are subroutines that we would not write a function for. For example opening a file. Most interupts have more than one function, this means we have to pass a number to the one we want. XOR - Clears a register. LEA - Load effective address - we wont be using this. Lets get started ---------------- I have explained a little bit of asm to you, which should help you understand where we go from here. For an example im going to make some shellcode which will write() a string to the screen. $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ /* * Linux x86 shellcode by bob from Dtors.net. * write(stdout,"bob from DSR", 15); exit; */ #include char shellcode[]= "\x31\xc0\x31\xdb\x31\xd2\x53\x68\x20\x44\x53\x52" "\x68\x66\x72\x6f\x6d\x68\x62\x6f\x62\x20\x89\xe1" "\xb2\x0f\xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80" int main() { void (*funct) (); (long) funct = &shellcode; funct(); } $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Now i bet your wondering what the hell is bob on about now, well im gonna step back now and explain how i got this. Well first of all lets execute this and see what it does. [bob@dtors bob]$ ./bob bob from DSR [bob@dtors bob]$ OK so its a simple write()...lets see how we done this. xor %eax,%eax #clear eax xor %ebx,%ebx #clear ebx xor %edx,%edx #clear edx We clear the registers, because we have to terminate that string with a 0. push %ebx #push ebx on the stack We push ebx which contains 0 bytes onto the stack so that our shellcode wont execute crap after our string. For example /bin/sh[stack crap]. push $0x52534420 #push DSR on the stack push $0x6d6f7266 #push from on the stack push $0x20626f62 #push bob on the stack Now this is where we differ from aleph1's method. Because we have the obstacle of finding where the string exists in memory, aleph1 used a JMP and a CALL instruction. This way is alot easier, what we do is just push the strings itself onto the stack, and then the $esp is the address of your string. mov %esp,%ecx #mov contents of esp into ecx Here we move the contents of esp into ecx, moving our string from one register to the other, freeing up the esp, incase we want to push something else onto the stack. mov $0x0f,%dl #reserve 15 bytes for arg This here will reserve 15 bytes for our string. In case you didnt notice, $0x0f is hex for 15. mov $0x4,%al #syscall for write Self explanitry, we get the syscall from unistd.h for write, and then declare it here. int $0x80 #execute the syscall The OS will no now that we want to execute the syscall. xor %eax,%eax #push a 0 byte into eax Once again we are clearing eax. Now we need the exit() syscall. mov $0x1,%al #syscall for exit int $0x80 #execute the syscall We give it the syscall and execute it to exit. Thats all we have to do...now we need to convert this into little endian. So we put it in C like so: //DSR.c void main(){ __asm__(" xor %eax,%eax #clear eax xor %ebx,%ebx #clear ebx xor %edx,%edx #clear edx push %ebx #push ebx on the stack push $0x52534420 #push DSR on the stack push $0x6d6f7266 #push from on the stack push $0x20626f62 #push bob on the stack mov %esp,%ecx #mov contents of esp into ecx mov $0x0f,%dl #reserve 15 bytes for arg mov $0x4,%al #syscall for write int $0x80 #execute the syscall xor %eax,%eax // exit; mov $0x1,%al #syscall for exit int $0x80 #execute the syscall "); } Then we compile this so we can disassemble it and open up in gdb: [bob@dtors.net bob]$ gcc DSR.c -o DSR -ggdb -g [bob@dtors.net bob]$ gdb ./DSR GNU gdb 19991004 Copyright 1998 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-redhat-linux"... (gdb) x/bx main+3 0x804839b : 0x31 (gdb) 0x804839c : 0xc0 (gdb) 0x804839d : 0x31 (gdb) 0x804839e : 0xdb (gdb) 0x804839f : 0x31 (gdb) PRESS ENTER UNTIL END Then we convert this to little endian: \x31\xc0\x31\xdb\x31 ...........and so on till you reach the end. The End. -------- That concludes the first paper on shellcoding. My main purpose for writing this, is because i always find it the best way to learn, by writing about it, for other to learn from. It will keep it fresh in me head ;) I would like to thank eSDee, r00tdude, and Laurens from netric.org, for helping me out in the past. Below you will find a few references to help you out: http://simas.wox.org/syscalls/ http://www.newroot.de/ http://linuxasm.org/ http://www.netric.org/ http://www.dtors.net/ Mesgs: ------ Check out http://hack.dtors.net It is a NEW public exploits archive of the latest exploits, or unreleased. It needs your help and support though to get it started. It does have an upload script for you to submit your exploits. With your support it CAN be the LARGEST available exploits archive on the net.