diff --git a/BappManifest.bmf b/BappManifest.bmf
index 46355a6..25673d4 100644
--- a/BappManifest.bmf
+++ b/BappManifest.bmf
@@ -2,12 +2,12 @@ Uuid: c61cfa893bb14db4b01775554f7b802e
ExtensionType: 1
Name: SAML Raider
RepoName: saml-raider
-ScreenVersion: 2.0.2
-SerialVersion: 16
+ScreenVersion: 2.0.3
+SerialVersion: 17
MinPlatformVersion: 0
ProOnly: False
Author: Roland Bischofberger / Emanuel Duss / Tobias Hort-Giess
ShortDescription: Provides a SAML message editor and a certificate management tool to help with testing SAML infrastructures.
-EntryPoint: build/libs/saml-raider-2.0.2.jar
+EntryPoint: build/libs/saml-raider-2.0.3.jar
BuildCommand: ./gradlew jar
SupportedProducts: Pro, Community
diff --git a/README.md b/README.md
index e4f5694..bc31174 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ Don't forget to rate our extension with as many stars you like :smile:.
### Manual Installation
First, download the latest SAML Raider version:
-[saml-raider-2.0.2.jar](https://github.com/SAMLRaider/SAMLRaider/releases/download/v2.0.2/saml-raider-2.0.2.jar).
+[saml-raider-2.0.3.jar](https://github.com/SAMLRaider/SAMLRaider/releases/download/v2.0.3/saml-raider-2.0.3.jar).
Then, start Burp Suite and click in the `Extensions` tab on `Add`. Choose the
SAML Raider JAR file to install it and you are ready to go.
diff --git a/build.gradle b/build.gradle
index f5f5223..8abdfa5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ plugins {
id "java-library"
}
-version = "2.0.2"
+version = "2.0.3"
repositories {
mavenCentral()
diff --git a/src/main/java/application/SamlTabController.java b/src/main/java/application/SamlTabController.java
index a42d74d..15b858a 100644
--- a/src/main/java/application/SamlTabController.java
+++ b/src/main/java/application/SamlTabController.java
@@ -16,9 +16,14 @@
import gui.XSWHelpWindow;
import helpers.XMLHelpers;
import helpers.XSWHelpers;
-import java.awt.Component;
-import java.awt.Desktop;
-import java.awt.Toolkit;
+import model.BurpCertificate;
+import org.w3c.dom.*;
+import org.xml.sax.SAXException;
+
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.parsers.ParserConfigurationException;
+import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.File;
@@ -36,33 +41,23 @@
import java.util.List;
import java.util.Observable;
import java.util.Observer;
-import javax.xml.crypto.MarshalException;
-import javax.xml.crypto.dsig.XMLSignatureException;
-import javax.xml.parsers.ParserConfigurationException;
-import model.BurpCertificate;
-import org.w3c.dom.DOMException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
import static java.util.Objects.requireNonNull;
public class SamlTabController implements ExtensionProvidedHttpRequestEditor, Observer {
- private static final String XML_CERTIFICATE_NOT_FOUND = "X509 Certificate not found";
- private static final String XSW_ATTACK_APPLIED = "XSW Attack applied";
- private static final String XXE_CONTENT_APPLIED = "XXE content applied";
- private static final String XML_NOT_SUITABLE_FOR_XXE = "This XML Message is not suitable for this particular XXE attack";
- private static final String XSLT_CONTENT_APPLIED = "XSLT content applied";
- private static final String XML_NOT_SUITABLE_FOR_XLST = "This XML Message is not suitable for this particular XLST attack";
- private static final String XML_COULD_NOT_SIGN = "Could not sign XML";
- private static final String XML_COULD_NOT_SERIALIZE = "Could not serialize XML";
- private static final String XML_NOT_WELL_FORMED = "XML isn't well formed or binding is not supported";
- private static final String XML_NOT_SUITABLE_FOR_XSW = "This XML Message is not suitable for this particular XSW, is there a signature?";
- private static final String NO_BROWSER = "Could not open diff in Browser. Path to file was copied to clipboard";
- private static final String NO_DIFF_TEMP_FILE = "Could not create diff temp file.";
+ public static final String XML_CERTIFICATE_NOT_FOUND = "X509 Certificate not found";
+ public static final String XSW_ATTACK_APPLIED = "XSW Attack applied";
+ public static final String XXE_CONTENT_APPLIED = "XXE content applied";
+ public static final String XML_NOT_SUITABLE_FOR_XXE = "This XML Message is not suitable for this particular XXE attack";
+ public static final String XSLT_CONTENT_APPLIED = "XSLT content applied";
+ public static final String XML_NOT_SUITABLE_FOR_XSLT = "This XML Message is not suitable for this particular XSLT attack";
+ public static final String XML_COULD_NOT_SIGN = "Could not sign XML";
+ public static final String XML_COULD_NOT_SERIALIZE = "Could not serialize XML";
+ public static final String XML_NOT_WELL_FORMED = "XML isn't well formed or binding is not supported";
+ public static final String XML_NOT_SUITABLE_FOR_XSW = "This XML Message is not suitable for this particular XSW, is there a signature?";
+ public static final String NO_BROWSER = "Could not open diff in Browser. Path to file was copied to clipboard";
+ public static final String NO_DIFF_TEMP_FILE = "Could not create diff temp file.";
private final CertificateTabController certificateTabController;
private XMLHelpers xmlHelpers;
@@ -433,6 +428,10 @@ private void setInfoMessageText(String infoMessage) {
samlGUI.getActionPanel().getInfoMessageLabel().setText(infoMessage);
}
+ public String getInfoMessageText() {
+ return samlGUI.getActionPanel().getInfoMessageLabel().getText();
+ }
+
private void resetInfoMessageText() {
samlGUI.getActionPanel().getInfoMessageLabel().setText("");
}
@@ -534,33 +533,45 @@ public void applyXXE(String collabUrl) {
}
public void applyXSLT(String collabUrl) {
- String xslt = "\n" +
- "\n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- "";
- String transformString = "";
+ var prefixed = true;
+ var transformString = "";
+
int index = orgSAMLMessage.indexOf(transformString);
+ if (index == -1) {
+ prefixed = false;
+ transformString = "";
+ }
+ index = orgSAMLMessage.indexOf(transformString);
if (index == -1) {
- setInfoMessageText(XML_NOT_SUITABLE_FOR_XLST);
- } else {
- int substringIndex = index + transformString.length();
- String firstPart = orgSAMLMessage.substring(0, substringIndex);
- String secondPart = orgSAMLMessage.substring(substringIndex);
- samlMessage = firstPart + xslt + secondPart;
- textArea.setContents(ByteArray.byteArray(samlMessage));
- isEdited = true;
- setRawMode(true);
- setInfoMessageText(XSLT_CONTENT_APPLIED);
+ setInfoMessageText(XML_NOT_SUITABLE_FOR_XSLT);
+ return;
}
+
+ var prefix = prefixed ? "ds:" : "";
+ var xslt = """
+
+ <%sTransform>
+
+
+
+
+
+
+
+
+
+ %sTransform>
+ """.formatted(prefix, collabUrl, prefix);
+
+ int substringIndex = index + transformString.length();
+ String firstPart = orgSAMLMessage.substring(0, substringIndex);
+ String secondPart = orgSAMLMessage.substring(substringIndex);
+ samlMessage = firstPart + xslt + secondPart;
+ textArea.setContents(ByteArray.byteArray(samlMessage));
+ isEdited = true;
+ setRawMode(true);
+ setInfoMessageText(XSLT_CONTENT_APPLIED);
}
public synchronized void addMatchAndReplace(String match, String replace) {
diff --git a/src/main/java/livetesting/ApplyXsltTest.java b/src/main/java/livetesting/ApplyXsltTest.java
new file mode 100644
index 0000000..623aefe
--- /dev/null
+++ b/src/main/java/livetesting/ApplyXsltTest.java
@@ -0,0 +1,96 @@
+package livetesting;
+
+import application.CertificateTabController;
+import application.SamlMessageAnalyzer;
+import application.SamlMessageDecoder;
+import application.SamlTabController;
+import burp.api.montoya.http.message.HttpRequestResponse;
+import burp.api.montoya.http.message.params.HttpParameterType;
+import burp.api.montoya.http.message.requests.HttpRequest;
+import gui.CertificateTab;
+
+public class ApplyXsltTest {
+
+ private final String rawRequest = """
+ POST /api/oauth/saml HTTP/1.1
+ Host: sso.eu.boxyhq.com
+ Content-Length: 13516
+ Cache-Control: max-age=0
+ Accept-Language: en-GB
+ Upgrade-Insecure-Requests: 1
+ Origin: https://mocksaml.com
+ Content-Type: application/x-www-form-urlencoded
+ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.57 Safari/537.36
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
+ Referer: https://mocksaml.com/
+ Accept-Encoding: gzip, deflate, br
+ Priority: u=0, i
+ Connection: keep-alive
+
+ SAMLResponse=PHNhbWxwOlJlc3BvbnNlIElEPSJfZmQ2MDFlMjEtNWY4MS00NjllLTg4YzctZGE3MmRjY2YxMzU3IiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAxNS0wNC0wNlQwNjo0MjozOS4yMTNaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zYW1sY2VudC9TaGliYm9sZXRoLnNzby9TQU1MMi9QT1NUIiBDb25zZW50PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y29uc2VudDp1bnNwZWNpZmllZCIgSW5SZXNwb25zZVRvPSJfNTQ1ZTYwZmUzNjAyYTA2ZDI1ZjI0MWI2MjJjNWE3NzMiIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiPjxJc3N1ZXIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHA6Ly9TQU1MV0lOLnNhbWwubGFuL2FkZnMvc2VydmljZXMvdHJ1c3Q8L0lzc3Vlcj48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiIC8%2BPC9zYW1scDpTdGF0dXM%2BPEFzc2VydGlvbiBJRD0iX2YyN2Q2NDAzLTMyZjMtNDVlYy04YjI0LThiMmZiNGNhOTliMCIgSXNzdWVJbnN0YW50PSIyMDE1LTA0LTA2VDA2OjQyOjM5LjIxMloiIFZlcnNpb249IjIuMCIgeG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPjxJc3N1ZXI%2BaHR0cDovL1NBTUxXSU4uc2FtbC5sYW4vYWRmcy9zZXJ2aWNlcy90cnVzdDwvSXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2IiAvPjxkczpSZWZlcmVuY2UgVVJJPSIjX2YyN2Q2NDAzLTMyZjMtNDVlYy04YjI0LThiMmZiNGNhOTliMCI%2BPGRzOlRyYW5zZm9ybXM%2BPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIiAvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8%2BPC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiIC8%2BPGRzOkRpZ2VzdFZhbHVlPmZvS0swY3JRc1lDb3VZVTJwdDlkdnlEZEk5WjRzNVowV0FIcnBjbEFmQTg9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8%2BPGRzOlNpZ25hdHVyZVZhbHVlPjVhL0JFR0F5WkZBcmFwRHJoS3B5Y0I3d0FEeHBOMXJ3Qk95NUFEeU1zbEZEWjJYYnJrNklMQlZkd1FoNzhYZDVPUXRBWGdhcCtac3g4ZElWRjVUTjRPN3M4VERUM1VrR0VSUXU0ZVRpc2poSmFOam5jK0hOWHRrdWJLblEyanBvR2RvRGZwZ2YyVUpJVnE3Yjl6WFF4SWtpNFY0RGNNT0pjbGhiaUl3STJHWEZsem03MGZXWURBa3VBa2JhQU93WDcxNmpiNnhrbU1oQTRrRUR5c3pPeEZsVWJMZEtwOTJINzREMHdsaG5JcVAyazZPTnp1VE1MZmpNR041RlplbnFaeUpVZzZJWDc5bWZmRnBDRzZ0Rk05d1J6YWVoVGhHUkxJUTJRdFloNE1jQll3QXExSnJMMlFYdXJTcEgwNmxyQXprMEQ3OUhLREJQUjYyWndzNTVKdz09PC9kczpTaWduYXR1cmVWYWx1ZT48S2V5SW5mbyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU%2BTUlJQzNEQ0NBY1NnQXdJQkFnSVFOMHU3SmZhS0ZyeFBvR3VQMEVlVmpUQU5CZ2txaGtpRzl3MEJBUXNGQURBcU1TZ3dKZ1lEVlFRREV4OUJSRVpUSUZOcFoyNXBibWNnTFNCVFFVMU1WMGxPTG5OaGJXd3ViR0Z1TUI0WERURTFNREl5TlRFM01URTBOMW9YRFRFMk1ESXlOVEUzTVRFME4xb3dLakVvTUNZR0ExVUVBeE1mUVVSR1V5QlRhV2R1YVc1bklDMGdVMEZOVEZkSlRpNXpZVzFzTG14aGJqQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQVBMVFlrYkJJdlBhMitLck92eG9pMWFsT2NPbnh6RlJsWkVMWWh5aUNqMmowaEt1UWQrZkIrT2dQNGZOdWFIL2RFYlNpWjBmRDNNdFEwbnJjNjVOVFlyWHBQcUFhc01FR3BWVk9lbWk0a2FLd3hyWU9EM05iRm9GeFFqdmpNVjlVUXQyUmFCZTE2MHNGZTU4bzVjV3ZOVnhYQTJTZjgxZkllSGxTQkVNYXZGT1FGUWtRYkRVL1htR3RXMFhqUWh5eWlKNE1FeTdad2d1MkhteHBpd05hNndTZmxEWFpJVVlxM2dVWitlRnI4a1RnQnJwZ0x0RDJsQWFhRjhlOVgwbjZ4aXN3RG9PUnM3MGNOaXlIZ1RONHl3TCsxalQrdk5qSG9WK1Y5YnRUY2ZyMGwvSnl0RnJDTlh4M3o2azhwRG1RVkdJZmJZN0o0blJkcXB6RWQ1TU9URUNBd0VBQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQXFPQ0pNcUU3cFJCczVxdnRtSjU1cjdmL0hGNkIrU1JpanpYNGswQmc3R0dLUXNObjJYM0JDNU1ZQ2NWWWxtelh3OGs1Snh4eE1ja0V4R2xuU3ZwaCsyRHlaSk95c3NwTWoyTkt1c2VEU0dhQkdiaEpYSC92RjBGbTlQcy9UZjRCS0lCclBFMTRnaENwNHZ0YVhscGQxMy93MWVYU3dxUTJySVJFYm1pZEdobzZQOWhrVkg2RzhyaTJpQ2xTNzhFZGFraG9za2NjMzVVdlh0NG82Ujc3UlRBOS9qUTlOeWx4WW9qMGVZQWxrSWxHK3JTRFFweDhSWFJpTFF4c09sNUVwWHFtb0Q5ekdBRVdXQXhjbXpUQWpKRkZ6aXMxRjduNm5WdXY4U1ZhS2pRQkV6L25tc3RkdXhMT28yMERSL00wVkFRUXp3TURNOXVpaFhOUXdOV0VNdz09PC9kczpYNTA5Q2VydGlmaWNhdGU%2BPC9kczpYNTA5RGF0YT48L0tleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPFN1YmplY3Q%2BPFN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfNTQ1ZTYwZmUzNjAyYTA2ZDI1ZjI0MWI2MjJjNWE3NzMiIE5vdE9uT3JBZnRlcj0iMjAxNS0wNC0wNlQwNjo0NzozOS4yMTNaIiBSZWNpcGllbnQ9Imh0dHBzOi8vc2FtbGNlbnQvU2hpYmJvbGV0aC5zc28vU0FNTDIvUE9TVCIgLz48L1N1YmplY3RDb25maXJtYXRpb24%2BPC9TdWJqZWN0PjxDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAxNS0wNC0wNlQwNjo0MjozOS4yMTBaIiBOb3RPbk9yQWZ0ZXI9IjIwMTUtMDQtMDZUMDc6NDI6MzkuMjEwWiI%2BPEF1ZGllbmNlUmVzdHJpY3Rpb24%2BPEF1ZGllbmNlPmh0dHBzOi8vc2FtbGNlbnQvc2hpYmJvbGV0aDwvQXVkaWVuY2U%2BPC9BdWRpZW5jZVJlc3RyaWN0aW9uPjwvQ29uZGl0aW9ucz48QXR0cmlidXRlU3RhdGVtZW50PjxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvdXBuIj48QXR0cmlidXRlVmFsdWU%2BYm93c2VyQHNhbWwubGFuPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcy9Hcm91cCI%2BPEF0dHJpYnV0ZVZhbHVlPkRvbcOkbmVuLUJlbnV0emVyPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9InVybjpvaWQ6MS4zLjYuMS40LjEuNTkyMy4xLjEuMS42IiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI%2BPEF0dHJpYnV0ZVZhbHVlPmJvd3NlckBzYW1sLmxhbjwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNS0wNC0wNlQwNjo0MjozOS4xNzhaIj48QXV0aG5Db250ZXh0PjxBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvQXV0aG5Db250ZXh0Q2xhc3NSZWY%2BPC9BdXRobkNvbnRleHQ%2BPC9BdXRoblN0YXRlbWVudD48L0Fzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg%3D%3D&RelayState=ss%3Amem%3Af3a11b409a62a95ea2f4620efb845bb0ad02dfde2e68e372cebb823ae01a3694""";
+
+ @TestOrder.Order(1)
+ public TestResult isSAMLMessage() {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var success = analysis.isSAMLMessage();
+ return new TestResult(success, null, null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(2)
+ public TestResult isSAMLResponse() {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var success = analysis.isSAMLMessage() && !analysis.isSAMLRequest();
+ return new TestResult(success, null, null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(3)
+ public TestResult canDecodeSAMLMessage() throws Exception {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var body = request.parameterValue("SAMLResponse", HttpParameterType.BODY);
+ var decodedSamlMessage = SamlMessageDecoder.getDecodedSAMLMessage(body, analysis.isWSSMessage(), analysis.isWSSUrlEncoded());
+ return new TestResult(true, decodedSamlMessage.message(), null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(4)
+ public TestResult canApplyXsltAttack() throws Exception {
+ try {
+ var certificateTab = new CertificateTab();
+ var certificateTabController = new CertificateTabController(certificateTab);
+ var samlTabController = new SamlTabController(true, certificateTabController);
+ var request = HttpRequest.httpRequest(rawRequest);
+ var requestResponse = HttpRequestResponse.httpRequestResponse(request, null);
+ samlTabController.setRequestResponse(requestResponse);
+ samlTabController.applyXSLT("https://example.com");
+ var infoMessageText = samlTabController.getInfoMessageText();
+
+ var success = SamlTabController.XSLT_CONTENT_APPLIED.equals(infoMessageText);
+
+ if (!success) {
+ return new TestResult(false, infoMessageText, null);
+ }
+
+ request = samlTabController.getRequest();
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var body = request.parameterValue("SAMLResponse", HttpParameterType.BODY);
+ var decodedSamlMessage = SamlMessageDecoder.getDecodedSAMLMessage(body, analysis.isWSSMessage(), analysis.isWSSUrlEncoded());
+ return new TestResult(true, decodedSamlMessage.message(), null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+}
diff --git a/src/main/java/livetesting/Issue78Test.java b/src/main/java/livetesting/Issue78Test.java
new file mode 100644
index 0000000..8809589
--- /dev/null
+++ b/src/main/java/livetesting/Issue78Test.java
@@ -0,0 +1,96 @@
+package livetesting;
+
+import application.CertificateTabController;
+import application.SamlMessageAnalyzer;
+import application.SamlMessageDecoder;
+import application.SamlTabController;
+import burp.api.montoya.http.message.HttpRequestResponse;
+import burp.api.montoya.http.message.params.HttpParameterType;
+import burp.api.montoya.http.message.requests.HttpRequest;
+import gui.CertificateTab;
+
+public class Issue78Test {
+
+ private final String rawRequest = """
+ POST /api/oauth/saml HTTP/1.1
+ Host: sso.eu.boxyhq.com
+ Content-Length: 13516
+ Cache-Control: max-age=0
+ Accept-Language: en-GB
+ Upgrade-Insecure-Requests: 1
+ Origin: https://mocksaml.com
+ Content-Type: application/x-www-form-urlencoded
+ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.57 Safari/537.36
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
+ Referer: https://mocksaml.com/
+ Accept-Encoding: gzip, deflate, br
+ Priority: u=0, i
+ Connection: keep-alive
+
+ SAMLResponse=PHNhbWxwOlJlc3BvbnNlIElEPV9mYjVhZjBmMC1mMmI2LTQ4YjctYTNmZS02ZTMwYTBjOGM3ZDEgVmVyc2lvbj0yLjAgSXNzdWVJbnN0YW50PTIwMjQtMDktMThUMTE6MTQ6NDMuMDUwWiBEZXN0aW5hdGlvbj1odHRwczovL2Rlc3RpbmF0aW9uLyBJblJlc3BvbnNlVG89T05FTE9HSU5fY2RiZjg1Mzg3NmE4MzcyZDQwYjkzNDFhNGY5NzE0NDJmMDhiNDEzZCB4bWxuczpzYW1scD11cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2w%2BPElzc3VlciB4bWxucz11cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uPmh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzIxZWE5MTZiLWQ5MmYtNDdmMC1iZDY1LWM2N2I5NzJlNjVhZS88L0lzc3Vlcj48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPXVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2Vzcy8%2BPC9zYW1scDpTdGF0dXM%2BPEFzc2VydGlvbiBJRD1fZTY4ZmMyNDQtZDUxNy00ZWNiLTk5OGYtNzhkYzBmNDI3YTAwIElzc3VlSW5zdGFudD0yMDI0LTA5LTE4VDExOjE0OjQzLjA0NlogVmVyc2lvbj0yLjAgeG1sbnM9dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbj48SXNzdWVyPmh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzIxZWE5MTZiLWQ5MmYtNDdmMC1iZDY1LWM2N2I5NzJlNjVhZS88L0lzc3Vlcj48U2lnbmF0dXJlIHhtbG5zPWh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyM%2BPFNpZ25lZEluZm8%2BPENhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPWh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIy8%2BPFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09aHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1Ni8%2BPFJlZmVyZW5jZSBVUkk9I19lNjhmYzI0NC1kNTE3LTRlY2ItOTk4Zi03OGRjMGY0MjdhMDA%2BPFRyYW5zZm9ybXM%2BPFRyYW5zZm9ybSBBbGdvcml0aG09aHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUvPjxUcmFuc2Zvcm0gQWxnb3JpdGhtPWh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIy8%2BPC9UcmFuc2Zvcm1zPjxEaWdlc3RNZXRob2QgQWxnb3JpdGhtPWh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1Ni8%2BPERpZ2VzdFZhbHVlPlY4UFg3Z1hHSCBXYkZGYkhzYndULzJ0cjlZV0hVcW1BU2RPRCB0Y2lLVnc9PC9EaWdlc3RWYWx1ZT48L1JlZmVyZW5jZT48L1NpZ25lZEluZm8%2BPFNpZ25hdHVyZVZhbHVlPnIxRFcwdUlERkJubHlzS0tISUE5VFlZRjFxRDd1VDdTa292Q1JrRWdlbm9ZWG1NVGQvWEtpYUlWNFgxTElsSTBzVjBxajZGTlV0dTFZR295UTNKWEQ2QTYxcXd2SUFJeUt0dmVRVGNaOUg3MTlEVTZEcHggZnQydGNQNm0yRDJCcGg5QlcyVklRMXFPY3BpQTlNU3pSSmV0eDZQaExpNnhaeDVncWxJRnp5Q0dnVGpFR3cwQW5scTZvMnJISVZFcGRlVGhJdWU0RndmYU51NGJybjRnMUloeFJRRC9jT1ZHUzVCcUNHakFwcExzSWlRc1FWT2IgL0RmRlBUeUxBSlBteFNyWGtXZGRnenBaTFhwUTZZTzFxcGV5MVRpVWZGQ3dZRVljc3J2RHQxM0h0a0d2cm44MjBpS0hIT0c4a2FkQTB3SmtBRXA3d0xYQmM4Wmo4YTZrUT09PC9TaWduYXR1cmVWYWx1ZT48S2V5SW5mbz48WDUwOURhdGE%2BPFg1MDlDZXJ0aWZpY2F0ZT5NSUlDOERDQ0FkaWdBd0lCQWdJUVVOWVNjVlpwIGFGQ2g4VCB3d0Y4UlRBTkJna3Foa2lHOXcwQkFRc0ZBREEwTVRJd01BWURWUVFERXlsTmFXTnliM052Wm5RZ1FYcDFjbVVnUm1Wa1pYSmhkR1ZrSUZOVFR5QkRaWEowYVdacFkyRjBaVEFlRncweU5EQTVNRE14TkRBek1ERmFGdzB5TnpBNU1ETXhOREF6TURCYU1EUXhNakF3QmdOVkJBTVRLVTFwWTNKdmMyOW1kQ0JCZW5WeVpTQkdaV1JsY21GMFpXUWdVMU5QSUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNDZMb25hRnZaeFFCR1BvM0pObi83U0FSRHBhRCBWcndacEszRzN6eVhQeDZ2aXdNMDR0UDM4NUJSZTJpbHlvNmx2IFEyNS9MblRXOWhNdFl1aGNEenNEbzBHYkpMWG5jeEtWaGFrb2owR1JUemFMNlhpdCBOZ2RDRkUzOGZaVG9kOGk4clFWMHpuZ2Z1IHNoanFyVXVxMVA2eElzcUEgT2xEbmZ0UDl3QzRYaXpZTDVyckpuenh5YUN3MDExaS9yeDI0TnFEOGtGZlRWcXQxTXRtQU1XR1ZaVGJzS3k1d1hXWWYgZHp2TVVZbDZWSHZGcWUwaDZnaEMvU3hVbnRUY3lRVGVRbFhIN2JYZEs2ZlRzNXV3V2ZnVGJSWmJrNDN6T0tyZmc2UUFZUVBQaWFuWDA4cFZ5RjZrRlhUcGhVenpLNWF2VjRVRUN0U0xwbzZSQkdXTGhRSURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCOTdSclk1ZHk0dHpQNlhUU1g1Nm1WQkdZL043M28vWklvRjFMU1dJbGZCVnFNZFkyOUVKYlhFSWhhdFY3SmcvRzFPQ1RLRG94Wm9NTzNlMVk2THlMZzE4MDhaSWpnQiBwZC9uMlN4QmZpaUhmdGNRWjIgWnNJUVpyWjJjY05xYk9RaktwQ081WXdaVmhWUkdNQTA5UkxhMmovUlYxZ1A3WVhOR2d2YWpRYXI5MmkyeDljV2EgLzV2SThWUUZ4clpTUUZFM0JnUDIgeTAwSjQ2RS9HaGtLaG1pMExPIEg4T2Q0eFFhdmxOeXo2MnVKMmJmYVZ5dzR5U2V6WnR1RTM3UnQgb0hJNDBzV01vVTg4QkZ0ckExTVczOVlQaiBUSGZONEo3MXVXWSBqOWdKWDZWOHNPMFF6dWplV2xndWg2dFZrb3lqUEZ4bXFXIGFIcWlVRTNiY208L1g1MDlDZXJ0aWZpY2F0ZT48L1g1MDlEYXRhPjwvS2V5SW5mbz48L1NpZ25hdHVyZT48U3ViamVjdD48TmFtZUlEIEZvcm1hdD11cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDplbWFpbEFkZHJlc3M%2Bbm9ib2R5QG5vd2hlcmUuY29tPC9OYW1lSUQ%2BPFN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPXVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXI%2BPFN1YmplY3RDb25maXJtYXRpb25EYXRhIEluUmVzcG9uc2VUbz1PTkVMT0dJTl9jZGJmODUzODc2YTgzNzJkNDBiOTM0MWE0Zjk3MTQ0MmYwOGI0MTNkIE5vdE9uT3JBZnRlcj0yMDI0LTA5LTE4VDEyOjE0OjQyLjkzNFogUmVjaXBpZW50PWh0dHBzOi8vZGVzdGluYXRpb24vLz48L1N1YmplY3RDb25maXJtYXRpb24%2BPC9TdWJqZWN0PjxDb25kaXRpb25zIE5vdEJlZm9yZT0yMDI0LTA5LTE4VDExOjA5OjQyLjkzNFogTm90T25PckFmdGVyPTIwMjQtMDktMThUMTI6MTQ6NDIuOTM0Wj48QXVkaWVuY2VSZXN0cmljdGlvbj48QXVkaWVuY2U%2BaHR0cHM6Ly9kZXN0aW5hdGlvbi88L0F1ZGllbmNlPjwvQXVkaWVuY2VSZXN0cmljdGlvbj48L0NvbmRpdGlvbnM%2BPEF0dHJpYnV0ZVN0YXRlbWVudD48QXR0cmlidXRlIE5hbWU9aHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9pZGVudGl0eS9jbGFpbXMvdGVuYW50aWQ%2BPEF0dHJpYnV0ZVZhbHVlPjIxZWE5MTZiLWQ5MmYtNDdmMC1iZDY1LWM2N2I5NzJlNjVhZTwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPEF0dHJpYnV0ZSBOYW1lPWh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vaWRlbnRpdHkvY2xhaW1zL29iamVjdGlkZW50aWZpZXI%2BPEF0dHJpYnV0ZVZhbHVlPjk4N2YyMThlLWQxMTMtNGFlZi04YmNkLWUwYTFkOGIwMzg4ODwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPEF0dHJpYnV0ZSBOYW1lPWh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vaWRlbnRpdHkvY2xhaW1zL2Rpc3BsYXluYW1lPjxBdHRyaWJ1dGVWYWx1ZT5Vc2VyMTwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPEF0dHJpYnV0ZSBOYW1lPWh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvZ3JvdXBzPjxBdHRyaWJ1dGVWYWx1ZT5iOTgxMWQxMy02Mjc1LTQ0MWYtODU5My0wNTQ2MWIwM2I4MDE8L0F0dHJpYnV0ZVZhbHVlPjwvQXR0cmlidXRlPjxBdHRyaWJ1dGUgTmFtZT1odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL2lkZW50aXR5L2NsYWltcy9pZGVudGl0eXByb3ZpZGVyPjxBdHRyaWJ1dGVWYWx1ZT5odHRwczovL3N0cy53aW5kb3dzLm5ldC8yMWVhOTE2Yi1kOTJmLTQ3ZjAtYmQ2NS1jNjdiOTcyZTY1YWUvPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9aHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9jbGFpbXMvYXV0aG5tZXRob2RzcmVmZXJlbmNlcz48QXR0cmlidXRlVmFsdWU%2BaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2F1dGhlbnRpY2F0aW9ubWV0aG9kL3Bhc3N3b3JkPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9aHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvZ2l2ZW5uYW1lPjxBdHRyaWJ1dGVWYWx1ZT5Vc2VyPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9aHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvc3VybmFtZT48QXR0cmlidXRlVmFsdWU%2BMTwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPEF0dHJpYnV0ZSBOYW1lPWh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWU%2BPEF0dHJpYnV0ZVZhbHVlPm5vYm9keUBub3doZXJlLmNvbTwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0yMDI0LTA5LTE4VDExOjE0OjQwLjA0OVogU2Vzc2lvbkluZGV4PV9lNjhmYzI0NC1kNTE3LTRlY2ItOTk4Zi03OGRjMGY0MjdhMDA%2BPEF1dGhuQ29udGV4dD48QXV0aG5Db250ZXh0Q2xhc3NSZWY%2BdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmQ8L0F1dGhuQ29udGV4dENsYXNzUmVmPjwvQXV0aG5Db250ZXh0PjwvQXV0aG5TdGF0ZW1lbnQ%2BPC9Bc3NlcnRpb24%2BPC9zYW1scDpSZXNwb25zZT4%3D""";
+
+ @TestOrder.Order(1)
+ public TestResult isSAMLMessage() {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var success = analysis.isSAMLMessage();
+ return new TestResult(success, null, null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(2)
+ public TestResult isSAMLResponse() {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var success = analysis.isSAMLMessage() && !analysis.isSAMLRequest();
+ return new TestResult(success, null, null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(3)
+ public TestResult canDecodeSAMLMessage() throws Exception {
+ try {
+ var request = HttpRequest.httpRequest(rawRequest);
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var body = request.parameterValue("SAMLResponse", HttpParameterType.BODY);
+ var decodedSamlMessage = SamlMessageDecoder.getDecodedSAMLMessage(body, analysis.isWSSMessage(), analysis.isWSSUrlEncoded());
+ return new TestResult(true, decodedSamlMessage.message(), null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+
+ @TestOrder.Order(4)
+ public TestResult canApplyXsltAttack() throws Exception {
+ try {
+ var certificateTab = new CertificateTab();
+ var certificateTabController = new CertificateTabController(certificateTab);
+ var samlTabController = new SamlTabController(true, certificateTabController);
+ var request = HttpRequest.httpRequest(rawRequest);
+ var requestResponse = HttpRequestResponse.httpRequestResponse(request, null);
+ samlTabController.setRequestResponse(requestResponse);
+ samlTabController.applyXSLT("https://example.com");
+ var infoMessageText = samlTabController.getInfoMessageText();
+
+ var success = SamlTabController.XSLT_CONTENT_APPLIED.equals(infoMessageText);
+
+ if (!success) {
+ return new TestResult(false, infoMessageText, null);
+ }
+
+ request = samlTabController.getRequest();
+ var analysis = SamlMessageAnalyzer.analyze(request, "SAMLRequest", "SAMLResponse");
+ var body = request.parameterValue("SAMLResponse", HttpParameterType.BODY);
+ var decodedSamlMessage = SamlMessageDecoder.getDecodedSAMLMessage(body, analysis.isWSSMessage(), analysis.isWSSUrlEncoded());
+ return new TestResult(true, decodedSamlMessage.message(), null);
+ } catch (Exception exc) {
+ return new TestResult(false, null, exc);
+ }
+ }
+}