Burp Suite - solving E-mail and SMS TAN multi-factor authentication with Hackvertor custom tags

Why bother investing time to automate work when doing IT security testing? On one hand, manual testing is a tedious work, where you spend time doing vulnerability tests that could be done by a machine. On the other hand, letting a machine decide fully on its own on how to do tests will mostly result in the machine doing nothing useful. This is especially true for security testing, where manually checking every parameter for injection attacks is very laborious and automated security scanners go on scanning for hours while a human would have aborted the scan for various reasons. However, if we teach automated tools to do things correctly each time, we get the sweet middle spot of semi-automated security testing, where the tools do the automatic and systematic security tests and the analyst can focus on the parts of a security test, where the tools are likely insufficient.

Burp Suite Pro is one of the main tools to do all kind of HTTP related security analysis and that supports a semi-automated testing. But now and then it lacks certain features. Burp extensions can again add some of them. In this post we would like to show how to use one of the most powerful extensions, Hackvertor by Gareth Hayes and its relatively new feature of Python scripting.

Use Hackvertor to generate Swiss social security numbers

Let's start with a simple example. Imagine you are security testing a website and you found an HTTP-API that expects the de facto Swiss social security number [1] as a parameter. Nearly every adult in Switzerland has such a number. After researching, you find out this unique number always starts with 756, followed by two times four random characters and ending with another two random characters like this:

756.9217.0769.85

If you would just like to brute-force random social security numbers in HTTP requests, you could use Burp's Intruder feature that allows you to try generate different numbers. But what if you would like to send a new random number each time you send the request in Burp's Repeater? This is where Hackvertor can be used. In Hackvertor's UI you can search for tags and you should quickly find the random_num tag. The purpose is simply to generate a random number as shown in the input and output field in the following picture:

Screenshot of the Burp Hackvertor showing the random_num Hackvertor tag in the input window and and a random number in the output widget.

So generating a new random social security number is as easy as pasting the following value into an HTTP request in Burp's Repeater:

756.<@random_num_0(4) />.<@random_num_1(4) />.<@random_num_2(2) />

For example, the following request can be created in the Burp Repeater:

Screenshot of the Burp Repeater showing several random_num Hackvertor tags in a HTTP request to create a Swiss social security number.

However, it will not be sent out from Burp as-is and the tags will be replaced by Hackvertor. How does an example request look like when it leaves Burp? This can be observed in the Logger++ extension (another very helpful extension you should use) as shown in the following picture:

Screenshot of the Burp Logger++ logging widget showing a HTTP request with a Swiss social security number generated by the Hackvertor tags that have been inserted into the Burp Repeater.

