Wednesday, August 8, 2012

Adding GUI features to an extension

A unique feature of our framework is the ability to add your own GUI features to your extensions. It takes advantaged of Jython, the Python for Java platform. There are many tutorials out there on using Jython, but to make your life easier I have added the 'AdvancedSkeleton.py' to the framework for you to take a peak it. It is a working example of a Jython SwingSampler working within our framework. Even with zero experience with Jython/Java you should be able to look at the current code and piece together aspects that you would like available in your extension. If you do have GUI development experience with Java, this is going to be cake for you.

Lets build a new extension that has some GUI functionality. We'll start by importing the correct modules to build a swing based GUI, including other modules that will be used for the extensions features. In this case we'll build a payload encoder and parser.


import javax.swing as swing
import java.awt as awt
import java.net as net
import urllib
import base64
import re
import os
import imp
import inspect



We can then continue on like the usual standard... include our INFO dictionary, our original class, and make sure that we subclass 'Extension'.


class PayloadEncoder(Extension):
    INFO = {
        'Name'    :    'Payload Encoder',
        'Usage'   :    'This extension will help encode and parse out which payloads you will be able to use by stripping out sanitized characters.',
        'Author'  :    'James Lester, Joseph Tartaro'
    }

    def finishedLaunching(self):
        for key in ["Name", "Usage", "Author"]:
            self.printLogTab("%s: %s\n" % (key, self.INFO[key]))
            self.printLogTab("---\n\n")
            PayloadEncoderMain(self)



We can now continue by building the pane we'll be adding to a tab, including the functionality of the extension. This will all be inside of the 'PayloadEncoderMain' class that is initiated upon 'finishedLaunching'. In this case we'll use the 'BorderLayout' layout manager, but you're not limited to this, there are various layout managers to choose from. I won't explain every line in detail, but a quick walkthrough... We setup two panels and define them with the 'BorderLayout' layout manager. We then add borders to them with specific titles, 'Payload Encoder' and 'Payload Parser'. We then populate them with textfields for input and also text areas for output. We then build a split pane that will be populated with both panels, which is then added to a tab and displayed in the GUI via the 'addTabPanel' method.


class PayloadEncoderMain(object):

    def __init__(self, parent):
        self.parent = parent
        
        Panel = swing.JPanel()
        Panel.layout = awt.BorderLayout()
        Panel.border = swing.BorderFactory.createTitledBorder("Payload Encoder")
        self.text = swing.JTextField( actionPerformed = self.encodePayload );
        Panel.add(self.text, Panel.layout.PAGE_START);
        
        self.textArea = swing.JTextArea()
        scrollPane = swing.JScrollPane(self.textArea)
        
        Panel.add(scrollPane, Panel.layout.CENTER)
        
        Panel1 = swing.JPanel()
        Panel1.layout = awt.BorderLayout()
        Panel1.border = swing.BorderFactory.createTitledBorder("Payload Parser")
        self.text1 = swing.JTextField( actionPerformed = self.parsePayload );
        Panel1.add(self.text1, Panel1.layout.PAGE_START);
        
        self.textArea1 = swing.JTextArea()
        scrollPane1 = swing.JScrollPane(self.textArea1)
        
        Panel1.add(scrollPane1, Panel1.layout.CENTER)

        self.splitPane = swing.JSplitPane(swing.JSplitPane.VERTICAL_SPLIT);

        self.splitPane.setDividerLocation(250)
        self.splitPane.setLeftComponent(Panel);
        self.splitPane.setRightComponent(Panel1);

        self.parent.addTabPanel("Options", self.splitPane)




