mcpField
A
attacking-saml

attacking-saml

github.com/trilwu安全17749 次安装12 周前更新
代码仓库

关于 attacking-saml

面向授权 SAML 安全测试的技能,供检查 SSO 消息和服务提供方行为的测试人员使用。涵盖断言验证缺陷、重放、XML 解析问题及相关身份伪造路径。

主要功能

  1. 01解码并检查 SAML 消息
  2. 02测试 XML 签名包装
  3. 03检查未签名断言处理
  4. 04评估断言与重放验证
  5. 05探测 SAML 解析器 XXE
  6. 06测试证书信任行为

适用场景

  1. 01评估 SAML ACS 端点
  2. 02测试签名验证和断言选择逻辑
  3. 03检查跨服务断言重放
  4. 04评估 XML 解析与证书信任

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill attacking-saml

安装后在 Claude Code 中输入/attacking-saml确认已加载。

详细介绍

攻击 SAML

SAML 安全取决于 XML 签名验证,而 XML 签名出了名地难以正确验证。断言经过了签名——但被签名的是哪个元素、XML 解析器读取了什么,以及应用最终信任什么,这三者可能完全不同。这种差异就是 XML 签名包装攻击,也是 SAML 出问题的频率远高于其密码学原理所暗示的原因。

仅可针对获准测试的系统。

适用场景

  • 请求或重定向中带有 SAMLRequest 或 SAMLResponse 参数
  • Base64 解码后(重定向绑定还需 DEFLATE 解压)得到的 XML 中包含 <saml:Assertion>、<samlp:Response> 或 <saml:Subject>
  • 目标暴露了 /saml/acs、/sso、/saml2/acs 或 /Shibboleth.sso 断言消费者服务端点
  • IdP 发起的登录会将断言直接 POST 到 SP,且之前没有 AuthnRequest
  • 联邦认证使用 Okta、ADFS、PingFederate、Azure/Entra、Shibboleth、 SimpleSAMLphp 或 Keycloak
  • 你控制着一个低权限联邦账户,并希望获得另一个身份或角色

不适用场景

  • SSO 流程使用 OAuth 2.0 或 OpenID Connect(code、id_token、 access_token、/authorize、/.well-known/openid-configuration)——使用 attacking-oauth-oidc
  • 令牌是 JWT(以 eyJ... 开头且使用点分隔),而非已签名的 XML——使用 attacking-jwt
  • 常规 Web 测试,范围内没有 SAML 产物——使用 testing-web-applications
  • 针对已被攻陷的 AD FS 服务或云租户进行 Golden SAML 攻击,且你 已持有令牌签名密钥——这是 attacking-entra-id 中的租户接管攻击
  • 评估签名原语本身(SHA-1 与 SHA-256、RSA 密钥长度、规范化 算法选择)——使用 reviewing-cryptography

解码与检查

一切都从读取消息开始。线上的格式取决于绑定方式。

# HTTP-Redirect binding: base64 then raw DEFLATE (no zlib header)
echo 'fVLLbtsw...' | base64 -d | python3 -c \
  "import sys,zlib; sys.stdout.write(zlib.decompress(sys.stdin.buffer.read(),-15).decode())"

# HTTP-POST binding: plain base64, no deflate
echo 'PHNhbWxwOl...' | base64 -d | xmllint --format -

重定向绑定使用原始 DEFLATE——窗口位数为 -15,不带头部。POST 绑定完全不进行 DEFLATE 压缩。猜错了就会得到乱码;两种方式都试试。

SAML Raider(Burp 扩展)是实际操作环境:它会拦截 ACS POST, 美化 XML 格式、导入 IdP 证书,并通过单击一次即可执行下文介绍的签名包装攻击。开始手动操作前,先安装它。

samltool.com(OneLogin 的 SAMLtool)可以解码并重新编码消息,有助于理解结构——但只能将其作为离线参考。切勿将生产环境中的实时断言粘贴到第三方网站;请改用上述命令进行解码。

先查看以下字段,因为它们决定了后续的所有攻击:

  • <ds:Signature>——它所在的位置,以及其 <ds:Reference URI="#..."> 指向的内容。这就是关键所在。
  • <saml:Subject><saml:NameID>——被断言的身份
  • <saml:AttributeStatement>——角色、群组、电子邮件、权限
  • <saml:Conditions>——NotBefore、NotOnOrAfter、AudienceRestriction
  • <saml:SubjectConfirmationData>——Recipient、NotOnOrAfter、InResponseTo
  • 响应封套上的 Destination 和 Issuer

XML 签名包装(XSW)

SAML 的核心攻击。签名在密码学上有效,但你可以将已签名元素移到签名检查器仍会接受的位置,同时让应用逻辑读取你控制的另一个未签名断言。验证器和使用方对哪个元素具有权威性存在分歧。

