A cyber security tester handling a keyboard and mouse in front of a computer screen.

XML Signature Wrapping in Samlify

Introduction

NodeJS is rapidly becoming prevalent as the platform of choice in projects of our clients. One of the advantages of this relatively new platform is the abundance of open source libraries: ‘middleware’ in Node-speak. This is a good thing of course, it increases speed of development and we all know that recycling is good for the environment.

For us, as security researchers, this requires us to rethink the way we assess custom applications for our clients. While we used to focus primarily on custom developed code, it becomes more and more important to also take the middleware layer into account when conducting code reviews.

Therefore we’ve recently extended our (code) review scope in a project and quickly realized the importance of this when we discovered a vulnerability in popular middleware, ‘Express-saml2’, which – depending on the actual use of the middleware – can have high impact consequences. Express-saml2 is used to support the implementation of the saml2-protocol which is used to facilitate single sign-on. And therefore obviously is an interesting target for attackers.

After diving in, we learned that ‘Express-saml2 is now deprecated and is superseded by ‘Samlify’ (https://samlify.js.org/#/). We checked out Samlify and concluded that the vulnerability was still present in the most recent version (2.2.0 at the time).

Issue description

An attacker who has observed a SAMLResponse is able to add NameID’s to the SAMLResponse message without breaking the signature check. Depending on the application logic, this can be abused to log on as any user.

Legitimate users are able to observe SAMLResponses by simply using their browser or an intercepting proxy like ZAP. Furthermore, SAMLResponses might be obtained by sniffing network traffic or conducting man-in-the-middle attacks.

Note that this issue can be seen as a XML Signature Wrapping attack, which is a known attack pattern. See:
https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final91-8-23-12.pdf

Analysis

The middleware parses certain elements from the SAMLResponse messages and exposes the acquired data to the calling application. The application trusts this data and uses it to authenticate the user. The vulnerability stems from the fact that the selection of elements is being done using naive XPath expressions. See code fragments below:

Express2-saml XSW vulnerability code #1
Express2-saml XSW vulnerability code #2
Express2-saml XSW vulnerability code #3

This eventually leads to the following Xpath expression to select the NameID element:

//*[local-name(.)='NameID']/text()

This expression simply selects all ‘NameID’ tags, whether they are part of a validated signature or not. All NameID values are passed along to the application using Express-saml2/Samlify.

Proof of concept

A simple PoC was developed based on the examples in the Express-saml2 module. Samlify 2.2.0 was used to process the SAMLReponses in the screenshots below.

Regular request (with valid signature). Only one NameID tag: a string is returned:

Express2-saml XSW vulnerability PoC #1

Extra NameID-tag is included in message:

Express2-saml XSW vulnerability PoC #2

Two NameID tags in the message: an array of strings is returned:

Express2-saml XSW vulnerability PoC #3

Mitigating factors

Whether this vulnerability leads to an exploitable scenario, is dependent on the logic in the application that is using the middleware to authenticate users. In the regular use case (e.g.: no attack), the middleware returns NameID as a string. When an attacker adds an extra NameID, the middleware returns an array. The application might use the first or the last value in this array (both are under control of an attacker) or break. In the latter case, the vulnerability in Express-saml2/Samlify might not be exploitable via the application.

Fixing the issue

After we discovered the vulnerability we contacted the lead developer of the Samlify project: Tony Ngan (tngan on github). The following actions were suggested to fix the vulnerability:

  • Validate all incoming SAMLResponses (and outgoing SAMLRequests) against the appropriate XSD and reject all requests that do not adhere to the standard.
  • Use only absolute XPath expressions to select elements from the SAMLResponses.
  • Additionally, the middleware should only use the data (such as NameID) from assertions that were successfully validated first.

Tony was very helpful and promptly addressed the issue.

Final thoughts

Version 2.3.0 of Samlify does now validate incoming messages against an XSD, so the vulnerability can no longer be exploited. If you’re using Samlify, ensure you upgrade to the latest version as soon as possible. If you’re still on Express-saml2, migrate to the latest version of Samlify as soon as possible. Samlify can be found on:

Furthermore, be aware that Samlify currently not fully implements all SAML2 checks. It remains the responsibility of the caller to properly verify timestamps and intended Audience / Destination. These checks might be incorporated in Samlify in the future.

Conclusion

Middleware and other applications components are a vital part of any custom application that uses them, and should therefore be treated as such when conducting security assessments.

Update: A CVE was assigned for this issue: CVE-2017-1000452