We can now build the methods that are called by the textfields and take input, 'encodePayload' and 'parsePayload'. Since burp already has an encoder, there's no real reason to have our own except for ease while parsing payloads... but the real time saver here is the payload parser. Inside of our 'encodePayload' we append different encodings of the input to the text area, URL, Double URL, Base64, HTML, etc... Someone can now simply take this and add any new encoding they would like, or let us know what you would like and we can update it. In our 'parsePayload' method we start by crawling recursively through 'lib/payloads/' and finding all .txt files. We then go line by line in each file and print out any line that does not include the users supplied input. The idea is that if you're in a situation where you're testing a parameter and single quote and semicolon are sanitized, but other characters get through fine... you can now parse your list of payloads for anything that you can potentially use. We recommend starting by populating it with something like fuzzdb.



    def encodePayload(self, event):
        self.textArea.setText("")
        self.textArea.append("URL Encoded: " + self.urlencode(self.text.getText()) + "\n")
        self.textArea.append("URL Encoded(full): " + self.urlencodefull(self.text.getText()) + "\n")
        self.textArea.append("Double URL Encoded: " + self.doubleurlencode(self.text.getText()) + "\n")
        self.textArea.append("Double URL Encoded(full): " + self.doubleurlencodefull(self.text.getText()) + "\n")
        self.textArea.append("Base64: " + self.base64encode(self.text.getText()) + "\n")
        self.textArea.append("HTML: " + self.htmlencode(self.text.getText()) + "\n")
        
    def parsePayload(self, event):
        self.textArea1.setText("")
        if len(self.text1.getText()) > 0:
            var =  "[" + self.text1.getText() + "]"
            for r,d,f in os.walk("lib/payloads/"):
                for files in f:
                    if files.endswith(".txt"):
                        path = os.path.join(r,files)
                        payloads = open(path, 'r')
                        self.textArea1.append("\n\n=== " + path + " ===\n\n")
                        for line in payloads:
                            if not re.findall(var, line):
                                self.textArea1.append(line)

    def urlencode(self, payload):
        return urllib.quote_plus(payload)

    def urlencodefull(self, payload):
        new = payload
        payload = ""
        for i in new:
            payload += "%" + str(hex(ord(i)))[2:]
        return payload
                
    def doubleurlencode(self, payload):
        payload = self.urlencode(payload)
        return re.sub('%', '%25', payload)
        
    def doubleurlencodefull(self, payload):
        payload = self.urlencodefull(payload)
        return re.sub('%', '%25', payload)

        
    def base64encode(self, payload):
        return base64.urlsafe_b64encode(payload)
        
    def htmlencode(self, payload):
        new = payload
        payload = ""
        for i in new:
            payload += "&#x" + str(hex(ord(i)))[2:] + ";"
        return payload  



There you have it, quickly building an extension with GUI functionality.

Extension Screenshot:


Extension Code:


from Extension import Extension
import javax.swing as swing
import java.awt as awt
import java.net as net
import urllib
import base64
import re
import os
import imp
import inspect

class PayloadEncoder(Extension):
    INFO = {
            'Name'      :   'Payload Encoder',
            'Usage'     :   'This extension will help encode and parse out which payloads you will be able to use by stripping out sanitized characters.',
            'Author'    :   'James Lester, Joseph Tartaro'
    }

    def finishedLaunching(self):
        for key in ["Name", "Usage", "Author"]:
            self.printLogTab("%s: %s\n" % (key, self.INFO[key]))
        self.printLogTab("---\n\n")
        PayloadEncoderMain(self)

class PayloadEncoderMain(object):

    def __init__(self, parent):
        self.parent = parent
        
        Panel = swing.JPanel()
        Panel.layout = awt.BorderLayout()
        Panel.border = swing.BorderFactory.createTitledBorder("Payload Encoder")
        self.text = swing.JTextField( actionPerformed = self.encodePayload );
        Panel.add(self.text, Panel.layout.PAGE_START);
        
        self.textArea = swing.JTextArea()
        scrollPane = swing.JScrollPane(self.textArea)
        
        Panel.add(scrollPane, Panel.layout.CENTER)
        
        Panel1 = swing.JPanel()
        Panel1.layout = awt.BorderLayout()
        Panel1.border = swing.BorderFactory.createTitledBorder("Payload Parser")
        self.text1 = swing.JTextField( actionPerformed = self.parsePayload );
        Panel1.add(self.text1, Panel1.layout.PAGE_START);
        
        self.textArea1 = swing.JTextArea()
        scrollPane1 = swing.JScrollPane(self.textArea1)
        
        Panel1.add(scrollPane1, Panel1.layout.CENTER)

        self.splitPane = swing.JSplitPane(swing.JSplitPane.VERTICAL_SPLIT);

        self.splitPane.setDividerLocation(250)
        self.splitPane.setLeftComponent(Panel);
        self.splitPane.setRightComponent(Panel1);

        self.parent.addTabPanel("Options", self.splitPane)
