> ESC
← Posts

Cosmic Components Co. - UniVsThreats26 Quals Web

πŸ“… 2026-03-06 πŸ“‚ Writeup ⏱ 5 min read
WebBusiness LogicCouponsNegative QuantitySSTICTFUniVsThreats26
TL;DR:
Stacking alternating coupons, abusing negative quantities and session-persistent discounts lets us buy every product for pennies, farm loyalty rewards, hit Elite tier, and grab the flag.

Category: Web
CTF: UniVsThreats26 Quals
Target: Cosmic Components Co. shop (Flask/Jinja2)


TL;DR

Two coupons (SPACESALE15, NEWCUSTOMER10) stack multiplicatively when alternated. Discounts persist across cart contents, so we stack on a cheap RAM item, swap in expensive gear, and pay pennies. Negative quantities and bundling make some steps cheaper, and loyalty rewards (+BBD 100 each purchase) turn every buy into profit. Final balance grows while purchasing all six items, unlocking Elite Customer and the flag.

Flag: UVT{sp4c3_sh0pp3r_3xtr40rd1n41r3_2026}


Recon

  • Flask/Jinja2 shop with login/register; debug hints in HTML:
    • Template engine Jinja2 v3.1.2, debug context exposed
    • Admin panel at /admin/dashboard (JWT admin role)
    • GraphQL at /graphql with introspection
    • Legacy wallet API /api/v1/users/{id}/wallet (PATCH)
  • Six products with tier gates and starting balance BBD 100.00.
  • Product hints suggest coupon games, quantity tricks, and bundling.
  • GraphQL introspection and the legacy wallet API existed but were unused because business-logic flaws alone were enough for full compromise.

Vulnerabilities

Coupon Stacking (core)

  • Two codes: SPACESALE15 (15%) and NEWCUSTOMER10 (10%).
  • Applying the same code twice is blocked, but alternating applies both, compounding forever (Γ—0.85, Γ—0.90, ...). ~77 alternations β†’ price β†’ ~BBD 0.01.
  • The cart stores a floating discount multiplier in session and multiplies totals by it on each apply; it never clamps to a minimum price nor resets after checkout.

Negative Quantity Acceptance

  • Cart accepts -99 to 99 quantities. -1 RAM gives a -300 line item.
  • Checkout blocks negative totals, but pairing with bundling lowers totals.
  • Input validation only checks type/range, not sign, so negatives pass straight to price calculation.

Bundling + Negative Quantities

  • Neutrino SSD can be bundled with Quantum RAM. +1 SSD + -1 RAM drops from 500 to 200, then coupons shrink further.
  • Bundling is enforced only for SSD+RAM; other products refuse mixed carts. The SSD uses the same cart total, so RAM’s negative value offsets SSD.

Coupon Persistence Across Products

  • Discount factor is stored in session, not recalculated per cart. Stack on RAM, remove RAM, add expensive item: discount still applies.
  • The code applies discounts to the cart total, not to individual line items, so swapping items inherits the discount factor.

Loyalty Reward Exploitation

  • Each purchase yields +BBD 100 loyalty credit, even if the purchase cost is near zero β†’ every buy nets profit.
  • Rewards are awarded before checking payment amount; no cap or proportional scaling.

SSTI (informational)

  • Profile bio renders Jinja2 ({{7*7}} β†’ 49). Sandbox blocks dangerous attributes, but context leaks session/config/app data. Not needed for the main chain.

Exploit Steps

Step 1: Register & Login

  • Create account β†’ balance 100, tier Rookie.

Step 2: Quantum RAM (Rookie β†’ Silver)

  1. Add RAM (product 1).
  2. Alternate coupons ~8 times to drop to ~BBD 87.33.
  3. Checkout β†’ +100 loyalty; balance 112.67; tier Silver.

Step 3: Neutrino SSD (Silver β†’ Gold)

  1. Add SSD (product 2) and -1 RAM (bundling allowed) β†’ total 200.
  2. Stack coupons to ~BBD 99.49.
  3. Checkout β†’ +100 loyalty; balance 113.18; tier Gold.

