Wednesday, April 22, 2015

Creating Burp extensions in Python, the "editor" case

Surely you've heard of the Burp Suite, quite useful software to perform security testing of web applications and in general to play with anything that talks HTTP(S). There's even a free edition which is often more than enough since I mostly use just Proxy and Repeater.

You can even write extensions to automate things or support some weird things you might see on top of HTTP. Burp being written in Java, you can write your extensions in Java. They also allow you to write them in Python or Ruby, using Jython or JRuby.

I needed to write an extension recently, in Python since I don't particularly like Java. This post shares my experience and resulting code.

Setting up Burp for Python extensions: Jython

Download the latest 2.7 Standalone Jar (not 2.5 and not the installer). In Burp go to the Extender tab, then the Options tab and set the jython jar location as well as the module directory - a directory where you'll put your python libraries. All set!

Writing our first "editor" extension

Let's say we have an application that makes POST requests with base64 encoded body data and the server replies the same way. The Proxy tab in Burp is not helpful to see what is going on.
It would be nice if we could have:
  • in Proxy, a tab for every request that would show the base64 decoded data
  • same for every response
  • in Repeater, the ability to edit the decoded data so that when we press send, the request gets rebuilt with the modified data base64 encoded

Using Burp extender documentation and inspiring from existing extensions, we can start.

First problems

I noticed a few annoying issues:
  • finding and calling the right Java interfaces to plug to is not easy
  • loading and unloading the extension takes a lot of time
  • doing it a few times and it blows up with an out of memory exception because Java has some issues with garbage, so you have to restart Burp (-Xms1024m helps too)
  • while Burp provides some helpers to parse the requests and responses, parameters, body, every call from Python to Java seems to slow things down
  • debugging your Python code via Burp is difficult as Jython does not seem to support exceptions properly: try/except does not work, and anything that is raised in Python becomes a Java stack trace with no information about the stack trace in Python
  • you end up debugging by printing or just give up
  • Update: Nicolas Gregoire (@Agarri_FR) pointed out that you can use the Python debugger pdb (see this)
  • Update: Philippe Arteau (@h3xstream) also said that pydevd remote debugging should work
We can do better: I'd like to share one way that I've found.

Separating between burp and logic, unit tests

Surely what we're trying to do with this fictional base64 extension can be generalized:
  • we can build a generic burp module to prepare the tabs and editor
  • and put the logic of parsing requests and responses, preparing text and rebuilding the request in a separate module
  • this separate module can then be developed with unit tests in which you put some of the example requests/responses
So here's what I came up with:
  • our Burp extension, using a minimal reusable template (just replace the import)
  • a minimal http parsing library (request, response, headers, query values) useful for extensions
  • our example base64 "editor" extension logic, it's quite minimal as you can see
  • unit tests with raw http messages to test the logic, avoiding the problems of developing the extension with trial and error inside Burp
I hope you'll find it helpful!

Anecdote: no native extensions, pure Python snappy library

For another extension I needed to decode some data compressed with snappy. There's python-snappy unfortunately it's bindings to the default implementation in C++, and Burp being in Java using Jython, we cannot use that. What can we do?

I initially thought I could use org.apache.commons.compress.compressors.snappy but the import fails, so I guess it's not part of Jython, or it has to be explicitly supported, I don't know.

My solution was to re-implement it in pure Python, so if you need it too here it is:
Let me know if you have other solutions.

No comments:

Post a Comment