Cross-Frame Buffer Over-Read via Recursion (Nested Frame Leak)
- •
What it is
- •
Use a recursive call and an over-read to expose values beyond the current buffer, potentially including another active frame's canary or pointers. Verify which frame each leaked value belongs to.
- •
- •
How it works
- •
Trigger recursion and inspect the resulting stack frames. Do not assume their spacing without checking the prologues and call-site stack state.
- •
An unterminated print can walk beyond its buffer only as far as its precision limit and the first null. Intermediate canaries or pointers may stop it.
- •
In the usual Linux challenge setup, another invocation carries the same guard value. Determine which copy is leaked and which overwritten frames will later return.
- •
A longer leak may include pointers or saved return addresses; identify each value before using it for address arithmetic.
- •
High addresses [ parent's frame: canary, saved rbp, saved return addr, other locals ] [ child's frame: saved return addr, saved rbp, canary (own copy) ] [ child's buffer (attacker input) ] Low addresses Over-read direction: buffer -> up through child's own frame -> INTO parent's frame
- •
- •
When to use it
- •
Use when re-entry and an over-read exist but diagnostics do not directly disclose the needed values.
- •
The print bound must reach the desired data, and no earlier null may terminate the string.
- •
Compare leaked pointers with live registers and frame memory in GDB. Their position in the output does not establish their identity.
- •
Reuse a pointer-to-target offset only after confirming the relationship across runs of the same build and call path.
- •
Stack offsets are build- and call-path-specific. Some follow from static analysis; others need runtime measurement. Do not transplant an offset from another challenge.
- •
- •
- •
pwntools
- •
canary = u64(b'\x00' + tail[:7]) # Only after verifying the leak boundary and the seven-byte tail.
- •
- •
Debugging
- •
bt p/x $rbp frame 1 # Compare the live parent frame with leaked values.
- •
- •
- •
Cards
- •
Why does the leaked canary's leading byte need to be overwritten with a nonzero byte for this over-read to work at all?
- •
The canary is deliberately designed to start with
0x00so string-printing leaks stop there — overwriting that leading byte with attacker-controlled data (by padding input to land exactly on it) removes that protection and lets the print continue into the real secret bytes beyond it.
- •
- •
Why shouldn't a leaked pointer-sized value be assumed to be the current frame's saved rbp just because of where it appears in the leaked byte stream?
- •
Its position in the output only reflects memory order, not identity — a debugger comparison ($rbp vs. the leaked value) is needed to confirm which frame (and which specific variable) it actually belongs to before building address arithmetic around it.
- •
- •