Building BurpSuite Extensions

Editing HTTP requests on the fly with the BurpSuite extension

Medium
30 min

Plugin registration

In this module, we will start practicing practical tricks related to HTTP requests. Let's build an extension whose sole purpose is to add a new header to every HTTP request passing through BurpSuite. Start by creating a new file and adding the same mandatory functions as in the previous module.

from burp import IBurpExtender
from burp import IHttpListener

class BurpExtender(IBurpExtender, IHttpListener):
  def registerExtenderCallbacks(self, callbacks):
    self.callbacks = callbacks
    self.helpers = callbacks.getHelpers()
    callbacks.setExtensionName("HTTP headers adder")
    callbacks.registerHttpListener(self)

Choose the desired name for the plugin and remember to register the plugin as an HTTP listener using the registerHttpListener function.

Handling HTTP Messages

Let's continue by adding a function called processHttpMessage.

def processHttpMessage(self, tool_flag, is_request, message_info):
    if is_request:
      return
    else:
      return

This function is called whenever BurpSuite sees an HTTP message, because our plugin is registered as a listener in the previous section. Here you can find BurpSuite's documentation related to that function.

https://portswigger.net/burp/extender/api/burp/ihttplistener.html

This method is invoked when an HTTP request is about to be issued, and when an HTTP response has been received.

The function is provided with three different parameters by Burp (tool_flag, is_request, and message_info.

  • tool_flag parameter provides information about which tool has executed this request (Proxy, repeater, intruder, extension, etc.)
  • is_request parameter is a boolean value indicating whether it is an HTTP request or response
  • message_info - is an object that allows us to process the HTTP message itself

Adding an HTTP Header

Since we only want to handle HTTP requests and not responses, we can focus only on situations where is_request == True.

if is_request:
      # if it is an HTTP request and not a response
      request = message_info.getRequest()
      request_info = self.helpers.analyzeRequest(request)

Through the message_info object, we can call a function named getRequest which returns the raw HTTP message, i.e., a byte array. We feed this into the analyzeRequest function under the previously referenced helpers class. This function returns a request_info object containing analyzed information related to the HTTP request.

  • getRequest - function returns the raw HTTP request
  • helpers class contains numerous functionalities to make life easier, such as this analyzeRequest function that can analyze raw HTTP requests on our behalf

You can find more detailed information about these here: https://portswigger.net/burp/extender/api/burp/iextensionhelpers.html

Next, we continue by ensuring that the target address of the HTTP request is correct. This is achieved by using the getHeaders function through the recently analyzed HTTP request. Other functions of the request_info class can be explored here.

if "127.0.0.1:5000" in request_info.getHeaders()[1]:

getHeaders function returns a list of HTTP request headers. Since we know that in this case the Host header is always the second in the list, we can refer to it directly (this may not be the best code practice, but works in this case). In this case, the target is local port 5000, it may be different in your case!

Finally, we read the body of the HTTP message, construct a new list of headers, add our own header to this list, build a new HTTP message (byte array) from these, and set it in place of the previous HTTP request (remember, at this point, we are still dealing with an incoming HTTP message that has not yet been sent from the device to the website).

body = request[request_info.getBodyOffset():]

new_headers = []
for header in request_info.getHeaders():
    new_headers.append(header)
new_headers.append("Hakatemia-Plugin: Part2")
      
new_message = self.helpers.buildHttpMessage(new_headers, body)
message_info.setRequest(new_message)

getBodyOffset function returns the index where the body of the HTTP message begins. Here is more information if it is not clear at this stage. In practice, we take the bytes from the raw HTTP request starting from where the HTTP body begins to the end of the message. If the request has no body, this will be a None value. Next, we create a new list, to which we add the headers from the previous HTTP request, and finally add our own header to this list.

Following these steps, we construct a new HTTP message from this body and the list of HTTP headers using the buildHttpMessage function of the helpers class. We then set this new modified message in place of the previous message using the setRequest function. The final code looks something like this:

from burp import IBurpExtender
from burp import IHttpListener

class BurpExtender(IBurpExtender, IHttpListener):
  def registerExtenderCallbacks(self, callbacks):
    self.callbacks = callbacks
    self.helpers = callbacks.getHelpers()
    callbacks.setExtensionName("HTTP headers adder")
    callbacks.registerHttpListener(self)

  def processHttpMessage(self, tool_flag, is_request, message_info):
    if is_request:
      request = message_info.getRequest()
      request_info = self.helpers.analyzeRequest(request)

      if "127.0.0.1:5000" in request_info.getHeaders()[1]:
        body = request[request_info.getBodyOffset():]
        
        new_headers = []
        for header in request_info.getHeaders():
          new_headers.append(header)
        new_headers.append("Hakatemia-Plugin: Part2")
      
        new_message = self.helpers.buildHttpMessage(new_headers, body)
        message_info.setRequest(new_message)

    else:
      pass
    return

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.