Overview
Sunshine CTF 2023 had two reverse-engineering challenges that my team completed (just before time ran out, too!). This post describes my thought process behind Dill, a challenge worth 100 points.
Dill
‘Dill’ provides players with a .pyc file that is unreadable to users. A .pyc file contains the bytecode of the python file, not the source code. The source code has already been compiled, and we need to decompile it to read it. We can also understand what the .pyc file is doing by running it in a debugger,
Luckily for us, this .pyc file can be easily decompiled by a tool called uncompyle.
- It can be downloaded here: https://pypi.org/project/uncompyle6/#files
- Choose the latest .whl file and install like:
pip install uncompyle6-3.2.3-py27-none-any.whl. - You should now be able to type
uncompyle6 --versionvia commandline and receive a version number. - With this tool, we can decompile dill.pyc like so:
uncompyle6 dill.pyc.
Now we have the source code:
|
|
Here is what I notice when reading through the class:
- the prefix and suffix are irrelevant to the encrypted string, since they are just part of the flag for Sunshine CTF.
self.encryptedmust be the encrypted string. We will have to understand how it was created to understand how to decrypt it.- the length of the encrypted and decrypted string is the same (32)
- there seems to be a strange ordering of numbers in array
odeclared at the top candvaluebuild the encrypted string. This is where we will be focusing the most, since we will have to undo this process.
I want to run this script locally to test it first. I removed the class and added a main function. I also wanted to understand what `c` and `value` were doing, so I printed them out.
|
|
Output

Ah, so these blocks of 4 letters have been rearranged according to the order listed in o. To put them back, we have to create a new array that organizes them in order. Since 0 should be the first block and is listed last in the array o, we know that the last index 7 should be printed first. Similarly, since 1 is the second block and is printed at index 1. 2 is the third block and is printed at index 5.
o = [5, 1, 3, 4, 7, 2, 6, 0]
To print the blocks in the correct order again, we will use this new array:
a = [7, 1, 5, 2, 3, 0, 6, 4]
By reordering the blocks, we arrive at the solution:
|
|
Solution output:

Just add the prefix back to the string, and we have the flag!