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

Merge develop into main branch #67

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
26d94d6
Optimize imports
HWisch Jan 17, 2024
8be1d9a
Refactor DBModel class to use only one method to bulk save entities
HWisch Jan 17, 2024
478e631
Use CypherQueryHandler for every query result to extract entities
HWisch Jan 17, 2024
6cbd428
Refactor entity classes
HWisch Jan 23, 2024
7fff451
Add self implemented ObservableList
HWisch Jan 31, 2024
29424d5
Bump org.json:json from 20231013 to 20240303
dependabot[bot] Mar 4, 2024
47ddfbf
Bump org.neo4j:neo4j from 5.16.0 to 5.19.0
dependabot[bot] Apr 12, 2024
1a91606
Bump org.neo4j:neo4j-bolt from 5.16.0 to 5.19.0
dependabot[bot] Apr 12, 2024
e90a596
Bump org.neo4j:neo4j-native from 5.16.0 to 5.19.0
dependabot[bot] Apr 12, 2024
f1a37e1
Bump org.openjfx:javafx-controls from 21.0.1 to 22.0.1
dependabot[bot] Apr 18, 2024
f854049
Merge pull request #47 from usdAG/dependabot/maven/develop/org.openjf…
HWisch May 28, 2024
654021f
Merge pull request #46 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch May 28, 2024
3767597
Merge pull request #45 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch May 28, 2024
e9966d2
Merge pull request #44 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch May 28, 2024
a104149
Merge pull request #34 from usdAG/dependabot/maven/develop/org.json-j…
HWisch May 28, 2024
4ee7c7f
Add dependabot configuration
fhaag95 Nov 14, 2023
5ad7b49
Update README
fhaag95 Mar 14, 2024
721ed26
Fix NullPointerException in DeferredMatching if no session has been d…
HWisch Apr 3, 2024
3091059
Update dependencies
HWisch May 28, 2024
59f93b9
Fix ConcurrentModificationException on saving many parameters whith d…
HWisch May 28, 2024
2548128
Fix auto scroll down bug in QueryView
HWisch May 28, 2024
800c1c7
Bump org.apache.maven.plugins:maven-assembly-plugin from 3.6.0 to 3.7.1
dependabot[bot] May 28, 2024
c7d9821
Set Detection Activated in GettingStartedView always to false
HWisch Jun 6, 2024
77f7e09
Bump org.neo4j:neo4j-bolt from 5.19.0 to 5.21.2
dependabot[bot] Jul 9, 2024
499897a
Bump org.neo4j:neo4j-native from 5.19.0 to 5.21.2
dependabot[bot] Jul 9, 2024
287f919
Bump org.neo4j:neo4j from 5.19.0 to 5.21.2
dependabot[bot] Jul 9, 2024
2149011
Bump org.neo4j.app:neo4j-server from 5.19.0 to 5.21.2
dependabot[bot] Jul 9, 2024
8771f6a
Merge pull request #60 from usdAG/dependabot/maven/develop/org.neo4j.…
HWisch Jul 18, 2024
cba6d5a
Merge pull request #59 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch Jul 18, 2024
9f40382
Merge pull request #58 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch Jul 18, 2024
763e586
Merge pull request #57 from usdAG/dependabot/maven/develop/org.neo4j-…
HWisch Jul 18, 2024
ff8e880
Merge pull request #50 from usdAG/dependabot/maven/develop/org.apache…
HWisch Jul 18, 2024
b406b60
Update dependencies
HWisch Jul 18, 2024
66a3ed5
Split up methods and change variable names
HWisch Jul 23, 2024
863ac78
Merge remote-tracking branch 'origin/code-refactoring' into develop
HWisch Jul 23, 2024
ac938e0
Merge code-refactoring branch into devleop
HWisch Aug 15, 2024
78878c6
Increase version to 1.1.1 in pom.xml
fhaag95 Aug 28, 2024
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
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "daily"
target-branch: "develop"
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,25 @@ A video demonstrating the end-to-end use of FlowMate is available on our YouTube
**FlowMate** is used best during the reconnaissance phase in a security assessment. The following steps explain on how to get started:
1. Load FlowMate into your BurpSuite with a project for your current assessment already created
2. After loading finished add the target application to the BurpSuite internal *Scope*. Only in-scope targets are tracked by FlowMate
3. Activate the detection by checking both boxes on the *Getting Started* tab of FlowMate
3. Activate the detection by checking both boxes on the *Getting Started* tab of FlowMate. You can choose *Live* or *Deferred* matching. *Deferred* is recommended for bigger applications as *Live* matching might slow down the browsing experience if hundreds of parameters are matched against every response.
4. Browse the application following the *General best practices* below
5. Stop the detection before starting manual analysis. This prevents payloads and duplicate values from polluting the graph
6. Profit from the data flow graph created for you!

