Burp Macros and Session Handling

Thurs 25th Jan 18

I've been using Burp Suite for years but somehow avoided macros up till a couple of weeks ago when I got stuck with a form I needed to brute force using Intruder. The page had a per-request CSRF token which was written into the form by a JavaScript function, for the brute force to work, I needed to pull the token from the JavaScript and ensure it was POSTed with each of my requests. I read the documentation and thought I understood how to do it but wanted to make sure before I targeted a live site so I created a small test app to simulate the client page and hit it till I got it all set up right. As I'd put the effort in to work it all out I figured I'd document the process and publish the app for others to practice on.

The Setup

This is the app we will be targeting, you can download a copy from GitHubGist or use my online version:

<?php
session_start();

$message = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    if (array_key_exists ("token", $_POST) && array_key_exists ("token", $_SESSION)) {
        if (array_key_exists ("token", $_SESSION)) {
            if ($_POST['token'] == $_SESSION['token']) {
                $message = "Success";
            } else {
                $message = "Tokens don't match";
            }
        } else {
            $message = "Token not in session";
        }
    } else {
        $message = "Token not sent in POST";
    }
}
$token = md5(mt_rand());
$_SESSION['token'] = $token;
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>Burp Suite Macro Demo Test Page</title>
    <meta name="Description" content="A page to use to practice with Burp Suite macros and session handling" />
</head>
<body>
    <h1>Burp Suite Macro Test Form</h1>
    <p>This form is designed to be used alongside the <a href="https://digi.ninja/blog/burp_macros.php">Burp Macros and Session Handling</a> blog post by <a href="https://digi.ninja/">Robin Wood</a>.</p>
    <p><?=$message?></p>
    <form method="post" action="<?=htmlentities ($_SERVER['PHP_SELF'])?>">
        <input type="submit" value="Submit" name="submit" />
        <input type="hidden" value="" name="token" id="token" />
    </form>
    <script>
        document.getElementById("token").value = "<?=htmlentities ($token)?>";
    </script>
</body>
</html>

On a GET, a session is started and token is generated and stored. A form is then written with an empty token input field and finally JavaScript is used to write the token into the input. This means that if the form is submitted without the JavaScript running, a blank token is submitted.

On a POST, the token submitted is compared to the one in the session, if they match then you get a "Success" message, otherwise you get a message telling you what you did wrong. A new token is then generated and a the process can be repeated.

As Burp does not run JavaScript, hitting the page through Repeater or Intruder should result in a "Tokens don't match" message as the token submitted will either be blank or a previously used one, this is where macros and session handling come in.

The Attack

First thing, set up Burp so that you can browse to the app and make sure that all requests are going through the Proxy. I'm going to assume that you can do this, if not, go learn some more about Burp basics then come back. Once you've done this, browse to the page and submit the form a few times so there are some hits in the proxy history.

Now we have the basics setup, we need to create a macro, to do this, go to the "Project options" tab and then the "Sessions" sub tab and hit the "Add" button in the Macros section.

Highlighting selecting the Project Options tab, then Sessions, then Add button in Macros

Doing this will bring up the "Macro Editor" dialog and, on top of that, the "Macro Recorder" dialog.

The Macro Recorder dialog listing all requests to the site

As you can see, I've got 3 POSTs and a GET. Select one of the POSTs and hit OK, this will close the dialog and return you to the "Macro Editor".

The Macro Editor dialog showing the selected request

Give the macro a name, I've called mine "Macro Demo", and then click "Configure Item".

The Configure Macro Item dialog, click add in the bottom right

In here, it would be tempting to think that Burp has worked out what is going on as it has recognised th token parameter and is showing an example, but this wrong. The parameter being shown is the value it took from the POST request which has already been used and so is a "dead" token. To pull the ever changing value from the JavaScript, click the Add button in the "Custom parameter locations in response" section. This brings up the "Define Custom Parameter" dialog.

In this dialog, give the parameter a name, in our example the parameter is called "token" and then in the request, highlight the token. This tells Burp where to find the parameter.

The Define Custom Parameter dialog box with the parameter name field populated and the token highlighted

You have now created a macro that will pull the token value out of each request and make it available to the session handler. Click OK to close all the dialogs back to the main Burp window.

A slight aside, the "Macro Editor" dialog has a "Test macro" button which I would have expected to make a request and show the token that it has captured but it doesn't so unfortunately this isn't much use for debugging in this scenario.

In the "Session Handling Rules" section of the Sessions tab, click the Add button to get the "Session handling rule editor" dialog. Give the rule and name and then click the Add button to add a Rule Action. This will give a drop down showing the different types of rules that can be performed. Select "Run a macro".

The Session handling rule editor dialog with the rule description populated

This shows the "Session Handling Action Editor" dialog, in here you can select the macro to run and then specify which parameters and which cookies get updated by the rule. I selected the "Macro Demo" macro we created earlier and left the other parameters as the defaults.

Selecting our macro in the Session Handling Action Editor dialog

OK that dialog to go back to the "Session handling rule editor" dialog for one final setting. Change to the Scope tab:

The session handling rule editor scope tab with custom scope selected and the URL for my test page added

In here I've selected to use a custom scope and entered the URL of the test page. In my real application, all pages had the token regardless of whether they had a form on them so I'd have gone with the suite scope option.

One final OK and it should all be set up. To test everything is working, send one of your previous POST requests to the Repeater and hit Go. If everything went well, the response will contain the "Success" message and you should see the token parameter magically update with every request you send.

The Repeater showing a successful response

And that is all there is to it. I followed the same steps in my test and all went well, both Repeater and Intruder worked seamlessly and I was able to forget about the CSRF protection.

Useful Links

Here are a couple of links to the official Burp Suite documentation which may help with better understanding and in more complex environments.