Sunday, September 27, 2015

Trend Micro CTF was this weekend. This is the first one of these Trend Micro CTF I've done and I was expecting it to be really well run and fun.

I was pretty surprised to see the real situation though. I felt the difficulty scaling was all over the place and just too many guessing games. Also a lack of communication with no official IRC channel and only a couple of tweets from Trend throughout the day.

Anyway, I still am determined to document at least one solution per CTF so here's the one I decided because I liked the idea.

This is in the Analysis-Defensive category, which is essentialy the same as any other CTF's Reverse Engineering category. We are given a ZIP file containing a single file called "vonn":

(Oh the program deletes itself also, just a tip, make a backup of it first)

Which doesn't say a lot but is a good clue. Trend Micro being a company related to AV has probably dealt with VM aware threats quite a lot. So perhaps this program uses a trick to determine if it's on a VM and behaves a certain way because of it.

Ok this is looking familiar no? This is the same main function as the dropper ("vonn") except there are no printf() messages and the non-VM function looks to be doing the work this time.

So the solution becomes clear at this point. The challenge is a two part binary. A dropper and an encrypted payload. When run on a VM the dropper will decrypt the payload, however the payload will only perform it's duties on a non-VM system.

To get the flag we only need to run the payload on a bare metal system.

Unfortunately I don't have that ready to hand, so I resort to patching the payload. In the graph view I identify an easy "JZ" instruction I can flip to a "JMP" instruction to take our desired execution path:

This JZ lives at address 0x400a33 in memory so let's use pwntools to patch that to a JMP and execute the patched version:

Monday, September 21, 2015

It's been a long break between the last CTF I wrote up and now. To be honest there has been a bit of a lull in the number and quality of CTFs since earlier in the year. It seems they are starting up again though and that's great news.

This weekend our team took part in CSAW 2015 Qualifiers round and finished a respectable 124th or so out of 1000 or so teams by scoring 2,210 points. I'm happy with that but more happy with the way the team worked together. Great job guys.

So a remote server listening on port 12012 and a file called "ftp", we perform the usual first steps. Download the file, use "file" command, use "strings" to check for simple flags.

We found it was a Linux ELF binary for 64bit architectures. Given this is a reverse engineering challenge I placed the file directly into IDA Pro to browse the disassembly while starting the process on a local system. It's written quite well (for a CTF program!) so it starts up first try and listens on port 12012 on localhost.

Upon connecting we see a welcome banner, I try the usual FTP commands such as USER and PASS and these work correctly. I don't have a valid username yet so let's check out those functions in IDA Pro to see how authentication works.

In IDA Pro I first open the Strings sub-view and find a nice easy string related to authentication. I found one called "Please send password for user". I double click this string and then follow the Data Xref to a function "sub_40159B".

This function seems to be taking the username and password, then validating them against stored constants. In the IDA Pro decompilation, the authentication mechanism looks like this:

So I've already renamed some of those functions in the snippet above, what it's doing is validating that your username is "blankwall" and your password hashed is equivalent to 0xD386D209.

Next I built a quick and dirty "FTP Client" in Python to send username "blankwall" with a password of "ABCDE" to see how the hash function deals with that. I located the hash function at sub_401540 and set a breakpoint there in GDB w/PEDA.

Note: You have to be careful when debugging this program as it fork's a new process ID for each connection, so I only attach the debugger after sending my username (but before sending my password).

I found that this function performs what I later found to be called "multiplicative hash" on the user input. It also uses a modulus to prevent overflowing the integer. Since a modulus is used, reversing the algorithm to "decrypt" the stored password value of 0xD386D209 is not possible as information is destroyed during the hashing process.

So the only way to recover the password I thought was to recreate the algorithm exactly and then brute force inputs until my hashed output was 0xD386D209! In order to do that I found the decompiled version of the function to be a good starting point:

However for me stepping through the binary in PEDA instruction by instruction gave an even simpler explanation of what the function was doing to the input as we can see the hash function building the output in the RAX/RCX registers. Here is the code I worked on. It prints the hash value after every calculation. This enables me to follow along with GDB to ensure my implementation of the multiplicative hash algorithm is correct.

Once I had this function implemented in Python, I used the magic itertools Python module to calculate every combination of alphabetic characters. I tried 4,5 and finally 6 character passwords before finally striking gold and finding that the password "cookie" hashes successfully to 0xD386D209. I used this code for that:

Now we had the password I was able to login. After login though I was again stuck. We could use the LIST command to view the files stored on the FTP server but the usual FTP command "RETR" to retrieve files seemed to be bugged and kept throwing up "Invalid characters" error message.

Back to IDA Pro. At this point I spent an hour or so reversing the RETR command to find out what I needed to fix to get it to send me a file. To no avail really. Then I regrouped my thoughts and approached the problem from another angle. What if the solution was built into the FTP server itself.

A quick few minutes later and I identified the function "sub_4025F8" which seemed to only exist to give a flag called "re_solution.txt" to connected clients! Great! This function is only called from one place too. In fact it's only ever called in response to entering a simple command in the FTP server:

So back to the server we went, logged in with our found username, cracked password, and knowledge of the command, and we were rewarded with the flag!