Skip to content
This repository was archived by the owner on May 2, 2025. It is now read-only.

Commit ba3d0b1

Browse files
authored
Merge pull request #128 from dominiqueroux/migrate-montoya
Migrated the extension to the MontoyaAPI.
2 parents 9b72aba + ead5ac6 commit ba3d0b1

File tree

6 files changed

+155
-158
lines changed

6 files changed

+155
-158
lines changed

build.gradle

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ buildscript {
1313
apply plugin: 'java'
1414
apply plugin: 'org.owasp.dependencycheck'
1515

16-
group 'eu.righettod'
17-
version '2.0.1'
16+
group = 'eu.righettod'
17+
version = '2.0.1'
1818
def burpExtensionHomepage = 'https://github.com/righettod/log-requests-to-sqlite'
1919
def burpExtensionJarName = 'LogRequestsToSQLite.jar'
2020

@@ -23,8 +23,9 @@ repositories {
2323
}
2424

2525
dependencies {
26-
compile 'org.xerial:sqlite-jdbc:3.49.1.0'
27-
compile 'net.portswigger.burp.extender:burp-extender-api:2.3'
26+
implementation 'org.xerial:sqlite-jdbc:3.49.1.0'
27+
// implementation 'net.portswigger.burp.extender:burp-extender-api:2.3'
28+
implementation 'net.portswigger.burp.extensions:montoya-api:2025.4'
2829
}
2930

3031
sourceSets {
@@ -39,15 +40,15 @@ sourceSets {
3940
}
4041

4142
compileJava {
42-
targetCompatibility '11'
43-
sourceCompatibility '11'
43+
targetCompatibility = '21'
44+
sourceCompatibility = '21'
4445
}
4546

4647
dependencyCheck {
4748
autoUpdate = true
4849
failOnError = true
4950
failBuildOnCVSS = 1
50-
cveValidForHours = 12
51+
nvd.validForHours = 12
5152
suppressionFile = "odc-suppress.xml"
5253
format = 'JSON'
5354
}
@@ -56,7 +57,7 @@ task fatJar(type: Jar) {
5657
manifest {
5758
attributes("Implementation-Version": project.version, "Implementation-Title": project.name, "Implementation-URL": burpExtensionHomepage)
5859
}
59-
archiveName = burpExtensionJarName
60-
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
60+
archiveBaseName = burpExtensionJarName
61+
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
6162
with jar
6263
}

src/burp/ActivityHttpListener.java

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package burp;
22

3+
import burp.api.montoya.http.message.requests.HttpRequest;
4+
import burp.api.montoya.http.handler.*;
5+
36
import java.util.Locale;
47

58
/**
69
* Handle the recording of HTTP activities into the activity log storage.
710
*/
8-
class ActivityHttpListener implements IHttpListener {
11+
class ActivityHttpListener implements HttpHandler {
912

1013
/**
1114
* Ref on handler that will store the activity information into the activity log storage.
@@ -17,54 +20,59 @@ class ActivityHttpListener implements IHttpListener {
1720
*/
1821
private Trace trace;
1922

20-
/**
21-
* Ref on Burp tool to manipulate the HTTP requests and have access to API to identify the source of the activity (tool name).
22-
*/
23-
private IBurpExtenderCallbacks callbacks;
24-
2523
/**
2624
* Constructor.
2725
*
28-
* @param activityLogger Ref on handler that will store the activity information into the activity log storage.
29-
* @param trace Ref on project logger.
30-
* @param callbacks Ref on Burp tool to manipulate the HTTP requests and have access to API to identify the source of the activity (tool name).
26+
* @param activityLogger Ref on handler that will store the activity information into the activity log storage.
27+
* @param trace Ref on project logger.
3128
*/
32-
ActivityHttpListener(ActivityLogger activityLogger, Trace trace, IBurpExtenderCallbacks callbacks) {
29+
ActivityHttpListener(ActivityLogger activityLogger, Trace trace) {
3330
this.activityLogger = activityLogger;
3431
this.trace = trace;
35-
this.callbacks = callbacks;
32+
}
33+
34+
@Override
35+
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent)
36+
{
37+
//Check if the response will be logged as well. If yes, wait until response is received.
38+
if (!ConfigMenu.INCLUDE_HTTP_RESPONSE_CONTENT) {
39+
try {
40+
if (this.mustLogRequest(requestToBeSent)) {
41+
this.activityLogger.logEvent(requestToBeSent, null, requestToBeSent.toolSource().toolType().toolName());
42+
}
43+
} catch (Exception e) {
44+
this.trace.writeLog("Cannot save request: " + e.getMessage());
45+
}
46+
}
47+
return RequestToBeSentAction.continueWith(requestToBeSent);
3648
}
3749

3850
/**
3951
* {@inheritDoc}
4052
*/
41-
public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
42-
try {
43-
//Save the information of the current request if the message is an HTTP response and according to the restriction options
44-
if (!messageIsRequest) {
45-
IRequestInfo reqInfo = callbacks.getHelpers().analyzeRequest(messageInfo);
46-
if (this.mustLogRequest(reqInfo)) {
47-
IResponseInfo responseInfoStatusCode = callbacks.getHelpers().analyzeResponse(messageInfo.getResponse());
48-
String statusCode = String.valueOf(responseInfoStatusCode.getStatusCode());
49-
byte[] responseInfo = null;
50-
if (ConfigMenu.INCLUDE_HTTP_RESPONSE_CONTENT) {
51-
responseInfo = messageInfo.getResponse();
52-
}
53-
this.activityLogger.logEvent(toolFlag, reqInfo, messageInfo.getRequest(), statusCode, responseInfo);
53+
@Override
54+
public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived)
55+
{
56+
if (ConfigMenu.INCLUDE_HTTP_RESPONSE_CONTENT) {
57+
try {
58+
//Save the information of the current request if the message is an HTTP response and according to the restriction options
59+
if (this.mustLogRequest(responseReceived.initiatingRequest())) {
60+
this.activityLogger.logEvent(responseReceived.initiatingRequest(), responseReceived, responseReceived.toolSource().toolType().toolName());
5461
}
62+
} catch (Exception e) {
63+
this.trace.writeLog("Cannot save response: " + e.getMessage());
5564
}
56-
} catch (Exception e) {
57-
this.trace.writeLog("Cannot save request: " + e.getMessage());
5865
}
66+
return ResponseReceivedAction.continueWith(responseReceived);
5967
}
6068

6169
/**
6270
* Determine if the current request must be logged according to the configuration options selected by the users.
6371
*
64-
* @param reqInfo Information about the current request
72+
* @param request HttpRequest object containing all the information about the request
6573
* @return TRUE if the request must be logged, FALSE otherwise
6674
*/
67-
private boolean mustLogRequest(IRequestInfo reqInfo) {
75+
private boolean mustLogRequest(HttpRequest request) {
6876
//By default: Request is logged
6977
boolean mustLogRequest = true;
7078

@@ -75,7 +83,7 @@ private boolean mustLogRequest(IRequestInfo reqInfo) {
7583
//First: We check if we must apply restriction about image resource
7684
if (ConfigMenu.EXCLUDE_IMAGE_RESOURCE_REQUESTS) {
7785
//Get the file extension of the current URL and remove the parameters from the URL
78-
String filename = reqInfo.getUrl().getFile();
86+
String filename = request.url();
7987
if (filename != null && filename.indexOf('?') != -1) {
8088
filename = filename.substring(0, filename.indexOf('?')).trim();
8189
}
@@ -91,7 +99,7 @@ private boolean mustLogRequest(IRequestInfo reqInfo) {
9199
}
92100
//Secondly: We check if we must apply restriction about the URL scope
93101
//Configuration restrictions options are applied in sequence so we only work here if the request is marked to be logged
94-
if (mustLogRequest && ConfigMenu.ONLY_INCLUDE_REQUESTS_FROM_SCOPE && !this.callbacks.isInScope(reqInfo.getUrl())) {
102+
if (mustLogRequest && ConfigMenu.ONLY_INCLUDE_REQUESTS_FROM_SCOPE && ! request.isInScope()) {
95103
mustLogRequest = false;
96104
}
97105
}

src/burp/ActivityLogger.java

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
import java.time.LocalDateTime;
1111
import java.time.format.DateTimeFormatter;
1212

13+
import burp.api.montoya.MontoyaApi;
14+
import burp.api.montoya.http.message.requests.HttpRequest;
15+
import burp.api.montoya.http.message.responses.HttpResponse;
16+
import burp.api.montoya.extension.ExtensionUnloadingHandler;
17+
1318
/**
1419
* Handle the recording of the activities into the real storage, SQLite local DB here.
1520
*/
16-
class ActivityLogger implements IExtensionStateListener {
21+
class ActivityLogger implements ExtensionUnloadingHandler {
1722

1823
/**
1924
* SQL instructions.
@@ -25,12 +30,6 @@ class ActivityLogger implements IExtensionStateListener {
2530
private static final String SQL_BIGGEST_REQUEST_AMOUNT_DATA_SENT = "SELECT MAX(LENGTH(REQUEST_RAW)) FROM ACTIVITY";
2631
private static final String SQL_MAX_HITS_BY_SECOND = "SELECT COUNT(REQUEST_RAW) AS HITS, SEND_DATETIME FROM ACTIVITY GROUP BY SEND_DATETIME ORDER BY HITS DESC";
2732

28-
/**
29-
* Empty string to use when response must be not be logged.
30-
*/
31-
private static final String EMPTY_RESPONSE_CONTENT = "";
32-
33-
3433
/**
3534
* Use a single DB connection for performance and to prevent DB file locking issue at filesystem level.
3635
*/
@@ -41,11 +40,6 @@ class ActivityLogger implements IExtensionStateListener {
4140
*/
4241
private String url;
4342

44-
/**
45-
* Ref on Burp tool to manipulate the HTTP requests and have access to API to identify the source of the activity (tool name).
46-
*/
47-
private IBurpExtenderCallbacks callbacks;
48-
4943
/**
5044
* Ref on project logger.
5145
*/
@@ -60,16 +54,13 @@ class ActivityLogger implements IExtensionStateListener {
6054
/**
6155
* Constructor.
6256
*
63-
* @param storeName Name of the storage that will be created (file path).
64-
* @param callbacks Ref on Burp tool to manipulate the HTTP requests and have access to API to identify the source of the activity (tool name).
65-
* @param trace Ref on project logger.
66-
* @throws Exception If connection with the DB cannot be opened or if the DB cannot be created or if the JDBC driver cannot be loaded.
57+
* @param storeName Name of the storage that will be created (file path).
58+
* @param trace Ref on project logger.
59+
* @throws Exception If connection with the DB cannot be opened or if the DB cannot be created or if the JDBC driver cannot be loaded.
6760
*/
68-
ActivityLogger(String storeName, IBurpExtenderCallbacks callbacks, Trace trace) throws Exception {
61+
ActivityLogger(String storeName, MontoyaApi api, Trace trace) throws Exception {
6962
//Load the SQLite driver
7063
Class.forName("org.sqlite.JDBC");
71-
//Affect the properties
72-
this.callbacks = callbacks;
7364
this.trace = trace;
7465
updateStoreLocation(storeName);
7566
}
@@ -98,26 +89,32 @@ void updateStoreLocation(String storeName) throws Exception {
9889
/**
9990
* Save an activity event into the storage.
10091
*
101-
* @param toolFlag A flag indicating the Burp tool that issued the request.
102-
* Burp tool flags are defined in the
103-
* <code>IBurpExtenderCallbacks</code> interface.
104-
* @param reqInfo Details of the request to be processed.
105-
* @param reqContent Raw content of the request.
106-
* @throws Exception If event cannot be saved.
92+
* @param request HttpRequest object containing all information about the request
93+
* which was either sent or will be sent out soon.
94+
* @param response HttpResponse object containing all information about the response.
95+
* Is null when only the request ist stored.
96+
* @param tool The name of the tool which was used to issue to request.
97+
* @throws Exception If event cannot be saved.
10798
*/
108-
void logEvent(int toolFlag, IRequestInfo reqInfo, byte[] reqContent, String statusCode, byte[] resContent) throws Exception {
99+
void logEvent(HttpRequest request, HttpResponse response, String tool) throws Exception {
109100
//Verify that the DB connection is still opened
110101
this.ensureDBState();
111102
//Insert the event into the storage
112103
try (PreparedStatement stmt = this.storageConnection.prepareStatement(SQL_TABLE_INSERT)) {
113104
stmt.setString(1, InetAddress.getLocalHost().getHostAddress());
114-
stmt.setString(2, reqInfo.getUrl().toString());
115-
stmt.setString(3, reqInfo.getMethod());
116-
stmt.setString(4, callbacks.getToolName(toolFlag));
117-
stmt.setString(5, callbacks.getHelpers().bytesToString(reqContent));
105+
stmt.setString(2, request.url());
106+
stmt.setString(3, request.method());
107+
stmt.setString(4, tool);
108+
stmt.setString(5, request.toString()); //Apparently, bodyToString() does not work..
118109
stmt.setString(6, LocalDateTime.now().format(this.datetimeFormatter));
119-
stmt.setString(7, statusCode);
120-
stmt.setString(8, (resContent != null) ? callbacks.getHelpers().bytesToString(resContent) : EMPTY_RESPONSE_CONTENT);
110+
//Make a distinction if only the request is stored or the response is added as well.
111+
if (response != null) {
112+
stmt.setString(7, String.valueOf(response.statusCode()));
113+
stmt.setString(8, response.bodyToString());
114+
} else {
115+
stmt.setString(7, null);
116+
stmt.setString(8, null);
117+
}
121118
int count = stmt.executeUpdate();
122119
if (count != 1) {
123120
this.trace.writeLog("Request was not inserted, no detail available (insertion counter = " + count + ") !");
@@ -188,8 +185,9 @@ private void ensureDBState() throws Exception {
188185
}
189186

190187
/**
191-
* {@inheritDoc}
188+
* Unloads the extension by releasing the DB connection.
192189
*/
190+
@Override
193191
public void extensionUnloaded() {
194192
try {
195193
if (this.storageConnection != null && !this.storageConnection.isClosed()) {

0 commit comments

Comments
 (0)