Scratch Space

Decoded into an mmap'd scratch page and then wiped — reconstruct the pre-wipe state

2026.09.30 NNS CTF 2026 105 pts Reversing
FLAG NNS{s34rch3d_7h3_mm4p_b3f0r3_17_w4s_w1p3d}

This challenge is part of a set written up together in ctf/writeup.txt. Shared context for that set:

All 6 “beginner” tier Reverse Engineering challenges were solved via pure static analysis (radare2 / objdump / Python), no interactive debugging required. Each binary encodes/XOR-obfuscates the flag with a small pseudo-random-number-generator (LCG) keystream, seeded and iterated with constants recovered from the disassembly. Recovering the flag is simply a matter of re-implementing the same PRNG in Python and applying it to the encoded bytes pulled straight out of the binary. Binary: x86-64 dynamically-linked ELF, not stripped.

main() mmaps a scratch page, then decodes a 42-byte blob at 0x404040 into it using an LCG seeded at 0x311023df:

state = state * 0x343fd + 0x269ec3   (mod 2^32)   [classic MS rand()]
ks = (state >> 16) & 0xFF
scratch[i] = blob[i] ^ ks

It then compares user input byte-by-byte against the scratch page, zeroes and munmaps it, and only afterward prints correct/rejected — hence strings/ltrace/strace show nothing. Since the decode again runs unconditionally and only depends on the compile-time seed/constants, we extract the raw 42-byte blob and replicate the LCG in Python — no debugger needed at all.

Flag: NNS{s34rch3d_7h3_mm4p_b3f0r3_17_w4s_w1p3d}