#(\/)(*;;;;*)(\/) whoop! whoop! whoop! whoop!
#Should add more...
    def encodePayload(self, event):
        self.textArea.setText("")
        self.textArea.append("URL Encoded: " + self.urlencode(self.text.getText()) + "\n")
        self.textArea.append("URL Encoded(full): " + self.urlencodefull(self.text.getText()) + "\n")
        self.textArea.append("Double URL Encoded: " + self.doubleurlencode(self.text.getText()) + "\n")
        self.textArea.append("Double URL Encoded(full): " + self.doubleurlencodefull(self.text.getText()) + "\n")
        self.textArea.append("Base64: " + self.base64encode(self.text.getText()) + "\n")
        self.textArea.append("HTML: " + self.htmlencode(self.text.getText()) + "\n")
        
    def parsePayload(self, event):
        self.textArea1.setText("")
        if len(self.text1.getText()) > 0:
            var =  "[" + self.text1.getText() + "]"
            for r,d,f in os.walk("lib/payloads/"):
                for files in f:
                    if files.endswith(".txt"):
                        path = os.path.join(r,files)
                        payloads = open(path, 'r')
                        self.textArea1.append("\n\n=== " + path + " ===\n\n")
                        for line in payloads:
                            if not re.findall(var, line):
                                self.textArea1.append(line)

    def urlencode(self, payload):
        return urllib.quote_plus(payload)

    def urlencodefull(self, payload):
        new = payload
        payload = ""
        for i in new:
            payload += "%" + str(hex(ord(i)))[2:]
        return payload
                
    def doubleurlencode(self, payload):
        payload = self.urlencode(payload)
        return re.sub('%', '%25', payload)
        
    def doubleurlencodefull(self, payload):
        payload = self.urlencodefull(payload)
        return re.sub('%', '%25', payload)

        
    def base64encode(self, payload):
        return base64.urlsafe_b64encode(payload)
        
    def htmlencode(self, payload):
        new = payload
        payload = ""
        for i in new:
            payload += "&#x" + str(hex(ord(i)))[2:] + ";"
        return payload  

Tuesday, August 7, 2012

Creating a basic extension

So you've set up the framework and have been using it.. but now you want to develop your own extension... Where to start?

If you did not notice, we've included a couple example skeletons for developers to look at so they have a nice base to work with. There are a couple of necessary calls to communicate with the framework and a little bit of a standard we've tried to enforce to make it cleaner for future extensions. For this post we'll go over a very basic extension.

First we'll start by importing some necessary modules
If you're planning on using a right click menu item you'll need to import the IMenuItemHandler module. As for the Extension import, this will always be necessary, it is the deciding factor if the extension will be imported or not.


from burp import IMenuItemHandler
from Extension import Extension



At this point we can now create our class. For all extensions that will be displayed in the GUI and imported will have to have 'Extension' subclassed... with the exception of an outbound extension that will be processed for each request, but that will be covered in a later date. The name of the class will by default be the name of the extension inside of the list. As a standard we've tried to implement a nice INFO dictionary at the beginning of all classes. By default it will print these values to that extensions Log tab so the user can view the extensions Name, Usage, and Author.


class SimpleSkeleton(Extension):
    INFO = {
        'Name'      :   'Simple Skeleton',
        'Usage'     :   'This is a Simple Example Skeleton',
        'Author'    :   'James Lester, Joseph Tartaro'
    }



Once this is complete you can now create the methods you would like for your extension. By default you'll start with a 'finishedLaunching' method that will always process the code once the GUI is finished loading. In this case we'll call the registerMenuItem method to add our right click menu demo. You can get more details on these methods by looking at the burp extender javadocs. In this case:
menuItemCaption - The caption to be displayed on the menu item.
menuItemHandler - The handler to be invoked when the user clicks on the menu item.


    def finishedLaunching(self):
        self.getCallBacks().registerMenuItem("Extension: ___Simple Example Menu Item___", MenuHandler(self))