八种经典变体(Somorovsky 等人)的区别在于原始已签名断言被移到了哪里,以及伪造断言被插入到了哪里:

  • XSW1 / XSW2 — 包装整个 <Response>;签名引用原始响应,而处理的是伪造响应。XSW2 使用非包裹式签名位置。
  • XSW3 / XSW4 — 针对断言级别。XSW3 将伪造断言设为已签名断言的同级元素;XSW4 将已签名断言嵌套在伪造断言中。使用相同或重叠的 ID。
  • XSW5 / XSW6 — 复制的断言将签名包裹起来;利用 ID 属性,使引用仍能解析。
  • XSW7 / XSW8 — 藏在宽松架构的包装元素中。XSW7 将伪造断言放入 <Extensions> 元素;XSW8 将原始已签名断言藏进 <Object>,使其通过验证但永远不会被使用。
# Attack in SAML Raider:
#   1. Intercept the ACS POST, select the signed assertion
#   2. Edit NameID / attributes in the assertion the app will read
#   3. Click XSW1..XSW8 in turn — each rebuilds the document layout
#   4. Forward; watch for a successful login as the forged identity

遍历全部八种。哪种有效完全取决于 SP 的 XML 库以及它如何选择要信任的断言——无法预测,所以在认定 SP 安全之前,先尝试每种变体。若能以一个你从未合法持有过的 NameID 成功登录,即为发现漏洞。

未签名断言与剥离签名

在尝试包装攻击之前,先测试最简单的故障:SP 是否会验证签名?

  • 剥离签名。 完全移除 <ds:Signature> 并转发。有些 SP 只会在存在签名时才验证。
  • 清空签名。 清空 SignatureValue 或 DigestValue。
  • 给错误的对象签名。 只对响应而非断言签名,或反之;当 SP 只检查其中一个时。
  • 降级算法。 在 SP 未固定预期算法时,尝试使用 SHA-1 的 SignatureMethod,甚至使用 md5 / 无操作算法。
# xmlsec1 can tell you what a document's signature actually covers
xmlsec1 --verify --pubkey-cert-pem idp.crt --id-attr:ID Assertion response.xml

如果 SP 接受被剥离签名或未签名的断言,你就可以完全不使用密码学手段伪造身份——这是严重性最高的 SAML 攻击结果。

篡改断言

一旦你能让断言被接受(剥离签名、未签名,或通过有效的 XSW 变体),就可以更改它所声明的内容:

  • NameID — 替换为目标用户(admin@corp、其他租户的用户)
  • 属性 — 将 Role / Group / memberOf 改为 admin,添加 IdP 从未签发的授权属性,将 email 改为触发 SP 上的账户关联
  • AudienceRestriction — 如果 SP 不检查 <Audience>,为同一联合身份体系中的另一个 SP 签发的断言也可在此重放
  • NotOnOrAfter / NotBefore — 有效期过长或未受检查时,捕获的断言可在本应过期很久之后重放
  • InResponseTo — 对于 SP 发起的流程,检查 SP 是否将响应绑定到自己的 AuthnRequest ID;如果没有,注入或重放的响应就会被接受

分别测试每一项。即使 SP 验证了签名,但忽略 AudienceRestriction 或重放时间窗口,仍然完全可被利用。

在 NameID 中注入注释

多个 SAML 库中存在一种经典规范化漏洞(2018 年 Duo / python-saml / OneLogin 类 CVE)。XML 文本节点处理与签名规范化对 XML 注释如何拆分文本节点的处理并不一致。

<saml:NameID>[email protected]</saml:NameID>

签名是基于规范化后的值计算的(注释可能会被丢弃,或文本节点会被拼接),而应用程序的文本提取只读取注释之前的节点——结果是 admin。因此,一个针对 [email protected](你合法拥有的账户)有效签名的断言,会将你认证为 admin。尝试在任何承载身份的字段中插入注释:NameID,以及用于账户映射的 email / username 属性。

通过 SAML 解析器利用 XXE

SP 会将攻击者提供的 XML 输入解析器。如果未禁用外部实体,ACS 端点就会成为 XXE 注入点。

