一、SAML协议介绍
SAML(Security Assertion Markup Language)是一种基于XML的开放式标准,用于在不同的安全域之间交换认证和授权数据。
1.SAML发展历史
SAML协议由结构化信息标准促进组织(OASIS)安全服务技术委员会在2002年提出,已经经历了1.0、1.1、2.0三个版本。目前国内外的主流云服务平台、SaaS应用以及一些常见软件系统,例如阿里云、AWS、Saleforce、Jira、Confluence、Sonarqube等,都支持通过SAML协议实现单点登录。
2.SAML相关概念
3.SAML Web SSO
在SAML Web SSO场景中,认证有以下几个流程:
二、SAML协议攻击面
SAML是一个基于XML的认证协议,由于XML数据格式灵活、处理复杂,导致实现过程非常容易造成逻辑漏洞,并且XML本身也存在XXE、XSLT等安全风险,这一攻击面也由SAML所继承。
1.XXE攻击
XXE(XML External Entity Injection)攻击是OWASP TOP10中的常客,其本身是XML的攻击面,但由于SAML基于XML,也就继承了这一攻击面。
XXE漏洞的主要原因是XML解析器在没有禁用外部实体( External Entity)的情况下,攻击者可以向被处理的XML文档中并且实体定义中可以包含一些控制服务器行为的指令。
XXE的常规攻击方式有以下两种:
本地文件包含(LFI)Payload
]>
&xxe;
服务端请求伪造(SSRF)Payload
]>
2.XSLT攻击
XSLT攻击指的是一种利用XSLT(Extensible Stylesheet Language Transformations)漏洞的攻击方式。XSLT是一种用于将XML文档转换为其他格式的语言,例如HTML或PDF。攻击者可以利用XSLT漏洞来执行恶意代码或获取敏感信息。
在SAML中造成XSLT的原因是SAML签名前使用了多个transform对签名内容进行一系列处理,每一个transform定义了数据处理算法,如
在w3c组织定义的transform算法中
Xslt payload
3.XSW攻击
XSW是一种基于XML文件格式变换的攻击手法,因为XML签名的验证和断言使用通常是在两个不同的函数进行处理,如果两个模块对同一个数据有不同的处理方式,那么就可以利用这种攻击来对Response进行伪造。
4.SAML重放
SAML重放攻击主要是由于实现中没有防止重放的安全机制如随机参数、过期时间等,攻击者在截获SP签发的断言后,可以利用截获的断言向SP进行验证,获取访问权限。
5.Golden SAML
Golden SAML是一种伪造SAML断言的权限维持攻击手法,攻击者首先通过攻陷Idp服务窃取Idp签名密钥,在得到签名密钥后即可对信任该Idp的服务签署任意用户的断言获取其访问权限。这种攻击手法与黄金票据较为类似。
三、SAML漏洞案例
1.XXE
在一些漏洞众测write-up中经常可以看到XXE漏洞案例,在下图中作者通过某云服务平台SAML配置后台,通过配置Idp元数据功能插入XXE payload造成本地文件泄露。
2.CVE-2022-47966
CVE-2022-47966影响Zoho ManageEngine系列多个产品,CVSS评分高达9.8,主要原因是这些产品都使用了xmlsec 1.4.1去验证SAML签名,而这一版本的xmlsec组件包含有多个漏洞。下面是SAML签名的示例。
SP在接收到用户传入的Response后首先会对断言的的签名进行验证,通常有以下几个步骤:
1)检查断言完整性,对断言进行格式转换(规范化、数字签名格式),计算hash摘要与DigestValue内容进行对比,如果结果不同说明签名被篡改。
2)利用Idp公钥解密SignatureValue,与DigestValue进行对比,如果结果不同说明断言不是由信任的Idp签发。
3)以上两个步骤同事满足时说明签名是合法的。
以上3个步骤中1和2的处理顺序是可以互换的,但是在步骤1中对断言进行转换会产生XSLT注入漏洞,如果按照这个顺序处理会造成未授权命令执行漏洞。
下图中xmlsec1.4.1对签名进行检查的逻辑,在[1]处首先检查了签名内容的完整性,也就是上述步骤1的内容,在[2]中根据签名算法验证了签名的合法性,这也就是漏洞在未授权情况下利用的核心原因。
3.CVE-2022-41912
CVE-2022-41912是crewjam/saml由go语言实现的saml库中存在的一个认证绕过的漏洞,这个漏洞是由于使用了两种不同方式处理Response导致的签名验证绕过。解析SAML响应的代码如下,首先在A代码部分利用golang原生的xml反序列化函数将SAML响应反序列化到Response结构中,在B代码又利用etree来将Response反序列化为Document对象。然后在C代码块将这两对象传入validateXMLResponse函数中。
跟进这个函数,在红框部分将responseEL变量传入validateSigend进行签名验证,通过后返回resp.Assertion,注意这里的responseEL和resp分别是上一步骤通过etree和go反序列化得到的结果。这里验证的是responseEL返回的却是resp的逻辑是这个漏洞的关键。
根据validateSigned函数,这里的处理逻辑是利用findChild函数从responseEL中找到Assertion,再从Assertion中找到Signature元素,两个元素不为空且Assertion合法性验证通过的话就通过验证。
回头再看一下最开始反序列化的地方利用go原生反序列化得到的Response结构定义如下,在这个结构中只有一个Assertion对象,如果处理的Response含有多个Assertion元素时,按照golang的处理,这里会取到最后一个Assertion。
再看一下findChild的实现,这里的逻辑是遍历所有子元素,如果命名空间和标签名匹配上就马上返回这个元素,所以在含有多个Assertion的情况下在validateSigned中得到的第一个Assertion。
作者给出的payload如下,SAML响应中包含两个Assertion其中第一个合法,第二个是伪造的Assertion。
最后处理的逻辑就是验证第一个Assertion,由于是合法的,可以通过验证,但是返回的是第二个也就是伪造的Assertion,如果通过验证的是一个低权限用户,那么就可以伪造一个高权限的用户Assertion来实现认证绕过和权限提升。
4.vcenter_saml_login
vcenter_saml_login是一个vCenter后利用工具,主要场景是拿到vCenter服务器root权限之后需要登录vCenter web控制台进行下一步攻击。
这个工具中也利用了SAML签名,我们可以结合SAML协议流程来分析一下这个工具的利用过程。首先看参数,target指定vCenter服务器的ip,path参数指定的是data.mdb文件,data.mdb是vCenter中用于存储ldap数据的文件,而vCenter用于SAML签名的私钥就存储在ldap数据库中。
重点有以下几个步骤:
首先是使用get_idp_cert获取ipd签名密钥,这里利用了data.mdb文件的特征字符定位到idp私钥的偏移,通过私钥的固定数据结构获取长度,再利用其读取取到私钥内容。
然后是伪造管理用户Assertion,这个工具通过编写一个SAML响应模板,并且响应中的Assertion部分填写的都是管理员的属性,在ID、签发时间、域名等动态参数做了标记,然后进行填充,就得到了一个伪造的SAML响应。
最后最关键的部分就是对伪造的SAML响应进行签名,这里利用的是第三方库,通过之前获取的Idp私钥对伪造的SAML响应签名,参数中的cert1和cert2是可选项。
最后生成的SAML响应就可以发送到断言消费接口(ACS)进行认证。