This week, I participated in the ekoparty CTF. Unfortunately, I wasn’t able to devote too much time to it (with the competition taking place over two work days), but I was able to solve a few challenges.
I will present my solutions for pwn50 and rev250 below, because I found the solutions to these interesting.
Pwn50 – Bleeding
This challenge begins, as many “pwn” challenges do, with a binary file: pwn50_af93ddaf35df98ff.
Upon opening this in IDA, the structure of the binary appears reasonably simple:
- it takes a piece of user input
- adds what appears to be some canary values
- encodes it in a static fashion (does not rely on any random or fetched key material)
- sends it to a server, and
- prints the reply.
However, there is a way of solving this challenge without really understanding what the binary does at all. The name of the bug implies a variation of Heartbleed, and XKCD’s excellent explanation practically gives away how to exploit this (taken from here):
Given that this is the case, we know that in the data which the application sends to the server, it should send some manner of “length” field, which if modified, will cause the server to return a different length of data (presumably containing the key).
We can simply brute force the location of this field, by setting the bytes one at a time to “0xFF”, and seeing what the server replies with. Thanks to the client we are provided, there’s no need to even patch the binary – simply point the binary to a listener on localhost, dump the output into a file, and mutate and send the file to the server. Very quickly, we get our key:
You can download the Python script for mutating the data here.
Rev250 – Fuckzing reverse
You can download the binary here: rev250_7349bb665456cae8.
Opening this executable in IDA, we realize that it reads a bit of user input, and then tries to match the input against a number of conditions. If you pass every check, the executable prints the flag. It is immediately apparent that manual analysis will not be a viable solution:
For this solve, we were able to use the “angr” tool to great effect. Instead of using angr as in previous attempts, we built an angr script which would focus on finding a state where stdout contained what we wanted:
import angr p = angr.Project('FUck_binary') pg = p.factory.path_group() pg.explore(find=lambda p: "Your flag is " in p.state.posix.dumps(1)) s = pg.found[0].state f = open("fuck","wb") f.write(s.posix.dumps(0)) f.close() print "ok"
Note that this is doable with “strings”-level analysis on the binary. Of note, the “s.posix.dumps” function works on file descriptor, so in this case, we simply dump whatever stdin gets us “Your flag is ” on stdout.
As the input we provided isn’t printable, we simply dump this to a file, and then pipe the file to the server for the flag:
One final note: the binary imports it’s get_flag function, so you will need to fake your own libget_flag.so. A simple gcc shared object returning a static value is enough.
Technique – Scrolling up in Screen
This week, I learned it was possible to scroll up in GNU Screen. Specifically, if you press Ctrl-C, and then hit the left square bracket button “[“, you are able to use your arrow keys to scroll up in a screen session. To return to normal operation, hit the Enter button twice. Computers are ~magic~.
I’d like to extend a thanks to ekoparty CTF team / NULL Life for putting on this fantastic event. I had a lot of fun tackling challenges which were outside the usual scope for pwn/reversing, even if I was unable to solve many of them – well done.
See you all at “hack the vote” CTF next weekend 🙂