# Custom Burp Editors
Scalpel’s main killer feature is the ability to program your own editors using Python.
# Table of content
# Event hooks
# 1. Edit a request
E.g: A simple script to edit a fully URL encoded query string parameter in a request:
from pyscalpel import Request
from pyscalpel.utils import urldecode, urlencode_all
# Hook to initialize the editor's content
def req_edit_in(req: Request) -> bytes | None:
param = req.query.get("filename")
if param is not None:
return urldecode(param)
# Do not modify the request
return None
# Hook to update the request from the editor's modified content
def req_edit_out(req: Request, modified_content: bytes) -> Request:
req.query["filename"] = urlencode_all(modified_content)
return req
- If you open a request with a
filename
query parameter, aScalpel
tab should appear in the editor like shown below: - Once your
req_edit_in()
Python hook is invoked, the tab should contain thefilename
parameter’s URL decoded content. - You can modify it to update the request and thus, include anything you want (e.g: path traversal sequences).
- When you send the request or switch to another editor tab, your Python hook
req_edit_out()
will be invoked to update the parameter.
# 2. Edit a response
It is the same process for editing responses:
def res_edit_in(res: Response) -> bytes | None:
# Displays an additional header in the editor
res.headers["X-Python-In-Response-Editor"] = "res_edit_in"
return bytes(res)
def res_edit_out(_: Response, text: bytes) -> Response | None:
# Recreate a response from the editor's content
res = Response.from_raw(text)
return res
# 3. Multiple tabs example
You can have multiple tabs open at the same time. Just suffix your function names:
E.g: Same script as above but for two parameters: “filename” and “directory”.
from pyscalpel import Request
from pyscalpel.utils import urldecode, urlencode_all
def req_edit_in_filename(req: Request):
param = req.query.get("filename")
if param is not None:
return urldecode(param)
def req_edit_out_filename(req: Request, text: bytes):
req.query["filename"] = urlencode_all(text)
return req
def req_edit_in_directory(req: Request):
param = req.query.get("directory")
if param is not None:
return urldecode(param)
def req_edit_out_directory(req: Request, text: bytes):
req.query["directory"] = urlencode_all(text)
return req
This will result in two open tabs. One for the filename
parameter and one for the directory
parameter (see the second image below).
# Binary editors
editors
To display the contents of your tab in a hexadecimal, binary, octal or decimal editor,
the user can apply the editor
decorator to the req_edit_in
/ res_edit_in
hook:
12def editor(mode: EditorMode): 13 """Decorator to specify the editor type for a given hook 14 15 This can be applied to a req_edit_in / res_edit_in hook declaration to specify the editor that should be displayed in Burp 16 17 Example: 18 ```py 19 @editor("hex") 20 def req_edit_in(req: Request) -> bytes | None: 21 return bytes(req) 22 ``` 23 This displays the request in an hex editor. 24 25 Currently, the only modes supported are `"raw"`, `"hex"`, `"octal"`, `"binary"` and `"decimal"`. 26 27 28 Args: 29 mode (EDITOR_MODE): The editor mode (raw, hex,...) 30 """ 31 32 if mode not in EDITOR_MODES: 33 raise ValueError(f"Argument must be one of {EDITOR_MODES}") 34 35 def decorator(hook: Callable): 36 hook.__annotations__["scalpel_editor_mode"] = mode 37 return hook 38 39 return decorator
Decorator to specify the editor type for a given hook
This can be applied to a req_edit_in / res_edit_in hook declaration to specify the editor that should be displayed in Burp
Example:
@editor("hex")
def req_edit_in(req: Request) -> bytes | None:
return bytes(req)
This displays the request in an hex editor.
Currently, the only modes supported are "raw"
, "hex"
, "octal"
, "binary"
and "decimal"
.
Args: mode (EDITOR_MODE): The editor mode (raw, hex,...)
# Example
E.g.: A simple script displaying requests in a hexadecimal editor and responses in a binary editor:
from pyscalpel import Request, Response, editor
@editor("hex")
def req_edit_in(req: Request) -> bytes | None:
return bytes(req)
@editor("binary")
def res_edit_in(res: Response) -> bytes | None:
return bytes(res)
The hexadecimal editor:
The binary editor:
# Further reading
Learn more about the available hooks in the technical documentation’s Event Hooks & API section.