Skip to content

Commit

Permalink
new functions and new context menu type MESSAGE_EDITOR
Browse files Browse the repository at this point in the history
  • Loading branch information
cyal1 committed Aug 13, 2023
1 parent 506d7f4 commit 6ab823c
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 123 deletions.
14 changes: 7 additions & 7 deletions src/main/java/io/github/cyal1/bcryptmontoya/BcryptMontoya.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import burp.api.montoya.proxy.Proxy;
import burp.api.montoya.scanner.audit.issues.AuditIssue;
import burp.api.montoya.ui.Theme;
import burp.api.montoya.utilities.Utilities;
import org.python.core.*;
import org.python.util.PythonInterpreter;
import javax.swing.*;
Expand All @@ -30,6 +31,7 @@ public class BcryptMontoya implements BurpExtension
public static MontoyaApi Api;
public static Http http;
public static Proxy proxy;
public static Utilities Utils;
public static PythonInterpreter pyInterp = new PythonInterpreter();
private BcryptMontoyaUI codePanel;
public static ArrayList<String> ALLOWED_URL_PREFIX;
Expand All @@ -47,6 +49,8 @@ public enum STATUS {
public void initialize(MontoyaApi api) {
BcryptMontoya.http = api.http();
BcryptMontoya.proxy = api.proxy();
// https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/utilities/Utilities.html
BcryptMontoya.Utils = api.utilities();
BcryptMontoya.Api = api;
this.codePanel = new BcryptMontoyaUI();
ALLOWED_URL_PREFIX = new ArrayList<>();
Expand Down Expand Up @@ -142,8 +146,6 @@ private void initPyEnv(){
// pyInterp = new PythonInterpreter();
pyInterp.setOut(Api.logging().output());
pyInterp.setErr(Api.logging().error());
// https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/utilities/Utilities.html
pyInterp.set("Utils", Api.utilities());
pyInterp.exec(BcryptMontoyaUI.readFromInputStream(BcryptMontoya.class.getResourceAsStream("/initEnv.py")));
}
private void runBtnClick(){
Expand Down Expand Up @@ -236,12 +238,10 @@ public static boolean isPrefixAllowed(String url){
return false;
}

public static void addIssue(java.lang.String name, java.lang.String detail, java.lang.String remediation, java.lang.String baseUrl, burp.api.montoya.scanner.audit.issues.AuditIssueSeverity severity, burp.api.montoya.scanner.audit.issues.AuditIssueConfidence confidence, java.lang.String background, java.lang.String remediationBackground, burp.api.montoya.scanner.audit.issues.AuditIssueSeverity typicalSeverity, burp.api.montoya.http.message.HttpRequestResponse... requestResponses){
Api.siteMap().add(AuditIssue.auditIssue(name, detail,remediation,baseUrl, severity,confidence,background,remediationBackground,typicalSeverity,requestResponses));
}
public static void addIssue(java.lang.String name, java.lang.String detail, java.lang.String remediation, java.lang.String baseUrl, burp.api.montoya.scanner.audit.issues.AuditIssueSeverity severity, burp.api.montoya.scanner.audit.issues.AuditIssueConfidence confidence, java.lang.String background, java.lang.String remediationBackground, burp.api.montoya.scanner.audit.issues.AuditIssueSeverity typicalSeverity, java.util.List<burp.api.montoya.http.message.HttpRequestResponse> requestResponses){
Api.siteMap().add(AuditIssue.auditIssue(name,detail,remediation,baseUrl,severity,confidence,background,remediationBackground,typicalSeverity,requestResponses));
public static void addIssue(AuditIssue auditIssue){
Api.siteMap().add(auditIssue);
}

public static List<Marker> getResponseHighlights(HttpRequestResponse requestResponse, String match)
{
List<Marker> highlights = new LinkedList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class MyContextMenuItemsProvider implements ContextMenuItemsProvider {
public enum MenuType {
CARET, // insertAtCursor lo4j
SELECTED_TEXT, // md5 hex
MESSAGE_EDITOR,
REQUEST, // sendtoxray nosqlinjectioin, fuzz param
REQUEST_RESPONSE, // checkCachePoisoning
}
Expand All @@ -34,10 +35,6 @@ public MyContextMenuItemsProvider() {

@Override
public List<Component> provideMenuItems(ContextMenuEvent event) {
if(event.isFromTool(ToolType.REPEATER)){
BcryptMontoya.pyInterp.set("MessageEditor", event.messageEditorRequestResponse().get());
}

if (BcryptMontoya.status != BcryptMontoya.STATUS.RUNNING || MENUS.size() == 0) {
return null;
}
Expand All @@ -58,10 +55,16 @@ public List<Component> provideMenuItems(ContextMenuEvent event) {
return null;
}

List<Component> messageEditorMenu = registerIterm(MenuType.MESSAGE_EDITOR, event);
List<Component> menus = new ArrayList<>(messageEditorMenu);

if(messageEditorMenu.size()!=0){
menus.add(new JSeparator(JSeparator.HORIZONTAL));
}

// request
List<Component> requestMenu = registerIterm(MenuType.REQUEST, event);
List<Component> menus = new ArrayList<>(requestMenu);

menus.addAll(requestMenu);

if (response != null) {
List<Component> requestResponseMenu = registerIterm(MenuType.REQUEST_RESPONSE, event);
Expand Down Expand Up @@ -110,6 +113,10 @@ private List<Component> registerIterm(MenuType type, ContextMenuEvent event) {
retrieveRequestItem.addActionListener(e -> handleSelectText(event, func));
menuItemList.add(retrieveRequestItem);
}
case MESSAGE_EDITOR -> {
retrieveRequestItem.addActionListener(e -> handleMessageEditor(event, func));
menuItemList.add(retrieveRequestItem);
}
case REQUEST -> {
retrieveRequestItem.addActionListener(e -> handleRequest(event, func));
menuItemList.add(retrieveRequestItem);
Expand Down Expand Up @@ -187,33 +194,13 @@ public void handleCaret(ContextMenuEvent event, PyFunction func) {
public void handleSelectText(ContextMenuEvent event, PyFunction func) {

MessageEditorHttpRequestResponse messageEditor = event.messageEditorRequestResponse().get();

Optional<Range> selectionRange = messageEditor.selectionOffsets();
int startIndex = selectionRange.get().startIndexInclusive();
int endIndex = selectionRange.get().endIndexExclusive();

ByteArray selectText = getSelectedText(messageEditor);
if (event.isFromTool(ToolType.REPEATER) && messageEditor.selectionContext() == MessageEditorHttpRequestResponse.SelectionContext.REQUEST) {
HttpRequest request = messageEditor.requestResponse().request();
ByteArray httpMessage = request.toByteArray();
ByteArray firstSection = httpMessage.subArray(0, startIndex);
ByteArray selectText = request.toByteArray().subArray(selectionRange.get());
ByteArray lastSection;
if (endIndex != httpMessage.length()) {
lastSection = httpMessage.subArray(endIndex, httpMessage.length());
} else {
lastSection = ByteArray.byteArrayOfLength(0);
}
PyObject pythonArguments = Py.java2py(selectText.toString());
PyObject r = func.__call__(pythonArguments);
String newText = (String) r.__tojava__(String.class);
messageEditor.setRequest(HttpRequest.httpRequest(firstSection.withAppended(newText).withAppended(lastSection)));
messageEditor.setRequest(replaceSelectedText(messageEditor, newText));
} else {
ByteArray selectText;
if(MessageEditorHttpRequestResponse.SelectionContext.REQUEST == messageEditor.selectionContext()){
selectText = messageEditor.requestResponse().request().toByteArray().subArray(selectionRange.get());
}else{
selectText = messageEditor.requestResponse().response().toByteArray().subArray(selectionRange.get());
}
PyObject pythonArguments = Py.java2py(selectText.toString());
PyObject r = func.__call__(pythonArguments);
String newText = (String) r.__tojava__(String.class);
Expand All @@ -231,4 +218,45 @@ public void handleSelectText(ContextMenuEvent event, PyFunction func) {
}
}

public void handleMessageEditor(ContextMenuEvent event, PyFunction func) {
PyObject pythonArguments = Py.java2py(event.messageEditorRequestResponse().get());
func.__call__(pythonArguments);
}

public static HttpRequest replaceSelectedText(MessageEditorHttpRequestResponse messageEditor, String newString){
HttpRequest request = messageEditor.requestResponse().request();
if (messageEditor.selectionContext() == MessageEditorHttpRequestResponse.SelectionContext.REQUEST && messageEditor.selectionOffsets().isPresent()) {
Optional<Range> selectionRange = messageEditor.selectionOffsets();
int startIndex = selectionRange.get().startIndexInclusive();
int endIndex = selectionRange.get().endIndexExclusive();
ByteArray httpMessage = request.toByteArray();
ByteArray firstSection = httpMessage.subArray(0, startIndex);
ByteArray lastSection;
if (endIndex != httpMessage.length()) {
lastSection = httpMessage.subArray(endIndex, httpMessage.length());
} else {
lastSection = ByteArray.byteArray();
}
request = HttpRequest.httpRequest(request.httpService(), firstSection.withAppended(newString).withAppended(lastSection));
if(request.body().length() != 0){
request = request.withHeader("Content-Length", String.valueOf(request.body().length()));
}
return request;
}
return request;
}

public static ByteArray getSelectedText(MessageEditorHttpRequestResponse messageEditor){
if (messageEditor.selectionOffsets().isPresent()) {
HttpRequest request = messageEditor.requestResponse().request();
HttpResponse response = messageEditor.requestResponse().response();
Optional<Range> selectionRange = messageEditor.selectionOffsets();
if (messageEditor.selectionContext() == MessageEditorHttpRequestResponse.SelectionContext.REQUEST){
return request.toByteArray().subArray(selectionRange.get());
}else{
return response.toByteArray().subArray(selectionRange.get());
}
}
return ByteArray.byteArray();
}
}
53 changes: 37 additions & 16 deletions src/main/resources/examples/api_documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/message/responses/HttpResponse.html
HttpResponse response

# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/core/Annotations.html
Annotations annotations

# Provide when registering a context menu of type EDIT_REQUEST.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/ui/contextmenu/MessageEditorHttpRequestResponse.html
MessageEditorHttpRequestResponse editor

# Various data conversion and querying features.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/utilities/Utilities.html
Utilities Utils
Expand All @@ -43,28 +36,43 @@
burp.api.montoya.proxy.Proxy proxy

# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/ui/contextmenu/MessageEditorHttpRequestResponse.html
# Only provide for repeater context menu
# Only provide for message editor context menu.
MessageEditorHttpRequestResponse MessageEditor


# Decorator
@run_in_pool(pool: RequestPool)
@run_in_thread


"""
FUNCTIONS
"""
# Create a new instance of HttpRequest from url, if specify the raw_http, it will parse raw http to HttpRequest
makeRequest(url, raw_http=None, fix_content_length=True) -> HttpRequest
# Build HttpRequest from url or raw http
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/message/requests/HttpRequest.html
httpRequestFromUrl()
httpRequest()

# An HTTP service for the HttpRequest.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/HttpService.html
httpService() -> HttpService

# Send HTTP requests
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/http/Http.html
sendReqeust()
sendReqeusts()

# Create annotations with requests and responses
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/core/Annotations.html
annotations()

urlencode()
urldecode()
base64encode()
base64decode()
randomstring(length=8)

# Create a new ByteArray from the provided.
# Same to the `ByteArray byteArray()`.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/core/ByteArray.html#byteArray(byte...)
bytearray()

Expand All @@ -74,15 +82,28 @@
urlparameter()
bodyparameter()
cookieparameter()

# Get all items in the Proxy HTTP history.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/proxy/Proxy.html#history()
# get all items in the Proxy HTTP history.
history()
# Create an issue. Same to auditIssue(*args)

# Create an audit issue for a URL.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/scanner/audit/issues/AuditIssue.html
addIssue()
auditIssue() -> AuditIssue

# Add issue to dashboard
addIssue(auditIssue: AuditIssue)

# Create an audit insertion point based on offsets.
# https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/scanner/audit/insertionpoint/AuditInsertionPoint.html
auditInsertionPoint() -> AuditInsertionPoint

# Create a list with the added markers. Used as the argument for withResponseMarkers and withRequestMarkers.
getResponseHighlights(requestResponse: HttpRequestResponse, highlightString: str)
getResponseHighlights(requestResponse: HttpRequestResponse, highlightString: str) -> List<Marker>

# Only work within message editor context menu. (MESSAGE_EDITOR menu type)
getSelectedText(MessageEditor: MessageEditorHttpRequestResponse) -> ByteArray
replaceSelectedText(MessageEditor: MessageEditorHttpRequestResponse, newText: str) -> HTTPRequest


"""
Expand Down Expand Up @@ -154,7 +175,7 @@ def registerContextMenu(menus):
To register a custom context menu.
:param menus: Using the `register(String menuItemName, PyFunction functionName, MenuType menuType)` method to register a custom context menu.
The menu types include CARET, SELECTED_TEXT, REQUEST, and REQUEST_RESPONSE.
The menu types include CARET, SELECTED_TEXT, REQUEST, REQUEST_RESPONSE and MESSAGE_EDITOR.
For example: menus.register("Base64 Encode", base64Encode, MenuType.SELECTED_TEXT)
:return:
"""
Expand Down
40 changes: 25 additions & 15 deletions src/main/resources/examples/customise_context_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,30 @@ def fuzzParamsOneRequest(request):
sendRequest(modifyAllParamsValue(request, payload, [HttpParameterType.COOKIE]))


def bypass403(request):
def bypass403(messageEditor):
ip = "127.0.0.1"
MessageEditor.setRequest(request.withHeader("X-Forwarded-For", ip).withHeader("X-Originating-IP", ip).withHeader("X-Remote-IP", ip).withHeader("X-Remote-Addr", ip).withHeader("X-Real-IP", ip).withHeader("X-Forwarded-Host", ip).withHeader("X-Client-IP", ip).withHeader("X-Host", ip))
request = messageEditor.requestResponse().request()
messageEditor.setRequest(request.withHeader("X-Forwarded-For", ip).withHeader("X-Originating-IP", ip).withHeader("X-Remote-IP", ip).withHeader("X-Remote-Addr", ip).withHeader("X-Real-IP", ip).withHeader("X-Forwarded-Host", ip).withHeader("X-Client-IP", ip).withHeader("X-Host", ip))


def purify_header(request):
def purify_header(messageEditor):
request = messageEditor.requestResponse().request()
needless_headers = ["Upgrade-Insecure-Requests", "Cache-Control", "Accept", "User-Agent", "Accept-Encoding", "Accept-Language", "Connection"]
for header in request.headers():
if header.name().lower().startswith("sec-") or header.name() in needless_headers:
request = request.withRemovedHeader(header.name())
MessageEditor.setRequest(request)
messageEditor.setRequest(request)


def insert_to_reflect_params(request, response):
def insert_to_reflect_params(messageEditor):
payload = "reflectplz'\">"
request = messageEditor.requestResponse().request()
response = messageEditor.requestResponse().response()
body = response.bodyToString()
for param in request.parameters():
if (param.type() == HttpParameterType.BODY or param.type() == HttpParameterType.URL) and (param.value() in body or urldecode(param.value()) in body):
request = request.withRemovedParameters(param).withParameter(parameter(param.name(), payload, param.type()))
MessageEditor.setRequest(request)
messageEditor.setRequest(request)


@run_in_pool(pool)
Expand All @@ -80,9 +84,9 @@ def no_sql_request(request):
body = requestResponse.response().bodyToString()
for highlight in ["unknown operator", "MongoError", "83b3j45b", "cannot be applied to a field", "expression is invalid"]:
if highlight in body:
addIssue("NoSQL Injection", "String detail", "String remediation", requestResponse.request().url(),
AuditIssueSeverity.HIGH, AuditIssueConfidence.CERTAIN, "String background",
"String remediationBackground", AuditIssueSeverity.MEDIUM, requestResponse.withResponseMarkers(getResponseHighlights(requestResponse, highlight)))
addIssue(auditIssue("NoSQL Injection", "String detail", "String remediation", requestResponse.request().url(),
AuditIssueSeverity.HIGH, AuditIssueConfidence.CERTAIN, "String background",
"String remediationBackground", AuditIssueSeverity.MEDIUM, requestResponse.withResponseMarkers(getResponseHighlights(requestResponse, highlight))))
break


Expand All @@ -107,28 +111,34 @@ def insertAtCursor():
return "'\"><img/src/onerror=alert(1)>"


@run_in_thread
def race_condition_10(request):
sendRequests([request] * 10)


def registerContextMenu(menus):
"""
To register a custom context menu using the register method,
three parameters need to be passed: the menu name, the menu function, and the menu type.
The menu types include CARET, SELECTED_TEXT, REQUEST, and REQUEST_RESPONSE.
The menu types include CARET, SELECTED_TEXT, REQUEST, REQUEST_RESPONSE and MESSAGE_EDITOR.
"""
menus.register("Purify Header", purify_header, MenuType.MESSAGE_EDITOR)
menus.register("Bypass 403", bypass403, MenuType.MESSAGE_EDITOR)
menus.register("Find Reflect Params", insert_to_reflect_params, MenuType.MESSAGE_EDITOR)

menus.register("Base64 Encode", base64Encode, MenuType.SELECTED_TEXT)
menus.register("Unicode Escape", unicodeEscape, MenuType.SELECTED_TEXT)
menus.register("JSON Unicode Escape", jsonUnicodeEscape, MenuType.SELECTED_TEXT)

menus.register("Race Condition x10", race_condition_10, MenuType.REQUEST)
menus.register("Log4Shell", log4shell, MenuType.REQUEST)
menus.register("FUZZ Param perReq", fuzzParamPerRequest, MenuType.REQUEST)
menus.register("FUZZ Param oneReq", fuzzParamsOneRequest, MenuType.REQUEST)
menus.register("NoSQL Injection", noSqliScan, MenuType.REQUEST)
menus.register("Send to Xray", sendRequestWithProxy, MenuType.REQUEST)
menus.register("File Extension Cache Poison", cachePoison, MenuType.REQUEST)
menus.register("Bypass 403", bypass403, MenuType.REQUEST)
menus.register("Purify Header", purify_header, MenuType.REQUEST)

menus.register("Reflect Params", insert_to_reflect_params, MenuType.REQUEST_RESPONSE)

menus.register("Insert XSS", insertAtCursor, MenuType.CARET)
menus.register("XSS At Cursor", insertAtCursor, MenuType.CARET)


def finish():
Expand Down
Loading

0 comments on commit 6ab823c

Please sign in to comment.