TheRustyFrame
Reverse engineering a PIE-enabled Rust binary to expose hidden execution branches via Ghidra.
Welcome to my writeup for the TheRustyFrame binary exploitation challenge from Breachpoint Online 2026!
The challenge provided a 64-bit ELF binary compiled in Rust. The description hinted at Rust's "safety boundaries" and runtime behavior, suggesting that the solution would require reverse engineering rather than simple memory corruption/exploitation.
Initial Reconnaissance
First, I inspected the binary to understand its basic architecture:
The output confirmed several key details:
- 64-bit ELF
- PIE enabled
- Dynamically linked
- Rust-compiled
Next, I checked the binary's security protections using checksec:
Based on the protections (Full RELRO, NX, and PIE), there was no obvious zero-day stack vulnerability. Memory corruption was highly unlikely to be the intended path.
Runtime Behavior
I started by running the program normally to observe its standard execution flow:
The final syscall in strace showed read(0, ..., which confirmed the binary was halting and waiting for user input from stdin.
I tested the input handling by piping some junk data:
The program exited completely silently. This behavior proved a few crucial things:
- No crash
- No buffer overflow
- No simple string comparison
- Controlled logical branching
So this was definitively not a buffer overflow challenge, but rather a logic-based reverse engineering task.
Static Analysis (Ghidra)
Knowing the runtime behavior, I imported the binary into Ghidra to analyze the logical flow.
Locate the Entry Point
Rust binaries wrap main() inside a massive layer of runtime initialization. By looking inside the entry function, I found the core execution hook:
__libc_start_main(FUN_0010f7d0, ...)
This revealed that FUN_0010f7d0 was the real, underlying program logic isolated from the Rust wrappers.
Analyze the Target Function
Opening FUN_0010f7d0 in the decompiler showed the following control flow:
- Input is read from
stdin. - A logical condition is evaluated against the input.
- Two execution paths branch out:
- The default/fail path prints
"b". - The hidden path prints the flag.
- The default/fail path prints
Crucially, the flag was not stored as plain text during standard strings output analysis, indicating it was either constructed dynamically at runtime or located in a deeply non-obvious memory reference.
By following the cross-references (XREFs) attached to the conditional branches, I was led directly to the function responsible for printing the flag string. The program contained a hidden execution branch that is completely bypassed under normal incorrect input.
Once decompiled, the true hidden string construction was revealed!
The Flag
This challenge successfully demonstrated Rust's heavy runtime wrapping of main, hidden conditional tracking, and how modern protections (PIE, NX) force attackers to rely on deep reverse engineering over basic exploitation.