352 words
2 minutes
ApoorvCTF 2026 - A Golden Experience - Reverse Engineering Writeup

Category: Reverse Engineering Flag: apoorvctf{N0_M0R3_R3QU13M_1N_TH15_3XP3R13NC3}

Challenge Description#

You have won, the flag is printing and then you hear it, REQUIEM!!!!!!

Analysis#

The binary looked like a classic stripped Rust executable, so the first thing I wanted was architecture and mitigation context before digging into control flow.

file ./requiem
./requiem: ELF 64-bit LSB pie executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, stripped
checksec --file=./requiem
[*] '/home/rei/Downloads/requiem'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        PIE enabled

That confirmed this wasn’t about memory corruption; it was pure logic recovery. Strings immediately showed the flavor text from the prompt, which was a big hint that output behavior itself was part of the trick.

strings ./requiem | rg -i "loading flag|printing flag|RETURN TO ZERO"
loading flag
i'printing flag.....
RETURN TO ZERO!!!!!!!!

The weird i' prefix before printing flag..... felt like adjacent encoded bytes leaking into a printable area, which ended up being exactly what mattered.

tableflip

Running the program only printed status lines and never showed the visible flag.

./requiem
loading flag
printing flag.....
RETURN TO ZERO!!!!!!!!

At this point the description clicked: the program likely decodes the flag and then wipes it (“REQUIEM” / “RETURN TO ZERO”). So I moved into disassembly and searched for transform constants and loop bounds in the user code path.

r2 -e scr.color=0 -e bin.relocs.apply=true -A -q -c "af @ 0xb9c0; pdf @ 0xb9c0" ./requiem | rg "mov edi, 0x2d|cmp r15, 0x2d|0x000484f4|xor bpl, 0x5a"
0x0000ba0e      bf2d000000     mov edi, 0x2d
0x0000ba40      49c7c7040000.  mov r15, 4
0x0000ba60      40f6f55a       xor bpl, 0x5a
0x0000ba6a      4983ff2d       cmp r15, 0x2d

Those lines gave everything needed: a 45-byte (0x2d) decode loop with XOR key 0x5a. The encoded data source was in .rodata, so I dumped exactly 45 bytes from the discovered address.

r2 -q -c "pxj 45 @ 0x484f4" ./requiem
[59,42,53,53,40,44,57,46,60,33,20,106,5,23,106,8,105,5,8,105,11,15,107,105,23,5,107,20,5,14,18,107,111,5,105,2,10,105,8,107,105,20,25,105,39]

From there the solve was delightfully short: XOR each byte with 0x5a and print.

smug

Solution#

# solve_requiem.py
enc = [
    59, 42, 53, 53, 40, 44, 57, 46, 60, 33,
    20, 106, 5, 23, 106, 8, 105, 5, 8, 105,
    11, 15, 107, 105, 23, 5, 107, 20, 5, 14,
    18, 107, 111, 5, 105, 2, 10, 105, 8, 107,
    105, 20, 25, 105, 39,
]

flag = ''.join(chr(b ^ 0x5A) for b in enc)
print(flag)
python solve_requiem.py
apoorvctf{N0_M0R3_R3QU13M_1N_TH15_3XP3R13NC3}
ApoorvCTF 2026 - A Golden Experience - Reverse Engineering Writeup
https://blog.rei.my.id/posts/111/apoorvctf-2026-a-golden-experience-reverse-engineering-writeup/
Author
Reidho Satria
Published at
2026-03-10
License
CC BY-NC-SA 4.0