Automated scanners require a constant flow of requests, and most tools have built-in session-handling logic. But automated scanning / session handling for web applications is tricky these days, especially because of the following vectors:
Burp sessions and macros
Burp has sessions, macros, and the ability to invoke extenders, which help with CSRF tokens (most scenarios), cookie-based session handling, and a few API-based scenarios. Shortcomings:
Custom macro extender
The ExtendedMacro plugin (GitHub) provides a UI-based workflow to select and replace tokens. The UI is great and is a superb start to solve a tough problem. But the plugin has a few bugs that make it unreliable. It’s also slow because it sends multiple login requests. Shortcomings:
We wanted to build a Burp plugin supporting complex login sequences with the following features:
To achieve the above, we built on the great work done by Fruh (ExtendedMacro) to create the Authentication Token Obtain and Replace (ATOR) plugin. Our work can be summarized in the following points:
Let’s break down how the ATOR plugin works using an example. Say an access token is valid for 30 minutes and then expires (after which a new access token has to be fetched). We have three scenarios:
1. Token is valid (Minute 0–29). ATOR sees that the request is valid and forwards the request to the server.
2. Token is expired (Minute 30). ATOR sees that the error condition is met. It triggers the login sequence, fetches a new access token (AT2), and saves the new access token in memory.
3. New access token needs to be used (Minute 31–59). ATOR replaces the token in request headers with AT2 till the error condition is met again. At that time—in this case, on Minute 60—ATOR goes back to Step 2 to fetch a new access token to store in memory.
1. Install the ATOR plugin.
Follow this four-step process for any application or API:
Let’s use the sample application TiredfulAPI by Payatu Labs for a walkthrough. The dockerized version works reliably. We highly recommend doing a sample setup once.
1. Generate an access token:
2. Test API access with the generated token:
3. Test API access with an invalid token:
In this example, we’ll fetch each new access token using a simple one-step login.
1. Identify the login sequence and configure it in ATOR.
We send an existing login response to ATOR:
We configure ATOR to extract the access token from the login response. Here, the variable “token” will contain the token string:
2. Specify the error pattern.
You can specify the error condition in four ways:
In this example, the server returns a status code of 401 when the access token is invalid:
So we specify the error type as “Status Code” and the message / status code value as “401”:
3. Specify the regex pattern to replace in the request.
Sample regex patterns:
In this example, we can see where the access token appears in the request:
So we specify the replacement pattern as Authorization: Bearer \w*.
4. Specify the new data to use in the request.
We set the replacement area as Authorization: Bearer token (we created the variable “token” in Step 1):
Using the same example as above, where the access token is valid for 30 minutes, let’s walk through the different scenarios:
The repeater sends a request with a valid token (AT1). ATOR checks the status code in the response. It’s OK (200), so ATOR sends the response to the repeater:
The Tiredful application allows us to revoke a token. Let’s use this feature to expire AT1:
The next repeater request contains AT1, which we just revoked:
So the server returns a status code of 401. ATOR senses that the error condition is met, invokes the login sequence, and extracts and stores a new token (AT2). Then it checks the flow, finds the last request, replaces the token with AT2, and resends the request:
The next repeater request is still using the expired token:
So ATOR replaces it with AT2 (the token currently stored in memory):
For the sake of completion, let’s run through another revocation of the token:
The next request uses the expired token (AT2):
When the server returns a status code of 401, ATOR invokes the login sequence again and stores the newest token (AT3) in memory. It checks the flow for the last request and resends it with AT3:
The next repeater request uses an expired token:
This time, ATOR just replaces the expired token with AT3 (the token currently stored in memory) instead of invoking the login sequence: