Skip to content
Open
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
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
10 changes: 6 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 @@ -30,7 +32,7 @@ dependencies {
testImplementation libs.org.junit.jupiter
}

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

Expand Down
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: 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
86 changes: 54 additions & 32 deletions src/main/java/application/SamlTabController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import burp.api.montoya.http.message.params.HttpParameterType;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.editor.RawEditor;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor;
import gui.CVEHelpWindow;
import gui.SamlMain;
import gui.SamlPanelInfo;
import gui.SamlXmlEditor;
import gui.SignatureHelpWindow;
import gui.XSWHelpWindow;
import helpers.CVE_2022_41912;
Expand Down Expand Up @@ -73,8 +73,7 @@ public class SamlTabController implements ExtensionProvidedHttpRequestEditor, Ob
private SamlMessageAnalysisResult samlMessageAnalysisResult;
private String orgSAMLMessage;
private String samlMessage;
private RawEditor textArea;
private RawEditor textEditorInformation;
private SamlXmlEditor textArea;
private SamlMain samlGUI;
private boolean editable;
private XSWHelpers xswHelpers;
Expand All @@ -84,10 +83,8 @@ public SamlTabController(boolean editable, CertificateTabController certificateT
this.certificateTabController = requireNonNull(certificateTabController, "certificateTabController");
this.editable = editable;
samlGUI = new SamlMain(this);
textArea = samlGUI.getTextEditorAction();
textArea = samlGUI.getXmlEditorAction();
textArea.setEditable(editable);
textEditorInformation = samlGUI.getTextEditorInformation();
textEditorInformation.setEditable(false);
xmlHelpers = new XMLHelpers();
xswHelpers = new XSWHelpers();
this.certificateTabController.addObserver(this);
Expand Down Expand Up @@ -126,7 +123,7 @@ public HttpRequest getRequest() {
setInfoMessageText(XML_NOT_WELL_FORMED);
}
} else {
String textMessage = textArea.getContents().toString();
String textMessage = textArea.getText();

String parameterToUpdate;
if (this.samlMessageAnalysisResult.isWSSMessage()) {
Expand Down Expand Up @@ -163,7 +160,11 @@ public HttpRequest getRequest() {

@Override
public Selection selectedData() {
return textArea.selection().orElse(null);
String sel = textArea.selectedText();
if (sel != null && !sel.isEmpty()) {
return Selection.selection(ByteArray.byteArray(sel));
}
return null;
}

@Override
Expand Down Expand Up @@ -199,8 +200,9 @@ public void setRequestResponse(HttpRequestResponse requestResponse) {
resetInfoMessageText();
isEdited = false;
if (requestResponse == null) {
textArea.setContents(null);
textArea.setText("");
textArea.setEditable(false);
textArea.resetModified();
setGUIEditable(false);
resetInformationDisplay();
} else {
Expand Down Expand Up @@ -258,22 +260,30 @@ public void setRequestResponse(HttpRequestResponse requestResponse) {
updateCertificateList();
updateXSWList();
orgSAMLMessage = samlMessage;
textArea.setContents(ByteArray.byteArray(samlMessage));

// Show prettified XML (editable) for sanity when working with big SAML blobs.
textArea.setText(prettifyXmlOrFallback(samlMessage));
textArea.setEditable(editable);

setGUIEditable(editable);
}
}

private String prettifyXmlOrFallback(String xml) {
try {
Document doc = xmlHelpers.getXMLDocumentOfSAMLMessage(xml);
return xmlHelpers.getStringOfDocument(doc, 2);
} catch (Exception ignored) {
return xml;
}
}

private void setInformationDisplay() {
samlGUI.getTextEditorInformation().setContents(ByteArray.byteArray(""));
SamlPanelInfo infoPanel = samlGUI.getInfoPanel();
infoPanel.clearAll();

try {
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(samlMessage);
String formattedDocumentWithIndentation = xmlHelpers.getStringOfDocument(xmlHelpers.getXMLDocumentOfSAMLMessage(samlMessage), 2);
textEditorInformation.setContents(ByteArray.byteArray(formattedDocumentWithIndentation.getBytes()));
NodeList assertions = xmlHelpers.getAssertions(document);
if (assertions.getLength() > 0) {
Node assertion = assertions.item(0);
Expand All @@ -289,7 +299,7 @@ private void setInformationDisplay() {
Node assertion = assertions.item(0);
infoPanel.setEncryptionAlgorithm(xmlHelpers.getEncryptionMethod(assertion));
}
} catch (SAXException | IOException e) {
} catch (SAXException e) {
setInfoMessageText(XML_NOT_WELL_FORMED);
}
}
Expand All @@ -304,17 +314,16 @@ private void resetInformationDisplay() {
infoPanel.setSignatureAlgorithm("");
infoPanel.setDigestAlgorithm("");
infoPanel.setEncryptionAlgorithm("");
textEditorInformation.setContents(ByteArray.byteArray(""));
}


public void removeSignature() {
resetInfoMessageText();
try {
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getContents().toString());
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getText());
if (xmlHelpers.removeAllSignatures(document) > 0) {
samlMessage = xmlHelpers.getStringOfDocument(document);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("Message signature successful removed");
} else {
Expand All @@ -327,9 +336,22 @@ public void removeSignature() {
}
}

public void formatXml() {
resetInfoMessageText();
String current = textArea.getText();
String formatted = prettifyXmlOrFallback(current);
if (formatted.equals(current)) {
setInfoMessageText("XML is already formatted (or not well-formed)");
} else {
textArea.setText(formatted);
setInfoMessageText("XML formatted");
}
}

public void resetMessage() {
samlMessage = orgSAMLMessage;
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
textArea.resetModified();
samlGUI.getStatusPanel().setText("");
isEdited = false;
}
Expand All @@ -340,7 +362,7 @@ public void resignAssertion() {
BurpCertificate cert = samlGUI.getActionPanel().getSelectedCertificate();
if (cert != null) {
setInfoMessageText("Signing...");
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getContents().toString());
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getText());
NodeList assertions = xmlHelpers.getAssertions(document);
String signAlgorithm = xmlHelpers.getSignatureAlgorithm(assertions.item(0));
String digestAlgorithm = xmlHelpers.getDigestAlgorithm(assertions.item(0));
Expand All @@ -351,7 +373,7 @@ public void resignAssertion() {
xmlHelpers.removeEmptyTags(doc);
xmlHelpers.signAssertion(doc, signAlgorithm, digestAlgorithm, cert.getCertificate(), cert.getPrivateKey());
samlMessage = xmlHelpers.getStringOfDocument(doc);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("Assertions successfully signed");
} else {
Expand All @@ -378,15 +400,15 @@ public void resignMessage() {
setInfoMessageText("Signing...");
BurpCertificate cert = samlGUI.getActionPanel().getSelectedCertificate();
if (cert != null) {
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getContents().toString());
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getText());
NodeList responses = xmlHelpers.getResponse(document);
String signAlgorithm = xmlHelpers.getSignatureAlgorithm(responses.item(0));
String digestAlgorithm = xmlHelpers.getDigestAlgorithm(responses.item(0));

xmlHelpers.removeOnlyMessageSignature(document);
xmlHelpers.signMessage(document, signAlgorithm, digestAlgorithm, cert.getCertificate(), cert.getPrivateKey());
samlMessage = xmlHelpers.getStringOfDocument(document);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("Message successfully signed");
} else {
Expand Down Expand Up @@ -440,7 +462,7 @@ private void updateXSWList() {

public void sendToCertificatesTab() {
try {
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getContents().toString());
Document document = xmlHelpers.getXMLDocumentOfSAMLMessage(textArea.getText());
String cert = xmlHelpers.getCertificate(document.getDocumentElement());
if (cert != null) {
certificateTabController.importCertificateFromString(cert);
Expand Down Expand Up @@ -495,25 +517,25 @@ public void applyCVE() {
switch (cve) {
case CVE_2022_41912.CVE:
samlMessage = CVE_2022_41912.apply(orgSAMLMessage);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("%s applied".formatted(cve));
break;
case CVE_2025_23369.CVE:
samlMessage = CVE_2025_23369.apply(orgSAMLMessage);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("%s applied".formatted(cve));
break;
case CVE_2025_25291.CVE:
samlMessage = CVE_2025_25291.apply(orgSAMLMessage);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("%s applied".formatted(cve));
break;
case CVE_2025_25292.CVE:
samlMessage = CVE_2025_25292.apply(orgSAMLMessage);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText("%s applied".formatted(cve));
break;
Expand All @@ -530,7 +552,7 @@ public void applyXSW() {
document = xmlHelpers.getXMLDocumentOfSAMLMessage(orgSAMLMessage);
xswHelpers.applyXSW(samlGUI.getActionPanel().getSelectedXSW(), document);
samlMessage = xmlHelpers.getStringOfDocument(document);
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText(XSW_ATTACK_APPLIED);
} catch (SAXException e) {
Expand All @@ -551,7 +573,7 @@ public void applyXXE(String collabUrl) {
String xmlDeclaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
samlMessage = xmlDeclaration + xxePayload + orgSAMLMessage;
}
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText(XXE_CONTENT_APPLIED);
}
Expand Down Expand Up @@ -592,7 +614,7 @@ public void applyXSLT(String collabUrl) {
String firstPart = orgSAMLMessage.substring(0, substringIndex);
String secondPart = orgSAMLMessage.substring(substringIndex);
samlMessage = firstPart + xslt + secondPart;
textArea.setContents(ByteArray.byteArray(samlMessage));
textArea.setText(prettifyXmlOrFallback(samlMessage));
isEdited = true;
setInfoMessageText(XSLT_CONTENT_APPLIED);
}
Expand Down Expand Up @@ -638,11 +660,11 @@ public void update() {
}

public String getEditorContents() {
return this.textArea.getContents().toString();
return this.textArea.getText();
}

public void setEditorContents(String text) {
this.isEdited = true;
this.textArea.setContents(ByteArray.byteArray(text));
this.textArea.setText(prettifyXmlOrFallback(text));
}
}
Loading