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.
- 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:
# 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)
# 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.