Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
38b0f6c
pin to Java 21
intrudir Feb 4, 2026
3383ea6
Make builds cross-platform: remove org.gradle.java.home pin, enable t…
intrudir Feb 4, 2026
422d92d
Improve SAML editor: prettify XML on load + add syntax-highlighted XM…
intrudir Feb 4, 2026
50a4b20
Add Format XML button to SAML Message panel
intrudir Feb 4, 2026
ca71584
Fix editor editability and remove Parsed & Prettified section
intrudir Feb 4, 2026
c504a11
Switch XML editor to Burp-native RawEditor
intrudir Feb 4, 2026
6a108ad
Restore XML syntax highlighting with RSyntaxTextArea
intrudir Feb 4, 2026
d2514e9
Replace RSyntaxTextArea with custom JTextPane XML highlighter
intrudir Feb 4, 2026
f6b202c
Add live search bar to XML editor
intrudir Feb 4, 2026
2af437f
Compact attack panel layout
intrudir Feb 4, 2026
376c258
Add row spacing and rename Send Certificate button
intrudir Feb 4, 2026
641ab97
Improve attack panel section clarity
intrudir Feb 4, 2026
07c9d92
Update SAML Attacks screenshot in README
intrudir Feb 4, 2026
122efb7
Update SAML Message Info screenshot in README
intrudir Feb 4, 2026
31dd887
Update README.md
intrudir Feb 4, 2026
bf9eaf0
Update README.md
intrudir Feb 4, 2026
e014c6e
Add OOB domain dialog for XXE/XSLT attacks
intrudir Feb 4, 2026
f680114
Disable Collaborator option on Burp Community Edition
intrudir Feb 4, 2026
2fe3228
Add search nav arrows and soft wrap toggle to XML editor
intrudir Feb 4, 2026
67825ca
Merge branch 'CompassSecurity:master' into master
intrudir Apr 22, 2026
37c3ce2
Add SAML attack helpers, tests, and attack playbook
intrudir Apr 24, 2026
c7e0cbc
Add attack configuration dialogs for XSLT, XSS, and metadata import
intrudir Apr 24, 2026
6869b8d
Overhaul attacks UI: tabbed layout and expanded message info panel
intrudir Apr 24, 2026
0e573f7
Extend XMLHelpers with response-level and encryption metadata extraction
intrudir Apr 24, 2026
e383f2f
Wire all new attacks into controller with signature staleness tracking
intrudir Apr 24, 2026
48c17c8
Fix base64 decoding and add Hackvertor-wrapped SAML support
intrudir Apr 24, 2026
e81e357
Update build dependencies
intrudir Apr 24, 2026
4837fa5
updates and bug fixes
intrudir Apr 27, 2026
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Features of the SAML Raider message editor:
* Supported Profiles: SAML Webbrowser Single Sign-on Profile, Web Services
Security SAML Token Profile
* Supported Bindings: POST Binding, Redirect Binding, SOAP Binding, URI Binding
* XML is pretty printed, syntax highlighted and editable live
* Search field at the bottom to auto scroll & highlight searched text

SAML Attacks:

Expand Down
11 changes: 7 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ repositories {
mavenCentral()
}

