Burp Extension Python Tutorial – Encode/Decode/Hash

This post provides step by step instructions for writing a Burp extension using Python. This is different from my previous extension writing tutorial, where we only worked in the message tab, and I will be moving a bit more quickly than in that post. Here is what this post will cover:

  • Importing required modules and accessing Burp’s interface
  • Created a tab for the extension
  • Writing the GUI text fields and buttons
  • Writing functions that occur when you click the buttons

This extension will have its own tab and GUI components, not to mention will be a little more useful than the extension written previously. Here is what we are going to be making:

This is inspired from a tool of the same name included in OWASP’s ZAP. Let’s get started.

Setup

  • Create a folder where you’ll store your extensions – I named mine extensions
  • Download the Jython standalone JAR file – Place into the extensions folder
  • Download exceptions_fix.py to the extensions folder – this will make debugging easier
  • Configure Burp to use Jython – Extender > Options > Python Environment > Select file
  • Create a new file (encodeDecodeHash.py) in your favorite text editor (save it in your extensions folder)

Importing required modules and accessing the Extender API, and implementing the debugger

Let’s write some code:


from burp import IBurpExtender, ITab 
from javax import swing
from java.awt import BorderLayout
import sys
try:
    from exceptions_fix import FixBurpExceptions
except ImportError:
    pass

The IBurpExtender module is required for all extensions, while ITab will register the tab in Burp and send Burp the UI that we will define. The swing library is what is used to build GUI applications with Jython, and we’ll be using layout management, specifically BorderLayout from the java.awt library. The sys module is imported to allow Python errors to be shown in stdout with the help of the FixBurpExceptions script. I placed that in a Try/Except block so if we don’t have the script the code will still work fine. I’ll be adding more imports when we start writing encoding method, but this is enough for now.

This next code snippet will register our extension and create a new tab that will contain the UI. If you’re following along type or paste this code after the imports:


class BurpExtender(IBurpExtender, ITab):
    def registerExtenderCallbacks(self, callbacks):
        
        # Required for easier debugging: 
        # https://github.com/securityMB/burp-exceptions
        sys.stdout = callbacks.getStdout()

        # Keep a reference to our callbacks object
        self.callbacks = callbacks

        # Set our extension name
        self.callbacks.setExtensionName("Encode/Decode/Hash")
        
        # Create the tab
        self.tab = swing.JPanel(BorderLayout())

        # Add the custom tab to Burp's UI
        callbacks.addSuiteTab(self)
        return

    # Implement ITab
    def getTabCaption(self):
        """Return the text to be displayed on the tab"""
        return "Encode/Decode/Hash"
    
    def getUiComponent(self):
        """Passes the UI to burp"""
        return self.tab

try:
    FixBurpExceptions()
except:
    pass

This class implements IBurpExtender, which is required for all extensions and must be called BurpExtender. Within the required method, registerExtendedCallbacks, the line self.callbacks keeps a reference to Burp so we can interact with it, and in our case will be used to create the tab in Burp. ITab requires two methods, getTabCaption and getUiComponent, where getTabCaption returns the name of the tab, and getUiComponent returns the UI itself (self.tab), which is created in the line self.tab=swing.JPanel(). FixBurpExceptions is called at the end of the script just in case we have an error (Thanks @SecurityMB!).

Save the script to your extensions folder and then load the file into Burp: Extender > Extensions > Add > Extension Details > Extension Type: Python > Select file… > encodeDecodeHash.py

The extension should load and you should have a new tab:

This tab doesn’t have any features yet, so let’s build the skeleton of the UI. Before I go into the code, I’ll model out the GUI so that it will hopefully make a little more sense. There are different layout managers that you can use in Java, and I chose to use BorderLayout in the main tab, so when I place panels on the tab, I can specify that they should go in relative positions, such as North or Center. Within the two panels I created boxes that contain other boxes. I did this so that text areas and labels would appear on different lines, but stay in the general area that I wanted them to. There are probably better ways to do this, but here is the model:

Onto the code:


class BurpExtender(IBurpExtender, ITab):
    ...
        self.tab = swing.Jpanel(BorderLayout())

        # Create the text area at the top of the tab
        textPanel = swing.JPanel()
        
        # Create the label for the text area
        boxVertical = swing.Box.createVerticalBox()
        boxHorizontal = swing.Box.createHorizontalBox()
        textLabel = swing.JLabel("Text to be encoded/decoded/hashed")
        boxHorizontal.add(textLabel)
        boxVertical.add(boxHorizontal)

        # Create the text area itself
        boxHorizontal = swing.Box.createHorizontalBox()
        self.textArea = swing.JTextArea('', 6, 100)
        self.textArea.setLineWrap(True)
        boxHorizontal.add(self.textArea)
        boxVertical.add(boxHorizontal)

        # Add the text label and area to the text panel
        textPanel.add(boxVertical)

        # Add the text panel to the top of the main tab
        self.tab.add(textPanel, BorderLayout.NORTH) 

        # Add the custom tab to Burp's UI
        callbacks.addSuiteTab(self)
        return
...

A bit of explanation. The code (textPanel = swing.JPanel()) creates a new panel that will contain the text label and text area. Then, a box is created (boxVertical), that will be used to hold other boxes (boxHorizontal) that contain the text label and area. The horizontal boxes get added to the vertical box (boxVertical.add(boxHorizontal)), the vertical box is added to the panel we created (textPanel.add(boxVertical)), and that panel is added to the main tab panel at the top (BorderLayout.NORTH). Save the code, unload/reload the extension and this is what you should see:

