Portswigger
Practitioner - SQL injection
How to detect SQL injection vulnerabilities¶
Detect SQL injection manually by using a systematic set of tests against every entry point in the application.
To do this, you would typically submit
- Use single quote to detect errors and other anomalies
'
- Use SQL-specific syntax that evaluates to the base/original value of the entry point, and to a different value, and look for systematic differences in the application responses
- Use Boolean conditions such as OR 1=1
and OR 1=2
, and look for differences in the applications responses
- Use payloads to design to trigger an out-of-band network interaction when executed within a SQL query and monitor any resulting interaction
SQL injection in different parts of the query¶
- Most SQL injection vulnerabilities occur within the
WHERE
clause of aSELECT
query - SQL injection vulnerabilities can occur at any location within the query
UPDATE
statements, within the updated values or theWHERE
clauseINSERT
statements, within the inserted valuesSELECT
statements, within the table of column nameSELECT
statements, within theORDER BY
clause
Retrieving hidden data¶
- Imagine a shopping web app that displays products in categories
- When the user clicks on the Gifts category, their browser requests the following URL
https://insecure-website.com/products?category=Gifts
- The application makes a SQL query to retrieve product details from the datebase
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
- This SQL query asks the database to return:
- all details
- from the
product
table - where the
category
isGifts
- and
released
is1
- The restriction
released = 1
is being used to hide unreleased products. - We could assume for unreleased products,
released = 0
-The application doesn't implement any defenses against SQL injection attacks. so the following attack can be constructed
https://insecure-website.com/products?category=Gifts'--
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
--
is a comment indicator in SQL
- The rest of the query is interpreted as a comment, effectively removing it
- In this example the query no longer includes AND released = 1
- Resulting in all products being displayed, including those not yet released
- A similar attack to cause the application to display all the products in any category, including categories that they don't know about.
https://insecure-website.com/products?category=Gifts'+OR+1=1--
- This results in the SQL query
`SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1`
- The modified query returns all the items where either the
category
isGifts
or 1 is equal to 1
Warning¶
Take care when injecting the condition OR 1=1
into a SQL query. Even if it appears to be harmless in the context you're injecting into, it's common for applications to use data from a single request in multiple different queries. If your condition reaches an UPDATE
or DELETE
statement, for example, it can result in an accidental loss of data.
Subverting application logic¶
- On a Web page or WebApp that lets users log in with a username and password
- If a user submits the username
weiner
and the passwordbluecheese
, the application checks the credentials by performing the following SQL querySELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
- If the query returns the details of a user, then the login is successful, otherwise it is rejected.
- In this case, and attacker can log in as any user without the need for a password
- Can be done using the SQL comment sequence
--
to remove the password check from theWHERE
clause of the query. - For example, submitting the username
adminstrator'--
and a blank password results in the following querySELECT * FROM users WHERE username = 'administrator'--' AND password = ''
- This query returns the user whose 'username' is
administrator
and successfully logs the attacker in as that user
SQL injection UNION attacks¶
- When an application is vulnerable to SQL injection, and the results of the query are returned within the applications responses, you can use the
UNION
keyword to retrieve data from other tables within the database. - The
UNION
keyword enables you to execute one or more additionalSELECT
queries and append the results to the original query. for exampleSELECT a, b FROM table1 UNION SELECT c, d FROM table2
-
This SQL query returns a single result set with two columns, containing values from columns
a
andb
intable1
and columnsc
andd
intable2
-
For a
UNION
query to work, two key requirements must be met- The individual queries must return the same number of columns
- The data types in each column must be compatible between individual queries
- To carry out a SQL injection UNION attack, make sure that your attack meets these two requirements. involves discovering
- How many columns are being returned from the original query
- Which columns returned from the original query are of a suitable data type to hold the results from the injected query
Determining the number of columns required¶
-
When performing a SQL injection UNION attack, here are 2 effective methods to determine how many columns are being returned the original query
-
Method 1
- injecting a series of
ORDER BY
clauses - incrementing the specified column index until an error occurs
- ex. if the injection point is a quoted string whithin the
WHERE
clause of the original query, you would submit' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3--
- injecting a series of
- This series of payloads modifies the original query to order the results by different columns in the result set.
- The column in an
ORDER BY
clause can be specified by its index, so you don't need to know the names of the columns - When the specified column index exceeds the number of actual columns in the result set, the database returns an error, like
The ORDER BY position number 3 is out of range of the number of items in the select list
- The application might return the database error in it's HTTP response, but it may also issue a generic error response
- It may simply return no results at all
-
As long as you can detect some difference in the response, you can infer how many columns are being returned from the query
-
Method 2
- Involves submitting a series of
UNION SELECT
payloads specifying a different number of null values'UNION+SELECT+NULL-- 'UNION+SELECT+NULL,NULL-- 'UNION+SELECT+NULL,NULL,NULL--
- Involves submitting a series of
- If the number of nulls does not match the number of columns, the database returns and error, like `All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
NULL
is used as the values returned from the injectedSELECT
query because the data types in each column must be compatible between the original and the injected queriesNULL
is convertible to every common data type, so it maximizes the chance that the payload will succeed when the column count is correct- Like with the
ORDER BY
technique, the application might actually return the database error in its HTTP response, but may return a generic error or simply return no results. - When the number of nulls matches the number of columns, the database returns an additional row in the result set, containing null values in each column.
- The effect on the HTTP response depends on the applications's code.
- If you are lucky, you will see som additional content within the response, like and extra rows on a HTML table. Otherwise , tne nuyll values might trigger a different error, like NullPointerException
- Worst case, the response might look the same as a response caused by an incorrect number of nulls. This would make this method ineffective
- Database-specific
- On Oracle, every
SELECT
query must use theFROM
keyword and specify a valid table. - There is a built-in table on Oracle called dual which can be used for this purpose. Injected queries would need to look like the following
'UNION SELECT NULL FROM DUAL--
- The payloads described use the double-dash comment sequence
--
to comment out the remainder of the original query following the injection point - On MySQL the double-dash sequence must be followed by a space. Alternatively, the hash character can be used to identify a comment SQL injection Cheat sheet
- On Oracle, every
Finding columns with a useful data type¶
- A SQL injection UNION attack enables you to retrieve the results from an injected query.
- Interesting data that you want to retrieve is normally in string form
- This means you need to find one or more columns in the original query results whose data type is, or is compatible with, string data
- After you determine the number of required columns, you can probe each column to test whether it can hold string data.
- To test, submit a series of
UNION SELECT
payloads that place a string value into each column in turn, for example'UNION SELECT 'a',NULL,NULL,NULL-- 'UNION SELECT NULL,'a',NULL,NULL-- 'UNION SELECT NULL,NULL,'a',NULL-- 'UNION SELECT NULL,NULL,NULL,'a'--
- If the column data is not compatible with string data, the injected query will cause a database error such as
Conversion failed when converting the varchar 'a' to data type int.
- If an error does not occur, and the application's response contains some additional content including the injected string value, then the relevant column is suitable for retrieving string data
Using a SQL injection UNION attack to retrieve interesting data¶
- After determining the number of columns returned by the original query and found which columns can hold string data, next step is to retrieve data
- Suppose the following
- The original query returns 2 columns, both of which can hold string data
- The injection point is a quoted string within the
WHERE
clause - The database contains a table called
users
with the columnsusername
andpassword
- In this example, you can retrieve the contents of the
users
table by submitting the input'UNION SELECT username, password FROM users--
- In order to perform this attack, you need to know that there is a table called
users
with 2 columns calledusername
andpassword
- without this info, you would have to guess the names of the tables and columns
- All modern databases provide ways to examine the databases structure, and determine what tables and columns they contain
Retrieving multiple values within a single column¶
- The previous example may only return a single column
- Retrieving multiple values together within a single column is possible by concatenating the values together.
- Including a separator will let you distinguish the combined values. Oracle example below.
'UNION SELECT username || '~' || password FROM users--
- double pipe
||
is string concatenation on Oracle - This query concatenates together the values
username
andpassword
fields, separated by the'~'
. and results in the following.... administrator~s3cure wiener~peter carlos~montoya ...
- Different databases use different syntax to perform string concatenation