<?xml version="1.0"?>
<!DOCTYPE samlp:Response [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response ...>...&xxe;...</samlp:Response>

使用带外 DTD(http://attacker/evil.dtd)进行盲文件读取,并对 SP 的内部网络发起 SSRF。完整的利用技术——参数实体、带外数据窃取、基于错误的信息泄露——请参阅 exploiting-xxe;SAML 方面的关键在于,断言是注入点,而 ACS 无需身份验证。

伪造证书和使用自签名证书重新签名

如果 SP 未固定 IdP 的证书——而是信任嵌入在 <ds:KeyInfo> 中的任意证书,或接受广泛 CA 证书包中的任何证书——你就可以移除真实签名,使用自己的密钥重新签名,并将自己的证书放入消息中。

# Generate a key/cert and re-sign a tampered assertion
openssl req -x509 -newkey rsa:2048 -keyout evil.key -out evil.crt -days 30 -nodes -subj "/CN=idp"
xmlsec1 --sign --privkey-pem evil.key,evil.crt \
        --id-attr:ID Assertion tampered.xml > forged.xml

SAML Raider 可自动完成此操作:“Send Certificate”会导入或生成证书,然后就地重新签名已编辑的消息。如果伪造的自签名断言被接受,说明 SP 信任的是消息中嵌入的密钥,而不是已固定的 IdP 证书——这就完全绕过了身份验证。

Recipient / Destination 混淆和 IdP 发起的重放

  • 未检查 Recipient / Destination。 如果 SP 忽略 SubjectConfirmationData 中的 Recipient 或响应中的 Destination,那么在一个 SP 捕获的断言就可以在另一个共享该 IdP 的 SP 上重放。
  • IdP 发起的重放。 IdP 发起的 SSO 没有可供绑定的 AuthnRequest,因此不存在 InResponseTo,而且通常也没有防重放状态。捕获有效的 IdP 发起 POST 并重新发送——在有效期内,它可能直接让你重新登录。日志、引荐来源或历史记录中泄露的断言都能成为可用凭据。
  • 跨租户重复使用令牌。 在多租户 SaaS 中,检查为租户 A 签发的断言是否会被租户 B 的 ACS 接受。

Golden SAML

这是最终目标,而非入门手段。如果你已经掌握 IdP 的私有令牌签名密钥(从 AD FS 服务器的证书存储区、Azure/Entra 联合信任或导出的 IdP 密钥库中窃取),就能为任意用户、任意角色伪造无限期有效且签名完美的断言——无需凭据、无需 MFA、无需与 IdP 交互,而且密码重置也无法阻止它。

# With the stolen signing key, mint an assertion for any identity
xmlsec1 --sign --privkey-pem tokensigning.key,tokensigning.crt \
        --id-attr:ID Assertion golden.xml > any-user.xml

获取密钥属于主机/租户入侵任务,而非 SAML 消息任务——这条路径(提取 AD FS 令牌签名证书、DKM 密钥或云联合密钥)请参阅 attacking-entra-id。只有在这里塑造伪造断言时才回到本节。

应当摒弃的自我安慰

  • “断言已签名,所以无法篡改。” 签名包装可以在保持签名有效的同时,让应用读取不同的元素。已签名不代表被信任的就是已签名的内容。
  • “XSW1 不起作用,所以 SP 是安全的。” XSW 有八种变体是有原因的。在得出结论之前,先运行 XSW1–XSW8 全部变体。
  • “它会验证签名——我检查过了。” 验证某个签名不等于验证你所使用的断言。而且它可能只在签名存在时才进行验证;移除签名后再测试。
  • “受众/接收方只是元数据。” 如果 SP 不强制执行 AudienceRestriction、Recipient 和 Destination,断言就能在不同 SP 和租户之间重放。
  • “注释那件事只是表面问题。” [email protected] 会以 admin 的身份通过身份验证。规范化不匹配会导致账户完全被接管。
  • “这是来自可信 IdP 的 XML,因此不用担心 XXE。” ACS 会先解析字节,再决定是否信任它们;而这些字节来自你的浏览器。它们并不可信。
  • “Golden SAML 需要私钥,所以不在范围内。” 伪造断言属于本节范围;请记录其影响,并将密钥提取的工作转到 attacking-entra-id——不要忽视其危害。

ATT&CK 覆盖范围

根据 secskills-core/ttp-index.json 生成——编辑该文件,然后运行 python3 scripts/sync_attack.py --write。在报告中引用 ID 前,请根据 当前 ATT&CK 版本重新核实。

凭据访问(TA0006)

  • T1606.002 SAML 令牌——另请参阅 attacking-entra-id

适用于以上任一项的检测内容:engineering-detections。主动搜寻:hunting-threats。入侵后响应:responding-to-incidents。

参考资料

  • attacking-oauth-oidc —— SSO 流程使用 OAuth 2.0 / OpenID Connect 时
  • attacking-jwt —— 令牌是已签名的 JWT,而非 XML 时
  • exploiting-xxe —— ACS 解析器为攻击目标时的完整 XXE 技术
  • attacking-entra-id —— 通过遭入侵的 AD FS 服务或租户实施 Golden SAML 攻击
  • testing-web-applications —— 相关的 Web 测试方法
  • reporting-security-findings —— 签名绕过和重放的严重性
  • SAML Raider(Burp 扩展)、Burp Suite、xmlsec1、SAMLtool(samltool.com)

评论

支持 Markdown