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> + + + + + + + + + + + """.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); + } + } +}