Skip to content

Commit

Permalink
Merge pull request #35 from usdAG/develop
Browse files Browse the repository at this point in the history
FlowMate v1.1 Release
  • Loading branch information
fhaag95 authored Mar 8, 2024
2 parents 44bca51 + 6719282 commit a0ee796
Show file tree
Hide file tree
Showing 79 changed files with 3,419 additions and 410 deletions.
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,35 @@ This tool operates from either a black-box or grey-box perspective, eliminating
## Key Features
Some key features of FlowMate are:
- Track parameter values of all applications added to the BurpSuite project scope.
- Matching of parameters can be performed live while browsing, or deferred in order to reduce load times while manually browsing the application.
- Store all data points in a local and file-based Neo4J instance.
- Integrates the Neo4J Browser directly to visualize and browse the resulting graph. No installation needed.
- Enables you to define *Sessions* within the plugin to ease tracking cross-session parameters.
- Performs automatic audit steps on the created graph to generate Findings with points of interest.
- Has the capability to define filters for parameters in order to reduce noise in the resulting data flow graph.

## Demo Video
A video demonstrating the end-to-end use of FlowMate is available on our YouTube channel.

[![FlowMate Demo Video](https://img.youtube.com/vi/BJhRhGmDATw/0.jpg)](https://www.youtube.com/watch?v=BJhRhGmDATw)

## How to Use
**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
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.
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!

### What can you get from the graph?
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
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
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 identify unsafe behavior of the application directly from the graph. Some examples here are:
- A user password is included in the applications sources in cleartext
- Security enhancements such as CSRF tokens are not changed in a secure manner
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
Expand Down
45 changes: 26 additions & 19 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.0</version>
<version>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.2.0</version>
<version>3.6.0</version>
<configuration>
<descriptors>
<descriptor>src/assembly/jar-descriptor.xml</descriptor>
Expand All @@ -41,67 +41,67 @@
<dependency>
<groupId>net.portswigger.burp.extensions</groupId>
<artifactId>montoya-api</artifactId>
<version>2023.3</version>
<version>2023.12.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j-bolt -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-bolt</artifactId>
<version>5.5.0</version>
<version>5.16.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>5.5.0</version>
<version>5.16.0</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>4.0.3</version>
<version>4.0.9</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-bolt-driver</artifactId>
<version>4.0.3</version>
<version>4.0.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j.client/neo4j-browser -->
<dependency>
<groupId>org.neo4j.client</groupId>
<artifactId>neo4j-browser</artifactId>
<version>5.4.0</version>
<version>5.15.0</version>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>5.5.0</version>
<version>5.16.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j-native -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-native</artifactId>
<version>5.5.0</version>
<version>5.16.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220320</version>
<version>20231013</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
<version>1.11.0</version>
</dependency>
<dependency>
<groupId>com.miglayout</groupId>
Expand All @@ -111,31 +111,38 @@
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.2</version>
<version>5.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19.0.2.1</version>
<version>21.0.1</version>
</dependency>
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.20.0</version>
<version>0.21.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.wnameless.json/json-flattener -->
<dependency>
<groupId>com.github.wnameless.json</groupId>
<artifactId>json-flattener</artifactId>
<version>0.16.4</version>
<version>0.16.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>

</dependencies>
</project>
9 changes: 8 additions & 1 deletion src/main/java/audit/AuditFinding.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package audit;

public abstract class AuditFinding {
import java.io.Serializable;
import java.util.Objects;

public abstract class AuditFinding implements Serializable {

public String name;
public FindingSeverity severity;
Expand All @@ -18,6 +21,10 @@ public String getLabelRepresentation(){
return String.format("Name: <b>%s</b><br>Severity: <b>%s</b><br>Description: %s", this.name, this.severity, this.getShortDescription());
}

public String getHash() {
return String.valueOf(Objects.hash(this.name, this.severity, this.getShortDescription(), this.getLongDescription()));
}

public enum FindingSeverity{
INFORMATIONAL,
LOW,
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/audit/CrossContentTypeAudit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package audit;

import db.MatchHelperClass;
import gui.AuditFindingView;

public class CrossContentTypeAudit {

private AuditFindingView auditFindingView;

public CrossContentTypeAudit(AuditFindingView auditFindingView) {
this.auditFindingView = auditFindingView;
}

public void performAudit(MatchHelperClass matchHelper) {
var inputValueType = matchHelper.getInputValueObj().getType();
var responseContentType = matchHelper.getResponseContentType();

// Ignore responseContentType HTML and JSON
if (responseContentType.equals("HTML") || responseContentType.equals("JSON") || responseContentType.equals("CSS") || inputValueType.equals("COOKIE")) {
return;
}

if (!responseContentType.equals(inputValueType)) {
AuditFinding finding = buildAuditFinding(matchHelper.getName(), inputValueType, responseContentType);
auditFindingView.addFinding(finding);
}
}

private AuditFinding buildAuditFinding(String paramName, String contentTypeEntered, String contentTypeFound) {
return new CrossContentTypeAuditFinding(paramName, contentTypeEntered, contentTypeFound);
}


}
52 changes: 52 additions & 0 deletions src/main/java/audit/CrossContentTypeAuditFinding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package audit;

public class CrossContentTypeAuditFinding extends AuditFinding {

private String parameterName;
private String contentTypeEntered;
private String contentTypeFound;
private static final String name = "Cross-Content-Type Parameter Match";

public CrossContentTypeAuditFinding(String parameterName, String contentTypeEntered, String contentTypeFound) {
super(name, AuditFinding.FindingSeverity.MIDDLE);
this.parameterName = parameterName;
this.contentTypeEntered = contentTypeEntered;
this.contentTypeFound = contentTypeFound;
}


@Override
public String getShortDescription() {
return String.format("The parameter %s was entered with content type %s and found in content type %s", this.parameterName, this.contentTypeEntered, this.contentTypeFound);
}

@Override
public String getLongDescription() {
String htmlTemplate = """
<h1>Description</h1>
FlowMate identified a <b>data flow where the input value is reflected in a different content type</b>. If the data is not properly sanitized or validated, this might allow vulnerabilities exploiting the specific syntax or processing rule for that content type.
For instance, if input values are contained in an XML-response, an attacker might be able to inject XML tags that manipulate data. Another example are CSV files, where attackers can inject formula expressions that might allow code execution when imported in Microsoft Excel.
<h1>Details</h1>
The following data flow has been identified:
<ul>
<li>Parameter (Value): PARAMETER_NAME</li>
<li>Input Location (Content Type): ENTERED_IN</li>
<li>Output Location (Content Type): FOUND_IN</li>
</ul>
<h1>How to Test</h1>
<ol>
<li>Try to inject meta sequences corresponding to the output file format of the application</li>
<li>Check if the parser is still able to process the resulting file format, if you break the expected format</li>
<li>Furthermore, you could use pingback URLs such as the Burp collaborator, to see if your input is processed insecurely (e.g. in case of XXE)</li>
</ol>
""";
return htmlTemplate.replace("PARAMETER_NAME", this.parameterName).replace("ENTERED_IN", this.contentTypeEntered).replace("FOUND_IN", this.contentTypeFound);
}
}
33 changes: 33 additions & 0 deletions src/main/java/audit/CrossScopeAudit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package audit;

import db.MatchHelperClass;
import db.entities.InputValue;
import gui.AuditFindingView;
import utils.URLExtension;

public class CrossScopeAudit {

private AuditFindingView auditFindingView;

public CrossScopeAudit(AuditFindingView auditFindingView) {
this.auditFindingView = auditFindingView;
}

public void performAudit(MatchHelperClass match) {
String parameterName = match.getName();
InputValue inputValue = match.getInputValueObj();
String inputDomain = URLExtension.stringToUrl(inputValue.getUrl()).getHost();
String matchDomain = URLExtension.stringToUrl(match.getUrl()).getHost();

if (!inputDomain.equals(matchDomain)) {
AuditFinding finding = buildAuditFinding(parameterName, inputDomain, matchDomain);
auditFindingView.addFinding(finding);
}
}

private AuditFinding buildAuditFinding(String paramName, String inputDomain, String matchDomain) {
return new CrossScopeAuditFinding(paramName, inputDomain, matchDomain);
}


}
53 changes: 53 additions & 0 deletions src/main/java/audit/CrossScopeAuditFinding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package audit;

public class CrossScopeAuditFinding extends AuditFinding {

private String parameterName;
private String inputDomain;
private String matchDomain;
private static final String name = "Cross-Scope Match";

public CrossScopeAuditFinding(String parameterName, String inputDomain, String matchDomain) {
super(name, AuditFinding.FindingSeverity.MIDDLE);
this.parameterName = parameterName;
this.inputDomain = inputDomain;
this.matchDomain = matchDomain;
}

@Override
public String getShortDescription() {
return String.format("The parameter %s was entered in domain %s and found in domain %s", this.parameterName, this.inputDomain, this.matchDomain);
}

@Override
public String getLongDescription() {
String htmlTemplate = """
<h1>Description</h1>
FlowMate identified a <b>data flow that crosses scope boundaries</b>, meaning that the output location is in another application or application component (domain) as the input parameter. Different applications often differ in their input and output handling, which increases the probability of related vulnerabilities.
Examples for vulnerabilities include Cross-Site Scripting (XSS), Server-Side Template Injections (SSTI), Second-Order SQL-Injections and Server-Site Request Forgery (SSRF).
As an example, consider a parameter that can be set using an API and its value is then displayed in a web application. This might allow bypassing of input filtering that the application might apply.
<h1>Details</h1>
The following data flow has been Identified:
<ul>
<li>Parameter (Value): PARAMETER_NAME</li>
<li>Input Location (Scope #1): INPUT_DOMAIN</li>
<li>Output Location (Scope #2): OUTPUT_DOMAIN</li>
</ul>
<h1>How to Test</h1>
<ol>
<li>Make sure to test the affected data flows for vulnerabilities arising specifically from different applications handling the inserted data</li>
<li>For instance, if different programming languages or frameworks are used to build these applications, vulnerabilities may emerge due to variations in their input handling and sanitization processes</li>
<li>This could lead to various types of injection vulnerabilities</li>
</ol>
""";
return htmlTemplate.replace("PARAMETER_NAME", this.parameterName).replace("INPUT_DOMAIN", this.inputDomain).replace("OUTPUT_DOMAIN", this.matchDomain);
}
}
Loading

0 comments on commit a0ee796

Please sign in to comment.