Now we will create our 'MenuHandler' class with 'IMenuItemHandler' subclassed. Inside of here is the second aspect of our standard INFO dictionary, where it will print to the Log tab. Methods such as 'printLogTab' are available since 'Extension' was subclassed... you can view /Lib/lib/Extension.py to see the other methods that can be used if they're not covered in future tutorials. For this extension we're going to make the method 'menuItemClicked', this is method will be called every time the user clicks the menu item that we've registered. As an example for now, we'll include 'menuItemCaption' and 'messageInfo' from the IMenuItemHandler as arguments, these will be sent from Burp by default when right click the various aspects of the Burp GUI (selections, requests, etc). For now we'll print to the Log tab that "You clicked the simple example button!" and also list all of the URL's from the items selected by the user when they click our menu item.


class MenuHandler(IMenuItemHandler):

    def __init__(self, parent):
        self.parent = parent
        for key in ["Name", "Usage", "Author"]:
            self.parent.printLogTab("%s: %s\n" % (key, self.parent.INFO[key]))

    def menuItemClicked(self, menuItemCaption, messageInfo):
        self.parent.printLogTab("You clicked the simple example button!\n")
        msglen = len(messageInfo)
        for l in range(0,msglen):
            self.parent.printLogTab(str(messageInfo[l].getUrl()) + "\n")



Well, there you have it. A very basic extension that should explain some of the frameworks inner workings to get you started. Feel free to ask questions in the comments, forums, or even our IRC channel (#burp irc.2600.net) Example screenshots:


Extension code:


from burp import IMenuItemHandler
from Extension import Extension

class SimpleSkeleton(Extension):
    INFO = {
            'Name'      :   'Simple Skeleton',
            'Usage'     :   'This is a Simple Example Skeleton',
            'Author'    :   'James Lester, Joseph Tartaro'
    }
    def finishedLaunching(self):
        self.getCallBacks().registerMenuItem("Extension: ___Simple Example Menu Item___", MenuHandler(self))
        


class MenuHandler(IMenuItemHandler):

    def __init__(self, parent):
        self.parent = parent
        for key in ["Name", "Usage", "Author"]:
            self.parent.printLogTab("%s: %s\n" % (key, self.parent.INFO[key]))

    def menuItemClicked(self, menuItemCaption, messageInfo):
        self.parent.printLogTab("You clicked the simple example button!\n")
        msglen = len(messageInfo)
        for l in range(0,msglen):
            #print all selected items in "scope" area
            self.parent.printLogTab(str(messageInfo[l].getUrl()) + "\n")
            #(\/)(*;;;;*)(\/) whoop! whoop! whoop! whoop!

Setting up the Extended framework

I'm going to quickly go over how to get the Burp Suite Extended framework up and running.

First, you'll need to go download it from our github. I would recommend downloading the entire repository as a zip, it has everything that you need, excluding a copy of burp suite. Extract it, to wherever you would like, then add a copy of the Burp Suite Pro jar. The current scripts will look for 'burp.jar', you can simply modify them or rename your jar. That's pretty much it. In a windows environment just double click the burp_extended.bat and osx/nix sh burp_extended.sh.

Now that you're up and running you'll notice a new convenient GUI window for your extensions. All extensions will be able to give output and add settings/gui options to this window... but do not close it, because it will also close burp upon doing so.

You'll notice a list on the left, these are all extensions that have been loaded that may have custom options or print output to a log tab. When you select a specific extension, the right pane of the gui will then be populated by that extensions features and options (if applicable). You'll also notice some new menuitems if you right click on any items inside of the Burp GUI.

Important things to remember:
  • All extensions are within scope. If it is not working make sure that you're working within scope.
  • You need to make sure the request has actually been made and a response has been gathered before you can call an extension to it. e.g. If it's greyed out.


Initial Blog Commit

Hello, world!

Welcome to our new blog about Burp Suite. We'll be posting various tips, tricks, extensions, opinions, unique situations and how we handled them, etc.

First and formost, we would like to showcase our Burp Suite Extended Framework. It is a dynamic extensions framework for Burp Suite where the user can develop multiple extensions in python and run them simultaneously. Some of you may have seen us present this in Las Vegas a couple of weeks ago, if you missed it you can view the presentation here
BSidesLV `12: Occupy Burp Suite

I'll also be showcasing it again at BSidesLA (Aug 16-17) in Los Angeles, you should stop by if you're nearby!

We will try out best to keep on top of this blog and making useful posts for you all. For any questions feel free to comment or email support[at]burpextensions[dot]com

Also please note that we will be using PortSwiggers forums for communication and support of burp extensions. You can also join #burp on irc.2600.net to chat