CVE-2025-29774/CVE-2025-29775: xml-crypto XML Signature Wrapping

CVE-2025-29774/CVE-2025-29775: xml-crypto XML Signature Wrapping

romi0x securitainment 2025-05-10 15:20

【翻译】[하루한줄] CVE-2025-29774, CVE-2025-29775 xml-crypto의 XML Signature Wrapping 취약점 

URL

https://workos.com/blog/samlstorm

Target

  • xml-crypto 库 (版本 <= 6.0.0)

Explain

该漏洞利用 XML 数字签名验证逻辑中的缺陷,可绕过 SAML 响应或基于 XML 签名的认证机制。该漏洞源于 xml-crypto
 库签名验证方式的结构性问题,分为 CVE-2025-29774 和 CVE-2025-29775 两个漏洞公开。

CVE-2025-29774
 是利用 “SignedInfo 节点重复” 的漏洞。在正常的已签名 XML 文档中,
 节点内应仅存在一个 
 节点。然而,xml-crypto
 的漏洞版本在存在多个 
 节点时,会对攻击者插入的伪造 
 节点进行签名验证,而不是验证正常的节点。这使得攻击者可以保留一个有效的 SignedInfo,同时在另一个节点中包含权限提升或用户篡改等恶意操作,从而绕过签名验证。在实际攻击示例中,攻击者会在 
 块中插入两个 
,并在其中一个包含伪造的 Digest 值,以实现认证绕过。

CVE-2025-29775
 是基于 DigestValue 操作的漏洞。该漏洞通过在 DigestValue 中插入 HTML 注释 (
) 的方式实现。正常的 DigestValue 应为 Base64 编码的纯数据,但 xml-crypto 的验证逻辑并未基于节点解析该值,而是基于字符串处理。因此,攻击者可以插入如下所示的注释和伪造值:

<DigestValue>
    <!--TBlYWE0ZWM4ODI1NjliYzE3NmViN2E1OTlkOGDhhNmI=-->
    c7RuVDYo83z2su5uk0Nla8DXcXvKYKgf7tZklJxL/LZ=
</DigestValue>

验证逻辑会忽略注释,仅验证实际的 DigestValue,因此会认为签名有效。然而,解析的应用程序会将注释和值结合起来处理,导致错误的数据。这使得攻击者能够巧妙地更改用户的身份信息或权限信息,同时绕过签名验证。

攻击者可以利用此漏洞进行认证绕过和权限提升攻击。这对所有基于 xml-crypto
 实现 SAML SSO 的服务都有广泛影响,特别是即使包含重要身份信息或权限信息的 XML 消息被篡改,仍然能够通过签名验证,这是一个严重的问题。

该漏洞已在 xml-crypto
 库的 6.0.1 版本中修复。所有 6.0.0 及以下版本均受影响。
1. SignedInfo 节点重复检测 (CVE-2025-29774 检测方法)

需要检查 SAML 响应或 XML 文档中 
 内是否存在两个或更多 
 节点。正常文档中必须只有一个。

<Signature>
    <SomeNode>
      <SignedInfo>
        <Reference URI="somefakereference">
          <DigestValue>forgeddigestvalue</DigestValue>
        </Reference>
      </SignedInfo>
    </SomeNode>
    <SignedInfo>
        <Reference URI="realsignedreference">
          <DigestValue>realdigestvalue</DigestValue>
        </Reference>
    </SignedInfo>
</Signature>

检测用的 JavaScript 代码如下:

const signedInfoNodes = xpath.select(".//*[local-name(.)='SignedInfo']", signatureNode);
if (signedInfoNodes.length > 1) {
  // Compromise detected
}
  1. DigestValue 内注释检测 (CVE-2025-29775 检测方法)

在正常的 XML 签名中,
 块内绝对不应存在 
 形式的注释。如果发现此类情况,应将其视为被篡改的消息。

<DigestValue>
    <!-- malicious comment -->
    validDigestValue==
</DigestValue>

检测用的 JavaScript 代码如下:

const digestValues = xpath.select("//*[local-name()='DigestValue'][count(node()) > 1]", decryptedDocument);
if (digestValues.length > 0) {
  // Compromise detected
}

参考文档 (Reference)

  1. xml-crypto 安全公告 GHSA-x3m8-899r-f7c3

  2. xml-crypto 安全公告 GHSA-9p8x-f768-wp2g