This weekend, I participated in the SharifCTF event. This was a 48-hour CTF organised by the Sharif University, and was an enjoyable event after two weeks of effectively not capturing any internet points at all. I will present three writeups (plus a bonus “writeup”) here, as follows:
Misc50 / Playfake
This challenge was presented as a Python file, which you can download here. This is a modified implementation of the Playfair cipher: we are given a ciphertext, and we are required to generate the original plaintext and use the make_flag function to generate a flag to submit.
As per Wikipedia, the Playfair cipher is a symmetric cipher, based on a key square which is used to perform digram replacements:
In this case, the ciphertext is a bit too short for meaningful cryptanalysis, so we will need to recover the original key square. Fortunately, the original code provides some assumptions to make this journey a bit easier:
- The key length is 5, the key is wholly alphabetical and uppercase
- The words “SharifCTF” and “contest” are in the original message
- The message consists of alphabetical characters, or whitespace characters, and no other characters.
Given the short key length, we can quickly apply brute force (best force) to solve this challenge. You can find the completed brute-force script here, which can be run to generate the flag:
This works by simply brute-forcing the “key”, and using make_key to generate the corresponding key square, reducing our search space to 26**5 characters.
for150 / strange_pdf.pdf
This challenge is originally presented as a PDF, which you can download here: strange_pdf
Opening this up in a text editor reveals a series of seemingly unobfuscated objects, but visual inspection of the PDF reveals no flag:
Opening the PDF up in a text editor, we can notice the content being displayed represented in object 5. Curiously enough, object 3, representing the “page”, contains a “Contents” item, referencing only object 5 – no reference can be found to any of the other objects, which appear to be vector objects.
My first attempt to solve this challenge was to combine all the objects into a single large object, by tacking the “draw streams” onto the end of Object 5, as follows:
5 0 obj << /Length 359 >> stream q 10 0 0 10 250 400 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do 0.7 0.5 -0.5 0.7 0 0 cm /A Do Q 2 w 100 650 m 100 620 l 100 615 m 100 585 l 120 650 m 140 650 l 140 645 m 140 625 l 120 620 m 140 620 l 120 615 m 120 595 l 120 590 m 140 590 l 160 650 m 180 650 l 180 645 m 180 625 l 160 620 m 180 620 l 180 615 m 180 595 l 160 590 m 180 590 l S 2 w 100 650 m 100 620 l 100 615 m 100 585 l 120 650 m 140 650 l 140 645 m 140 625 l 120 645 m 120 625 l 120 615 m 120 595 l 120 590 m 140 590 l 140 615 m 140 595 l 160 650 m 180 650 l 180 645 m 180 625 l 160 645 m 160 625 l 160 615 m 160 595 l 160 590 m 180 590 l 180 615 m 180 595 l S ... blah blah blah all the other objects... endstream endobj
Unfortunately, after combining all 34 objects, I was met with the following:
This was puzzling, as I was expecting at least 33 characters to show up, if not more (as each object from 7 onwards appeared to “draw” at least one character. I then noticed that these were drawing characters over the same coordinates, meaning that I could only display one at a time.
A little while of copy and paste later, I had retrieved the numbers drawn by each PDF object individually. These turned out to be the decimal representation of characters in a flag (the giveaway was 123/125 at the ends):
There is no meaningful solution to download for this challenge – unfuck.py was a simple integer-character conversion script. Try it yourself!
rev300 / Login.apk
This challenge was presented as an APK file, which you can download here. I made a specific point of attempting this challenge, as I am generally terrible with mobile-related challenges and need to improve greatly in this area.
On retrieving the APK, our first step is to extract it, as a zip file. This reveals the insides of the APK file, including the “classes.dex” file which we decompile:
From here, we can use the dex2jar toolkit to convert the “classes.dex” file to a Java archive. We can then use any number of Java decompilers to inspect the application with more clarity. In this case, I used jd-gui:
From here, we can tell that a native function is being used to perform the bulk of the “logic” behind the application. We can continue our investigation of the application’s native libraries: in the “lib” folder in the apk archive, a a variety of precompiled libraries are helpfully provided. We will look at the x86 version, for simplicity, called “libhidingutil.so”.
Opening inspection in IDA Pro, 2 things immediately stand out. Firstly a “_value_with_key” function:
Also, a single base64-encoded string:
I assumed that this base64 string was being used along with the password (“My_S3cr3t_P@$$W0rD”) somehow. Luckily, a quick google of “My_S3cr3t_P@$$W0rD” reveals the source code to the original algorithm, which boils down to XOR, matching the disassembly above.
A quick Python script can be used to apply the XOR again, revealing the flag, for an easy 300 points. One “gotcha” is that on my first attempt, my XOR key appeared to be one character short – this is because the original implementation included the final null byte in the XOR key.
rev100 / repairme.exe
This challenge was presented as an executable, which you can download here.
This runs perfectly in wine, immediately revealing the flag (and 100 free points):
Hacking accomplished, fuck yeah.
As always, I’d like to thank Sharif University for putting together this event – the challenges were fun, and I look forward to eventually solving the ones I didn’t manage to complete in time.
If I might offer a bit of feedback – I feel the “format string 1/2/3” challenges were poorly explained, leaving many of us stumped as to what we were actually trying to do. The scoreboard reflects this, with many teams (including some top teams) scoring only 50 points in the “pwn” section.
See you all in the 33C3 CTF.