### General best practices
- Enter *unique* and *long enough* values (generally more than 6 characters) when browsing an application with FlowMate enabled
- Do not enter payloads during this phase
- Browse all user roles and functionality available

### What can you get from the graph?
1. You can look up the locations where a specific parameter you are testing reappears in the application, including the immediate surroundings of the match, giving a first impression of which payloads might be useful for exploitation
2. You can more easily identify occurrences of a parameter in places that are not directly visible, such as in hidden input fields or when a value is used in resources like stylesheets or scripts for example
1. You can lookup in which locations an specific parameter you are testing reappers in the application including the near surrounding of the match giving a first impression on which payloads might be useful for exploitation
2. You can more easily identify occurrences of a parameter in not directly visible places, such as in hidden input fields or when a value is used in resources like stylesheets or scripts for example
3. In conjunction with the session tracking feature you can track cross-session parameter occurrences. In case of attack vectors like Cross-Site Scripting (XSS) this may lead to attacks on higher privileged accounts (privilege escalation, account takeover)
4. If your target application consists of multiple domains, for example APIs and the actual web frontend, the graph helps to detect cross-domain occurrences of parameter matches
5. You can directly identify unsafe behavior of the application from the graph. Some examples include:
- A user password is included in the applications sources in cleartext
- Security enhancements such as CSRF tokens are not changed in a secure manner

### General best practices
- Enter *unique* and *long enough* values (generally more than 6 characters) when browsing an application with FlowMate enabled
- Do not enter payloads during this phase
- Browse all user roles and functionality available


## Installation

