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:
Binary Architecture
$file rusty_frame_S6NV0Zx
rusty_frame_S6NV0Zx: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, Rust-compiled, stripped
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:
$checksec --file=rusty_frame_S6NV0Zx
[*] '/root/rusty_frame_S6NV0Zx'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
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:
$./rusty_frame_S6NV0Zx
b
$strace ./rusty_frame_S6NV0Zx
...
read(0, ...
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:
$echo AAAA | ./rusty_frame_S6NV0Zx
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.
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.