Once you have established that a database is vulnerable to SQL injection, it is often useful to exploit the vulnerability to demonstrate any potential implications. A successful SQL injection exploit can potentially read sensitive data from the database, modify database data, execute administration operations on the database and in some cases issue commands on the operating system.
The UNION operator is used in SQL to combine the results of two or more SELECT statements. When a web application contains a SQL injection vulnerability that occurs in a SELECT statement, you can often employ the UNION operator to perform an additional query and retrieve the results.
First, ensure that Burp is correctly configured with your browser.
Ensure "Intercept is off" in the Proxy "Intercept" tab.
Visit the web page of the application that you have identified as having a potential SQL injection vulnerability.
Return to Burp and ensure "Intercept is on" in the Proxy "Intercept" tab.
Now send a request to the server. In this example by refreshing the page.
The request will be captured in the Proxy "Intercept" tab.
The parameter we will attempt to exploit is the "id" parameter in the URL.
The first task is to discover the number of columns returned by the original query being executed by the application, because each query in a UNION statement must return the same number of columns.
Right click on anywhere on the request and click "Send to Repeater".
In this example we exploit the fact that NULL can be converted to any data type to systematically inject queries with different number of columns until the injected query is executed.
For example:
UNION SELECT NULL--
UNION SELECT NULL, NULL--
UNION SELECT NULL, NULL, NULL--
Note: In this example we do not need a single quote to terminate any existing string. In addition, the space character must be encoded as %20.
The application displays an error message that can be viewed in the response tab. The error message says that the used SELECT statements have a different number of columns.
We can continue adding NULLs to our query until we see a change in the application's response.
Our query is executed when the number of columns returned by our injected query is equal to the number in the original query.
When we inject 8 NULLs, the page displays the content without any issues and there are no error messages. When we add a 9th NULL to the query, the application produces an error. So we can infer that the original query returns 8 columns.
Having identified the number of columns, the next task is to discover a column that has a string data type so that we can use this to extract arbitrary data from the database.
We can do this by injecting a query containing the required number of NULLs, as we have previously, and replacing each NULL in turn with 'a'.
For example:
UNION SELECT 'a', NULL, NULL ...
UNION SELECT NULL, 'a', NULL ...
UNION SELECT NULL, NULL, 'a' ...
When an 'a' is specified at a column that has a string data type, the injected query is executed, and you should see an additional row of data containing the value a.
However, in our example the page is not showing anything other than the original content.
We can see that the query is being executed, but because the application is only showing the first result we cannot see the result of the injected query.
We can ensure that our data is the first row returned by modifying the original query so that it does not return any rows:
0 AND 1=2 UNION SELECT NULL, NULL,'a', NULL, NULL, NULL, NULL, NULL
We can now see in the response that the application is displaying the injected 'a' string instead of the actual user details.
The 'a' is displayed in the data field corresponding to the column in which we supplied it.
We can now use the relevant column to extract data from the database.
0 and 1=2 UNION SELECT NULL, NULL, version(), NULL, NULL, NULL, NULL, NULL
In this example we have altered the injected code to display the version number of the database. We can then continue to use this technique to retrieve any accessible data from the database.