This weekend, I participated in the AlexCTF competition, hosted by Alexandria University. Overall, this event was easier than many previous CTF’s, with the last challenges being released significantly spiking the difficulty.
As always, I will present writeups for the challenges I found most interesting below:
Catalyst
This challenge was presented as an x86 ELF binary, which you can download here. From initial analysis, the structure of the program is as follows (the functions were not initially named thus, this is from an in-progress IDA session):
We begin our investigation by trying to call the do_flag function directly. Unfortunately, this produces an invalid flag. On further investigation, we note that the flag is derived from the password:
Our first step is to patch out the delay calls. Once done, we can focus on the four “check” functions towards the bottom right. By observing which paramters (corresponding to fgets calls) match which arguments are passed to the functions – we can tell that the first three functions check for the username alone. The first function is reasonably uninteresting:
The next function appears to be a series of linear equations:
From this, we can observe the following:
- The username is likely 12 characters in length, as it is divided up into three 32-bit register-sized chunks for processing here.
- Part0-Part1+Part2 = 0x5C664B56
- (Part0+Part2)*3 + Part1 = 0x2E700C7B2
- Part1 * Part2 = 0x32AC30689A6AD314
Furthermore, we can also determine the valid character set (‘a’-‘z’ + ‘_’) by looking at the third check function.
This is enough to derive the username via a “cheap” brute-force attack – by checking for all the combinations where:
- Each byte of Part1 is a legitimate character
- Part2 = 0x32AC30689A6AD314 / Part1
- Each byte of Part2 is a legitimate character
We can determine that Part1 is “lyst” and Part2 is “_ceo”: making the username “catalyst_ceo”. We can confirm this with a breakpoint at the fourth check function (0x400977), which gets hit:
From here, we can continue on to an analysis of the fourth check function. This check function uses the “username” to seed a PRNG, which is used to generate a series of random numbers to validate the password. No problem, we can simply breakpoint each of the checks, to reveal the password, four characters at a time:
Slowly, bit by 4-byte bit, we build up our password, eventually revealing the flag:
UnVM Me
This challenge was presented as a compiled Python file, which you can download here.
For this challenge, we can use the “uncompyle” utility, which spits out a nice chunk of Python source code, complete with symbols:
From this, we know that the program will accept a flag, and “match” each chunk of 5 characters from a user input (the flag) against a set of known MD5’s – if all of them match, you’ve got the flag.
The solution to this is a trivial efficient brute force of the 5-character keyspace, noting down which “chunks” match the known MD5’s, revealing the flag after a few moments of brute forcing:
You can download the solution script here. It’s not pretty, and requires about 5 minutes of manual “sorting the chunks” after you’re done, but it works.
Unknown Format
This challenge was presented as a packet capture file, which you can download here.
Upon initial analysis, we can see that this is a USB bulk data transfer capture. We begin by reconstructing the file being transferred:
Having recompiled the file,a quick inspection reveals this to be a Kindle Update file – the “SP01” header is a tell for this, and the filenames referencing books are but more confirmation.
Nothing obvious showed up in the file itself, but a bit of Google led to a tool for hiding data within Kindle Update files:
A bit of compiling later, and we are able to extract another file from the original update binary. Unlike the original, this file contains a surprise:
One “-e” argument to binwalk later, and we have another extracted file containing what appears to be garbage. This time, strings reveals success:
Mailclient
This challenge was presented as a GDB core file, which you can download here. The goal of the challenge was to find a username and a password.
Initially, I had no idea how to tackle this challenge. I began by manually inspecting the file in a hex editor, and using “strings” to extract interesting text. From what I could derive, this was a crash dump from the “mutt” mail client (i.e. the clue about this being a Thunderbird crash was a troll).
Initially, I identified some promising content: an email address (alexctf@example.com) and an [sm]tp_pass variable, containing a password:
Unfortunately, sending these yielded no success. My next avenue of attack was to install “mutt”, and try to use GDB to search through the program memory – unfortunately (and logically, in hindsight), this too was fruitless – besides, any interesting data would be contained in the core file, legitimate mutt install or not.
I then applied the power of brute force best force, simply trying to log in to the challenge server with “alexctf@example.com” and each of the strings in the binary as the password:
You can download the brute force script here. The “uniqnotes” file is simply a sorted list of unique strings, generated from the core file.
As always, I would like to thank our hosts, Alexandria University, for putting on this event. I enjoyed the event overall, and I believe this is the first such CTF (at least I didn’t see it last year) – if so, well done for putting together this event and having it run so smoothly.
See you all next week in HackIM / Codegate Qualifiers!
how to generate the “uniqnotes” file from the core file?
strings core.1719 | sort | uniq