My previous experience with exploitation from the IO wargame on Smash the Stack led me to choose this challenge as my first target in the CSAW competition.
The challenge text is such:
nc 22.214.171.124 54321 Read the key out of ./key in the current working directory.
Okay, lets run the command and see what type response we get. Note: on my machine `nc’ is `ncat’ because I am using the version that comes with nmap:
I’ll take that misspelling as subtle humor. This seems pretty straight forward: we give the program a specially crafted input name and it gives us the key. Time to investigate the executable.
Binary Analysis: Preliminary
Nothing too interesting there, but I’m happy to see it’s 32 bit (and therefore runnable on my system). Next I use the `strings’ command to extract all the referenced text strings from the program:
I’ve only included the most important entries. It looks like the binary is accessing the key file, so we probably don’t have to do it. The calls to recv and strcmp are important because that’s where our input will be processed. The last string seems to be a big hint as to what we should type in. First, lets create a test key file:
$ echo "ABCDEFG" > key
Okay, lets start up the server and test our find:
and on a different terminal:
Wow. That was simple. Lets try it on the flag server:
Well no joy there. It looks like the server has a different passphrase than our client. Now we need to start to debug. Before we jump in to the debugger, I want to stress test the program a little. Lets do some tests:
That misspelled welcome is starting to annoy me. So we sent 511 B’s and nothing happened. 512, on the other hand yielded us the key and 2000 was not completely read by the program, causing an improper disconnect. At this point we could call it a day and move on, but I want to know why this worked.
Binary Analysis: GDB
Lets debug the server:
The server’s main function creates a listening socket and forks a new process when a connection is received. Handle is called for further processing on the new connection. Lets disassemble in chunks:
Allocates stack space for a buffer and a sets a boolean variable to false.
Sends the user the input prompt and receives the response.
NULL terminates the end of the buffer and compares it to the passphrase.
Checks to see if strcmp returned 0. If it did, then do not jump and set the boolean variable to true. If the boolean is false, then jump to the end.
If the boolean was true, read in the key from “./key” and send it to the user.
The vulnerable code is at <+109>. The recv call reads in 4 more bytes than the buffer was allocated for, therefore overwriting the boolean (ebp-0xc) determining if the passphrase was correct. Lets see this in action:
The 4 extra A’s have now overwritten $ebp-0xc.
Nothing happens. The program is safe.
On 512 A’s, the new line that was read in from recv changed the boolean to true, therefore giving us access to the key.