Exploring Security Vulnerabilities by Exploiting Buffer Overflow using the MIPS ISA Andrew T. Phillips Jack S. E. Tan Department of Computer Science University of Wisconsin – Eau Claire
Smashing the stack Limitations of C permit security exploits Library routines: strcpy, strcat, sprintf, etc. no automatic bounds checking. Shortcomings: allow writing past end of array. Major source of security exploitssecurity exploits
The Original Exploit The trade magazine "Phrack" published: "Smashing the Stack for Fun and Profit" by Aleph One Original exploit done on the Intel architecture
Overall Strategy Write a small program that starts a shell window: use something like system("/bin/sh") Translate the program into HEX, modifying individual bytes as needed (explained later) Put the HEX code into a buffer, followed by the address of the start of that buffer, repeated many times Will overwrite the return address (on the stack) of the servers buffer handler routine
Basic Steps Get a copy of the OS to be attacked Analyze the system stack layout for that OS Put the "shell window" HEX code into a buffer Send your buffer to a program on the target OS (maybe one that runs as "root") that takes a buffer as input, makes a copy of that buffer, and doesn't check its bounds
Typical MIPS Memory Layout
Stack Frame On a function call: Preserve state of calling function Allocate additional memory for calling function Stack frame (activation record) created Pushed onto execution stack
Stack Frame – cont’d Stack frame (activation record) contains: Function arguments Local variables Return address ($ra) Global pointer ($gp) Note: Not all local variables may be stacked: Optimizing compiler may put them in registers.
Typical Procedure Call Memory Layout Return address (if any) Arguments (if > 4 args; $4-$7 holds 1 st four) Saved Registers (preserved across calls) Local Variables Old SP New SP Global pointer (to static data segment for fast access using offset) Subsequent examples will exclude saved registers & argument details for brevity. Note:
Mechanics of Function Calls Simple C program where: main( ) foo( ) bar( ) main( )foo(x)bar(y) foo(8)foo_p = x +2bar_q = y bar(foo_p)
Mechanics of Function Calls – cont’d void bar(int y) { int bar_q;/* will be allocated on the stack */ bar_q = y; } void foo(int x) { int foo_p;/* will be allocated on the stack */ foo_p = x + 2; bar(foo_p); /* return address points to here */ } void main( ) { foo(8); /* return address points to here */ }
Memory Layout for foo( )
Overview of an Overflow void foo(char *buf) { char local_buf[10]; strcpy(local_buf,buf); } void main() { char *large_buf = “a……a”; // lots of a’s foo(large_buf); /* location of return from foo() */ }
Overflowing foo( )’s Buffer local_buf$ra …… ‘a’…. ‘a’ (a) Stack before strcpy( ) in foo( ) (b) Stack after strcpy( ) in foo( )
Implementing Overflow in the MIPS ISA void foo(char *buf) { char local_buf[10]; int i = 0; while (buf[i] != 0) { local_buf[i] = buf[i]; i++; } bar(); /* code for bar() not shown */ /* bar( )’s RA in $31 reg.; foo( )’s RA on stack */ } void main() { char *large_buf = “a……a”; // lots of a’s foo(large_buf); /* location of return from foo() */ }
32-bit MIPS stack during call to foo( ) addrStack contents new $sp X-28allocated by compiler X-24allocated by compiler X-20local_buf[0] … local_buf[3] X-16local_buf[4] … local_buf[7] X-12local_buf[8], local_buf[9], null, null X-8Global pointer ($gp) from main() X-4Return address ($ra) back into main() old $sp X…
32 bit MIPS translation using “gcc –S –O2”.L4: jalbar lw$ra,24($sp) lw$gp,20($sp) jr$ra addu$sp, $sp, 28.endfoo.LC0:# lots of a’s.byte0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61.byte0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61.byte0x61,0x61,0x61,0x61,0x00 main: subu$sp,$sp,16 sw$ra,12($sp) sw$gp,8($sp) la$a0,.LC0 jalfoo ….endmain foo: subu$sp,$sp,28 sw$ra,24($sp) sw$gp,20($sp) lbu$v0,0($a0) beq$v0,$zero,.L4 addi$a1,$zero,0 addu$a2,$sp,8 # addr local_buf[0].L5 lbu$v0,0($a0) addu$a0, $a0, 1 addu$v1,$a2,$a1 sb$v0,0($v1) # write onto stack lbu$v0,0($a0) bne$v0,$zero,.L5 addu$a1,$a1,1
Buffer Overflow With Code Exploit To cause the exploit, when foo is called: Pass a buffer of length greater than foo( )’s local buffer Ensure none of values copied into foo( )’s buffer prior to $ra contain value of 0 (terminates buffer copy prematurely) Ensure bytes in buffer contain MIPS (exploit) code Overwrite $ra with address that points back into buffer containing MIPS exploit code Ensure buffer copy is terminated by a 0 value after $ra
Buffer Overflow With Code Exploit void foo(char *buf) { char local_buf[256]; strcpy(local_buf,buf); } void main() { char *large_buf =“\x01\x20\x48\x20” /* add $t1, $t1, $zero */ “\x01\x20\x48\x20” … “\x20\x84\xFF\xFF” /* addi $a0, $a0, -1 */ “\x12\x34\x56\x78” /* guess address of exploit */ “\x00”; foo(large_buf); /* location of return from foo() */ }
Example of an Exploit addrStack contents new $sp X-28 allocated by the compiler X-24 allocated by the compiler X-20 N O P (actually: add $t1 $t1 $0) X-16 N O P X-12 N O P X-8 addi $a0, $a0, -1 (\x20\x84\xFF\xFF) X-4 (X – ?) /* the old $ra */ old $sp X…
Detailed Paper Explaining the Exploit