Single sign-on (SSO) lets users login across different sites without having to manage multiple accounts. I'm sure most of us appreciate the convenience of seeing "Sign in with …" buttons that let us login with a single username. Hackers, however, see a possible avenue for exploitation, and you'll soon learn how an attacker can exploit a SAML vulnerability to assume another user's identity.
SAML, or Security Assertion Markup Language, is a common standard that lets an identity provider (IdP) communicate securely with a service provider (SP) and pass on a user's authorization. This XML-based communication usually happens through the user's browser, which allows attackers to intercept and modify it. Let's walk through the flow of a SAML exchange.
First, a user attempts to access a secured page on the SP server and is redirected to the IdP login page with a SAML request:
<samlp:AuthnRequest AssertionConsumerServiceURL="https://megauniversity.edu/Shibboleth.sso/SAML2/POST" Destination="https://sso.megauniversity.edu/idp/endpoint/HttpRedirect" ID="_c2a8cff29965b4a61bcff7d4b871b8a2" IssueInstant="2018-04-19T19:58:22Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://megauniversity.edu/shibboleth </saml:Issuer> <samlp:NameIDPolicy AllowCreate="1"/> </samlp:AuthnRequest>
This request forwards info about the service provider to the identity provider and initiates the login process.
The user then logs in via a form on the identity provider's site. The IdP generates a SAML response with authentication information and forwards it via the user's browser to the assertion consumer service URL (an address given by the SP) provided in the first SAML request. Here's a simplified version of what that response looks like:
<samlp:Response Destination="https://megauniversity.edu/Shibboleth.sso/SAML2/POST" ID="_760ac3d612ea7cdfbb3dd59f6ebc16b91524600051040" InResponseTo="_c2a8cff29965b4a61bcff7d4b871b8a2" IssueInstant="2018-04-19T20:00:51.040Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_760ac3d612ea7cdfbb3dd59f6ebc16b91524600051040" Version="2.0" IssueInstant="2018-04-19T20:00:51.040Z"> <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://sso.megauniversity.edu </saml:Issuer> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">firstname.lastname@example.org</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData InResponseTo="_c2a8cff29965b4a61bcff7d4b871b8a2" NotOnOrAfter="2018-04-19T20:05:51.040Z" Recipient="https://megauniversity.edu/Shibboleth.sso/SAML2/POST"/> </saml:SubjectConfirmation> </saml:Subject> <saml:AttributeStatement> <saml:Attribute Name="userId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"> <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType"> 005f4000001qmg6 </saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"> <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType"> email@example.com </saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion> </samlp:Response>
The <saml:NameID/> node (isolated on its own line above) is the pertinent part of this response. The NameID is the user identifying information sent by the IdP. A SAML response will also contain user attributes, such as email and user ID. Signature and key info is also given for the service provider to verify origin and validity.
The user is then redirected to the assertion consumer service URL given in the initial request, and the response is forwarded to that URL via the user's browser. When the service provider validates the response, the user is authorized.
Attentive hackers will note that the SAML response sent to the SP is cryptographically signed, meaning the SP would know if a response had been modified and reject it. However, XML documents ignore two things: whitespace and comments. Developers may insert comments into SAML requests and responses for debugging purposes, but these need to be removed via a technique referred to as XML canonicalization. In short, the systems that encode and send these messages strip non-pertinent information out before cryptographically signing or verifying, meaning that the following two elements would have the same signature.
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">admin<!-- an inline comment -->@megauniversity.edu</saml:NameID>
Things get interesting when we look at a bug in the open-source XMLTooling-C package that a large number of SSO systems depend on. Prior to a recent update, the XMLTooling-C library has a vulnerability in how it processes comments and whitespace appearing in XML data. An in-line comment will split text appearing on either side of it within an element — without changing the cryptographic signature. From a document tree perspective, the example above would look like this:
-SAML Element: NameID
--comment: an inline comment
Lazy sysadmins will not necessarily anticipate more than one text node for a NameID attribute — they may assume that the first text node in the document is the value they're looking for. Meaning, a document tree that looks like this:
-SAML Element: NameID
--comment: let's trick XMLTooling-C
Would have the same signature as the original response that was sent with a single text node. With this response being correctly signed and validated, the naively implemented SP would only look for the first node and would then authorize a session for the provided NameID. Let's dive into a scenario where a hacker could take advantage of this bug!
You're a student at Home State MegaUniversity, a revered institution of higher learning. Early in the semester, you made a noob mistake: you left your laptop open in your dorm room while you were down the hall playing Mario Kart.
Your roommate, being a prankster and opportunist, opened your browser and navigated to the student portal to register you for a new course: "Intro to Accordion," meeting at 6:30 a.m. on Mondays, Wednesdays, and Fridays. By the time you realize this, the drop deadline for courses has passed.
You could give up on sleeping in and develop a new interest in polka music, but you instead decide to take advantage of the skills you've been learning in your information security program. Fortunately for you, the sysadmin of Home State MegaUniversity is extremely lazy. She's missed a few key security items that work to your advantage:
- Users can arbitrarily create new accounts with unverified email addresses.
- Two-factor authentication isn't enforced. Users can arbitrarily create new accounts with unverified email addresses.
- An unpatched version of the Shibboleth SP package (a popular open-source solution for single sign-on) is being used to authenticate users in university subsystems.
You've taken advantage of the first issue by creating an account that you'll use to execute this attack: firstname.lastname@example.org. To take advantage of the rest, you fire up a Kali Linux live session.
One of the many useful tools in Kali Linux is Portswigger's Burp Suite, a proxy debugging tool that allows you to intercept and view HTTP traffic going through your browser. First, you'll need to set up your browser to work with Burp.
If you're using Firefox, start by navigating to Preferences –> Advanced –> Network, then open the "Settings" panel under Connections. Make sure your proxy configuration looks like the following, with a manual proxy configuration of 127.0.0.1 with the Port being 8080.
Next, start Burp Suite with a new temporary project and make sure the proxy is active by navigating to the "Proxy" tab, then "Options." You should see a proxy listener set up on 127.0.0.1 using port 8080:
Finally, visit http://burp in your browser, where you can download a certificate that allows you to sniff SSL traffic. Navigate in Firefox preferences to Advanced –> Certificates –> View Certificate, and "Import" the Portswigger CA certificate. Make sure you've selected to "Trust this CA to identify websites," then hit "OK."
Now we need to install an extension that lets us view and modify SAML requests and responses. SAML Raider is my personal favorite. Navigate in Burp to the "Extender" tab, then "BApp Store." Once there, select and install "SAML Raider" from the list.
Now that we've set up our tools, make sure that the "Proxy" tab in Burp shows that "Intercept is on." This allows Burp to capture and modify requests being made to servers.
When you point your browser to Home State MegaUniversity's secured registrar page, you'll see in Burp that you're forwarded to the IdP system. SAML Raider will show a tab of the same name when there's SAML information that can be decoded. You may have to forward a few other requests before you see the "SAML Raider" tab appear with a request.
Hit the "Forward" button to pass that request on, and you'll be redirected to the IdP login page.
When you enter your credentials for email@example.com, Burp will again intercept a few web requests. Until you see one that populates a "SAML Raider" tab, you'll just hit "Forward" to pass them on unchanged. Eventually, you'll intercept the SAML response from the IdP.
SAML requests and responses give timeframes that the communication must happen within, so it's important to work quickly from this point.
Look through the response and locate the "NameID" element, which should be below the key and signature information. This is what the line looks like in my example:
Now, all we have to do is insert a comment in the right place, then forward the response.
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">firstname.lastname@example.org<!-- letmein -->.fakedomain.com</saml:NameID>
Since the signature still matches the original response, the service provider accepts this as valid and parses the first text object in the NameID element: email@example.com.
With elevated privileges on the registrar page, you're free to drop "Intro to Accordion" and maybe even sign up your roommate for "Underwater Basket Weaving" while you're in.
A more diligent sysadmin at Home State MegaUniversity could take a few steps to make sure that this kind of attack isn't possible. Updating Shibboleth and other SSO packages to the latest versions fixes the XML canonicalization and parsing bugs that this attack depends on. Forcing two-factor authentication would also prevent users from authorizing themselves as other accounts. Finally, the creation of accounts with unverified email addresses is always a bad idea.
Until next time, happy hacking!