compileJava {
targetCompatibility "21"
sourceCompatibility "21"
// Build/compile against Java 21 regardless of system default Java
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

dependencies {
Expand All @@ -28,9 +30,10 @@ dependencies {
testImplementation libs.net.portswigger.burp.extensions.montoya.api
testImplementation libs.org.bouncycastle.bcpkix.jdk15on
testImplementation libs.org.junit.jupiter
testRuntimeOnly libs.org.junit.platform.launcher
}

compileJava {
tasks.withType(JavaCompile).configureEach {
options.compilerArgs << "-Xlint:deprecation"
}

Expand Down
478 changes: 478 additions & 0 deletions doc/PLAYBOOK.md

Large diffs are not rendered by default.

Binary file modified doc/saml_attacks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/saml_info.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Keep builds cross-platform.
# This project uses Gradle toolchains (see build.gradle) to compile with Java 21.
# Do NOT hard-pin org.gradle.java.home to a machine-specific path.

# If a matching JDK isn't installed locally, allow Gradle to auto-provision one.
org.gradle.java.installations.auto-download=true
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ net-portswigger-burp-extensions-montoya-api = "2024.7"
org-apache-santuario-xmlsec = "2.1.7"
org-bouncycastle-bcpkix-jdk15on = "1.52"
org-junit-jupiter = "5.10.2"
org-junit-platform-launcher = "1.10.2"
xerces-xercesimpl = "2.12.2"

[libraries]
Expand All @@ -18,4 +19,5 @@ net-portswigger-burp-extensions-montoya-api = { module = "net.portswigger.burp.e
org-apache-santuario-xmlsec = { module = "org.apache.santuario:xmlsec", version.ref = "org-apache-santuario-xmlsec" }
org-bouncycastle-bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "org-bouncycastle-bcpkix-jdk15on" }
org-junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "org-junit-jupiter" }
org-junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "org-junit-platform-launcher" }
xerces-xercesimpl = { module = "xerces:xercesImpl", version.ref = "xerces-xercesimpl" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/application/CertificateTabController.java
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,10 @@ public List<BurpCertificate> getCertificatesWithPrivateKey() {
return burpCertificateStore.getBurpCertificatesWithPrivateKey();
}

public List<BurpCertificate> getAllCertificates() {
return burpCertificateStore.getBurpCertificates();
}

/*
* Remove
*/
Expand Down
51 changes: 43 additions & 8 deletions src/main/java/application/SamlMessageAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,44 @@ else if (request.hasParameter("wresult", HttpParameterType.BODY)) {
BurpExtender.api.logging().logToError(e);
}
} else {
var samlResponseInBody = request.parameterValue(samlResponseParameterName, HttpParameterType.BODY);
var samlResponseInUrl = request.parameterValue(samlResponseParameterName, HttpParameterType.URL);
var samlRequestInBody = request.parameterValue(samlRequestParameterName, HttpParameterType.BODY);
var samlRequestInUrl = request.parameterValue(samlRequestParameterName, HttpParameterType.URL);
var log = BurpExtender.api.logging();
log.logToOutput("[SAML Raider] analyze() — contentType=" + request.contentType()
+ " body[0..80]=" + request.bodyToString().replace("\n","").replace("\r","").substring(0, Math.min(80, request.bodyToString().length())));

var samlResponseInBody = extractParameterValue(request, samlResponseParameterName, HttpParameterType.BODY);
var samlResponseInUrl = request.parameterValue(samlResponseParameterName, HttpParameterType.URL);
var samlRequestInBody = extractParameterValue(request, samlRequestParameterName, HttpParameterType.BODY);
var samlRequestInUrl = request.parameterValue(samlRequestParameterName, HttpParameterType.URL);

log.logToOutput("[SAML Raider] responseInBody=" + (samlResponseInBody != null ? samlResponseInBody.substring(0, Math.min(40, samlResponseInBody.length())) : "null")
+ " requestInBody=" + (samlRequestInBody != null ? samlRequestInBody.substring(0, Math.min(40, samlRequestInBody.length())) : "null"));

isSAMLMessage =
samlResponseInBody != null
|| samlResponseInUrl != null
|| samlRequestInBody != null
|| samlRequestInUrl != null;

log.logToOutput("[SAML Raider] isSAMLMessage=" + isSAMLMessage);

if (isSAMLMessage) {
isSAMLRequest = samlRequestInBody != null || samlRequestInUrl != null;
isURLParam = samlResponseInUrl != null || samlRequestInUrl != null;

String message =
Stream.of(samlResponseInBody, samlResponseInUrl, samlRequestInBody, samlRequestInUrl)
Stream.<String>of(samlResponseInBody, samlResponseInUrl, samlRequestInBody, samlRequestInUrl)
.filter(str -> str != null)
.findFirst()
.orElseThrow();

var decodedSAMLMessage = SamlMessageDecoder.getDecodedSAMLMessage(message, isWSSMessage, isWSSUrlEncoded);
isInflated = decodedSAMLMessage.isInflated();
isGZip = decodedSAMLMessage.isGZip();
try {
var decodedSAMLMessage = SamlMessageDecoder.getDecodedSAMLMessage(message, isWSSMessage, isWSSUrlEncoded);
isInflated = decodedSAMLMessage.isInflated();
isGZip = decodedSAMLMessage.isGZip();
} catch (Exception e) {
// Decode failure doesn't hide the tab
BurpExtender.api.logging().logToError(e);
}
}
}

Expand All @@ -102,6 +116,27 @@ else if (request.hasParameter("wresult", HttpParameterType.BODY)) {
isURLParam);
}

/**
* Returns the value of a body parameter, falling back to a raw-body scan when Burp's
* URL-param parser returns null (e.g. because Hackvertor tags containing literal '<' chars
* are present in the body and break standard URL-encoded parsing).
*/
public static String extractParameterValue(HttpRequest request, String paramName, HttpParameterType type) {
String value = request.parameterValue(paramName, type);
if (value != null) return value;

if (type != HttpParameterType.BODY) return null;

// Strip Hackvertor tags then scan the raw body for name=value
String rawBody = request.bodyToString().replaceAll("</?@[^>]+>", "");
String marker = paramName + "=";
int idx = rawBody.indexOf(marker);
if (idx < 0) return null;
String val = rawBody.substring(idx + marker.length());
int amp = val.indexOf('&');
return amp >= 0 ? val.substring(0, amp) : val;
}

private SamlMessageAnalyzer() {
// static class
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/application/SamlMessageDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public static DecodedSAMLMessage getDecodedSAMLMessage(String message, boolean i
}

String urlDecoded = BurpExtender.api.utilities().urlUtils().decode(message);
urlDecoded = urlDecoded.replaceAll("\\R", "");
urlDecoded = urlDecoded.replaceAll("\\R", "").replace(" ", "+");
// Strip Hackvertor tags (<@tag>...</@tag>) so the tab survives Hackvertor-wrapped requests
urlDecoded = urlDecoded.replaceAll("</?@[^>]+>", "").strip();
byte[] base64Decoded = Base64.getDecoder().decode(urlDecoded);

boolean isInflated = true;
Expand Down
Loading