### If you want to use a pre-built JAR file, follow these steps
Expand All @@ -54,4 +54,7 @@ A video demonstrating the end-to-end use of FlowMate is available on our YouTube
1. Clone the repository, switch into it and run `mvn package`. The `target` folder then contains a built version of FlowMate
2. Follow the steps to install an extension from JAR file here: [Installing an extension from a file](https://portswigger.net/burp/documentation/desktop/extensions/installing-extensions#installing-an-extension-from-a-file)

## Reporting Issues
If you encounter issues with FlowMate please report to us via a GitHub Issue. Error Logs are written to the logfile in `~/.flowmate` folder on your system running the plugin as well as the error log console in the BurpSuite Extension tab ("Extension" Tab > "Installed" Tab > Select "FlowMate" > "Errors" Tab).

Supplying us with this information as well as a short description of when the error occurs helps us to troubleshoot and fix the issue. Furthermore, keeping the BurpState might help if we have questions back to you.
43 changes: 16 additions & 27 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>de.usd</groupId>
<artifactId>flowmate</artifactId>
<version>1.1</version>
<version>1.1.1</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
Expand All @@ -18,7 +18,7 @@
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<version>3.7.1</version>
<configuration>
<descriptors>
<descriptor>src/assembly/jar-descriptor.xml</descriptor>
Expand Down Expand Up @@ -47,89 +47,78 @@
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-bolt</artifactId>
<version>5.16.0</version>
<version>5.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>5.16.0</version>
<version>5.22.0</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>4.0.9</version>
<version>4.0.10</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-bolt-driver</artifactId>
<version>4.0.9</version>
<version>4.0.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j.client/neo4j-browser -->
<dependency>
<groupId>org.neo4j.client</groupId>
<artifactId>neo4j-browser</artifactId>
<version>5.15.0</version>
<version>5.21.0</version>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>5.16.0</version>
<version>5.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j-native -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-native</artifactId>
<version>5.16.0</version>
<version>5.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
<version>20240303</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
<version>3.16.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>com.miglayout</groupId>
<artifactId>miglayout</artifactId>
<version>3.7.4</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21.0.1</version>
</dependency>
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.21.0</version>
<version>0.22.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.wnameless.json/json-flattener -->
<dependency>
Expand All @@ -141,7 +130,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
<version>2.16.1</version>
</dependency>

</dependencies>
Expand Down
7 changes: 1 addition & 6 deletions src/main/java/audit/CrossSessionAudit.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
package audit;

import db.DBModel;
import db.MatchHelperClass;
import db.entities.InputValue;
import db.entities.ParameterMatch;
import db.entities.Session;
import gui.AuditFindingView;
import org.neo4j.ogm.model.Result;
import scala.reflect.macros.Universe;

import java.util.*;
import java.util.Vector;

public class CrossSessionAudit {

Expand Down
8 changes: 7 additions & 1 deletion src/main/java/burp/BurpExtender.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class BurpExtender implements BurpExtension {
private RegexMatcher regexMatcher;
private DeferMatching deferMatching;
private HttpListener listener;
private RetroactiveParser retroactiveParser;
private MontoyaApi api;

public Neo4JDB neo4j;
Expand Down Expand Up @@ -93,8 +94,11 @@ public void initialize(MontoyaApi api) {
queryView = new QueryView(this.listener.parameterHandler, this.listener.matchHandler, this.api);
queryViewModel = new QueryViewModel();
queryViewController = new QueryViewController(api, queryView, queryViewModel, this.listener.parameterHandler, this.listener.matchHandler, sessionViewController);
this.retroactiveParser = new RetroactiveParser(this.api, this.listener.parameterHandler, this.queryViewController);
gettingStartedView = new GettingStartedView(this.api, this.propertiesHandler, this.deferMatching, this.listener.parameterHandler,
this.listener.matchHandler, this.noiseReductionController, this.queryViewController, this.auditFindingView, this.sessionViewController);
this.listener.matchHandler, this.noiseReductionController, this.queryViewController, this.auditFindingView, this.sessionViewController, this.retroactiveParser);

this.api.userInterface().registerContextMenuItemsProvider(new HistoryContextMenu(this.api, gettingStartedView));

if (this.propertiesHandler.isFirstTimeLoading) {
historyStart = this.api.proxy().history().size() + 1;
Expand All @@ -105,6 +109,8 @@ public void initialize(MontoyaApi api) {

noiseReductionController.addRuleContainerListener(queryViewController);
deferMatching.addDeferMatchingFinishedListener(sessionViewController);
deferMatching.addDeferMatchingFinishedListener(queryViewController);
listener.addItemsAddedListener(queryViewController);

api.extension().registerUnloadingHandler(new MyExtensionUnloadHandler());

Expand Down
13 changes: 8 additions & 5 deletions src/main/java/burp/ContainerConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import db.CypherQueryHandler;
import db.DBModel;
import db.MatchHandler;
import db.entities.*;
import db.entities.InputParameter;
import db.entities.InputValue;
import db.entities.MatchValue;
import db.entities.ParameterMatch;
import gui.container.*;
import org.neo4j.ogm.model.Result;
import utils.MessageHashToProxyId;
Expand Down Expand Up @@ -33,7 +36,7 @@ public Vector<ParameterContainer> parameterToContainer(List<InputParameter> inpu
var name = parameter.getName();
var type = parameter.getType();
Map<String, String> values = Collections.singletonMap("name", name);
String query = "MATCH (n:InputParameter {name: $name, type: \"%s\"})-[OCCURS_WITH_VALUE]-(m:InputValue) RETURN m".formatted(type);
String query = "MATCH (n:InputParameter {name: $name, type: \"%s\"})-[OCCURS_WITH_VALUE]-(o:InputValue) RETURN o".formatted(type);
Result result = DBModel.query(query, values);
List<InputValue> inputValueList = new ArrayList<>(CypherQueryHandler.getOccurrencesFromQueryResult(result));
int occurrences = inputValueList.size();
Expand All @@ -55,7 +58,7 @@ public Vector<SessionParameterContainer> parameterToContainerSessionDef(List<Par

for (ParameterMatch match : parameterMatches) {
Map<String, String> values = Map.of("name", match.getName(), "type", match.getType(), "value", match.getValue());
String valueQuery = "MATCH (p:InputParameter {name: $name, type: $type})-[OCCURS_WITH_VALUE]-(m:InputValue {type: $type, value: $value}) RETURN m";
String valueQuery = "MATCH (p:InputParameter {name: $name, type: $type})-[OCCURS_WITH_VALUE]-(o:InputValue {type: $type, value: $value}) RETURN o";
Result result = DBModel.query(valueQuery, values);
for (var parameterValue : CypherQueryHandler.getOccurrencesFromQueryResult(result).stream().distinct().toList()) {
String type = parameterValue.getType();
Expand Down Expand Up @@ -119,7 +122,7 @@ public Vector<MatchValueContainer> entryOccurrenceToContainer(List<MatchValue> o
}

public int getNumberOfMatchesForParameterName(String paramName, String type) {
List<ParameterMatch> parameterMatchList = new ArrayList<>(this.matchHandler.observableParameterMatchList.stream().toList());
List<ParameterMatch> parameterMatchList = new ArrayList<>(this.matchHandler.parameterMatchStorage.values());
List<Integer> duplicates = new ArrayList<>();
List<ParameterMatch> correctParameterMatchList = new ArrayList<>();
for (var match : parameterMatchList) {
Expand All @@ -136,7 +139,7 @@ public int getNumberOfMatchesForSessionTabForParameterName(String paramName, Str
Map<String, String> values = Map.of("sessionName", sessionName, "value", value, "type", type);
String query = "MATCH (m:ParameterMatch {session: $sessionName, value: $value, type: $type}) RETURN m";
Result result = DBModel.query(query, values);
List<ParameterMatch> parameterMatchList = new ArrayList<>(CypherQueryHandler.getMatchesFromQueryResult(result));
List<ParameterMatch> parameterMatchList = new ArrayList<>(CypherQueryHandler.getParameterMatchesFromQueryResult(result));
return parameterMatchList.stream().distinct().filter(e -> e.getName().equals(paramName)).toList().size();
}

Expand Down
93 changes: 93 additions & 0 deletions src/main/java/burp/HistoryContextMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package burp;

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.contextmenu.ContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider;
import gui.GettingStartedView;
import utils.Hashing;
import utils.MessageHashToProxyId;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

public class HistoryContextMenu implements ContextMenuItemsProvider {

private MontoyaApi api;
private GettingStartedView gettingStartedView;

private boolean isStartSet;
private boolean isEndSet;
private int startValue;
private int endValue;

public HistoryContextMenu(MontoyaApi api, GettingStartedView gettingStartedView) {
this.api = api;
this.gettingStartedView = gettingStartedView;
this.isStartSet = false;
this.isEndSet = false;
}

@Override
public List<Component> provideMenuItems(ContextMenuEvent event) {

List<Component> menuItems = new ArrayList<>();
JMenuItem setStartPointMenu = new JMenuItem("Set as start point for Retroactive Parsing");
JMenuItem setEndPointMenu = new JMenuItem("Set as end point for Retroactive Parsing");

menuItems.add(setStartPointMenu);
menuItems.add(setEndPointMenu);

setStartPointMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
isStartSet = true;
HttpRequest selectedRequest = event.selectedRequestResponses().get(0).request();
String messageHash = Hashing.sha1(event.selectedRequestResponses().get(0).request().toByteArray().getBytes());
startValue = MessageHashToProxyId.getInstance(api).calculateId(messageHash);
if (!selectionsAreValid(selectedRequest)) {
isStartSet = false;
startValue = -1;
return;
}

gettingStartedView.setStartValue(startValue);
}
});

setEndPointMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
isEndSet = true;
HttpRequest selectedRequest = event.selectedRequestResponses().get(0).request();
String messageHash = Hashing.sha1(event.selectedRequestResponses().get(0).request().toByteArray().getBytes());
endValue = MessageHashToProxyId.getInstance(api).calculateId(messageHash);
if (!selectionsAreValid(selectedRequest)) {
isEndSet = false;
endValue = -1;
return;
}

gettingStartedView.setEndValue(endValue);
}
});

return menuItems;
}

private boolean selectionsAreValid(HttpRequest selectedRequest) {
if (!selectedRequest.isInScope()) {
JOptionPane.showMessageDialog(null, "Selected request is not in scope!", "Warning", JOptionPane.WARNING_MESSAGE);
return false;
}
if ((isEndSet && isStartSet) && endValue < startValue) {
JOptionPane.showMessageDialog(null, "Start value is greater than End value", "Warning", JOptionPane.WARNING_MESSAGE);
return false;
}
return true;
}
}
Loading