Testing for SQL
How SQL Injection Works
When user input is inserted directly into SQL queries without sanitization, attackers can break out of the intended query and execute arbitrary SQL.
Vulnerable PHP Code Example
$username = $_POST['username'];
$query = "SELECT * FROM logins WHERE username='$username'";If user inputs: admin'-- -
Query becomes:
SELECT * FROM logins WHERE username='admin'-- -'The -- - comments out the rest, bypassing any password check.
SQLi Discovery
Escape Context Characters
Try these to break out of the current query context:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))Test Payloads
'
%27
"
%22
`
%60
#
%23
;
%3B
)
%29
')
%27%29
"))
%22%29%29
If you get a SQL error or different behavior, injection may be possible.
SQL Comments (End Query Early)
MySQL
#, -- - (space required), /*comment*/
PostgreSQL
--, /*comment*/
MSSQL
--, /*comment*/
Oracle
--
SQLite
--, /*comment*/
Note: -- requires a space after. Use -- - or URL encode as --+
Types of SQL Injection
Union-based
Results visible on page, use UNION to extract data
Error-based
Database errors reveal query output
Boolean Blind
True/false responses based on conditions
Time Blind
Use SLEEP() to infer data based on response time
Out-of-band
Exfiltrate data via DNS or HTTP requests
Authentication Bypass
Common Payloads
How OR Injection Works
Original query:
With input admin' OR '1'='1'-- -:
Since '1'='1' is always true, authentication is bypassed.
When Auth Bypass Payloads Get Blocked
If classic login bypasses get blocked but a single quote still produces a database error, continue testing the same parameter for UNION injection instead of stopping at auth bypass.
Use the username field as the injection point and keep the password boring:
Once a visible column is identified, enumerate normally:
If the dumped values look like base64 (A-Z, a-z, 0-9, +, /, often ending in =), decode and try them against other exposed services such as SSH or Cockpit.
UNION Injection
UNION combines results from multiple SELECT statements. Both queries must return the same number of columns.
Step 1: Detect Number of Columns
Method A: ORDER BY
Method B: UNION SELECT
Step 2: Find Visible Columns
If page displays 2 and 3, those columns are visible for data extraction.
Step 3: Extract Data
Database Enumeration
MySQL Fingerprinting
SELECT @@version
MySQL/MariaDB version string
SELECT POW(1,1)
1 (numeric test)
SELECT SLEEP(5)
5 second delay
Enumerate Databases
Current Database
Enumerate Tables
Enumerate Columns
Dump Data
MySQL Useful Functions & Variables
File Read (MySQL)
Check FILE Privilege
Read Files with LOAD_FILE()
File Write (MySQL)
Check secure_file_priv
Empty = can write anywhere
/path/= can only write to that directoryNULL = cannot write files
Write Files with INTO OUTFILE
Write Web Shell
Then access: http://target/shell.php?0=id
Stacked SQLi to Web Shell
Stacked queries are blind. Thus you have no ability to really get the database credentils. Try to write a webshell to the server.
If a blind SQLi confirms stacked queries with SLEEP() and the database user can write files, try INTO OUTFILE even when data extraction is awkward. Example pattern from a POST body parameter:
URL-encoded:
Then trigger:
Web Root Paths
Apache (Linux)
/var/www/html/, /var/www/, /srv/http/
Nginx (Linux)
/var/www/html/, /usr/share/nginx/html/
IIS (Windows)
C:\inetpub\wwwroot\
XAMPP
/xampp/htdocs/, C:\xampp\htdocs\
Blind SQL Injection
Boolean-Based
Time-Based
Second-Order SQL Injection
Payload stored in database, executed later in different query.
Example: Register with username admin'-- -, later displayed/used in vulnerable query.
Pattern: First query uses prepared statements (safe); a second query uses the result of the first in plain concatenation. Example: first query fetches username, country by cookie (parameterized); second query does SELECT ... WHERE country = '" . $row['country'] . "' with no prepared statement — so stored payload in country is executed in the second query.
Vulnerable PHP example (from HTB Validation):
Attack: register with country=Brazil' UNION ALL SELECT ... -- - (or time-based payload); when account page loads, second query executes the stored payload.
WAF Bypass Techniques
Case Manipulation
Comment Injection
URL Encoding
Double URL Encoding
Whitespace Alternatives
Operator Alternatives
UNION SELECT Bypass Strings
Hex Spacing for Gaps
MSSQL Specific
Version
Current User
Databases
Tables
Enable xp_cmdshell (RCE)
Execute on Linked Server
Check Impersonation Rights
Impersonate User
PostgreSQL Specific
Version
Current User
Databases
Tables
File Read
Command Execution
Oracle Specific
Version
Current User
Tables
Columns
Remote MySQL Connection
After Connection
Change WordPress Password
Output Format Fix
When SQL output is messy in terminal:
UNION Injection Full Walkthrough
Step-by-step example against a search form vulnerable to SQL injection.
1. Identify Injection Point
Input a single quote ' into the search field. If you get a SQL error, injection is likely:
2. Fuzz for SQLi with ffuf
Save the POST request from Burp with the injection point and fuzz with a SQLi wordlist:
3. Determine Column Count
Increment the UNION SELECT column count until the error disappears:
4. Identify Visible Columns
5. Extract Database Name
6. Enumerate Tables
If your column is not the last one reflected back, ensure your
FROMis after the remainingNULL
7. Enumerate Columns
If your reflected column is not the last one ensure your
FROMis after the remainingNULL
8. Dump Credentials
If you only have one reflected column to work with you can
CONCATmultiple columns together
SQLMap
See dedicated page: SQLMap Guide
Quick commands:
After SQLi (file-write, no interactive shell): If you get DB creds (e.g. from config.php via LFI or file-read) and a webshell on the same host, run MySQL one-shot from the shell: mysql -u USER -p'PASS' -e "show tables;" dbname. No need for a stabilized reverse shell. Prefer the wright.php webshell (/usr/share/webshells/php/wright.php) over a minimal ?cmd= shell—see Shells / web-shells and sqlmap --file-write.
Resources
Last updated