Know Meh Better
Decompile a PyInstaller executable to reverse engineer an XOR encryption routine and recover a hidden base64-encoded flag.
Flag: HQX{2483296533b73b50eb2cde9245401d74}
Approach (Step by Step)
- The challenge provided a Windows executable named
know_meh_better.exeand a text file namedoutput_bBe4FD65f8.txt. - I started by using
pyinstxtractorto decompile the executable, which is a common approach for Python binaries packaged with PyInstaller:python3 pyinstxtractor.py know_meh_better.exe - This successfully extracted the
.pycfiles into a directory. The main logic of the challenge was located inknow_meh_better.pyc. - I then used
uncompyle6to decompile the.pycfile back into readable Python source code:uncompyle6 know_meh_better.pyc > know_meh_better.py
Analyzing the Source Code
- The decompiled script revealed a questionnaire-style challenge containing fake trivia questions about the author. A
FLAGvariable was present, but it was just a fake flag (HQX{fake_flag}). -
However, the script contained
encode_flaganddecode_flagfunctions, which used an XOR-based encryption routine:slt = len.__doc__ def encode_flag(flg): encoded = ('').join([chr(ord(flg[i]) ^ ord(slt[i % len(slt)])) for i in range(len(flg))]).encode('utf-8').encode('hex') return encoded def decode_flag(flg): encoded_bytes = flg.decode('hex') decoded = ('').join([chr(ord(encoded_bytes[i]) ^ ord(slt[i % len(slt)])) for i in range(len(encoded_bytes))]) return decoded - The script relies on the docstring of the built-in
lenfunction (len.__doc__) as its XOR key (slt). - Let’s look at
output_bBe4FD65f8.txt:0123322c1714694427216d173a393b543f5a210f6e133a0c23276205374a2b4a39283b412c033f543c6a131d2e31115e4625==The
outputfile contained a hex string, but it was oddly appended with==. Hexadecimal encodings do not use padding characters like base64 does.
Decrypting the Flag
-
I created a custom Python script to replicate the decryption routine, keeping in mind that the
==might have been unintentionally excluded from the hex conversion but was part of the original encoded string (like a base64 payload).slt = len.__doc__ def decode_flag(flg): if flg.endswith('=='): # Remove the base64 padding to decode the hex part flg = flg[:-2] # Convert the hex string to bytes encoded_bytes = bytes.fromhex(flg) # XOR each byte with the key (len.__doc__) decoded = "".join([chr(encoded_bytes[i] ^ ord(slt[i % len(slt)])) for i in range(len(encoded_bytes))]) return decoded ciphertext = "0123322c1714694427216d173a393b543f5a210f6e133a0c23276205374a2b4a39283b412c033f543c6a131d2e31115e4625==" print(decode_flag(ciphertext)) - Running the script gave the output:
SFFYezI0ODMyOTY1MzNiNzNiNTBlYjJjZGU5MjQ1NDAxZDc0fQ. -
Appending the missing
==padding and decoding the resulting base64 string (SFFYezI0ODMyOTY1MzNiNzNiNTBlYjJjZGU5MjQ1NDAxZDc0fQ==) revealed the actual flag!echo "SFFYezI0ODMyOTY1MzNiNzNiNTBlYjJjZGU5MjQ1NDAxZDc0fQ==" | base64 -dResult:
HQX{2483296533b73b50eb2cde9245401d74}