Skip to content

Commit

Permalink
dynamic function support
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-m0nst3r committed Jun 30, 2020
1 parent 4eb10a2 commit c470aa8
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 316 deletions.
70 changes: 68 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,82 @@ m0nst3r(Song Xinlei) @ CFCA

# TODO
- [x] to python3, from version `1.3`
- [ ] `dynamic` function transform
- [x] `dynamic` function transform

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

# Usage
# Usage (`=v2.0`)
> NOTE: MAKE SURE YOU HAVE ALL DEPENDENCIES INSTALLED, INCLUDING THE DEPENDENCIES NEEDED FOR YOUR PYTHON SCRIPT
1. install PyRO, version 4 is used.
2. configure python and pyro settings
3. configure the python file you wanna run
4. click "Start server", burpy will read your python script file and get all functions to generate the context menu
5. use context memu item to invoke your script's regarding function
6. write own payload processor, especially usefull with enc/dec

> 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
# the python script sample
Just write your own logic to modify the header/body as your need, and return the header/body, just that simple!

All functions will be extracted to generate context menu, except thos with `_`, `__`, `main` prefix!

```python
class Burpy:
'''
header is dict
body is string
'''
def __init__(self):
'''
here goes some code that will be kept since "start server" clicked, for example, webdriver, which usually takes long time to init
'''
pass

def main(self, header, body):
return header, body

def _test(self, param):
'''
function with `_`, `__`, `main` as starting letter will be ignored for context menu
'''
# param = magic(param)
return param

def encrypt(self, header, body):
'''
Auto Enc/Dec feature require this function
'''
header["Cookie"] = "admin=1"
return header, body

def decrypt(self, header, body):
'''
Auto Enc/Dec feature require this function
'''
# header = magic(header)
# body = magic(body)
return header, body

def processor(self, payload):
'''
Enable Processor feature require this function
payload processor function
'''
return payload+"123"
```

# Usage (`<v2.0`)

> check the examples for scripts
> NOTE: MAKE SURE YOU HAVE ALL DEPENDENCIES INSTALLED, INCLUDING THE DEPENDENCIES NEEDED FOR YOUR PYTHON SCRIPT
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>me.m0nst3r</groupId>
<artifactId>burpy</artifactId>
<version>1.3-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>
<name>burpy</name>
<description>burp plugin to run custom python</description>
<properties>
Expand Down
135 changes: 135 additions & 0 deletions res/burpyServicePyro3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#coding:utf-8
import Pyro4
import sys

m_module = sys.argv[-1]

import importlib.util
module_name = m_module.split("/")[-1][:-2]
spec = importlib.util.spec_from_file_location('{}.Burpy'.format(module_name),m_module)
b = importlib.util.module_from_spec(spec)
spec.loader.exec_module(b)

from base64 import b64decode as b64d

class http:
'''
accept data string
'''

def __init__(self,data):
self.data = data
self.first_line, self.headers, self.body = self.parse_headers_and_body(data)

def parse_headers(self, s):
headers = s.split("\r\n")
headers_found = {}
for header_line in headers:
try:
key, value = header_line.split(':', 1)
except:
continue
headers_found[key] = value.strip()
return headers_found

def parse_headers_and_body(self,s):
try:
crlfcrlf = b"\x0d\x0a\x0d\x0a"
crlfcrlfIndex = s.find(crlfcrlf)
headers = s[:crlfcrlfIndex + len(crlfcrlf)].decode("utf-8")
body = s[crlfcrlfIndex + len(crlfcrlf):]
except:
headers = s
body = ''
first_line, headers = headers.split("\r\n", 1)
return first_line.strip(), self.parse_headers(headers), str(body,encoding="utf-8")

# def build(self, isRequest):
def build(self):
'''
convert self to strings
'''
# if(isRequest):
# get headers as dict
newhttp = list()
newhttp.append(self.first_line)
for k in self.headers.keys():
newhttp.append("{}: {}".format(k,self.headers[k]))

newhttp.append("")
newhttp.append(self.body)
newhttp = map(lambda l: l if isinstance(l, bytes) else l.encode('utf-8'), newhttp)

http_str = b'\r\n'.join(newhttp)
return str(http_str,encoding="utf-8")

# else:
# return "response"
# return p

class Unbuffered(object):
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def writelines(self, datas):
self.stream.writelines(datas)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)

@Pyro4.expose
class BridaServicePyro:
def __init__(self, daemon):
self.daemon = daemon
self.burpy = b.Burpy()
self.method_list = [func for func in dir(b.Burpy) if callable(getattr(b.Burpy, func)) and not func.startswith("__") and not func.startswith("_")]

def get_methods(self):
return self.method_list

def invoke_method(self,method_name, data):
data = http(b64d(data))

func = getattr(self.burpy, method_name)
if data is None:
return "Parse HTTP data failed"
try:
# headers is dict, body is str
if func.__name__ != "processor":
data.headers, data.body = func(data.headers, data.body)
ret_val = data.build()
else:
ret_val = func(data)
except Exception as e:
print( e )
ret_val = "{} in BurpyService failed".format(method_name)
return ret_val



@Pyro4.oneway
def shutdown(self):
print('shutting down...')
try:
# self.burpy.down()
del self.burpy
except Exception:
print("burpy.down() method not found, skipped.")
self.daemon.shutdown()

# Disable python buffering (cause issues when communicating with Java...)
sys.stdout = Unbuffered(sys.stdout)
sys.stderr = Unbuffered(sys.stderr)

host = sys.argv[1]
port = int(sys.argv[2])
daemon = Pyro4.Daemon(host=host,port=port)

#daemon = Pyro4.Daemon(host='127.0.0.1',port=9999)
bs = BridaServicePyro(daemon)
uri = daemon.register(bs,objectId='BurpyServicePyro')

print("Ready.")
daemon.requestLoop()
Loading

0 comments on commit c470aa8

Please sign in to comment.