There are many tools available for automated testing of web applications. One of the best known is probably sqlmap. Sqlmap allows you to identify and exploit SQL injection vulnerabilities with ease from the command line. However, controls such as CSRF tokens or simple anti-automation techniques such as including a unique hidden value within the form can prevent automated tools from working correctly. Macros in Burp Suite are a great way to bypass these measures in order to carry out automated testing, although they can be complicated to implement.

In this post, we are going to look at a sample application in which the user can search for pictures of animals:

This is an ASP.NET application with SQL Server as the back-end database. The application has a blind SQL injection vulnerability. We can see this here:

If we have a look at the page source, we can see that there is a GUID token in a hidden input field:

<form method="post" action="./" id="form1"> <div> <input name="txtQuery" type="text" id="txtQuery" style="width:270px;" /> <input type="submit" name="btnSearch" value="Search" id="btnSearch" /> <input type="hidden" name="token" id="token" value="012aedf8-412a-4418-bd76-cf61f13ec22f" /> </div> </form> <span id="lblResultText"></span> <br /> </body> </html>

This token is generated every time a response is sent from the server and if the token doesn’t match on a POST request, an error is encountered:

So, with all of this in mind, let’s begin by looking at what happens when we try sqlmap without using a macro to modify the requests. The command we run is:

$ sqlmap -u http://10.99.10.20:8080 --method=POST --data= "__VIEWSTATE=ThFsV9HLtQRaOW3ksjD%2F8jPJ%2BK4oYtIZJ9UZjSdVZecr9MFluyVQIMvZTKyg3Q1eCjcahMgDNYnhBeQIA2FCGq1HaWWj8WE3CPXbXZc5j3I%3D&__VIEWSTATEGENERATOR=CA0B0334&__EVENTVALIDATION=3OHOMEoCmtD5YRvASiOGybpufR%2BFQoZetngO2sq5zb9YFl3HtW%2BBzrISbPZE58dZtG6LsC6qns%2BlotceoeBunvTMcKLH8MIyzmxk3PoHuiWpavLOqJGozuk6py0DvKaWvWHDuFZO1QU2dfG5yPZ29nTLapvb3KcAPWAMDBI25FM%3D&txtQuery=cat&btnSearch=Search&token=77d5a318-c2b0-466d-a4ba-b8c5d155c54f" --proxy=http://127.0.0.1:8080 -p txtQuery

The first thing we notice from the sqlmap output is a redirect to the error page:

[16:42:45] [INFO] testing connection to the target URL sqlmap got a 302 redirect to 'http://10.99.10.20:8080/error.html?aspxerrorpath=/default.aspx'. Do you want to follow? [Y/n]

This doesn’t look promising for sqlmap. Let’s continue the process and see what happens.

[16:45:57] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind (IF)' [16:45:58] [INFO] testing 'Oracle AND time-based blind' [16:45:58] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns' [16:45:58] [WARNING] using unescaped version of the test because of zero knowledge of the back-end DBMS. You can try to explicitly set it with option '--dbms' [16:46:02] [WARNING] POST parameter 'txtQuery' does not seem to be injectable [16:46:02] [CRITICAL] all tested parameters appear to be not injectable.

Well, sqlmap seems to think that the parameter isn’t injectable; but we know better. Let’s now create a Burp macro which will replace the “token” parameter in the request with a new token so that we can exploit using sqlmap.

A macro in Burp Suite is a series of HTTP requests to be sent to the server prior to requests which have been proxied by Burp. Once the macro requests have been carried out, the set of parameters taken from the response of the final macro request can then be passed on to the request that called the macro.

The first thing to do is to record the series of requests we want to make. In this case there is only one request: the GET request to the server. Macros can be used to carry out complex operations however, such as logging into the application and retrieving cookies. In Burp Suite go to the “Project options” tab and the “Sessions” sub-tab.

Scroll down to the Macros section, then click add.

