Skip to content

Commit c470aa8

Browse files
committed
dynamic function support
1 parent 4eb10a2 commit c470aa8

File tree

4 files changed

+248
-316
lines changed

4 files changed

+248
-316
lines changed

README.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,82 @@ m0nst3r(Song Xinlei) @ CFCA
1313

1414
# TODO
1515
- [x] to python3, from version `1.3`
16-
- [ ] `dynamic` function transform
16+
- [x] `dynamic` function transform
1717

1818
# Changelog
1919
- change to use class instead of pure function, so that we can init webdriver+selenium when loading without init it per call
2020
- modified plugin to enable 4 function calls: main/enc/dec/sign
2121
- add payload processor
2222
- add auto enc/dec. encrypt function automatically called when you click GO in burp, and decrypt function automatically called when receive response
2323
- changed default pyro4 port, avoiding brida conflicts
24+
- migration to python3
25+
- dynamic context menu items extracted from your python script
2426

25-
# Usage
27+
# Usage (`=v2.0`)
28+
> NOTE: MAKE SURE YOU HAVE ALL DEPENDENCIES INSTALLED, INCLUDING THE DEPENDENCIES NEEDED FOR YOUR PYTHON SCRIPT
29+
30+
1. install PyRO, version 4 is used.
31+
2. configure python and pyro settings
32+
3. configure the python file you wanna run
33+
4. click "Start server", burpy will read your python script file and get all functions to generate the context menu
34+
5. use context memu item to invoke your script's regarding function
35+
6. write own payload processor, especially usefull with enc/dec
36+
37+
> Install editor plugin example: mvn install:install-file -DgroupId=com.fifesoft -DartifactId=rsyntaxtextarea -Dversion=2.6.1.edited -Dpackaging=jar -Dfile=/home/m0nst3r/study/java/rsyntaxtextarea-2.6.1.edited.jar
38+
39+
# the python script sample
40+
Just write your own logic to modify the header/body as your need, and return the header/body, just that simple!
41+
42+
All functions will be extracted to generate context menu, except thos with `_`, `__`, `main` prefix!
43+
44+
```python
45+
class Burpy:
46+
'''
47+
header is dict
48+
body is string
49+
'''
50+
def __init__(self):
51+
'''
52+
here goes some code that will be kept since "start server" clicked, for example, webdriver, which usually takes long time to init
53+
'''
54+
pass
55+
56+
def main(self, header, body):
57+
return header, body
58+
59+
def _test(self, param):
60+
'''
61+
function with `_`, `__`, `main` as starting letter will be ignored for context menu
62+
63+
'''
64+
# param = magic(param)
65+
return param
66+
67+
def encrypt(self, header, body):
68+
'''
69+
Auto Enc/Dec feature require this function
70+
'''
71+
header["Cookie"] = "admin=1"
72+
return header, body
73+
74+
def decrypt(self, header, body):
75+
'''
76+
Auto Enc/Dec feature require this function
77+
78+
'''
79+
# header = magic(header)
80+
# body = magic(body)
81+
return header, body
82+
83+
def processor(self, payload):
84+
'''
85+
Enable Processor feature require this function
86+
payload processor function
87+
'''
88+
return payload+"123"
89+
```
90+
91+
# Usage (`<v2.0`)
2692

2793
> check the examples for scripts
2894
> NOTE: MAKE SURE YOU HAVE ALL DEPENDENCIES INSTALLED, INCLUDING THE DEPENDENCIES NEEDED FOR YOUR PYTHON SCRIPT

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>me.m0nst3r</groupId>
44
<artifactId>burpy</artifactId>
5-
<version>1.3-SNAPSHOT</version>
5+
<version>2.0-SNAPSHOT</version>
66
<name>burpy</name>
77
<description>burp plugin to run custom python</description>
88
<properties>

