Mirror Mirror
Mirror Mirror
Platform: Broncoctf2026 | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-11 | Status: Solved Techniques: checker_reimplementation, self_referential_hash, source_code_analysis, xor_keystream_reconstruction
Summary
Task: a self-referential Python flag checker reconstructs the flag at runtime by XORing a hardcoded byte blob with a SHA-256 keystream computed over a 300-char slice of its own source. Solution: ignore the anti-debug guards and re-implement the pure XOR math externally, feeding the same source file so the SHA-256 slice matches.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
broncoctf2026| ID:20260711_broncoctf2026_mirror_mirror - Tags: sha256, python, xor, anti_debug, flag_checker, source_code, self_referential
- Indicators: reads file and hashes a slice of its own source, XOR of hardcoded blob with SHA-256 keystream, anti-debug guards: sys.gettrace, frame name check, name check
- Source:
20260711_broncoctf2026_mirror_mirror.md
Foothold
Vulnerability / Misconfiguration
- Checker_reimplementation
- Self_referential_hash
- Source_code_analysis
- Xor_keystream_reconstruction
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- checker_reimplementation
- self_referential_hash
- source_code_analysis
- xor_keystream_reconstruction
- Tags: sha256, python, xor, anti_debug, flag_checker, source_code, self_referential
Original Writeup
<details><summary>Click to expand original content</summary>Description
"I've been told that this magic mirror will only clear when I give it the flag. Can you help me figure out what I should say?"
A single Python file mirror.py is provided — a self-referential flag checker themed around Snow White's magic mirror. The flag is never stored directly; it is reconstructed at runtime from a hardcoded byte array and a keystream derived from the script's own source.
Recon
The full challenge source:
import sys
import hashlib
def verify(attempt):
try:
with open(__file__, 'r') as f:
src = f.read()
pivot = src.index("MIRROR_SURFACE_DO_NOT_SCRATCH")
specular_map = hashlib.sha256(src[pivot:pivot+300].encode()).digest()
except (FileNotFoundError, ValueError):
return "The mirror has been shattered."
if sys.gettrace() is not None:
return "Nice try, but the glass turns opaque. No observers allowed!"
if sys._getframe().f_code.co_name != 'verify' or __name__ != "__main__":
return "You are looking at the mirror from a distorted angle."
blob = [17, 241, 10, 247, 215, 233, 146, 221, 156, 40, 37, 198, 153, 173, 10, 103, 20, 56, 232, 116, 208, 121, 53, 12, 122, 86, 127, 164, 109, 62, 88, 200, 127, 234, 5]
try:
looking_glass = "MirrorMirror"
flag = ""
for i, b in enumerate(blob):
reflection_byte = specular_map[i % len(specular_map)] ^ ord(looking_glass[i % len(looking_glass)])
flag += chr(b ^ reflection_byte)
if attempt == flag:
return f"The reflection clears!"
except Exception:
pass
return "All you see is a distorted blur. (Wrong Password)"
if __name__ == "__main__":
inp = input("Enter the password to gaze into the mirror: ")
print(verify(inp))
Analysis
The flag is derived, not stored. For each index i:
flag[i] = blob[i] ^ specular_map[i % 32] ^ ord("MirrorMirror"[i % 12])
where specular_map = SHA-256( src[pivot : pivot+300] ) and pivot is the offset of the literal string MIRROR_SURFACE_DO_NOT_SCRATCH inside the source.
Key observations:
-
Self-referential keystream. The marker string
MIRROR_SURFACE_DO_NOT_SCRATCHappears in the source only inside thesrc.index(...)call, sopivotand the 300-char slice are fully deterministic. To reproduce the SHA-256 you must use the exact same source text (byte-for-byte), so keepmirror.pyunmodified when extracting. -
Anti-analysis guards are red herrings. Three checks try to block dynamic analysis:
sys.gettrace() is not None— refuses to run under a debugger/tracer.sys._getframe().f_code.co_name != 'verify'— must be called asverify.__name__ != "__main__"— refuses to run when imported.
None of these matter for a static re-implementation: we do not run the checker at all. We re-derive the pure XOR math ourselves and only feed it the same source file for the hash.
- Theme/joke. The recovered flag
bronco{REDACTED}("who is the fairest reverser") is the classic Snow White magic-mirror line.
Solution
Re-implement the exact computation outside the checker, pointing it at the unmodified mirror.py so the SHA-256 slice matches:
python3 -c 'import hashlib
s=open("mirror.py").read()
p=s.index("MIRROR_SURFACE_DO_NOT_SCRATCH")
m=hashlib.sha256(s[p:p+300].encode()).digest()
b=[17,241,10,247,215,233,146,221,156,40,37,198,153,173,10,103,20,56,232,116,208,121,53,12,122,86,127,164,109,62,88,200,127,234,5]
k="MirrorMirror"
print("".join(chr(x^m[i%len(m)]^ord(k[i%len(k)])) for i,x in enumerate(b)))'
Output:
bronco{REDACTED}
Verification against the unmodified checker (so all guards pass naturally):
printf '%s\n' 'bronco{REDACTED}' | python3 mirror.py
# Enter the password to gaze into the mirror: The reflection clears!
</details>
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR