Burp Extension Python Tutorial

This post provides step by step instructions for writing a Burp extension in Python. The end result will be an extension that decodes the credentials in an Authorization header using Basic Authentication. More importantly, I’ll go through the code that implements the following processes:

Importing the required modules

Hooking into the Burp Extender API to access all of the base classes and useful methods

Implementing an easier debugger

Creating a message tab and accessing the HTTP request headers

Processing the headers and displaying them in the message tab

While decoding the Authorization value isn’t anything too special, the goal is to show the steps to implement the code in order to create custom extensions to suit the needs of any future test.

Much of this code is inspired by an nVisium video tutorial, which involved writing an extension to decode a cookie value. While that walkthrough is great, it does move quickly, so what follows is my attempt at a gentler introduction to writing an extension. Hopefully you will come away understanding how the code works, so you can write your own extension according to your needs.

Initial setup

Create a directory to store your extensions – I named mine burp-extensions

Download the Jython standalone JAR file – Place into the burp-extensions folder

Download exceptions_fix.py to the burp-extensions folder – This will make debugging much easier

Create a new file (make sure you save it in your burp_extensions folder) in your favorite text editor and start importing the required modules:

Importing the required modules

from burp import IBurpExtender # Required for all extensions
from burp import IMessageEditorTab # Used to create custom tabs within the Burp HTTP message editors
from burp import IMessageEditorTabFactory # Provides rendering or editing of HTTP messages, within within the created tab
import base64 # Required to decode Base64 encoded header value
from exceptions_fix import FixBurpExceptions # Used to make the error messages easier to debug
import sys # Used to write exceptions for exceptions_fix.py debugging

The IBurpExtender module is required for all extensions, while the IMessageEditorTab and IMessageEditorTabFactory will be used to display messages in Burp’s message tab. The base64 module will be used to decode the basic authorization header, and the FixBurpExceptions and sys modules will be used for debugging, which I’ll cover shortly.

Hook into the Burp Extender API to access all of the base classes and useful methods

This class implements IBurpExtender, which is required for all extensions and must be called BurpExtender. Within the required method, registerExtendedCallbacks, the lines self._callbacks and self._helpers assign useful methods from other classes. The callbacks.setExtensionName gives the extension a name, and the callbacks.registerMessageEditorTabFactory is required to implement a new tab. The createNewInstance method is required to create a new HTTP tab. The controller parameter is an IMessageEditorController object, which the new tab can query to retrieve details about the currently displayed message. The editable parameter is a Boolean value that indicates whether the tab is editable or read-only.

Now we can save the file, and load the extension into Burp, which will cause an error.

From this error message, it is difficult for me to figure out exactly what the problem is, but luckily @SecurityMB wrote some magical code to make this readable.

Implement nicer looking error messages

To make the error messages readable, add the following to the code:

In the registerExtenderCallbacks method:

and at the end of the script:

Now the errors should make more sense. To reload the extension, just click the loaded checkbox, unload the extension, and click again to load it.

Now the errors tab should look something like this:

The error specifically mentions that with the createNewInstance method the global name DisplayValues is not defined. This error is of course expected since we have not yet created that class, which we will do now. At this point, your script should look like this:

The DisplayValues class uses Burp’s IMessageEditorTab to create the custom tab, and ultimately controls the logic for whether the tab gets displayed and its message. This class requires several methods to be implemented for it to work. Here is the code that will create a tab and display all of the request headers:

class DisplayValues(IMessageEditorTab):
''' Creates a message tab, and controls the logic of which portion
of the HTTP message is processed.
'''
def __init__(self, extender, controller, editable):
''' Extender is a instance of IBurpExtender class.
Controller is a instance of the IMessageController class.
Editable is boolean value which determines if the text editor is editable.
'''
self._txtInput = extender._callbacks.createTextEditor()
self._extender = extender
def getUiComponent(self):
''' Must be invoked before the editor displays the new HTTP message,
so that the custom tab can indicate whether it should be enabled for
that message.
'''
return self._txtInput.getComponent()
def getTabCaption(self):
''' Returns the name of the custom tab
'''
return "Decoded Authorization Header"
def isEnabled(self, content, isRequest):
''' Determines whether a tab shows up on an HTTP message
'''
if isRequest == True:
requestInfo = self._extender._helpers.analyzeRequest(content)
headers = requestInfo.getHeaders();
headers = [header for header in headers]
self._headers = '\n'.join(headers)
return isRequest and self._headers
def setMessage(self, content, isRequest):
''' Shows the message in the tab if not none
'''
if (content is None):
self._txtInput.setText(None)
self._txtInput.setEditable(False)
else:
self._txtInput.setText(self._headers)
return

If you are following along, paste this code after the BurpExtender class you just created, but be sure to make the FixBurpExceptions() the last line of the script. The comments explain the methods, so I’m only going to focus on the isEnabled and setMessage methods. For more info on this class, you can look at the IMessageEditorTab in the Burp Extender API.

The isEnabled method accepts message contents and the isRequest parameter (which determines whether the message is a request or a response). If the message is a request, the extender helpers extract the request headers, which for the example purposes I assign to the headers variable via a list comprehension and then assign to self._headers as a string (this needs to be a string). I then return the isRequest and self._headers. In the setMessage method, the content will be received and displayed in a new tab. If you reload this extension and make a request, you should now have a new message tab that is displaying the request headers from the requests you make.

Process the headers and populate the message tab

Now that we have access to the headers, you can go ahead and process the headers as you see fit. In this example, we will look for the Authorization: Basic header, and decode it if it is present. We need to make a few changes to the isEnabled and setMessage methods.

The only change made here is displaying the decoded authorization header (self._txtInput.setText(self._decodedAuthorizationHeader)).

Test run

Once you reload the extension, you should have a functional extension which will display a new HTTP message tab if you visit a site requiring Basic Authentication. To test it out, header over to https://httpbin.org/basic-auth/user/passwd and enter in some fake credentials:

Conclusion

Hopefully this walkthrough was a helpful introduction to writing Burp extensions. Below is the full script. If you don’t understand how it works, I urge you to play around with it, putting in print statements in various places so you can experiment. You print statements will appear in the output subtab within the extender tab.

Post navigation

Your email address will not be published. Required fields are marked *

Comment

Name *

Email *

Website

About me…

I’m an information security professional with a focus on offensive security. My day job is in penetration testing, but I also have experience in host defense, audit, and system administration. When I’m not doing that, I enjoy coding, building things in the AWS cloud, and ultra running.