res/burpyServicePyro3.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#coding:utf-8
2+
import Pyro4
3+
import sys
4+
5+
m_module = sys.argv[-1]
6+
7+
import importlib.util
8+
module_name = m_module.split("/")[-1][:-2]
9+
spec = importlib.util.spec_from_file_location('{}.Burpy'.format(module_name),m_module)
10+
b = importlib.util.module_from_spec(spec)
11+
spec.loader.exec_module(b)
12+
13+
from base64 import b64decode as b64d
14+
15+
class http:
16+
'''
17+
accept data string
18+
'''
19+
20+
def __init__(self,data):
21+
self.data = data
22+
self.first_line, self.headers, self.body = self.parse_headers_and_body(data)
23+
24+
def parse_headers(self, s):
25+
headers = s.split("\r\n")
26+
headers_found = {}
27+
for header_line in headers:
28+
try:
29+
key, value = header_line.split(':', 1)
30+
except:
31+
continue
32+
headers_found[key] = value.strip()
33+
return headers_found
34+
35+
def parse_headers_and_body(self,s):
36+
try:
37+
crlfcrlf = b"\x0d\x0a\x0d\x0a"
38+
crlfcrlfIndex = s.find(crlfcrlf)
39+
headers = s[:crlfcrlfIndex + len(crlfcrlf)].decode("utf-8")
40+
body = s[crlfcrlfIndex + len(crlfcrlf):]
41+
except:
42+
headers = s
43+
body = ''
44+
first_line, headers = headers.split("\r\n", 1)
45+
return first_line.strip(), self.parse_headers(headers), str(body,encoding="utf-8")
46+
47+
# def build(self, isRequest):
48+
def build(self):
49+
'''
50+
convert self to strings
51+
'''
52+
# if(isRequest):
53+
# get headers as dict
54+
newhttp = list()
55+
newhttp.append(self.first_line)
56+
for k in self.headers.keys():
57+
newhttp.append("{}: {}".format(k,self.headers[k]))
58+
59+
newhttp.append("")
60+
newhttp.append(self.body)
61+
newhttp = map(lambda l: l if isinstance(l, bytes) else l.encode('utf-8'), newhttp)
62+
63+
http_str = b'\r\n'.join(newhttp)
64+
return str(http_str,encoding="utf-8")
65+
66+
# else:
67+
# return "response"
68+
# return p
69+
70+
class Unbuffered(object):
71+
def __init__(self, stream):
72+
self.stream = stream
73+
def write(self, data):
74+
self.stream.write(data)
75+
self.stream.flush()
76+
def writelines(self, datas):
77+
self.stream.writelines(datas)
78+
self.stream.flush()
79+
def __getattr__(self, attr):
80+
return getattr(self.stream, attr)
81+
82+
@Pyro4.expose
83+
class BridaServicePyro:
84+
def __init__(self, daemon):
85+
self.daemon = daemon
86+
self.burpy = b.Burpy()
87+
self.method_list = [func for func in dir(b.Burpy) if callable(getattr(b.Burpy, func)) and not func.startswith("__") and not func.startswith("_")]
88+
89+
def get_methods(self):
90+
return self.method_list
91+
92+
def invoke_method(self,method_name, data):
93+
data = http(b64d(data))
94+
95+
func = getattr(self.burpy, method_name)
96+
if data is None:
97+
return "Parse HTTP data failed"
98+
try:
99+
# headers is dict, body is str
100+
if func.__name__ != "processor":
101+
data.headers, data.body = func(data.headers, data.body)
102+
ret_val = data.build()
103+
else:
104+
ret_val = func(data)
105+
except Exception as e:
106+
print( e )
107+
ret_val = "{} in BurpyService failed".format(method_name)
108+
return ret_val
109+
110+
111+
112+
@Pyro4.oneway
113+
def shutdown(self):
114+
print('shutting down...')
115+
try:
116+
# self.burpy.down()
117+
del self.burpy
118+
except Exception:
119+
print("burpy.down() method not found, skipped.")
120+
self.daemon.shutdown()
121+
122+
# Disable python buffering (cause issues when communicating with Java...)
123+
sys.stdout = Unbuffered(sys.stdout)
124+
sys.stderr = Unbuffered(sys.stderr)
125+
126+
host = sys.argv[1]
127+
port = int(sys.argv[2])
128+
daemon = Pyro4.Daemon(host=host,port=port)
129+
130+
#daemon = Pyro4.Daemon(host='127.0.0.1',port=9999)
131+
bs = BridaServicePyro(daemon)
132+
uri = daemon.register(bs,objectId='BurpyServicePyro')
133+
134+
print("Ready.")
135+
daemon.requestLoop()

0 commit comments

Comments
 (0)