Now we’ll add the tabs:


        self.tab.add(textPanel, BorderLayout.NORTH)

        # Created a tabbed pane to go in the center of the
        # main tab, below the text area
        tabbedPane = swing.JTabbedPane()
        self.tab.add("Center", tabbedPane);

        # First tab
        firstTab = swing.JPanel()
        firstTab.layout = BorderLayout()
        tabbedPane.addTab("Encode", firstTab)

        # Second tab
        secondTab = swing.JPanel()
        secondTab.layout = BorderLayout()
        tabbedPane.addTab("Decode", secondTab)

        # Third tab
        thirdTab = swing.JPanel()
        thirdTab.layout = BorderLayout()
        tabbedPane.addTab("Hash", thirdTab)

        # Add the custom tab to Burp's UI
        callbacks.addSuiteTab(self)
        return
...

After you add this code and save the file, you should have your tabs:

To keep this post short, we’re only going to build out the Encode tab, but the steps will be the same for each tab.


        # First tab
        firstTab = swing.JPanel()
        firstTab.layout = BorderLayout()
        tabbedPane.addTab("Encode", firstTab)

        # Button for first tab
        buttonPanel = swing.JPanel()
        buttonPanel.add(swing.JButton('Encode', actionPerformed=self.encode))
        firstTab.add(buttonPanel, "North")

        # Panel for the encoders. Each label and text field
        # will go in horizontal boxes which will then go in 
        # a vertical box
        encPanel = swing.JPanel()
        boxVertical = swing.Box.createVerticalBox()
        
        boxHorizontal = swing.Box.createHorizontalBox()
        self.b64EncField = swing.JTextField('', 75)
        boxHorizontal.add(swing.JLabel("  Base64   :"))
        boxHorizontal.add(self.b64EncField)
        boxVertical.add(boxHorizontal)

        boxHorizontal = swing.Box.createHorizontalBox()
        self.urlEncField = swing.JTextField('', 75)
        boxHorizontal.add(swing.JLabel("  URL         :"))
        boxHorizontal.add(self.urlEncField)
        boxVertical.add(boxHorizontal)

        boxHorizontal = swing.Box.createHorizontalBox()
        self.asciiHexEncField = swing.JTextField('', 75)
        boxHorizontal.add(swing.JLabel("  Ascii Hex :"))
        boxHorizontal.add(self.asciiHexEncField)
        boxVertical.add(boxHorizontal)

        boxHorizontal = swing.Box.createHorizontalBox()
        self.htmlEncField = swing.JTextField('', 75)
        boxHorizontal.add(swing.JLabel("  HTML       :"))
        boxHorizontal.add(self.htmlEncField)
        boxVertical.add(boxHorizontal)

        boxHorizontal = swing.Box.createHorizontalBox()
        self.jsEncField = swing.JTextField('', 75)
        boxHorizontal.add(swing.JLabel("  JavaScript:"))
        boxHorizontal.add(self.jsEncField)
        boxVertical.add(boxHorizontal)

        # Add the vertical box to the Encode tab
        firstTab.add(boxVertical, "Center")

        # Second tab
        ...

        # Third tab
        ...

        # Add the custom tab to Burp's UI
        callbacks.addSuiteTab(self)
        return

    # Implement the functions from the button clicks
    def encode(self, event):
        pass

    # Implement ITab
    def getTabCaption(self):

First we create a panel (buttonPanel) to hold our button, and then we add a button to the panel and specify the argument actionPerformed=self.encode, where self.encode is a method that will run when the button is clicked. We define encode at the end of the code snippet, and currently have it doing nothing. We’ll implement the encoders later. Now that our panel has a button, we add that to the first tab of the panel (firstTab.add(buttonPanel, “North”)). Next we create a separate panel for the encoder text labels and fields. Similar to before, we create a big box (boxVertical), and then create a horizontal box (boxHorizontal) for each pair of labels/textfields, which then get added to the big box. Finally that big box gets added to the tab. After saving the file and unloading/reloading, this is what the program should look like:

 

The button might not seem to do anything, but it is actually executing the encode method we defined (which does nothing). Lets fix that method and have it encode the user input:


…
try:
    from exceptions_fix import FixBurpExceptions
except ImportError:
    pass
import base64
import urllib
import binascii
import cgi
import json
...

        # Add the custom tab to Burp's UI
        callbacks.addSuiteTab(self)
        return

    # Implement the functions from the button clicks
    def encode(self, event):
        """Encodes the user input and writes the encoded 
        value to text fields.
        """
        self.b64EncField.text = base64.b64encode(self.textArea.text)
        self.urlEncField.text = urllib.quote(self.textArea.text)
        self.asciiHexEncField.text = binascii.hexlify(self.textArea.text)
        self.htmlEncField.text = cgi.escape(self.textArea.text)
        self.jsEncField.text = json.dumps(self.textArea.text) 

    # Implement ITab
    def getTabCaption(self):
…

The encode method sets the text on the encode fields we created by encoding whatever the user types in the top text area (self.textArea.text). Once you save and unload/reload the file you should have full encoding functionality.

And that’s it! The process is the same for the other tabs, and if you’re interested in the whole extension, it is available on my GitHub (Update: I’m maintaining this code for training purposes, but if you do like the extension, you can use EncodeDecodeHash.py in the same repo, which implements GUI improvements (scroll panes, line wrap) and performance improvments (multithreading). Hopefully this post makes developing your own extensions a little easier. It was definitely a good learning experience for me. Feedback is welcome.

One comment

Leave a Reply

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