Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search bar to filter scan results; fix UI logic #58

Merged
merged 17 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/main/java/burp/BurpExtender.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

package burp;

import burp.api.montoya.BurpExtension;
Expand All @@ -14,6 +13,9 @@ public void initialize(MontoyaApi burpApi) {
mainUI.initializeUI();

burpApi.extension().setName(mainUI.getExtensionName());
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
burpApi.logging().logToError(throwable);
});

burpApi.logging().logToOutput("Extension loaded successfully!%nVersion loaded: %s".formatted(Utils.getExtensionVersion()));
} catch (Exception e) {
Expand Down
15 changes: 10 additions & 5 deletions src/main/java/com/cys4/sensitivediscoverer/MainUI.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

package com.cys4.sensitivediscoverer;

import burp.api.montoya.MontoyaApi;
import com.cys4.sensitivediscoverer.model.RegexEntity;
import com.cys4.sensitivediscoverer.model.ScannerOptions;
import com.cys4.sensitivediscoverer.model.RegexScannerOptions;
import com.cys4.sensitivediscoverer.ui.tab.AboutTab;
import com.cys4.sensitivediscoverer.ui.tab.ApplicationTab;
import com.cys4.sensitivediscoverer.ui.tab.LoggerTab;
import com.cys4.sensitivediscoverer.ui.tab.OptionsTab;
import com.cys4.sensitivediscoverer.utils.SwingUtils;

import javax.swing.*;
import java.awt.*;
Expand All @@ -21,7 +21,7 @@ public class MainUI {
private final List<RegexEntity> generalRegexList;
private final List<RegexEntity> extensionsRegexList;
private final Properties configProperties;
private final ScannerOptions scannerOptions;
private final RegexScannerOptions scannerOptions;
private JTabbedPane mainPanel;
private boolean interfaceInitialized;

Expand All @@ -31,7 +31,7 @@ public MainUI(MontoyaApi burpApi) throws Exception {

// parse configurations
this.configProperties = loadConfigFile();
scannerOptions = new ScannerOptions();
scannerOptions = new RegexScannerOptions();
scannerOptions.setConfigMaxResponseSize(Integer.parseInt(configProperties.getProperty("config.max_response_size")));
scannerOptions.setConfigNumberOfThreads(Integer.parseInt(configProperties.getProperty("config.number_of_threads")));
scannerOptions.setConfigRefineContextSize(Integer.parseInt(configProperties.getProperty("config.scanner.refine_context_size")));
Expand All @@ -47,7 +47,7 @@ public boolean isInterfaceInitialized() {
return interfaceInitialized;
}

public ScannerOptions getScannerOptions() {
public RegexScannerOptions getScannerOptions() {
return scannerOptions;
}

Expand All @@ -58,7 +58,12 @@ public void initializeUI() {
SwingUtilities.invokeLater(this::_initializeUI);
}

/**
* UI initialization logic that must run in the EDT
*/
private void _initializeUI() {
SwingUtils.assertIsEDT();

mainPanel = new JTabbedPane();
LoggerTab loggerTab = new LoggerTab(this);
mainPanel.addTab(loggerTab.getTabName(), loggerTab.getPanel());
Expand Down
63 changes: 49 additions & 14 deletions src/main/java/com/cys4/sensitivediscoverer/RegexScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@
import com.cys4.sensitivediscoverer.utils.BurpUtils;
import com.cys4.sensitivediscoverer.utils.ScannerUtils;

import javax.swing.*;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
* Class to perform scans of HTTP items using regexes.
* <br><br>
* <b>Warning</b>: this class doesn't support concurrent scans within a single instance.
*/
public class RegexScanner {
/**
* List of MIME types to ignore while scanning when the relevant option is enabled
Expand All @@ -42,33 +48,50 @@ public class RegexScanner {
MimeType.VIDEO
);
private final MontoyaApi burpApi;
private final ScannerOptions scannerOptions;
private final RegexScannerOptions scannerOptions;
private final List<RegexEntity> generalRegexList;
private final List<RegexEntity> extensionsRegexList;
private final Object analyzeLock = new Object();
/**
* Flag that indicates if the scan must be interrupted.
* Used to interrupt scan before completion.
*/
private boolean interruptScan;
private volatile boolean interruptScan;
/**
* Counter of analyzed items. Used mainly for the progress bar
*/
private int analyzedItems;
/**
* Reference to a progress bar to update during the scan
*/
private JProgressBar progressBar;

public RegexScanner(MontoyaApi burpApi,
ScannerOptions scannerOptions,
RegexScannerOptions scannerOptions,
List<RegexEntity> generalRegexList,
List<RegexEntity> extensionsRegexList) {
this.burpApi = burpApi;
this.scannerOptions = scannerOptions;
this.generalRegexList = generalRegexList;
this.extensionsRegexList = extensionsRegexList;
this.interruptScan = false;
this.progressBar = null;
}

private void setupAnalysis(int maxItems) {
this.analyzedItems = 0;
if (Objects.nonNull(progressBar)) SwingUtilities.invokeLater(() -> {
progressBar.setMaximum(maxItems);
progressBar.setValue(0);
});
}

/**
* Method for analyzing the elements in Burp > Proxy > HTTP history
*
* @param progressBarCallbackSetup A setup function that given the number of items to analyze, returns a Runnable to be called after analysing each item.
* @param logEntriesCallback A callback that's called for every new finding, with a LogEntity as the only argument
* @param logEntriesCallback A callback that's called for every new finding, with a LogEntity as the only argument
*/
public void analyzeProxyHistory(Function<Integer, Runnable> progressBarCallbackSetup, Consumer<LogEntity> logEntriesCallback) {
public void analyzeProxyHistory(Consumer<LogEntity> logEntriesCallback) {
// create a copy of the regex list to protect from changes while scanning
List<RegexEntity> allRegexListCopy = Stream
.concat(generalRegexList.stream(), extensionsRegexList.stream())
Expand All @@ -80,13 +103,21 @@ public void analyzeProxyHistory(Function<Integer, Runnable> progressBarCallbackS
// removing items from the list allows the GC to clean up just after the task is executed
// instead of waiting until the whole analysis finishes.
List<ProxyHttpRequestResponse> proxyEntries = this.burpApi.proxy().history();
Runnable itemAnalyzedCallback = progressBarCallbackSetup.apply(proxyEntries.size());
if (proxyEntries.isEmpty()) return;
this.setupAnalysis(proxyEntries.size());

for (int entryIndex = proxyEntries.size() - 1; entryIndex >= 0; entryIndex--) {
ProxyHttpRequestResponse proxyEntry = proxyEntries.remove(entryIndex);
executor.execute(() -> {
if (interruptScan) return;

analyzeSingleMessage(allRegexListCopy, scannerOptions, proxyEntry, logEntriesCallback);
itemAnalyzedCallback.run();

synchronized (analyzeLock) {
this.analyzedItems++;
}
if (Objects.nonNull(progressBar))
SwingUtilities.invokeLater(() -> progressBar.setValue(this.analyzedItems));
});
}

Expand All @@ -112,7 +143,7 @@ public void analyzeProxyHistory(Function<Integer, Runnable> progressBarCallbackS
* @param logEntriesCallback A callback that's called for every new finding, with a LogEntity as the only argument.
*/
private void analyzeSingleMessage(List<RegexEntity> regexList,
ScannerOptions scannerOptions,
RegexScannerOptions scannerOptions,
ProxyHttpRequestResponse proxyEntry,
Consumer<LogEntity> logEntriesCallback) {
// The initial checks must be kept ordered based on the amount of information required from Burp APIs.
Expand Down Expand Up @@ -143,22 +174,22 @@ private void analyzeSingleMessage(List<RegexEntity> regexList,
}

private void performMatchingOnMessage(RegexEntity regex,
ScannerOptions scannerOptions,
RegexScannerOptions scannerOptions,
HttpRecord requestResponse,
Consumer<HttpMatchResult> logMatchCallback) {
Pattern regexCompiled = regex.getRegexCompiled();
Optional<Pattern> refinerRegexCompiled = regex.getRefinerRegexCompiled();

regex.getSections()
.stream()
.map(httpSection -> ScannerUtils.getSectionText(httpSection, requestResponse))
.map(httpSection -> ScannerUtils.getHttpRecordSection(requestResponse, httpSection))
.flatMap(sectionRecord -> {
Matcher matcher = regexCompiled.matcher(sectionRecord.text());
Matcher matcher = regexCompiled.matcher(sectionRecord.content());
return matcher.results().map(result -> {
String match = result.group();
if (refinerRegexCompiled.isPresent()) {
int startIndex = result.start();
Matcher preMatch = refinerRegexCompiled.get().matcher(sectionRecord.text());
Matcher preMatch = refinerRegexCompiled.get().matcher(sectionRecord.content());
preMatch.region(Math.max(startIndex - scannerOptions.getConfigRefineContextSize(), 0), startIndex);
if (preMatch.find())
match = preMatch.group() + match;
Expand All @@ -178,6 +209,10 @@ public void setInterruptScan(boolean interruptScan) {
this.interruptScan = interruptScan;
}

public void setProgressBar(JProgressBar progressBar) {
this.progressBar = progressBar;
}

private record HttpMatchResult(HttpSection section, String match) {
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/cys4/sensitivediscoverer/RegexSeeder.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.cys4.sensitivediscoverer;

import com.cys4.sensitivediscoverer.model.HttpSection;
import com.cys4.sensitivediscoverer.model.JsonRegexEntity;
import com.cys4.sensitivediscoverer.model.RegexEntity;
import com.cys4.sensitivediscoverer.model.RegexEntityJsonAdapter;
import com.cys4.sensitivediscoverer.utils.Utils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
Expand All @@ -19,13 +19,13 @@ public class RegexSeeder {
private static final Gson gson = new Gson();

private static List<RegexEntity> fill(String[] regexFiles) {
Type tArrayListRegexEntity = new TypeToken<ArrayList<JsonRegexEntity>>() {
Type tArrayListRegexEntity = new TypeToken<ArrayList<RegexEntityJsonAdapter>>() {
}.getType();

return Stream.of(regexFiles)
.map(Utils::readResourceFile)
.filter(Objects::nonNull)
.<List<JsonRegexEntity>>map(regex_file -> gson.fromJson(regex_file, tArrayListRegexEntity))
.<List<RegexEntityJsonAdapter>>map(regex_file -> gson.fromJson(regex_file, tArrayListRegexEntity))
.flatMap(Collection::stream)
.map(element -> new RegexEntity(
element.getDescription(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.cys4.sensitivediscoverer.event;

public interface LogEntriesListener {
void onSizeChange(int entriesCount);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.cys4.sensitivediscoverer.event;

import com.cys4.sensitivediscoverer.model.ScannerOptions;
import com.cys4.sensitivediscoverer.model.RegexScannerOptions;

import javax.swing.*;
import java.awt.event.ActionListener;

public abstract class OptionsScannerUpdateListener implements ActionListener {

protected final ScannerOptions scannerOptions;
protected final RegexScannerOptions scannerOptions;
protected JLabel currentValueLabel;
protected JTextField updatedStatusField;

public OptionsScannerUpdateListener(ScannerOptions scannerOptions) {
public OptionsScannerUpdateListener(RegexScannerOptions scannerOptions) {
this.scannerOptions = scannerOptions;
this.currentValueLabel = null;
this.updatedStatusField = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.cys4.sensitivediscoverer.event;

import com.cys4.sensitivediscoverer.model.ScannerOptions;
import com.cys4.sensitivediscoverer.model.RegexScannerOptions;

import javax.swing.*;
import java.awt.event.ActionEvent;

import static com.cys4.sensitivediscoverer.Messages.getLocaleString;
import static com.cys4.sensitivediscoverer.utils.Messages.getLocaleString;

public class OptionsScannerUpdateMaxSizeListener extends OptionsScannerUpdateListener {

public OptionsScannerUpdateMaxSizeListener(ScannerOptions scannerOptions) {
public OptionsScannerUpdateMaxSizeListener(RegexScannerOptions scannerOptions) {
super(scannerOptions);
}

Expand All @@ -20,7 +21,7 @@ public void actionPerformed(ActionEvent actionEvent) {
throw new NumberFormatException(getLocaleString("exception-sizeMustBeGreaterEqualThanOne"));

scannerOptions.setConfigMaxResponseSize(newMaxSizeValue);
currentValueLabel.setText(String.valueOf(scannerOptions.getConfigMaxResponseSize()));
SwingUtilities.invokeLater(() -> currentValueLabel.setText(String.valueOf(newMaxSizeValue)));
} catch (NumberFormatException ignored) {
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.cys4.sensitivediscoverer.event;

import com.cys4.sensitivediscoverer.model.ScannerOptions;
import com.cys4.sensitivediscoverer.model.RegexScannerOptions;

import javax.swing.*;
import java.awt.event.ActionEvent;

import static com.cys4.sensitivediscoverer.Messages.getLocaleString;
import static com.cys4.sensitivediscoverer.utils.Messages.getLocaleString;

public class OptionsScannerUpdateNumThreadsListener extends OptionsScannerUpdateListener {

public OptionsScannerUpdateNumThreadsListener(ScannerOptions scannerOptions) {
public OptionsScannerUpdateNumThreadsListener(RegexScannerOptions scannerOptions) {
super(scannerOptions);
}

Expand All @@ -20,7 +21,7 @@ public void actionPerformed(ActionEvent actionEvent) {
throw new NumberFormatException(getLocaleString("exception-numberNotInTheExpectedRange"));

scannerOptions.setConfigNumberOfThreads(newThreadNumber);
currentValueLabel.setText(String.valueOf(scannerOptions.getConfigNumberOfThreads()));
SwingUtilities.invokeLater(() -> currentValueLabel.setText(String.valueOf(newThreadNumber)));
} catch (NumberFormatException ignored) {
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package com.cys4.sensitivediscoverer.model;

/**
* Record containing the various section of an HTTP request/response object
*
* @param requestUrl
* @param requestHeaders
* @param requestBody
* @param responseHeaders
* @param responseBody
*/
public record HttpRecord(
String requestUrl,
String requestHeaders,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.cys4.sensitivediscoverer.Messages.getLocaleString;
import static com.cys4.sensitivediscoverer.utils.Messages.getLocaleString;

/**
* Enum to identify all the various section that a regex can match in an HttpProxyItem object.
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/com/cys4/sensitivediscoverer/model/LogEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@

/**
* A LogEntity represents the results of a successful match of a regex in a request/response.
* <br><br>
* Dev notes:<br>
* <p>
* <b>Note</b>:<br>
* LogEntity instance that reference a specific row in a table are usually named logEntry.
* </p>
* <p>
* <b>Dev notes</b>:<br>
* This entity contains immutable references to:
* <ul>
* <li>the request object</li>
Expand Down Expand Up @@ -118,9 +122,7 @@ public boolean equals(Object o) {
return Objects.equals(
this.getMatch(),
logEntity.getMatch()) &&
Objects.equals(
this.getMatchedSection(),
logEntity.getMatchedSection()) &&
this.getMatchedSection() == logEntity.getMatchedSection() &&
Objects.equals(
this.getRegexEntity(),
logEntity.getRegexEntity()) &&
Expand Down
Loading
Loading