August 13, 2026
Hacker Holidays Day 8: Towel on the Sunbed
The setup
By Devyaniitware
3 min read
The setup
Day 8 introduces "Ponzi Portfolio" — an in-app crypto rewards system where guests can claim a daily staking reward and work toward "Whale Vault" status. The room's whole framing is a joke about someone's towel getting "claimed" on a sunbed multiple times while they weren't looking — a not-so-subtle hint about what's actually wrong with the app.
What's expected: register a guest account, understand the daily reward mechanic, then find a gap that lets you claim far more than the intended once-per-24-hours limit.
Quick definitions before we start
- Race condition — a bug where an app checks something ("has this user already claimed today?") and then acts on it ("give them the reward") as two separate steps, with a tiny gap in between. If multiple requests arrive at nearly the same instant, they can all sneak past the check before any of them finishes the "act" step.
- Burp Suite — a widely-used tool for intercepting, inspecting, and replaying web requests. It has a free "Community" edition and a paid "Professional" edition with more advanced features.
How I started
Registered a guest account, explored the dashboard — a "Claim Reward" button gave 50 PONZI, with a 24-hour cooldown after use. Whale Vault needed 150 PONZI total. I captured the claim request in Burp: a simple POST /claim with just a session cookie, no body needed.
My thinking process — and where the tooling fought back
My first instinct was to use Burp's built-in "send group in parallel" feature — duplicate the captured request many times, fire them all at once, and see how many slip past the cooldown check. Except: that feature doesn't exist in Burp Community Edition. Right-clicking a Repeater tab only offered "Duplicate tab" as an option — and that option didn't exist either. Turns out true parallel request firing is a Burp Professional feature.
Plan B: fire requests from the terminal instead. My first attempt used a bash loop spawning 20 background curl processes:
for i in {1..20}; do
curl -s -X POST http://TARGET/claim -H "Cookie: connect.sid=..." -o response_$i.json &
done
waitfor i in {1..20}; do
curl -s -X POST http://TARGET/claim -H "Cookie: connect.sid=..." -o response_$i.json &
done
waitAll 20 came back "already claimed." Turned out the account had already used its one legitimate claim earlier, while I was just capturing the request format in Burp — the race needed to target a genuinely fresh, never-claimed account.
Second attempt: registered a brand new account, grabbed its session cookie directly from browser DevTools without ever clicking the button, then reran the same 20-background-process approach. Still all 20 failed. The real issue: spawning 20 separate curl processes has real startup overhead — forking a new process, establishing a new connection — so even "simultaneous" background jobs land on the server milliseconds apart. That's plenty of time for the server to fully process the first request before the second one arrives.
What actually worked: curl has a genuine internal parallel mode, -Z --parallel-immediate, which fires many requests from inside one process instead of twenty separate ones — much tighter timing. Using a config file listing 30 identical claim requests:
curl -Z --parallel-immediate -K race_config.txtcurl -Z --parallel-immediate -K race_config.txtAll 30 succeeded. Balance jumped to 1,500 PONZI — ten times over the Whale Vault threshold, and the account jumped straight to "Whale" tier.
Getting the flag
Back on the dashboard, the Whale Vault was now unlockable. Opening it revealed the flag directly.
("Double spent" is literally the technical term for this exact bug class in payment/currency systems — a fitting name.)
The big takeaway
A "check, then act" pattern with no protection against simultaneous requests is a race condition waiting to happen. The real-world fix is a database-level lock or atomic operation — doing the check-and-update as one indivisible step — not just adding a timer, since a timer is exactly the kind of check an attacker can slip past by racing it.
This is a genuinely real, well-documented vulnerability class — it's shown up in actual production bugs involving coupon codes, loyalty points, and even cryptocurrency withdrawal systems, which is exactly why this room used a "crypto rewards" theme.
Next up: Day 9, CryptoCabana, where an Azure storage token with more permissions than it needed led all the way to a Key Vault secret hidden in its own version history.
No race condition needed to claim these — LinkedIn and GitHub, yours anytime.