This post was written in 2022, but I had never posted it by accident. Published in October 2024.
Introduction
To do a small warming up before the Purple Pill Challenge CTF, we participated in the WPICTF 2022 CTF (online, hosted by Worcester Polytechnic Institute Cyber Security Club). Since the solved reverse challenges were a bit simple, you’ll find in this post a collection of some of them rather than a single one (opposed to the tradition).
Taylor’s Serious Data
This was a (very) simple one. We were given an x64 ELF binary with a text file “songLyrics.txt” that seems encrypted. After opening the binary in Cutter, we can find the encryption routine in the main
function:
As we can see in the decompiler window, the binary takes two arguments:
- An initial file path,
- A file path to store the decrypted version of the first file.
Then, the function load a file from disk (for sure the songLyrics.txt
file), and read it. After that, it retrieves the content size of the file, and start the decryption loop. When dealing with this kind of loop, I prefer to deal with the assembly directly rather the decompiler. After a simple analysis, I found that the decryption loop was:
|
|
As we can see, the Ghidra decompiler was right (this time 😁), and we can write a simple python script that will decrypt the given file for us:
|
|
We then obtain the decrypted version of our file (and the filename was right, it’s a song lyric):
|
|
And we get the flag WPI{TaYl0rs_v3rS1oN}
. This was a very simple warmup, no tricky things here.
xf1ltr80r
Let’s investigate a second challenge. We start with a x64 ELF binary, and since I liked using Cutter on the previous challenge, I’ll continue with it. After opening the binary, we easily find the function containing “data to exfiltrate”:
The padding (==
) at the end of the many blobs of data seem to indicate a base64 encoded string. Let’s retrieve the full encoded string:
|
|
We can now use Cyberchef to perform the operation:
And another flag: WPI{3xtr3m3ly_n#rdy_13375p34k}
. Very trivial.
NeedToCough
This is the last “easy” challenge I did and it was, in my opinion, the best one (still trivial, but the journey was nice and somehow realistic). We start the challenge with a pcap
file that contains multiple HTTP requests and an encrypted file that was a jpg
image. After analyzing some frames, I found that these requests contained a file. Therefore, I exported it using Wireshark:
I obtained (again) a nice x64 ELF binary file. Since it worked well for the previous challenges, I stayed with Cutter here, and analyzed the code. After a high level review on the disassembly, I found that the majority of the code was garbage about a notice drop (ransomware-like), so I focused on the encryption loop. I found four interesting functions:
- One that converts an input to hexadecimal code,
- A second that generates a hexadecimal table (for the permutation),
- An encryption function that uses a permutation table (over hexadecimal),
- And a last one that generates the permutation table.
The part that generates the permutation table is at the beginning of a function that also deals with the notice part (useless here):
As I said before, I prefer to look at the assembly rather than the decompiler code (especially when you see how little code is present). I extracted this pseudo-code used to generate the permutation table:
|
|
I then successfully extracted the two keys key1
and key2
from the binary:
|
|
Since we were in little endian, we needed to convert it before concatenation:
|
|
We do the same with the key2
:
|
|
We can now recreate the algorithm that generates the permutation table:
|
|
Then, we can continue with another easy part, by analyzing the hexadecimal table generation code:
We can translate this assembly function to python:
|
|
As we can see, it’s a complicated code for a simple task, in the end it just generate this string:
|
|
We can now analyze the main encryption loop:
As we can see in Cutter, the permutation loop is very simple, and we can reconstruct it in python:
|
|
We then revert the operation and get this python code:
|
|
Since our image already contains the ASCII representation of the file content in hexadecimal, we can retrieve the initial image with this python code:
|
|
A tip I used to debug this script was checking that we get the magic number of JPEG files for the first bytes. This can also be used to brute force the permutation table (if you don’t like reverse engineering 😉).
After running the script on the provided file (containing the encrypted image to retrieve), I obtained the initial image:
And the flag was WPI{cybercriminals != pentesters}
!
Thanks for this well-made challenge, that were not difficult but well constructed (from Wireshark to reverse).
Conclusion
Those reverse challenges were fun to complete even if a bit too simple. They were a good training for our big event (the Purple Pill Challenge CTF) that were 5 days after this one. Maybe it can help someone getting into reverse 🤷♂️