I really love Burp. Since I use it on a daily basis I thought there might be some way to automate it. Usually I mainly do these steps to scan some URL:
- Define scope
- Start manual exploring OR spider the URL in order to get some target map
- Activate passive scanning
- Activate live scanning
- Wait to the scan to finish
- Have a look at the results
- Save/export the results
Well these are a lot of steps which have to be done manually. We all know that necessity is the mother of invention so I’ve started looking for some concepts how to automate those steps. This is what I’ve found…
Requirements
Before I’ve started googling for some code I’ve collected some requirements which should be fulfilled:
- Functional
- Ability to communicate with Burp using some API
- Control Burp by command line
- Interact with Burp through some console
- Tamper requests before being sent in the wild
- Create events in order to trigger specific actions
- Technical
- OS independent (should at least work on Linux and Windows)
- Extendibility: Use your favourite programming language (Python, Java whatever) to interact with the API
- Reportings
- Ability to create/generate/export results as XML, CSV, whatever.
Having this written I’ve started googling.
Google found…
Burp Extender lets you load Burp extensions, to extend Burp's functionality using your own or third-party code.
Burp extensions can customize Burp's behavior in numerous ways, such as modifying HTTP requests and responses, customizing the UI, adding custom Scanner checks, and accessing key runtime information, including the Proxy history, Target site map and Scanner results. (Source: http://portswigger.net/burp/help/extender.html)
The GDS Burp API exposes a Python object interface to requests/responses recorded by Burp (whether Proxy/Spider/Repeater, etc). The API is used to parse Burp logs, creating a list of Burp objects that contain the request and response data and related meta-data. (Source: https://github.com/GDSSecurity/burpee)
Jython-Burp-API exposes a Jython interface to the popular Burp Suite web security testing tool, as an alternative to Buby for those testers who prefer Python over Ruby. (Souce: https://github.com/mwielgoszewski/jython-burp-api)
The Burp Extender API is the main component and plays a crucial role in automating burp. There are a lot of extension (Java, Python, Ruby) and you could easily write your own one. As you might have noticed there are 3 main supported languages: Java, Ruby and Python. And because I love the pythonic way of life I had closer look at the Jython Burp API. As stated on the github page you can get a jython console to interact with Burp. That’s crazy! And this was one of my main requirements.
Jython Burp API
First I’ve cloned the github repo and copied Burp into the* jython-burp-api *folder as described in the README.
1
2
3
4
5
6
|
$ ls -l
total 13173
drwxr-xr-x 3 vd vd 1024 2013-07-31 14:50 custom-modules
drwxr-xr-x 4 vd vd 1024 2013-08-02 11:27 jython-burp-api-master
lrwxrwxrwx 1 vd vd 28 2013-07-31 14:19 jython.jar -> jython-standalone-2.7-b1.jar
-rw-r--r-- 1 vd vd 13432713 2013-07-31 13:49 jython-standalone-2.7-b1.jar
|
I *cd into jython-burp-api-master, *copied Burp into it and compiled the Burp Extender files:
1
2
3
4
5
6
7
8
9
10
11
|
$ ls -l
total 9068
-rw-r--r-- 1 vd vd 2087 2013-05-13 20:27 burp.ini
-rwxr-x--- 1 vd vd 9225061 2013-07-31 14:07 burpsuite_pro_v1.5.11.jar
drwxr-xr-x 3 vd vd 1024 2013-05-13 20:27 java
drwxr-xr-x 3 vd vd 1024 2013-07-31 15:39 Lib
-rw-r--r-- 1 vd vd 739 2013-05-13 20:27 LICENSE
-rw-r--r-- 1 vd vd 6662 2013-05-13 20:27 README.md
-rw-r--r-- 1 vd vd 3592 2013-07-31 15:30 run.py
$ javac -cp ../jython.jar java/src/*.java java/src/burp/*.java
|
Afterwards I tried to start Burp (as described in the README) using:
1
2
3
4
5
6
7
|
$ java -Xmx1g -jar ../jython.jar run.py -i -d -B burpsuite_pro_v1.5.11.jar
Traceback (most recent call last):
File "run.py", line 117, in <module>
start_burp(opt, *args)
File "run.py", line 15, in start_burp
from burp_extender import BurpExtender as MyBurpExtender, ConsoleThread
ImportError: No module named burp_extender
|
Hmmm.. Strange. I’ve created this issue and informed the developer about the bug. Finally I was able to solve it by myself. The problem was that jython didn’t know where to find the module *burp_extender. *So the class path had to be changed:
1
2
3
4
5
6
7
8
9
10
|
$ java -jar ../jython.jar -Dpython.path=Lib/ run.py -B burpsuite_pro_v1.5.11.jar -i -d -v
Jython 2.7b1 (default:ac42d59644e9, Feb 9 2013, 15:24:52)
[OpenJDK 64-Bit Server VM (Sun Microsystems Inc.)] on java1.6.0_20
>>>
2013-08-02 11:39:08,582 - BurpExtender - DEBUG - Monitoring jython-burp-api-master/Lib/gds/burp/menu/console.py for changes
2013-08-02 11:39:08,594 - BurpExtender - DEBUG - Monitoring jython-burp-api-master/burp.ini for changes
help
>>> Burp
>>>
|
Ahh there we go! Now you should have Burp fired up and a jython console to interact with. Check out examples for some commands.
Automation
Having this done the next step was to automate the scanning process. The jython console is very helpful but I somehow have to automate Burp with one command. Sth like:
1
|
$ java -jar ../jython.jar -Dpython.path=Lib/ run.py -B burpsuite_pro_v1.5.11.jar --send-to-spider http://dornea.nu --add-to-scope http://dornea.nu -i
|
Well I had some closer look at the *run.py *and modified it a little bit. This is what came out (own modifications have been highlighted):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
# -*- coding: utf-8 -*-
from java.lang import System
from org.python.util import JLineConsole, PythonInterpreter
import logging
import os.path
import sys
import time
from threading import Thread
class MyThread(Thread):
# Run own thread to get things done
def __init__(self, burp, options):
Thread.__init__(self, name='jython-console')
self.opts = options
self.burp = burp
def run(self):
from java.net import URL
# Add new scope
if self.opts.add_to_scope:
self.burp.includeInScope(URL(self.opts.add_to_scope))
print("[--] Added new scope ...")
# Send URL to spider
if self.opts.send_to_spider:
self.burp.sendToSpider(URL(self.opts.send_to_spider))
print("[--] Starting spider ...")
# Start interactive jython console
if self.opts.interactive:
from java.util import Properties
pre_properties = System.getProperties()
pre_properties['python.console'] = 'org.python.util.ReadlineConsole'
post_properties = Properties()
PythonInterpreter.initialize(pre_properties, post_properties, [])
# Attach threaded console to BurpExtender
self.burp.console = console = JLineConsole()
console.set('Burp', self.burp)
try:
self.burp.stdout.write('Launching interactive session...\n')
except Exception:
sys.stdout.write('Launching interactive session...\n')
ConsoleThread(console).start()
def start_burp(options, *args):
sys.path.extend([os.path.join('java', 'src'), options.burp])
from burp_extender import BurpExtender as MyBurpExtender, ConsoleThread
from burp import StartBurp
from pprint import pprint
import BurpExtender
from gds.burp.config import Configuration
if options.debug:
logging.basicConfig(
filename='jython-burp.log',
format='%(asctime)-15s - %(levelname)s - %(message)s',
level=logging.DEBUG)
elif options.verbose:
logging.basicConfig(
filename='jython-burp.log',
format='%(asctime)-15s - %(levelname)s - %(message)s',
level=logging.INFO)
else:
logging.basicConfig(
filename='jython-burp.log',
format='%(asctime)-15s - %(levelname)s - %(message)s',
level=logging.WARN)
# Set the BurpExtender handler to the Pythonic BurpExtender
Burp = MyBurpExtender()
Burp.config = Configuration(os.path.abspath(opt.config))
Burp.opt = options
Burp.args = args
BurpExtender.setHandler(Burp)
StartBurp.main(args)
# In latest Burp, callbacks might not get registered immediately
while not Burp.cb:
time.sleep(0.1)
# Disable Burp Proxy Interception on startup
Burp.setProxyInterceptionEnabled(False)
# Check for options and start new thread(s)
MyThread(Burp, options).start()
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-B', '--load-burp', dest='burp',
help='Load Burp Jar from PATH', metavar='PATH')
parser.add_option('-i', '--interactive',
action='store_true',
help='Run Burp in interactive mode (Jython Console)')
parser.add_option('-f', '--file', metavar='FILE',
help='Restore Burp state from FILE on startup')
parser.add_option('-d', '--debug',
action='store_true',
help='Set log level to DEBUG')
parser.add_option('-v', '--verbose',
action='store_true',
help='Set log level to INFO')
parser.add_option('-P', '--python-path',
default='',
help='Set PYTHONPATH used by Jython')
parser.add_option('-C', '--config',
default='burp.ini',
help='Specify alternate jython-burp config file')
parser.add_option('--disable-reloading',
action='store_true',
help='Disable hot-reloading when a file is changed')
parser.add_option('--send-to-spider', type=str, help='Send URL to spider')
parser.add_option('--add-to-scope', type=str, help='Add URL to scope')
opt, args = parser.parse_args()
if not opt.burp:
print('Load Burp Error: Specify a path to your burp.jar with -B')
parser.print_help()
sys.exit(1)
start_burp(opt, *args)
|
Now I can easily automate following steps:
- send some URL to the spider
- add URL to the scope
1
2
3
4
|
$ java -jar ../jython.jar -Dpython.path=Lib/ testing.py -B burpsuite_pro_v1.5.11.jar --send-to-spider http://heise.de --add-to-scope http://heise.de -i
[--] Added new scope ...
[--] Starting spider ...
...
|
The above code is just a PoC. Maybe I’ll extend it to some features like
- logging (specify format)
- tamper requests before being sent
- export results (XML)
- write results to some DB