Link: https://wargame.whitehat.vn/Challenges/DetailContest/143
Points: 200
Category: Forensics

Description

http://material.wargame.whitehat.vn/contests/11/for1_206e72e52f2f73fa1a1080b70d528657.zip
nc 118.70.80.143 7337

tl;dr

https://codisec.com/veles/.
Zip archive containing disk image. Mount it with ntfs-3g. There is a binary file and after looking for deleted files you can also find a .pyc file. Turns out the python code is a custom RSA implementation. It also includes code to contact server and query it for public key. After implementing function to decode files encrypted with python app we can use it to retrieve jpeg image from the first file we found on the disk image. The flag is visible on the image.

Solution

The first part of this task was done by Jakub, the second by me. So I’m basing the initial part on his notes.

In this task we got a zip archive. After unpacking it we see a single file:

Hmm, looks like a this image. Maybe we can mount it?

Ok, so we have a file. But it’s just some binary data, no idea what to do with it. Maybe we can get something more? After a few minutes of googling we know enough to try it.

Nice, we got a .pyc file. We can now recover it using uncompyle2. At this point Jakub said the he has some python file to analyse, so naturally I jumped on a chance to work on it 🙂

Turns out encrypt.py is a custom implementation of RSA. The code is somewhat obfuscated, with a bunch of dead code, some unused variables with strange values, etc. After reading the main function it is pretty clear that running it will encrypt all files in the current directory subtree, which matches the list of extensions defined in the code (.doc, .docx, .mp3, .txt, .jpeg, …). So instead of going deeper into the code I just created a directory with a single .txt file containing aaaaaaa. I’ve added a bunch of breakpoints in code using pdb and just printed out the exponent, the modulus and the data after each step of the algorithm (how it’s encoded to a number, padding, etc).

It looks like the program is reading the file in 100 byte chunks, encrypting each chunk and writing it to a resulting .encrypted file. However, it also appends some additional data after each chunk. This additional bytes are generated by the below function:

Like the rest of the code this function is intentionally complicated, but all it really does is return the #$%&'()*+,-./:;<=>?@\x0f\x15.

Interestingly the encrypt.py script also has a decrypt method.

Ok, looks like all it does is contact a remote server and get us the RSA private exponent. And that’s really all we need – with private exponent we can decrypt the RSA and that is the only one-way function in the script. For everything else we can just write a reverse function.

After some coding I have a script that can decrypt the simple text file I encrypted earlier. It also works with a larger “lorem ipsum” text file. Ok, let’s try something more difficult – a .png image of a cat. That one didn’t work out so well. It took me some debugging to find out that there is no logic in encrypt.py to add padding in case of RSA result being small enough to produce a hexstring at least 2 character shorter than expected).

Finally I managed to write a working decryption script:

Running this script on the encrypted file we found on the disk image produced a JPEG image:
flag

Later Jakub pointed out to me that the last step (padding) wasn’t really necessary. Without it the resulting jpeg was a bit garbled, but still easily readable.


Leave a Reply