It is a fact that writing extension for
Burp is a pain, and other tools that do,
only provide plugins in the language they're written in.
So the basic core idea behind
proxenet, is to allow pentesters to easily
interact with HTTP requests/responses in their favorite high-level language.
HOWTO write a plugin
Proxenet was purposely made to be extremely extensible, and as such, it is easy to
write plugins for it in your favorite language. You just have to implement two functions
called (by default)
These two functions have the following properties:
- take 3 arguments
response_id) - type Integer - the request/response identifier. This parameter is unique for each request and allows linking a request to its response(s) from the server (as a response can be delivered in different chunks).
response) - type String - the request/response itself. The format (depending of the interpreter), is either a regular string or an array of bytes.
uri- type String - the full URI
- return a String (or array of bytes)
To use, simply drop the new plugin into the default plugins directory (as defined by
CFG_DEFAULT_PLUGINS_PATH (by default
./proxenet-plugins), or by specifying the
command line option
You can then load the plugin via the client.
>>> plugin load 1MyNewPlugin.rb Plugin '1MyNewPlugin.rb' successfully added!
Step-by-Step : A basic plugin example
For the sake of simplicity, here's a very simple example of a proxenet plugin written in Python. Note that the exact same methodology applies for plugins written in Ruby, Lua, etc.
The demo plugin is purposely dumb. It's simply to make you familiar with the way
proxenet proceeds with plugins. It will append an HTTP header in every request
Let's assume that an instance is already up and running.
A very basic Python template for creating plugins would be like this:
def proxenet_request_hook(request_id, request, uri): return request def proxenet_response_hook(response_id, response, uri): return response if __name__ == "__main__": pass
The "hard" work
Create a new Python script in the plugins directory, and copy/paste this template.
Appending an HTTP header simply means that we want to substitute the double CRLF - marking the end of the HTTP headers blob, with our header, followed by this double CRLF.
The implementation comes then right out of the box:
def proxenet_request_hook(request_id, request, uri): crlf = "\r\n" hdr = "X-Proxenet-Rules: Python-Style" return request.replace(crlf * 2, crlf + hdr + crlf * 2) def proxenet_response_hook(response_id, response, uri): return response if __name__ == "__main__": pass
Plug it in
Once the plugin is ready, simply use the client to load it. Valid loaded scripts will immediately become active, and can also be disabled through the client.
>>> plugin load 1AddHeader.py Plugin '1AddHeader.py' successfully added!
Now use any site and check the headers sent. Yup, it was that simple.
Too easy for you ? Want a more real-life use of
proxenet. No worries, just
A more advanced plugin example
Now let's do some useful stuff.
The following plugin will log every HTTP request/response in a
SQLite database, given us the possibility to
(transparently) save the whole HTTP sessions during a pentest. For the record,
this 'feature' is not available in the free version of BurpSuite. So by hooking
proxenet behind your free Burp and using this plugin, you will never lose any
Re-use working stuff
We will use the exact same template from the previous example, along with 2 Python
time. Both of which are built-in.
The "hard" work
We want our plugin to have a low priority, meaning that other plugins (which
potentially modify requests/responses) will be executed first.
Create a file in the plugins directory, for example
copy/paste the template example provided above.
Unfortunately, SQLite (not unlike many tools and libraries) does not support
proxenet was designed to multi-thread only the
hooking functions and nothing else.
Subsequently, we only need to define the SQLite database object as a Python
global in the main thread. Like this:
import time, sqlite3 class SqliteDb: def __init__(self, dbname="/tmp/proxenet.db"): self.data_file = dbname self.execute("CREATE TABLE requests (id INTEGER, request BLOB, uri TEXT, timestamp INTEGER)") self.execute("CREATE TABLE responses (id INTEGER, response BLOB, uri TEXT, timestamp INTEGER)") return def connect(self): self.conn = sqlite3.connect(self.data_file) self.conn.text_factory = str return self.conn.cursor() def disconnect(self): self.conn.close() return def execute(self, query, values=None): cursor = self.connect() cursor.execute(query, values) self.conn.commit() return cursor db = SqliteDb()
By defining our database globally, the Python main thread acquires the lock for it, but it is still reachable by other threads.
Now we simply have to fill the functions:
def proxenet_request_hook(request_id, request, uri): global db db.execute("INSERT INTO requests VALUES (?, ?, ?, ?)", (request_id, request, uri, int( time.time() ))) return request def proxenet_response_hook(response_id, response, uri): global db db.execute("INSERT INTO responses VALUES (?, ?, ?, ?)", (response_id, response, uri, int( time.time() ))) return response
That's it! Now simply load it in
proxenet and never lose any request/response
again! The full version of this plugin is available
Want to add your 50c ?
The GitHub repository proxenet-plugins contains a few plugins already (more will come). But if you want to share your cool plugin, feel free to send a "Pull Request".
Thanks for using