Skip to content

Commit ddd3b4d

Browse files
committed
upgrade pyro due to bug#80 @pyrolite
1 parent 3ec94bd commit ddd3b4d

File tree

12 files changed

+236
-472
lines changed

12 files changed

+236
-472
lines changed

pom.xml

Lines changed: 6 additions & 13 deletions
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>2.4.4-SNAPSHOT</version>
5+
<version>3.0-SNAPSHOT</version>
66
<name>burpy</name>
77
<description>burp plugin to run custom python</description>
88
<properties>
@@ -87,27 +87,20 @@
8787
<version>3.8.1</version>
8888
<scope>test</scope>
8989
</dependency>
90-
90+
9191
<!-- https://mvnrepository.com/artifact/net.razorvine/pyrolite -->
9292
<dependency>
9393
<groupId>net.razorvine</groupId>
9494
<artifactId>pyrolite</artifactId>
95-
<version>4.20</version>
95+
<version>5.1</version>
9696
</dependency>
97-
97+
9898
<!-- https://mvnrepository.com/artifact/net.razorvine/serpent -->
9999
<dependency>
100100
<groupId>net.razorvine</groupId>
101101
<artifactId>serpent</artifactId>
102-
<version>1.23</version>
103-
</dependency>
104-
105-
<!-- Local dependency that must be installed locally with Maven -->
106-
<!-- <dependency>-->
107-
<!-- <groupId>com.fifesoft</groupId>-->
108-
<!-- <artifactId>rsyntaxtextarea</artifactId>-->
109-
<!-- <version>2.6.1.edited</version>-->
110-
<!-- </dependency>-->
102+
<version>1.40</version>
103+
</dependency>
111104

112105
</dependencies>
113106
</project>

res/.idea/.gitignore

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/.idea/inspectionProfiles/profiles_settings.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/.idea/misc.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/.idea/res.iml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

res/burpyServicePyro.py

Lines changed: 126 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,146 @@
1-
#coding:utf-8
2-
import codecs
3-
import Pyro4
1+
# coding:utf-8
2+
# import Pyro4
3+
# from Pyro5.compatibility import Pyro4
4+
import Pyro5.api
45
import sys
5-
m_module = sys.argv[-1]
6-
import imp
7-
try:
8-
imp.load_source("f",m_module) #imp.load_source("test","/tmp/test.py")
9-
except Exception:
10-
print("Failed to get python file, pls recheck")
11-
from f import Burpy # which loads the destination file
6+
from importlib import reload
7+
import importlib.util
8+
from base64 import b64decode as b64d
129

10+
reload(sys)
11+
m_module = sys.argv[-1]
1312

14-
@Pyro4.expose
15-
class BridaServicePyro:
13+
module_name = m_module.split("/")[-1][:-2]
14+
spec = importlib.util.spec_from_file_location('{}.Burpy'.format(module_name), m_module)
15+
b = importlib.util.module_from_spec(spec)
16+
spec.loader.exec_module(b)
17+
18+
class http:
19+
'''
20+
accept data string
21+
'''
22+
23+
def __init__(self, data):
24+
self.data = data
25+
self.first_line, self.headers, self.body = self.parse_headers_and_body(data)
26+
27+
def parse_headers(self, s):
28+
headers = s.split("\r\n")
29+
headers_found = {}
30+
for header_line in headers:
31+
try:
32+
key, value = header_line.split(':', 1)
33+
except:
34+
continue
35+
headers_found[key] = value.strip()
36+
return headers_found
37+
38+
def parse_headers_and_body(self, s):
39+
try:
40+
crlfcrlf = "\r\n\r\n".encode('utf-8')
41+
crlfcrlfIndex = s.find(crlfcrlf)
42+
headers = s[:crlfcrlfIndex + len(crlfcrlf)].decode("utf-8")
43+
body = s[crlfcrlfIndex + len(crlfcrlf):]
44+
except:
45+
headers = s
46+
body = ''
47+
first_line, headers = headers.split("\r\n", 1)
48+
return first_line.strip(), self.parse_headers(headers), str(body, encoding="utf-8")
49+
50+
# def build(self, isRequest):
51+
def build(self):
52+
'''
53+
convert self to strings
54+
'''
55+
# if(isRequest):
56+
# get headers as dict
57+
newhttp = list()
58+
first_line = self.headers.pop("first_line")
59+
newhttp.append(first_line)
60+
for k in self.headers.keys():
61+
newhttp.append("{}: {}".format(k, self.headers[k]))
62+
63+
newhttp.append("")
64+
newhttp.append(self.body)
65+
newhttp = map(lambda l: l if isinstance(l, bytes) else l.encode('utf-8'), newhttp)
66+
67+
http_str = b'\r\n'.join(newhttp)
68+
return str(http_str, encoding="utf-8")
69+
70+
# else:
71+
# return "response"
72+
# return p
73+
74+
75+
class Unbuffered(object):
76+
def __init__(self, stream):
77+
self.stream = stream
78+
79+
def write(self, data):
80+
self.stream.write(data)
81+
self.stream.flush()
82+
83+
def writelines(self, datas):
84+
self.stream.writelines(datas)
85+
self.stream.flush()
86+
87+
def __getattr__(self, attr):
88+
return getattr(self.stream, attr)
89+
90+
91+
@Pyro5.api.expose
92+
class BurpyServicePyro:
1693
def __init__(self, daemon):
1794
self.daemon = daemon
18-
self.burpy = Burpy()
19-
20-
def disconnect_application(self):
21-
22-
self.device.kill(self.pid)
23-
return
24-
25-
def hello_spawn(self):
26-
data = "it's working"
27-
return data
28-
29-
def hello(self, header, body):
30-
data = body[0].decode("hex")
31-
if data is None:
32-
return "No data selected"
33-
try:
34-
# header is a list, but body is string
35-
# so we append body to header list
36-
nheader, nbody = self.burpy.main(header, data)
37-
nheader = nheader or list()
38-
nheader.append("")
39-
nheader.append(nbody)
40-
http_str = "\x0d\x0a".join(nheader)
41-
ret_val = http_str
42-
43-
except Exception as e:
44-
print( e )
45-
ret_val = "helo(main) BurpyService failed"
46-
return ret_val
47-
48-
def encrypt(self, header, body):
49-
data = body[0].decode("hex")
50-
if data is None:
51-
return "No data selected"
52-
try:
53-
# header is a list, but body is string
54-
# so we append body to header list
55-
nheader, nbody = self.burpy.encrypt(header, data)
56-
nheader = nheader or list()
57-
header.append("")
58-
nheader.append(nbody)
59-
http_str = "\x0d\x0a".join(nheader)
60-
ret_val = http_str
61-
62-
except Exception as e:
63-
print( e )
64-
ret_val = "Encrypt in BurpyService failed"
65-
return ret_val
66-
67-
def decrypt(self, header, body):
68-
data = body[0].decode("hex")
69-
if data is None:
70-
return "No data selected"
71-
try:
72-
# header is a list, but body is string
73-
# so we append body to header list
74-
nheader, nbody = self.burpy.decrypt(header, data)
75-
nheader = nheader or list()
76-
nheader.append("")
77-
nheader.append(nbody)
78-
http_str = "\x0d\x0a".join(nheader)
79-
ret_val = http_str
95+
self.burpy = b.Burpy()
96+
self.method_list = [func for func in dir(b.Burpy) if
97+
callable(getattr(b.Burpy, func)) and not func.startswith("__") and not func.startswith(
98+
"_") and not func == "processor"]
8099

