Category | Difficulty | Solves | Author |
---|---|---|---|
reverse |
medium |
8 | tetratarius |
Description
We’ve found what we suspect to be one of the hacker’s programs for storing secrets, we believe that a secret key is hidden within the program.
Players are given a file to download: secretman.pyc
.
There are also two hints available:
- Look up what a
.pyc
file is. - Look up how to reverse engineer a
.pyc
file.
Analysis
First, let’s run file secretman.pyc
for some basic information:
secretman.pyc: Byte-compiled Python module for CPython 3.10, timestamp-based, .py timestamp: Sat Nov 19 00:00:40 2022 UTC, .py size: 3308 bytes
.pyc
files like this contain compiled Python bytecode: a machine-optimized form of Python code.
This means we cannot simply open the file in a text editor to read it.
Usually, we can use a decompiler like decompyle3
or pycdc
to try to recover something resembling the original source code.
However, my solution uses a different approach: we’re going to use dynamic analysis instead.
Solution
Note: I’m using IPython for a better interactive shell, but the default Python shell should work as well.
.pyc
files can be imported just like any old .py
file:
In [1]: import secretman
m1n074ur's secrets
1. view all secrets
2. view specific secret
3. enter new secret
5. exit
Enter your selection (#): 5
Exiting...
The program’s main menu appears when we try to import it, so I entered 5
to exit.
(This happens when you don’t use if __name__ == "__main__"
blocks.)
Now, we can use tab-completion to explore the module’s top-level objects:
In [2]: secretman.<TAB>
display_all_sc() main() translate_key()
display_menu() md5() write_sc_to_db()
exists() new_sc() xor()
get_scs_from_db() specific_sc() secretman.pyc
index text
At this point, we’re free to try executing various functions, inspecting global variables, etc.
One function sticks out to me: translate_key()
Let’s try running it:
In [2]: secretman.translate_key()
Out[2]: 'clubeh{tH3s3us_sUcK50rz}'
Huh. That was easy.
Fully-automated Solve Script
Because why not — and it’s even a one-liner!
python -c '__builtins__.input = lambda x: "5"; import secretman; print(secretman.translate_key())' | tail -n1
__builtins__.input = lambda x: "5";
overrides the input()
function so it always returns “5” (to auto-exit the menu).