tiny_easy was a great example of how you can still put a large amount of complexity into a challenge that’s only 4 instructions. If you haven’t tried the challenge on your own make sure you check out at http://pwnable.kr/play.php . This write-up contains spoilers, consider yourself warned!
The challenge starts by prompting you to ssh into a box running Ubuntu. I tried cat-ing /proc/sys/kernel/randomize_va_space and it looks like they left ASLR enabled. Excellent.
1
|
|
Looks like the executable is a pretty standard pwnable. It’s a setuid binary where the objective is to call setuid and then spawn a shell so you can cat the flag.
I decided that it would be easier to work with the executable locally so I scp-ed it onto my own hardware.
I started the analysis by running file on the executable. This actually yielded two important pieces of information. First, the executable is statically linked. Second, the executable has a corrupted section header size. Both of these will come into play later during exploitation.
This is where analyzing the executable starts to become more difficult. Running objdump on the executable didn’t dump any instructions! I am not entirely sure why this happened. My best guess is that since the executable didn’t contain a section header table, objdump just gave up on doing any disassembly.
So it was time to be creative! I decided that the easiest way to get to the instructions would be to load executable into gdb and place a breakpoint on the executable’s entry point. I was able to get that entry point using readelf, which does a pretty reliable job of parsing through the elf header.
Some other interesting information we get from readelf is the fact that the program header and the elf header compose (32+52) = 84 out of the 90 bytes in the program. This means that there are only 6 bytes worth of executable instructions in the file.
My gdb is slightly more colorful than the one most people are familiar with. Its actually gdb-peda you can check it out here: https://github.com/longld/peda “Python Exploit Development Assistance for GDB” makes exploitation significantly easier.
tiny_easy doesn’t even bother trying to create a stack frame. Instead it pops argc into eax, pops a char pointer (argv[0]) into edx, dereferences that pointer/stores its contents into edx, and then finally it calls edx. When we type c and tell the program to continue, it does exactly what we expect it to: segfault. Let’s take a look at the registers at the time of the crash.
Once again nothing surprising here. The program crashes at the first 4 ascii characters of argv[0]. After quite a bit of googling it turns out that the built in command exec in bash lets you modify the value of argv when executing.
By opening up the core dump in gdb we can see that we got it to crash to 0x42424242 W00t!
But we are not quite done yet. Actually we are far from done! Now that we control the value of eip where should we tell it to go?
ASLR makes this tricky and we can’t really use return oriented programing since our 6 byte program doesn’t call any functions. Since the program is statically compiled we don’t even have any dynamic libraries/a GOT we can poke around with.
I decided to depend on an extremely messy technique influenced by some old write-ups I’ve read for IE6. Quite a few IE6 exploits use “heap spraying” to get code execution.
1 2 3 4 5 6 |
|
The idea here is you fill the heap with NOPS followed by shellcode and hope you land somewhere in the middle of one of the sleds so you can slide into your shellcode.
We are going to apply the same technique here but instead of spraying the heap we are going to spray the stack. I decided to use environmental variables to do the spraying.
1 2 3 4 5 |
|
It took two tries before I was able to get successful code execution.
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 |
|
Success! Time to claim the spoils of victory
1 2 |
|