[pwnable.tw] start — 100pt
As it’s the first challenge of a wargame platform I’d expect a plain shellcode injection. That is reinforced by the binary you’re given. It read 60 bytes from stdin while it has room for only 20 bytes. You’ve executable stack. Plan was to inject some code to do an exec of
/bin/sh, get the shell, search for the flag in the filesystem.
It could have worked. The first problem I encountered was that the shortest shellcode I found was too big and I had an hard time trying to shorten it. Solution: make the shellcode jump to a larger space you have write access as well where you can write the actual shell spawn procedure.
You don’t know the address of stack words so you’ll have to guess. But I assumed ASLR was disabled and I could easily bruteforce lots of values.
I was wrong. After many attempts it was clear ASLR was enabled.
How to solve that? Make the binary leak some informations about the stack… but what?
I started better analyzing what the binary does. It pushes esp, pushes the address of an exit procedure, pushes a string onto the stack, writes it to the stdout, reads 60 bytes from stdin, leave, ret.
Pushing a string onto the stack to print it sounded strange, but who knows?, maybe it was a way to make the binary convoluted.
Turning point was noticing there was no reason for the binary to push esp at the entry point. It was a great hint. You can make the binary leak the stack address via making it leak that esp: you want to print stored esp, jump again into the main function, perform the exploit now knowing more about the stack position.
To do that you’ll need a bunch of rop gadgets. Let’s search for them. I’ve used ROPgadgets.py as I couldn’t make r2 do the search I needed.
Not quite the gadgets one would expect — not
pop;ret stuff. In fact I was confused, ended up ignoring the output above and just checked if jumping back into the main function could lead to the leak of esp.
Long story short, here’s what I come up with: leverage the
write() to the stdout from the stack that was used to print
/bin/sh to print the stored value of esp. To do that, write
0x08048087 into the return address. Binary will now invoke a
read() by which you can write on the stack — inject the shellcode now.
Once popped the shell, it turned out the flag was in
/home/start/flag. Getting it was pretty straightforward.