BDSec CTF 2025

revME – Reverse Engineering Challenge Writeup | BDSec CTF 2025

Hey crackers, welcome to another write-up!

This time I’m sharing the official solution for revMe, a reverse engineering challenge from the BDSec CTF 2025. I was the author of this challenge, so you’re getting the inside scoop straight from the source.

The challenge was designed to be short but tricky — a small ELF binary that hides its true flag behind a simple but slightly misleading decryption routine. Many solvers found only the “hint” output and got stuck, which was exactly the point.

Initial Analysis

When running the binary, it appeared deceptively simple — it printed BDSEC and exited. That alone was meant to lure players into thinking they had found the flag, when in reality, it was only a hint.

Opening the binary in radare2 revealed that there was only one function present: entry0. This immediately suggested a very small program, likely written in assembly, with no additional functions or library calls.

            ;-- section..text:
            ;-- segment.LOAD1:
            ;-- _start:
            ;-- rip:
┌ 71: entry0 ();
│           0x00401000      488d350d10..   lea rsi, loc.enc_hint       ; 0x402014 ; [01] -r-x section size 71 named .text
│           0x00401007      488d3d0e10..   lea rdi, loc.dec_hint       ; loc.__bss_start
│                                                                      ; 0x40201c
│           0x0040100e      b905000000     mov ecx, 5
│           ;-- decrypt_loop:
│           ; CODE XREF from entry0 @ 0x401023(x)
│       ┌─> 0x00401013      8a06           mov al, byte [rsi]
│       ╎   0x00401015      3205fe0f0000   xor al, byte [loc.key]      ; [0x402019:1]=170
│       ╎   0x0040101b      8807           mov byte [rdi], al
│       ╎   0x0040101d      48ffc6         inc rsi
│       ╎   0x00401020      48ffc7         inc rdi
│       └─< 0x00401023      e2ee           loop loc.decrypt_loop
│           0x00401025      b801000000     mov eax, 1
│           0x0040102a      bf01000000     mov edi, 1
│           0x0040102f      488d35e60f..   lea rsi, loc.dec_hint       ; loc.__bss_start
│                                                                      ; 0x40201c
│           0x00401036      ba05000000     mov edx, 5
│           0x0040103b      0f05           syscall
│           0x0040103d      b83c000000     mov eax, 0x3c               ; '<' ; 60
│           0x00401042      4831ff         xor rdi, rdi
└           0x00401045      0f05           syscall

Disassembling entry0 showed a short loop that loads five bytes from a location in .data (enc_hint), XORs each byte with a single key value from memory (0xAA), and writes the result into .bss (dec_hint). After this decryption loop, the program writes those five bytes to stdout via a Linux syscall and then exits.

At this point, we knew two important things:

  • The XOR key was 0xAA (loaded from loc.key at 0x402019).
  • Only five bytes were being decrypted and printed, yielding the “BDSEC” hint.

The implication was clear — the real flag must be hidden elsewhere in the binary, likely protected by the same XOR key.

Why the .data Section Became the Prime Suspect

With the disassembly in hand, it was clear that the program’s printed output came from a small buffer in memory — dec_hint in .bss — which was populated by XOR-decrypting another buffer, enc_hint, located in .data.

Since .data typically holds initialized global variables, it’s a natural place for small, static payloads to live. In this case, enc_hint was the immediate source of the visible “BDSEC” output. But there were two clues that pointed to more:

  • The minimal code footprint — With only entry0 present, there was no logic to fetch or compute additional data at runtime. If there were more encrypted bytes, they had to be embedded in the binary from the start.
  • The nature of the challenge — The printed “BDSEC” was clearly a tease. It’s common in CTF RE challenges to store the real flag near the hint data, often in the same section, just not referenced directly by the running code.

Armed with this reasoning, the .data section became our first stop in the hunt for the full flag. If more ciphertext was present, decoding it with the already-known XOR key (0xAA) should reveal the hidden treasure.

Finding and Decoding the Flag in .data

With .data as the main suspect, the next step was to inspect it directly in radare2. Running:

iS~.data ## shows the data section memory address 0x00402000
px 0x1a @ 0x00402000 ## shows the content of the data section

showed that the section was only 0x1a (26) bytes long, starting at 0x00402000. What stood out immediately was that enc_hint wasn’t alone — there were many more non-zero bytes following it.

The first five bytes in .data — e8 ee f9 ef e9 — are exactly what entry0 XOR-decodes to print “BDSEC”. More importantly, additional non-zero bytes follow immediately, filling the rest of the section. That’s the giveaway: the real flag is stored as contiguous ciphertext right next to the teaser.

Since we already know the XOR key is 0xAA, our next step is to grab the ciphertext so we can decode it.

px 0x1a @ 0x00402000

The hex bytes shown are the XOR-encrypted flag. With these in hand, we can decode them externally — for example, using a short Python script to XOR each byte with 0xAA and recover the plaintext flag.

cipher_hex = [
    0xe8, 0xee, 0xf9, 0xef, 0xe9, 0xd1, 0xd8, 0x99,
    0xfc, 0xf5, 0xc7, 0x99, 0xf5, 0xeb, 0xd9, 0xe7,
    0xf5, 0xe8, 0xee, 0xd7, 0xe8, 0xee, 0xf9, 0xef,
    0xe9, 0xaa
]

key = 0xAA
plain_bytes = bytes([b ^ key for b in cipher_hex])
print(plain_bytes.decode(errors="ignore"))

Final Thoughts

I hope you enjoyed this official write-up and found it both helpful and instructive. revMe was intentionally designed as a simple, beginner-friendly reverse engineering challenge — something approachable for those just getting started, but still satisfying to solve.

My goal in creating it for BDSec CTF 2025 was to give new players a taste of binary analysis, XOR decoding, and the fun of finding “hidden” data without overwhelming them with complexity.

Happy cracking, and I’ll see you in the next writeup! 🏴‍☠️

0 people love this