201911-01
Signature validation bypass
Background
XMLSecLibs is a library written by Rob Richards that implements the xml-enc and xml-dsig W3C recommendations. It allows its users to handle encrypted and digitally signed XML documents. SimpleSAMLphp delegates encryption and signature handling to this library.
Description
Producing a digital signature over an XML document or part of it is a complex set of steps that must be performed one after the other:
- First, the signed element, in this case a SAML assertion, needs to be canonicalized (that is, computing a unique version of the XML independent of formatting).
- The canonicalized version of the signed element is then passed to a hash or digest algorithm, which computes a fixed-length, non-reversible, deterministic representation of the original string.
- This digest is then included in a
Reference
element, which is in turn placed inside aSignedInfo
element. ThisReference
element is actually referring to the XML element that is being signed, by means of itsURI
attribute. The value of thisURI
attribute is essentially an URI matching the identifier (ID
) of the element. - The entire
SignedInfo
element is also canonicalized. - The canonicalized
SignedInfo
is then fed to a cryptographic algorithm using the private key belonging to the entity signing the piece of XML. The output of this algorithm is stored as the content of theSignatureValue
element, which is included as the next child of the topSignature
XML element. - Finally, depending on the type of XML signature, this
Signature
element is either provided as a detached document or enveloped inside the actual signed XML document.
For signature validation, the process is similar, although the SignatureValue
is validated with the public key of
the signing entity, and the result is then compared to the digest computed over the canonicalized element whose
signature is being validated. All the steps in the validation procedure must be taken carefully to ensure that we are
inspecting the right elements of the XML document.
There are multiple ways to locate elements inside an XML document, and a very popular one, used by XMLSecLibs, is the query language known as XPath (XML Path Language). XPath allows to retrieve elements from an XML document by writing expressions. These expressions can be either relative or absolute to the root of the document, and they can match one or multiple elements at the same time. If an expression is not written carefully, it might select multiple elements at the same time, even though that wasn’t expected.
The issue at hand is rooted at the way XPath expressions are used by XMLSecLibs to select Reference
elements inside of
SignedInfo
. The XPath expression ` ./secdsig:SignedInfo/secdsig:Reference will select multiple
Reference elements
inside a
SignedInfo` element from the current element, as in the following example:
<Signature>
<SignedInfo>
<Reference URI="#1">...</Reference>
<Reference URI="#2">...</Reference>
</SignedInfo>
</Signature>
However, it will also select multiple Reference
elements from different SignedInfo
elements when all of them are
children of the current element:
<Signature>
<SignedInfo>
<Reference URI="#1">...</Reference>
</SignedInfo>
<SignedInfo>
<Reference URI="#2">...</Reference>
</SignedInfo>
</Signature>
The resulting set of Reference
elements is the same with such XPath expression and the given documents. XMLSecLibs
iterates over the list of references and processes all of them, adding them to a list of validated nodes. When the
signature is computed, only the first SignedInfo
element (canonicalized) will be taken into account, though. If the
original signed element is kept in a different part of the XML document, the original SignedInfo
will still validate.
However, a modified assertion taking the place of the original can now also be validated if an unsigned reference to it
is included in a new SignedInfo
element that will be processed by XMLSecLibs, due to the previous XPath expression.
Affected versions
All XMLSecLibs versions 1.x, 2.x and 3.x are affected, up to (including) 1.4.2, 2.1.0 and 3.0.3, respectively.
All SimpleSAMLphp versions are affected, up to (including) 1.17.6.
Impact
An attacker could leverage this issue to manually craft an assertion and have the message validated as correctly signed without access to the signing key. This message will then be consumed by a SimpleSAMLphp service provider and the malicious assertion will be processed as if it was legal.
The attacker needs, however, to be able to generate a valid SAML response issued by the targeted identity provider. This means the attacker must be in possession of an account in that IdP. While this can be seen as a mitigation, it should be noted that there is no limitation for an attacker in terms of what to include in the malicious assertion. Therefore, it is possible to impersonate any identity at the targeted IdP once the attacker has any kind of account there.
Resolution
Upgrade to the latest versions of the library, 3.0.4 or 2.1.1.
For SimpleSAMLphp users, run composer update
or upgrade to SimpleSAMLphp 1.17.7. Refer to the documentation for
instructions on how to run composer.
For those using the simplesamlphp/saml2
library directly, run composer update
to upgrade to the latest version of
the library.
Credit
This security issue was discovered by Juraj Somorovsky and Karsten Meyer zu Selhausen (Hackmanit) during a security audit commissioned by SURFnet, and reported on October 24, 2019. Additional details can be found in a blog post written by Hackmanit.