shakespeares-revenge
b01lersc
Task: reverse a custom Shakespeare interpreter that exposes a single syscall through stack-based scenes. Solution: abuse its 32-bit word stacking and the 0xffffffff cstring substitution to place /bin/sh on Romeo's stack, forge Hamlet's stack for execve, then interact with the spawned shell to read /app/flag.txt.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
shakespeares-revenge — b01lers CTF
Description
The Infamous Hello World Program.
Romeo, a young man with a remarkable patience. Hamlet, the flatterer of Andersen Insulting A/S.
The provided file was a Shakespeare-style program executed by a custom ELF interpreter. The goal was to understand the VM well enough to turn its single exposed syscall into code execution and then retrieve the flag from the remote service.
Analysis
The key bug was not memory corruption but runtime semantics.
- The interpreter keeps separate Romeo and Hamlet stacks.
- Values are really handled as 32-bit words. Pushing a 64-bit constant stores
high32first, thenlow32. - In the main challenge loop, arithmetic branches (selectors
2/3/4) pop only the top two Romeo words and push the result onto the Hamlet stack.
That means each arithmetic operation can do two things at once:
- consume carefully chosen low words to build future syscall arguments on Hamlet's stack;
- leave the corresponding high words behind on Romeo's stack in a controlled order.
The final syscall scene has another important quirk: if an argument is 0xffffffff, Hamlet replaces it with reference_stack_cstring(). Because Scene I does Reference Romeo., that cstring actually comes from Romeo's stack, not Hamlet's.
So the exploit strategy was:
- use arithmetic scenes to prepare Hamlet's stack for
execve(path, argv, envp); - simultaneously leave bytes for
/bin/sh\x00on Romeo's stack; - call the syscall with
path = 0xffffffff,argv = 0,envp = 0; - let the runtime resolve
0xffffffffinto a Romeo-stack cstring pointing to/bin/sh.
This spawns /bin/sh over the same socket. From there, the remaining work is operational:
...
$ grep --similar
Similar writeups
- [pwn][Pro]KHP Protocol Challenge Scenario— hackthebox
- [pwn][Pro]0xDiablos— hackthebox
- [pwn][Pro]Taste— grodno_new_year_2026
- [pwn][Pro]Bottoms Up— miptctf
- [pwn][Pro]Canary leak + ret2win (string_leak)— spbctf