This was just an easy example to start. But the truth is, Swiss social security numbers are not fully random and the last character is an EAN13 checksum over the other characters. And instead of sending incorrect social security numbers to a website, how about calculating that checksum in Hackvertor? That's where custom Hackvertor code execution tags come into play. You can write them in JavaScript or Python, we'll use Python here. Hackvertor code execution tags allow you to write code that takes an input (passed in the variable input, that's whatever is put between the tags) and define the output variable. A no-transformation example looks like this:

Screenshot of the Hackvertor widget showing a dialog for the creation of a custom tag. You select Python as language and can enter program code into a text area. Currently the text area just assigns the input to the output.

So here's a little Python one-liner that calculates the checksum number from the nine random numbers that were passed as input and assigns the value to the variable output:

z=input;y=z.replace('.','');output=z+str(10-(sum([3*int(x) for x in y[1:][::-2]])+sum([int(x) for x in y[::-1][1::2]]))%10)[-1]

Defining it as the tag name ean13 and you should get the following picture when you open the tag in the edit window:

Screenshot of the Hackvertor widget for editing a custom tag. It is the same dialog type as above, but now it edits the ``ean13`` tag with the Python code shown above.

Note that the leading underscore is used for every custom tag, so Hackvertor knows it is not a built-in Hackvertor tag. So how do we use such a custom tag?

First of all, there is a security measure so other people that send traffic through your Burp can't execute the custom tag on your Burp machine. Code execution tags are only executed when a certain random token is included in the tag. This means you'll need to create a custom tag in the Hackvertor UI first to get that random token. Creating the custom tag for our ean13 tag in the Hackvertor UI will result in something like this:

Screenshot of the Hackvertor Burp plugin showing an EAN13 tag and with an error message in the output window. The error message describes that code execution is disabled and how to enable it.

So keep in mind that for your Burp installation, that random number in double qutoes will be different. As the output windows in the above picture tells you, code execution tags are still disabled by default for security reasons. This is a second setting you'll need to change. You can enable them in the top main menu of Burp under the Hackvertor item. What you need to do then is to allow code execution tags in Hackvertor:

Screenshot of the Hackvertor menu showing how to enable code execution tags.

After that you will probably not see much in the output window of Hackvertor. That's because we have to give our custom tag the correct input. For example:

<@_ean13_3("83a52168fad35b2d85f6972b0eb1db91")>756.9217.0769.8<@/_ean13_3>

Now you should see the correct social security number being generated, namely 756.9217.0769.85. And here comes the real power of Hackvertor. Now you can combine the generation of random numbers feature of Hackvertor and our custom tag in a nested form:

<@_ean13_3("83a52168fad35b2d85f6972b0eb1db91")>756.<@random_num_0(4) />.<@random_num_1(4) />.<@random_num_2(1) /><@/_ean13_3>

Whenever you send this value in the Burp Repeater, it will be replaced with a random social security number with a correct checksum. Of course you can now not only generate random social security numbers, but you can also generate the random numbers with Burp Intruder and brute-force with valid EAN13 checksums.

In some cases it might be even possible to simply paste the above tags into the browser you use with Burp and the web server will receive a random social security number. However, this only works if the web application you are testing does not encode the values we put into HTML fields and Hackvertor is still able to see the tag exactly as written above. This is rather a rare case, but it might work.

Use Hackvertor to fetch second-factor authentication token

Let's do a more advanced custom tag example. Could you use the scripting capabilities of Hackvertor to automatically solve TAN second factor verification in multi-factor authentication web forms? At Pentagrid we have an SMS to E-mail gateway for testing purposes, meaning if second factor TANs are sent out via SMS or E-mail, they will always land in one of our testing E-mail inboxes. Can we retrieve the second factor TAN tokens from the E-mail inbox with a Hackvertor tag? Yes we can, with the very useful Python imaplib and an E-mail server that supports IMAP. Of course the entire parsing logic for the incoming TANs is highly dependent on the web application and how the SMS or E-mails look like. You will need to change the parsing code according to your needs. So here's a quick'n'dirty example that worked for us for a certain web application. We created the new Hackvertor tag like this:

import getpass, imaplib
import time

time.sleep(0.1)

class Email:
    def __init__(self, data):
        self.data = data.decode()
        self.body = "\r\n\r\n".join(self.data.split("\r\n\r\n")[1:])

M = imaplib.IMAP4_SSL(host='use-your-own-mail-host') # warning: no certificate verification
M.login("pentagrid@example.org", "email-password")
M.select()
typ, data = M.search(None, 'ALL')
token = "NO TOKEN WAS FOUND"
for num in data[0].split()[::-1]:
    typ, data = M.fetch(num, '(RFC822)')
    email = Email(data[0][1])
    for line in email.body.splitlines():
        #print(line)
        if line.startswith("Your TAN is: "):
            token = line.split("Your TAN is: ")[1].strip()
    if token:
        print(token)
        break
    else:
        print("No token found")
    #print('Message %s\n%s\n' % (num, data[0][1]))
print("Final token:", token)
output = token
M.close()
M.logout()

The Python code will login to the IMAP mailbox, retrieve E-mails starting with the newest, quick'n'dirty parse the TAN from the E-mail by interating through each line of the E-mail and assign the the first token found to the output variable that Hackvertor expects. You might need to play with the sleep delay we introduced at the beginning of the script to make sure the E-mail reaches the mailbox before you try to retrieve it. Otherwise you could change the script to only consider the very newest E-mail but you would need to take care to delete old E-mails. And of course you need to change your E-mail server, username and password. Please be aware that this is as well not thread-safe, you would need a seperate E-mail mailbox for each thread to make it concurrent.

Configuring a search and replace rule in the Burp Proxy to replace any second factor you enter with the Hackvertor tab is left as an exercise to the reader. We were able to test websites without ever entering the second factor manually again, as the entered token was replaced with a Hackvertor tag and Hackvertor fetched the token from the mailbox.

Hackvertor is therefore the perfect solution if you would like to script things that are sent in HTTP requests. With the new scripting capabilities, it is not necessary to write extensions when you want to change things sent out. Or do you? Unfortunately, there are certain limitations with this approach and in Burp. The search and replace rule for the Proxy of course only works for the Burp Proxy. But what if we want to make the Burp Crawler be able to login with second-factor TANs? We can't use session handling rules (another advanced topic of Burp), as they don't apply for Burp Crawler. But we were able to write an extension that handles that part, but that's for another blog post (it is really cool to see the headed browser of Burp login correctly). And what if you would also like to modify HTTP responses? Or what if you would like to even enhance Burp with a Transfer-Encoding feature it does not yet support? Do you want to know how you could set up an SMS to E-mail gateway? Stay tuned for our next blog posts, subscribe to our RSS feed or follow us on Twitter or LinkedIn.