Two dialog boxes will pop up. The first is the macro editor, the second is the macro recorder. In order to determine the series of requests we want to carry out, we will need to “record” the macro that we want to create. This can be done in two ways: we can now carry out the actions we want to do as part of the macro (i.e. browse to the login in page, send a specific GET request etc.), then select them from the list; or we can select requests which are already present in the proxy history. Seeing as we are only looking for one request, which we have already made, we will be using the second option here.

Once we have highlighted the desired request(s), we click ok, and then we are taken to the macro editor.

From here we will need to make a small change to the intercepted request. With the request highlight, we click “Configure item”, the “Configure Macro Item” dialog is presented. We then click on the add button of the “Custom parameter location in response” section.

We then need to locate the parameter in the response body, highlight the value we are looking to extract and name the parameter so it can be passed to the final request once the macro has completed.

The “Define start and end” section is completed automatically when we highlight the required value in the response. All the other settings can be left as default. Click OK to close the “Define Custom Parameter” dialog, click OK to close the “Configure Macro Item” dialog and finally click OK again to close the Macro Editor.

Now we’ve created our macro, but we still need to implement a session handling rule to allow the macro to act upon the required requests. On the Session tab go to the “Session Handling Rules” section and click the add button.

When the dialog pops up click add under the “Rule Actions” section and select “Run a macro” from the drop-down menu.

This brings up the “Session Handling Action Editor”. Here we select our macro, choose “Update only the following parameters” and add our parameter to the list. If we required cookies to be modified based on the final request of the macro, then we could add this here as well. For the purposes of this example no cookies are set.

Click ok to close this dialog and then click on the “Scope” tag of the Session Handling Rule Editor.

Here we need to define the scope of requests which are affected by the rule. Under “Tools Scope” the proxy is not selected by default (as this could affect every single request passing through Burp if not configured correctly). In order to use this rule with sqlmap we must enable the rule in the proxy. To limit the scope we are using the “Use suite scope” option which for this exercise only includes the example site. Finally, we limit the “Parameter Scope” to only affect requests which include the “token” parameter as this is the one that we need to be modified. Click OK to close the dialog.

That’s all we need to configure for our macro to affect sqlmap. Now when sqlmap’s requests pass through the proxy, Burp will first make the GET request to the server and replace the “token” parameter from sqlmap’s POST request with the value extracted from the GET request.

N.B.: Burp does not display the modified request in the proxy history so if you believe that the macro is not working as intended you will need to open the sessions tracer from the Session tab in Project Options. This can be used to move step by step through every request made by the session handling rules and you will be able to observe any changes made to the requests.

Once the macro is enabled sqlmap should be able to correctly identify the SQL injection vulnerability in our site and subsequently exploit it:

[20:38:09] [INFO] POST parameter 'txtQuery' appears to be 'Microsoft SQL Server/Sybase stacked queries (comment)' injectable [20:38:09] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind (IF)' [20:38:09] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind (IF - comment)' [20:38:19] [INFO] POST parameter 'txtQuery' appears to be 'Microsoft SQL Server/Sybase time-based blind (IF - comment)' injectable [20:38:19] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns' [20:38:19] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found [20:38:19] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test [20:38:19] [INFO] target URL appears to have 1 column in query [20:38:20] [INFO] POST parameter 'txtQuery' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable POST parameter 'txtQuery' is vulnerable. Do you want to keep testing the others (if any)? [y/N]

As you can see, sqlmap has found that the parameter is vulnerable and we can now use sqlmap to extract data such as users and tables:

[20:41:46] [INFO] fetching database users [20:41:46] [WARNING] reflective value(s) found and filtering out [20:41:46] [INFO] the SQL query used returns 2 entries [20:41:46] [INFO] retrieved: animals [20:41:47] [INFO] retrieved: sa database management system users [2]: [*] animals [*] sa <…SNIP…> [20:42:44] [INFO] analyzing table dump for possible password hashes Database: Animals Table: AnimalImages [4 entries] +----+-----------+-------------+ | ID | imageData | description | +----+-----------+-------------+ | 1 | blank | dog | | 2 | blank | cat | | 3 | blank | mouse | | 4 | blank | musk ox | +----+-----------+-------------+