Step 4: Ion Processor Core (Gold β†’ Platinum)

  1. Add RAM, stack ~80 alternating coupons (price β†’ ~0.01).
  2. Remove RAM; add Ion Processor (product 3) β†’ 9000 becomes ~21.10.
  3. Checkout β†’ +100 loyalty; balance 191.98; tier Platinum.

Why it works: the discount multiplier is stored in session and not tied to a product. After RAM is removed, the multiplier (β‰ˆ0.0023) is applied to the Ion Processor’s 9000 price.

Step 5: Nvidia 8090 Ti GPU (Platinum β†’ Diamond)

  • Reuse coupon-stack-and-swap β†’ GPU costs ~0.04.
  • Checkout β†’ +100 loyalty; balance 291.94; tier Diamond.

Step 6: Dark Matter PSU (Diamond β†’ Elite)

  • Same method β†’ PSU costs ~0.06.
  • Checkout β†’ +100 loyalty; balance 391.88; tier Elite.

Step 7: Collect Flag

  • GET /flag returns UVT{sp4c3_sh0pp3r_3xtr40rd1n41r3_2026}.

Key Payloads / Snippets

Stack coupons by alternating:

for i in range(80):
    coupon = "SPACESALE15" if i % 2 == 0 else "NEWCUSTOMER10"
    requests.post(f"{BASE}/cart/coupon", data={"csrf_token": csrf, "coupon": coupon})

Negative quantity test:

requests.post(f"{BASE}/cart/add", data={"productId": "1", "quantity": "-1"})
# {"success": true, "total": -300.0}

Discount persistence swap:

add_to_cart(1)  # RAM
stack_coupons()
remove_from_cart(1)
add_to_cart(3)  # Ion Processor β†’ ~21.10 after discounts persist

Quick math check for stacking:

price = 300.0
for i in range(8):
    price *= 0.85 if i % 2 == 0 else 0.90
print(round(price, 2))  # 87.33 after 8 alternations on RAM

Final Wallet Ledger

Date       | Description                          | Amount      | Balance
-----------|--------------------------------------|-------------|--------
2026-02-27 | Initial Credit                       | +BBD 100.00 | 100.00
2026-02-27 | Customer Loyalty Reward              | +BBD 100.00 | 200.00
2026-02-27 | Purchase: Quantum RAM Stick (Γ—1)     | -BBD  87.33 | 112.67
2026-02-27 | Customer Loyalty Reward              | +BBD 100.00 | 212.67
2026-02-27 | Purchase: Neutrino SSD Drive (Γ—1)    | -BBD  99.49 | 113.18
2026-02-27 | Customer Loyalty Reward              | +BBD 100.00 | 213.08
2026-02-27 | Purchase: Ion Processor Core (Γ—1)    | -BBD  21.10 | 191.98
2026-02-27 | Customer Loyalty Reward              | +BBD 100.00 | 291.98
2026-02-27 | Purchase: Nvidia 8090 Ti GPU (Γ—1)    | -BBD   0.04 | 291.94
2026-02-27 | Customer Loyalty Reward              | +BBD 100.00 | 391.94
2026-02-27 | Purchase: Dark Matter PSU (Γ—1)       | -BBD   0.06 | 391.88

Total spend: BBD 208.02 for BBD 13,010.00 of goods (β‰ˆ98.4% discount) plus loyalty profit.


Takeaways / Fixes

  1. Validate quantities as positive integers server-side; reject negatives/zeros.
  2. Make coupons idempotent and single-apply; track per-cart, not just last code.
  3. Recompute discounts per cart rebuild; avoid session-level discount factors.
  4. Remove template rendering of user input; avoid SSTI in bios/comments.
  5. Clamp loyalty rewards to paid value; decouple rewards from discounted totals.
  6. Add minimum payable amounts per item and per order; refuse free orders produced by discounts.