Develop Burp Suite extensions in Java (Montoya API) or Python (Jython).
Use this skill when you need to:
| Feature | Java (Montoya API) | Python (Jython) |
|---|---|---|
| --------- | ------------------- | ----------------- |
| API Version | Montoya API (New) | Extender API (Legacy) |
| Java Version | JDK 21+ | JDK 17+ |
| Performance | Best | Slower |
| Setup Complexity | Medium | Simple |
| Best For | Production extensions | Quick scripts/prototypes |
Recommendation: Use Java for production extensions. Use Python for rapid prototyping.
# Install Java 21
brew install openjdk@21
echo 'export PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Verify installation
java -version
# Install IntelliJ IDEA (optional)
brew install --cask intellij-idea-ce
# Install Java 21
winget install EclipseAdoptium.Temurin.21.JDK
# Set environment variables
$env:JAVA_HOME = "C:\Program Files\Eclipse Adoptium\jdk-21"
$env:Path += ";$env:JAVA_HOME\bin"
# Verify installation
java -version
# Install Java 21
sudo apt-get update
sudo apt-get install temurin-21-jdk
# Verify installation
java -version
# Install IntelliJ IDEA (optional)
sudo snap install intellij-idea-community --classic
# Clone the official starter project
git clone https://github.com/PortSwigger/burp-extensions-montoya-api-starter.git my-extension
cd my-extension
# Build
./gradlew build # macOS/Linux
gradlew.bat build # Windows
# Output: build/libs/my-extension.jar
build/libs/my-extension.jarpackage burp.extension;
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
public class MyExtension implements BurpExtension {
@Override
public void initialize(MontoyaApi api) {
api.extension().setName("My Extension");
api.logging().logToOutput("Extension loaded successfully!");
}
}
import burp.api.montoya.proxy.http.InterceptedRequest;
import burp.api.montoya.proxy.http.ProxyRequestHandler;
import burp.api.montoya.proxy.http.ProxyRequestReceivedAction;
import burp.api.montoya.proxy.http.ProxyRequestToBeSentAction;
public class MyProxyHandler implements ProxyRequestHandler {
private final MontoyaApi api;
public MyProxyHandler(MontoyaApi api) {
this.api = api;
}
@Override
public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {
api.logging().logToOutput("Request: " + interceptedRequest.url());
return ProxyRequestReceivedAction.continueWith(interceptedRequest);
}
@Override
public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {
return ProxyRequestToBeSentAction.continueWith(interceptedRequest);
}
}
import burp.api.montoya.scanner.AuditResult;
import burp.api.montoya.scanner.ScanCheck;
import burp.api.montoya.http.message.HttpRequestResponse;
public class MyScanCheck implements ScanCheck {
private final MontoyaApi api;
public MyScanCheck(MontoyaApi api) {
this.api = api;
}
@Override
public AuditResult passiveAudit(HttpRequestResponse baseRequestResponse) {
// Implement passive scan logic
return null;
}
@Override
public AuditResult activeAudit(HttpRequestResponse baseRequestResponse,
AuditResult auditResult) {
// Implement active scan logic
return null;
}
}
public class MyExtension implements BurpExtension {
@Override
public void initialize(MontoyaApi api) {
api.extension().setName("My Extension");
// Register components
api.proxy().registerRequestHandler(new MyProxyHandler(api));
api.scanner().registerScanCheck(new MyScanCheck(api));
api.userInterface().registerSuiteTab("My Extension", new MyTab());
}
}
my-extension/
├── src/main/java/
│ └── burp/extension/
│ ├── MyExtension.java
│ ├── MyProxyHandler.java
│ └── MyScanCheck.java
├── build.gradle
├── settings.gradle
└── README.md
plugins {
id 'java'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'net.portswigger.burp.extensions:montoya-api:2.3.+'
}
tasks.named('jar') {
manifest {
attributes 'Extension-ClassName': 'burp.extension.MyExtension'
}
}
# burp_extender.py
from burp import IBurpExtender
from burp import IHttpListener
from java.io import PrintWriter
class BurpExtender(IBurpExtender):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName("My Python Extension")
# Setup output streams
self._stdout = PrintWriter(callbacks.getStdout(), True)
self._stderr = PrintWriter(callbacks.getStderr(), True)
self._stdout.println("Extension loaded!")
# Register listeners
callbacks.registerHttpListener(HttpListener(self))
class HttpListener(IHttpListener):
def __init__(self, extender):
self._extender = extender
self._callbacks = extender._callbacks
self._helpers = extender._helpers
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
try:
if messageIsRequest:
requestInfo = self._helpers.analyzeRequest(messageInfo)
url = str(requestInfo.getUrl())
self._extender._stdout.println("Request: " + url)
except Exception as e:
self._extender._stderr.println("Error: " + str(e))
burp_extender.pyAlways wrap your code in try-catch blocks to prevent extension crashes:
Java:
@Override
public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {
try {
// Your logic here
return ProxyRequestReceivedAction.continueWith(interceptedRequest);
} catch (Exception e) {
api.logging().logToError("Error: " + e.getMessage());
return ProxyRequestReceivedAction.continueWith(interceptedRequest);
}
}
Python:
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
try:
# Your logic here
except Exception as e:
self._extender._stderr.println("Error: " + str(e))
isInScope() before heavy processingUse Burp's logging API instead of System.out:
Java:
api.logging().logToOutput("Info message");
api.logging().logToError("Error message");
Python:
self._stdout.println("Info message")
self._stderr.println("Error message")
Only process in-scope requests to improve performance:
Java:
if (api.scope().isInScope(request.url())) {
// Process request
}
Python:
if self._callbacks.isInScope(requestInfo.getUrl()):
# Process request
Register unload handlers to clean up resources:
api.extension().registerUnloadHandler(() -> {
api.logging().logToOutput("Extension unloading...");
// Cleanup resources
});
```
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
```
self._stdout.println() for logging| Issue | Solution |
|---|---|
| ------- | ---------- |
| Extension won't load | Check Java version (21+ required for Montoya API) |
| ClassNotFoundException | Verify Montoya API dependency in build.gradle |
| Python import errors | Check Jython version and path configuration |
| No HTTP traffic | Ensure listener is registered in initialize() |
| Performance issues | Use async processing, limit scope with isInScope() |
| OutOfMemoryError | Increase JVM heap size: -Xmx1g |
Log all HTTP requests passing through Burp Proxy:
public class RequestLogger implements ProxyRequestHandler {
private final MontoyaApi api;
public RequestLogger(MontoyaApi api) {
this.api = api;
}
@Override
public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {
api.logging().logToOutput("[" + interceptedRequest.httpService().host() + "] " +
interceptedRequest.method() + " " + interceptedRequest.url());
return ProxyRequestReceivedAction.continueWith(interceptedRequest);
}
@Override
public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {
return ProxyRequestToBeSentAction.continueWith(interceptedRequest);
}
}
Detect missing security headers:
public class SecurityHeaderCheck implements ScanCheck {
private final MontoyaApi api;
public SecurityHeaderCheck(MontoyaApi api) {
this.api = api;
}
@Override
public AuditResult passiveAudit(HttpRequestResponse baseRequestResponse) {
HttpResponse response = baseRequestResponse.response();
if (response != null) {
List<String> headers = response.headers();
boolean hasXFrameOptions = headers.stream()
.anyMatch(h -> h.toLowerCase().contains("x-frame-options"));
if (!hasXFrameOptions) {
// Report issue
}
}
return null;
}
@Override
public AuditResult activeAudit(HttpRequestResponse baseRequestResponse,
AuditResult auditResult) {
return null;
}
}
Q: Which language should I choose?
A: Use Java for production extensions (better performance, newer API). Use Python for quick scripts and prototyping.
Q: Can I use Python 3?
A: No, Burp Suite uses Jython which supports Python 2.7 syntax only.
Q: Do I need Burp Suite Professional?
A: Community Edition works for most extensions. Some features (like scanner) require Professional.
Q: How do I debug my extension?
A: Use IntelliJ remote debugging for Java. Use print statements and Burp's Output tab for Python.
共 2 个版本