Building BurpSuite Extensions

Developing an extension with the Montoya API: automatic session management part 2

Medium
30 min

Writing an extension with Java and Montoya API

This module involves transitioning the login automation previously done with Python to a Java implementation of the Montoya API. Here we are using Portswigger's sample example that we opened in our IDEA environment in the previous module. You can also find documentation in the same way here.

We will modify this as follows, so the HttpHandlerExample.java file looks like this.

```java
package example.httphandler;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;

public class HttpHandlerExample implements BurpExtension {
    @Override
    public void initialize(MontoyaApi api) {
        api.extension().setName("HTTP Handler Example");

        //Register our http handler with Burp.
        api.http().registerHttpHandler(new MyHttpHandler(api));
    }
}
```

Here we practically just set our own name for this extension using the setName function. All the more complex functionality happens in the MyHttpHandler.java file:

```java
package example.httphandler;

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.http.HttpService;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.logging.Logging;
import burp.api.montoya.http.message.HttpHeader;

import java.util.List;

import static burp.api.montoya.http.handler.RequestToBeSentAction.continueWith;
import static burp.api.montoya.http.handler.ResponseReceivedAction.continueWith;

class MyHttpHandler implements HttpHandler {
    private static Logging logging = null;
    private static String session_token;
    private static MontoyaApi api;

    public MyHttpHandler(MontoyaApi api) {
        this.logging = api.logging();
        this.api = api;
        this.session_token = null;
    }

    @Override
    public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
        if (isTarget(requestToBeSent)) {
            if (session_token != null) {
                logging.logToOutput("Setting new cookies to request");
                HttpRequest modRequest = requestToBeSent.withUpdatedHeader("Cookie","session="+session_token);
                return continueWith(modRequest);
            }
        }
        
        return continueWith(requestToBeSent);
    }

    @Override
    public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived) {

        if (needsLogin(responseReceived)) {
            logging.logToOutput("Updating cookies");
            makeAuth();

            HttpRequest orig_req = responseReceived.initiatingRequest().withUpdatedHeader("Cookie","session="+session_token);
            HttpService httpService = HttpService.httpService("127.0.0.1",5000,false);
            HttpRequestResponse resp = api.http().sendRequest(orig_req);
            return continueWith(resp.response());
        }
        
        return continueWith(responseReceived);
    }

    private static boolean isTarget(HttpRequestToBeSent httpRequestToBeSent) {
        return httpRequestToBeSent.url().contains("127.0.0.1:5000");
    }

    private static boolean needsLogin(HttpResponseReceived httpResponseReceived) {
        if (httpResponseReceived.statusCode() == (short)302) {
            List<HttpHeader> headers = httpResponseReceived.headers();
            for (HttpHeader header : headers)
            {
                if (header.toString().equalsIgnoreCase("Location: /")) {
                    return true;
                }
            }
        }
        
        return false;
    }

    private static void makeAuth() {
        HttpService httpService = HttpService.httpService("127.0.0.1",5000,false);
        HttpRequest req = HttpRequest.httpRequest(httpService, "POST /login HTTP/1.1\r\nHost: 127.0.0.1:5000\r\nContent-Length: 17\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nusername=username");
        HttpRequestResponse resp = api.http().sendRequest(req);
        session_token = resp.response().cookies().getFirst().value();
    }
}
```

The functionality is completely the same as in the Python version. The only notable differences are that in this example, we no longer use the processHttpMessage function, but rather two separate functions: handleHttpRequestToBeSent and handleHttpResponseReceived. The former is responsible for handling requests and the latter for responses. We also have three custom functions:

  • isTarget - which essentially just checks if the URL address contains our target identifier.
  • needsLogin - which checks if the login cookie has expired based on the HTTP response. It iterates through the headers and checks the status code.
  • makeAuth - which performs a programmatic reauthentication and updates the shared session_token value.

Exercises

Flag

Find the flag from the lab environment and enter it below.

hakatemia pro

Ready to become an ethical hacker?
Start today.

As a member of Hakatemia you get unlimited access to Hakatemia modules, exercises and tools, and you get access to the Hakatemia Discord channel where you can ask for help from both instructors and other Hakatemia members.