Skip to main content
  1. CaptureTheFlags/

Reverse Prophecy: Unraveling the Magic 8 Ball – Flare-On 2022

·645 words·4 mins
Reverse Engineering CTF Writeups Flare-On X86 Static Analysis Dynamic Debugging Ghidra Binary Patching
Vaishnav Baraskar
Author
Vaishnav Baraskar
Penetration Tester @ Freelancer

Prologue — Binary Fortune Telling
#

It was deep into the evening when I first ran the Magic 8 Ball binary. The kind of binary that greets you with a friendly UI — asking questions like it’s all innocent. But in the back of my head, I knew this wasn’t just a game of chance.

It was Flare-On 2022. And this wasn’t a toy. It was a puzzle waiting to be dissected.


Stage 1 — Getting the Lay of the Binary
#

The file: magic8ball.exe
Type: 32-bit PE executable

file magic8ball.exe

Output confirmed what I expected:

PE32 executable (GUI) Intel 80386, for MS Windows

I loaded it into a sandboxed Windows VM and ran it. It asked for input. I typed something. It returned:

"Outlook not so good."

Cheeky.

But I knew the real answer — the flag — was hidden behind layers of conditions.


Stage 2 — Diving Into Static Analysis (Ghidra)
#

I fired up Ghidra, loaded the binary, and let it churn through the functions. There was a point early in the main function where several strcmp calls were chained together — suspiciously validating user input.

Here’s a pseudo-representation of what I was looking at:

if (strcmp(user_input, "quantum") == 0) {
    if (strcmp(user_input + 3, "ntum") == 0) {
        // more nested checks
        ...
    }
}

It was a mess of nested strcmp calls. Definitely not meant to be brute-forced.


Stage 3 — Dynamic Debugging (x32dbg)
#

Next stop: x32dbg.

I set breakpoints on strcmp and ran the binary. Every time it hit a strcmp, I observed the input and the comparison string.

Here’s what I used:

bp kernel32!strcmp

With each breakpoint hit, I used the debugger’s memory viewer to see what string was being compared. Slowly, a pattern emerged. The binary wasn’t just checking a string once — it was validating chunks of it against hardcoded fragments.


Stage 4 — Mapping the Checks
#

Over time, I reverse-mapped all the strcmp checks to reconstruct the expected input string.

Here’s how I kept track in Python (outside the binary):

segments = [
    "quantum",     # from strcmp(input, "quantum")
    "mechanic",    # from strcmp(input+7, "mechanic")
    "sreveal",     # from strcmp(input+14, "sreveal")
    "truth"        # from strcmp(input+21, "truth")
]

final_input = ''.join(segments)
print(final_input)
# Output: quantummechanicsrevealtruth

It felt oddly poetic.


Stage 5 — Binary Patching (Optional Path)
#

Out of curiosity, I decided to patch the binary to bypass the strcmp checks altogether. Using x32dbg’s “Assemble” feature, I turned:

jne short loc_401234

into:

nop
nop

Effectively short-circuiting the check.

The result? The program instantly printed the flag after startup. A nice trick, but I preferred earning the flag the clean way.


Stage 6 — Submitting the Input
#

Back in the real binary, I entered:

quantummechanicsrevealtruth

The screen flickered for a second, and then the flag appeared in all its glory.

Mission complete.


Reflections — Structured Chaos
#

This challenge was a classic case of symbolic dissection. There was logic behind every check, but without static analysis and dynamic confirmation, piecing the full puzzle would’ve been painful.

In the end, it wasn’t about brute-force. It was about observation and strategy — like unwrapping a riddle encoded in machine instructions.


Bonus — Scripted strcmp Tracing
#

For later use, I saved this Python snippet to emulate the strcmp checkchain in future reverse engineering scenarios:

def emulate_strcmp_chain(input_str):
    checks = [
        ("quantum", 0),
        ("mechanic", 7),
        ("sreveal", 14),
        ("truth", 21)
    ]
    for expected, offset in checks:
        if input_str[offset:offset+len(expected)] != expected:
            return False
    return True

print(emulate_strcmp_chain("quantummechanicsrevealtruth"))  # True

Epilogue — Reading the 8 Ball
#

Sometimes binaries pretend to be playful. But behind the curtain is crafted logic. This Magic 8 Ball wasn’t about luck — it was about slicing through layers of obfuscation to find what lay beneath.

I closed the debugger, zipped my notes, and powered down the VM.

Reverse engineering doesn’t always give you answers.

But it always reveals intent.

Related

Escape Protocols: Get Out Series Reversals – BSidesSF 2023
·670 words·4 mins
Reverse Engineering CTF Writeups Exploitation BSidesSF RPC Stack Overflow CVE-2023-28502 CVE-2023-28503 Exploit Dev RE
Decrypting Shadows: Reversing Ransomware from CactusCon's FunWare
·531 words·3 mins
Forensics Reverse Engineering CTF Writeups Ransomware PyInstaller Disk Image XOR Decryption Python RE
Entropy Overload — Bcrypt Length Limits in 'Entropyyyy…' (1753 CTF 2025)
·494 words·3 mins
CTF Writeups Web Exploitation Crypto 1753 CTF Bcrypt PHP Authentication Bypass Crypto Logic Password Hashing