PyBurp is a powerful Burp Suite extension that enables you to write simple Python code to dynamically modify HTTP requests and responses. It is especially useful for handling scenarios where HTTP requests and responses are encrypted, as it supports remote invocation of encryption and decryption methods in Chrome or mobile applications.
In addition, PyBurp supports:
- Complex nested JSON, Query String, and XML Content-Type conversions
- Dynamic registration of custom context menus
- Saving relevant information from HTTP history to an SQLite database
- Chrome DevTools Protocol
- gRPC
- ...
Video
Interaction with Chrome: https://youtu.be/FRCnZ8a7UGI
Interaction with Frida: https://youtu.be/zfvNqd5VmY0?t=45
For method calls in mobile applications, PyBurp relies on Frida for remote interaction.
Please note that the above features have been thoroughly tested on Burp Suite v2024.5.4. It is recommended to use this version or a later one for optimal compatibility and stability.
Download from the Release page or install directly from the BApp Store. You can open PyBurp from the top level menu bar.
To use gRPC or invoke methods in mobile applications, you also need to install pyburp.
pip install pyburp
PyBurp includes several predefined functions. When you define these functions in your script, they are automatically registered in Burp Suite with the corresponding functionality. The detailed predefined functions are listed in the table below:
function name | Description |
---|---|
handleRequest(request, annotations) | Handles requests between Burp Suite and the server |
handleResponse(response, annotations) | Handles responses between Burp Suite and the server |
handleProxyRequest(request, annotations) | Handles requests between the client and Burp Suite |
handleProxyResponse(response, annotations) | Handles responses between the client and Burp Suite |
urlPrefixAllowed(urls) | Sets URL prefixes that the current PyBurp tab is allowed to handle, using urls.add(url) to add prefixes, must use with the above 4 functions. Without writing this function, all requests will go through the four overridden functions above. You can also define your own filters in those four functions above. |
registerContextMenu(menus) | See Registering Context Menus |
processPayload(str) | Provides custom payload processing for Intruder |
handleInteraction(interaction) | Polls the Collaborator server. This method automatically registers a Collaborator client, and Payloads can be obtained via getOOBCanary() . Example script: collaborator.py |
passiveScan(baseRequestResponse) | Passive scanning |
activeScan(baseRequestResponse, auditInsertionPoint) | Performs active scanning |
finish() | Called when the script stops |
After running the script, you can view the registration details in the Details tab of the Extensions in Burp Suite.
To help you get familiar with using predefined functions, PyBurp includes several common scripts, as listed in the table below:
file name | Description |
---|---|
api_documentation.py | Provides documentation of PyBurp’s predefined and built-in functions. No need to run |
notes.md | Save some Payloads (this file is not saved, please create your own). No need to run |
env_init.py | Environment initialization, includes common classes and methods executed automatically in each PyBurp tab. No need to run |
bambdas.py | Quickly extract information from Proxy history, including the following examples: Find large redirect responses, Find secretKey from history, and Custom word list generate from history. |
chrome_devtools_protocol.py | Remote invocation of Chrome DevTools methods |
collaborator.py | Example for Collaborator |
customise_context_menu.py | Example of registering context menus with items like NoSQL injection, race conditions, unicode escape, authorization bypasses |
default.py | Default script demonstrating simple request and response modification |
encryptedCompleteBody.py | Example for handling encrypted HTTP body |
encryptedCompleteBodyAes.py | Example for handling AES encrypted HTTP body |
encryptedJsonParam.py | Example for handling encrypted JSON parameters |
encryptedJsonParamRpc.py | Example of handling encryption and decryption using RPC |
encryptedQueryForm.py | Example of handling encryption and decryption for query strings |
highlight_interesting_http.py | Highlights interesting requests and adds notes. It is generally recommended to use passive scanning |
passive_active_scan.py | Example of active and passive scanning |
process_intruder_payload.py | Create a payload processing for Intruder |
race_condition.py | Race condition examples (single-packet for HTTP2, last-byte sync for HTTP1.1) |
rpc_debug.py | gRPC testing |
save_subdomain_to_sqlite.py | Collects subdomains from Proxy HTTP history and saves them to a database or file |
signatureHeader.py | Handles signatures in headers |
traffic_redirector.py | Demonstrates redirecting outgoing HTTP requests from one host to another |
urls_from_file.py | Reads URLs from a file and send requests (Python threading) |
urls_from_file2.py | Reads URLs from a file and send requests(built-in RequestPool) |
use_pip2_packages.py | Example of using Python third-party libraries. Not all third-party libraries are compatible with Jython |
Please note that modifications to the built-in example script files will not be saved.
To register context menu items in your code, you first need to define a function named registerContextMenu
that accepts a menus
as a parameter.
Then, call the register
method of the menus
object to register specific menu items. The register
method takes three parameters: the name of the menu, the name of the function associated with the menu item (which is called when the menu item is clicked), and the MenuType
. The table below shows the MenuType
options and the requirements for associated functions:
MenuType | Function |
---|---|
CARET | No parameters, returns a string to be inserted at the current cursor position |
SELECTED_TEXT | Accepts the selected string as a parameter and returns the processed string. In writeable HTTP message editor, it replaces the selected string; otherwise, it displays the returned string in a popup. |
REQUEST | Accepts an HttpRequest parameter with no return value,used when only an HTTP request is needed. |
REQUEST_RESPONSE | Accepts an HttpRequestResponse parameter with no return value, used when both HTTP request and response are needed. |
MESSAGE_EDITOR | Accepts a MessageEditorHttpRequestResponse parameter with no return value. This is used when modifying content in HTTP message editor is required; typically, using SELECTED_TEXT is more convenient. |
The following code demonstrates how to register a purify headers
context menu item that removes extraneous request headers from an HTTP message editor request:
def removeBoringHeaders(editor):
request = editor.requestResponse().request()
editor.setRequest(request.withRemovedHeader("Sec-Ch-Ua")\
.withRemovedHeader("Sec-Ch-Ua-Mobile")\
.withRemovedHeader("Sec-Ch-Ua-Platform")\
.withRemovedHeader("Sec-Fetch-Site")\
.withRemovedHeader("Sec-Fetch-Mode")\
.withRemovedHeader("Sec-Fetch-Dest")\
.withRemovedHeader("Priority")
)
def registerContextMenu(menus):
menus.register("purify headers", removeBoringHeaders, MenuType.MESSAGE_EDITOR)
When using MESSAGE_EDITOR
as the menu type, the following two utility methods are also available:
- getSelectedText(editor), Retrieves the selected text, returning a ByteArray object.
- replaceSelectedText(editor, "new string"),Replaces the selected text in editor, returning an HttpRequest object.
For more examples, please refer to customise_context_menu.py.
PyBurp allows calling methods provided by other programs via gRPC. You need to implement the service interfaces defined in burpextender.proto for these calls.。
For Python users, the related service interfaces are already implemented in pyburp. You can install and use this library via pip install pyburp
.
For other programming languages, generate code from the burpextender.proto file and implement the corresponding service interfaces.
Here’s a Python demonstration:
-
Run the RPC server with the following code, which provides
test1
andtest2
functions:import pyburp from base64 import b64encode def test1(s): return b64encode(s) def test2(i, j): return i + j pyburp.expose(test1) pyburp.expose(test2) pyburp.run("127.0.0.1:30051")
-
Run the client code in PyBurp as follows:
server = rpc("localhost", 30051) result1 = server.callFunc('test1', bytearray("123")) result2 = server.callFunc('test2', 3, 4) print(result1) print(result1.tostring()) # or print(bytearray(result1)) print(result2) server.shutdown()
For examples of interactions with Frida, please check server_frida.py
Note:
- PyBurp supports only the following parameter types:
str
,bool
,int
,float
,bytes
,None
. - If the server-side exposed method has only one parameter and it is of type bytes,in PyBurp, you need to wrap the parameter using bytearray or place it in
[]
; otherwise,byte[]
will be treated as a variable-length argument array, with each byte being treated as an individual argument. - The
bytes
type returned by the server is of type array.array('b',initializer) in PyBurp,you can consider it asbyte[]
, except that you need to usetostring()
to convert it to a string instead oftoString()
.
We’re excited about the future of this project and have a roadmap of upcoming work. We welcome contributions from the community to help us achieve our goals. Whether you’re fixing bugs, adding features, or improving documentation, your help is greatly appreciated!. Here’s what we’re focusing on next:
- Simplify the
HttpRequestEditorProvider
andHttpResponseEditorProvider
registration process - Code Completion, here is an example.
- Perhaps a lightweight search box is needed.
- HyperLink clickable.
Thank you for your support and involvement!
-
Why are some Python libraries or methods not available in PyBurp?
PyBurp uses the Jython interpreter rather than standard CPython, so not all third-party Python libraries are compatible. However, it can seamlessly access Java libraries. -
How do you create a byte array compatible with
byte[]
in Jython?
Here are three methods to create it. Note that you need to usetostring()
to convert it to a string instead oftoString()
.- bytestring("asdf")
- bytearray("asdf").getBytes()
import array; print(array.array('b', [97, 115, 100, 102]))
Much of PyBurp’s inspiration comes from Turbo Intruder