Malware Analysis 101
Malware Analysis 101 — Writeup
Summary
This challenge hides the flag in malware_analysis_101/flag.txt.ctf behind a two-stage Python loader.
The important result: the candidate flag is correct.
Static analysis
recon.md pointed to two key artifacts:
malware_analysis_101/Free_Robux_glitch.pymalware_analysis_101/flag.txt.ctf
From the source, line 588 is the critical obfuscated loader. It defines:
- an outer key (
aowirngoiarwngoarw) - a decryptor lambda (
oanwgoiranwognawiogn) - an embedded ciphertext blob (
awoignbawouibgioawiog)
The exact chain is:
aowirngoiarwngoarwis recovered from a YouTube page embedded in the obfuscated expression.- That outer key decrypts the embedded stage blob.
- The stage blob is another Python payload.
- Inside that stage payload, a second key (
awroujaw) is constructed. flag.txt.ctfis decrypted bybase64.b64decode(...)then repeating-key XOR withawroujaw.
Discrepancy resolved
Earlier findings mixed up two different keys:
- Outer runtime-derived key:
df9f190f1c9f5e9bffe17626145220ff- Used only to decrypt the embedded stage payload.
- Embedded stage key:
e888fb9f04ff82e23fc448ee6fb66722- Used to decrypt
flag.txt.ctf.
- Used to decrypt
Only the embedded stage key matters for the flag file.
Decryption chain
1) Outer stage
Free_Robux_glitch.py evaluates an obfuscated import chain that resolves to requests, fetches a YouTube page, and extracts the outer key string.
Recovered outer key:
df9f190f1c9f5e9bffe17626145220ff
That key is then used by the reverse lambda to decrypt the huge embedded blob at line 588 into a second-stage Python script.
2) Inner stage
The decrypted stage script defines its own key:
e888fb9f04ff82e23fc448ee6fb66722
The stage decryptor is equivalent to:
plaintext = base64.b64decode(ciphertext)
result = ''.join(chr(plaintext[i] ^ ord(key[i % len(key)])) for i in range(len(plaintext)))
3) Flag file
flag.txt.ctf contains:
I2FoezIkC1BLegkJV10KbVo5BFtAZxcEWBUNW0FWQFc6UVZLEgdYAm9bADleQABXbDQMVkFAGA==
Decoding it with the stage key yields:
FYPCTF26{Nooooo_i_got_ransomware_instead_of_free_Robux}
Verification evidence
The decisive offline check was:
import base64
ct = "I2FoezIkC1BLegkJV10KbVo5BFtAZxcEWBUNW0FWQFc6UVZLEgdYAm9bADleQABXbDQMVkFAGA=="
key = "e888fb9f04ff82e23fc448ee6fb66722"
raw = base64.b64decode(ct)
flag = ''.join(chr(raw[i] ^ ord(key[i % len(key)])) for i in range(len(raw)))
print(flag)
Output:
FYPCTF26{Nooooo_i_got_ransomware_instead_of_free_Robux}
Minimal replayable offline steps
- Read
recon.mdto identify the two files. - Inspect
Free_Robux_glitch.pyline 588 for the obfuscated outer decryptor. - Recover the outer key and decrypt the embedded stage payload.
- Extract
awroujawfrom the stage payload. - Base64-decode
flag.txt.ctf. - XOR the decoded bytes with the stage key, repeating the key as needed.
Final flag
FYPCTF26{Nooooo_i_got_ransomware_instead_of_free_Robux}