Hackerman's Hacking Tutorials

The knowledge of anything, since all things have causes, is not acquired or complete unless it is known by its causes. - Avicenna

Dec 19, 2018 - 5 minute read - Comments - Burp Burp extension

Python Utility Modules for Burp Extensions

We can create and load Python/Java utility modules in Burp and then use them in extensions. It's a somewhat unknown/unused capability in Burp's Python/Java extensions.

Note: Alternatively, the modules can be placed in the same path as the extension and loaded/used the same way. For example, instead of putting the Burp Exceptions file in the modules folder, store it in the extension directory.

Loading Modules

If you use Burp, you have seen this screen. This is where we set the Jython jar file. Everyone ignores that second input field here (under Python Environment). Any Python module in this path will be loaded with Burp. Then the extension can use any function/object inside them.

The same capability exists for Java but not for Ruby. In this blog post I will discuss how I use these modules in my Python extensions.

Extender options Extender options

Burp Exceptions Extension

Before starting to develop any Python extension, please make sure to use:

The instructions to set it up are easy and straightforward. You need to load a module and then add a few lines to your extension. Be sure to remove them before you release your code.

Let's say we have referenced a non-existent field or variable in the extension (self.nothing). This is the meaningless error message in we will see Burp:

Burp's error message Burp's error message

This is the error message from the extension (appears in the Output tab):

Meaningful error message Meaningful error message

It actually tells us where the problem is. SO YEAH, USE THE DAMN EXTENSION.

Using Modules

I couldn't find any usage documentation or tutorials about modules. Burp documentation mentions the field but that's about it. If you have setup Burp Exceptions, you have probably figured out how they are imported. Modules are imported by their file name. If our file is named mylibrary.py, it's can be imported in the extension like this:

from mylibrary import *
# or a single function
from mylibrary import myFunction

Now we can use any function inside mylibrary.py (or just myFunction in the second case) in our extension.

Drawback

The end user needs to setup the modules path and copy extra files there. I am also not sure how modules work when extensions are installed from Burp App store.

My solution (yours could be different) is using modules for development/personal/work extensions and then copying the needed functions (or all of them) from the modules to the actual extension for release.

What's Inside the Module?

Anything and everything. Anything you want and think is useful. I have turned it into a utility library. Things like base64 encoding/decoding, encryption (more on that in the next blog post) and functions that use the Burp's IExtensionHelpers methods. It has very helpful methods.

Using IExtensionHelpers in Modules

The only way to get an object to use these methods is through the IBurpExtenderCallbacks.getHelpers() method. As a result, I pass an instance of it manually as a function parameter to each helper function that uses it.

Let's look at a minimal example based on the custom editor tab example at https://github.com/PortSwigger/example-custom-editor-tab/blob/master/python/CustomEditorTab.py.

We will see a complete example in the next blog post. The callbacks object is available inside the registerExtenderCallbacks

class BurpExtender(IBurpExtender, IMessageEditorTabFactory):
    
    #
    # implement IBurpExtender
    #
    
    def	registerExtenderCallbacks(self, callbacks):
        # keep a reference to our callbacks object
        self._callbacks = callbacks
        
        # obtain an extension helpers object
        self._helpers = callbacks.getHelpers()

Here we are saving the helper object as field. This saves it to the extender object that is passed to __init__ of the tab object. Here we are assigning extender to the _extender. What I usually do is, add helpers directly to a field.

class Base64InputTab(IMessageEditorTab):
    def __init__(self, extender, controller, editable):
        self._extender = extender
        self._editable = editable

        # adding helpers as a direct field.
        self.helpers = extender._helpers
        
        # create an instance of Burp's text editor, to display our deserialized data
        self._txtInput = extender._callbacks.createTextEditor()
        self._txtInput.setEditable(editable)

Now we can use self.helpers inside the extension and use its methods like this:

self.helpers.analyzeRequest(content)
self.helpers.base64Encode(someBytes)

Base64 is an exception because Jython already has a base64 module, so it can be written without the need for helpers. You could also write your own implementation of IExtensionHelpers methods but why re-implement when it's already been done.

Note: You cannot use anything that is not in the Jython standard library. For example, pycrypto for encryption/decryption is not available inside Burp extensions. We will discuss a couple of workarounds in the next blog post.

I also pass it directly as a parameter to helper functions inside my Python module:

# inside mylibrary.py

# getInfo processes the request/response and returns info
def getInfo(content, isRequest, helpers):
    if isRequest:
        return helpers.analyzeRequest(content)
    else:
        return helpers.analyzeResponse(content)

# getBody returns the body of a request/response
def getBody(content, isRequest, helpers):
    info = getInfo(content, isRequest, helpers)
    return content[info.getBodyOffset():]

Now instead of manually doing it, we can just call a function and get the body of what we have.

# inside the extension
# import the module
from mylibrary import getInfo, getBody

# later inside one of the tab functions
def setMessage(self, content, isRequest):
    if content is None:
        # clear our display
        self._txtInput.setText(None)
        self._txtInput.setEditable(False)
    
    else:
        # get the body of the message
        body = getBody(content, isRequest, self.helpers)

Conclusion

We learned about Burp modules in Python and Java. In the next blog post, I will use this as a building block to show what I learned from creating a Burp extension to decrypt some custom protocol.