81-
except Exception as e:
82-
print( e )
83-
ret_val = "Decrypt in BurpyService Failed"
84-
return ret_val
100+
def get_methods(self):
101+
return self.method_list
85102

86-
def sign(self, header, body):
87-
data = body[0].decode("hex")
103+
def invoke_method(self, method_name, data):
104+
func = getattr(self.burpy, method_name)
88105
if data is None:
89-
return "No data selected"
106+
return "Parse HTTP data failed"
90107
try:
91-
# header is a list, but body is string
92-
# so we append body to header list
93-
nheader, nbody = self.burpy.sign(header, data)
94-
nheader.append("")
95-
nheader.append(nbody)
96-
http_str = "\x0d\x0a".join(nheader)
97-
ret_val = http_str
98-
108+
# headers is dict, body is str
109+
if func.__name__ != "processor":
110+
# fix processor bug
111+
data = http(b64d(data))
112+
data.headers.update({"first_line": data.first_line})
113+
data.headers, data.body = func(data.headers, data.body)
114+
ret_val = data.build()
115+
else:
116+
ret_val = func(data)
99117
except Exception as e:
100-
print( e )
101-
ret_val = "Can't find method name burpy or script file not found"
118+
print(e)
119+
ret_val = "{} in BurpyService failed".format(method_name)
102120
return ret_val
103121

104-
def processor(self, data):
105-
try:
106-
ret_val = self.burpy.processor(data)
107-
return ret_val
108-
except Exception as e:
109-
print( e )
110-
return "Can't process payload"
111-
122+
# @Pyro5.api.oneway
123+
# def shutdown(self):
124+
# print('shutting down...')
125+
# try:
126+
# # self.burpy.down()
127+
# del self.burpy
128+
# except Exception:
129+
# print("burpy.down() method not found, skipped.")
130+
# self.daemon.close()
112131

113-
@Pyro4.oneway
114-
def shutdown(self):
115-
print('shutting down...')
116-
try:
117-
# self.burpy.down()
118-
del self.burpy
119-
except Exception:
120-
print("burpy.down() method not found, skipped.")
121-
self.daemon.shutdown()
122132

133+
# Disable python buffering (cause issues when communicating with Java...)
134+
sys.stdout = Unbuffered(sys.stdout)
135+
sys.stderr = Unbuffered(sys.stderr)
123136

124137
host = sys.argv[1]
125138
port = int(sys.argv[2])
126-
daemon = Pyro4.Daemon(host=host,port=port)
139+
daemon = Pyro5.api.Daemon(host=host, port=port)
127140

128-
#daemon = Pyro4.Daemon(host='127.0.0.1',port=9999)
129-
bs = BridaServicePyro(daemon)
130-
uri = daemon.register(bs,objectId='BurpyServicePyro')
141+
# daemon = Pyro4.Daemon(host='127.0.0.1',port=9999)
142+
bs = BurpyServicePyro(daemon)
143+
uri = daemon.register(bs, objectId='BurpyServicePyro')
131144

132-
print("Ready.")
145+
print("Ready. Object uri =", uri)
133146
daemon.requestLoop()

0 commit comments

Comments
 (0)