概括
Ivanti Connect Secure 22.7R2.1 和 22.7R2.2 之前的版本以及 Ivanti Policy Secure 22.7R1.1 之前的版本包含 CRLF 注入漏洞,经过身份验证的管理员可以利用该漏洞以root特权执行任意代码。
描述
攻击者可以通过利用以前的漏洞或凭证泄露获得对 Web 应用程序的管理访问权限,然后利用特权在底层系统上执行任意代码root。
影响
root该漏洞允许经过身份验证的管理员以底层系统的权限执行任意代码。
虽然该漏洞需要身份验证,但过去的漏洞(例如CVE-2020-8260和CVE-2020-8243)也需要身份验证,并已被野外利用。不过,Ivanti 表示,在公开披露之前,他们并不知道该漏洞已被野外利用。
缓解步骤
更新到 ICS 版本 22.7R2.1、22.7R2.2 或 Ivanti Policy Secure 22.7R1.1。
遵循 Ivanti 发布的缓解指南,确保管理界面不暴露给界面,从而限制攻击者利用本公告中所述漏洞的机会。
受影响的版本
22.7R2.1 之前的 ICS 版本。
时间线
-
2024-04-05:向 Ivanti 报告漏洞。
-
2024-04-08:收到 Ivanti 的确认。
-
2024-07-04:90 天披露期限已过。
-
2024-07-09:向 Ivanti 发送后续信息,请求在截止日期后更新状态。
-
2024-07-10:Ivanti 确认问题重现,并表示已开发出补丁,预计发布时间为 2024 年 7 月下旬。保留 CVE-2024-37404。
-
2024-09-03:向 Ivanti 发送跟进信息,询问当前状态。
-
2024-09-04:Ivanti 建议计划在 2024 年 9 月 6 日星期五之前提供更新。
-
2024-09-10:向 Ivanti 发送后续信息,告知我们计划在 2024 年 9 月 16 日星期一之前发布。
-
2024-09-11:Ivanti 回复称该修复实际上已包含在 ICS 22.7R2.1 中。
-
2024-10-04:与 Ivanti 约定的协调披露日期为 2024-10-08。
-
2024-10-08:Ivanti 公告发布。
-
2024-10-08:AmberWolf 公告发布。
参考
-
https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-Connect-Secure-and-Policy-Secure-CVE-2024-37404
-
https://www.ivanti.com/blog/october-2024-security-update
漏洞详细信息
CSR 生成
Ivanti Connect Secure 为管理用户提供了通过以下 URL 的管理 Web 应用程序生成新证书的功能:/dana-admin/cert/admincert.cgi
以下屏幕截图显示了该admincert.cgi页面:
管理员证书生成页面
当点击“新 CSR”选项时,系统会提示用户填写一些详细信息,这些信息将用于通过以下 CGI 脚本生成 CSR:/dana-admin/cert/admincertnewcsr.cgi
新证书签名申请表
该表单生成的请求POST如下所示:
POST /dana-admin/cert/admincertnewcsr.cgi HTTP/1.1
Host: 192.168.2.92
Cookie: DSSignInURL=/admin; SUPPORTCHROMEOS=1; PHC_DISABLED=1; DSBrowserID=f5afd4b930af818747c03bc6f2adaf59; id=state_16f05e4e8ed9a95921f9e5561b63b977; DSSIGNIN=url_admin; DSPERSISTMSG=; DSDID=00064f3b9acd709a; DSFirstAccess=1705398262; DSLastAccess=1705398282; DSLaunchURL=2F64616E612D61646D696E2F636572742F61646D696E636572742E636769; DSID=4b2c0f96862dc17c23622ef26a7a6db8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 594
Origin: https://192.168.2.92
Referer: https://192.168.2.92/dana-admin/cert/admincertnewcsr.cgideletecsr=&selectedCSRIds=&xsauth=4e2fea1b8e12585a4744fc72820de0cc
Connection: close
xsauth=4e2fea1b8e12585a4744fc72820de0cc&commonName=vpn.pcs.local&organizationName=Example+Corp&organizationalUnitName=IT+Group&localityName=SomeCity&stateOrProvinceName=California&countryName=US&emailAddress=test%40example.com&keytype=RSA&keylength=1024&eccurve=prime256v1&random=aaaaaaaaaaaaaaaaaaaa&newcsr=yes&certType=device&btnCreateCSR=Create+CSR
查看用 Perl 编写的源代码admincertnewcsr.cgi,我们可以看到主子程序从POST请求中获取这些值。
已commonName根据正则表达式进行了验证,但其他值似乎没有经过验证检查:
通用名称验证
这些用户控制的值被添加到一个新对象中:DSCert::NewCSR()。这是一个 Perl 模块,可以在 找到/home/perl/DSCert.pm。该模块包含 Swig 包装器,它调用 中的本机代码DSCert.so:
DSCert::新CSR
DSCert.soDSCert::NewCSR::NewCSR从以下位置导入函数libdsplibs.so:
新的CSR 功能
一旦在中创建了 CSR 对象admincertnewcsr.cgi,它就会调用DSCert::Admin::addCSR
addCSR 函数
因为我们知道这是由导出的libdsplibs.so,所以我们可以用 IDA 反编译代码来查看 CSR 是如何生成的。
此函数对某些参数进行了一些额外的验证,例如国家代码:
国家代码验证
然而,许多参数未经过滤就被传递,并被写入 CSR 配置文件中/home/runtime/tmp/csrconf.<pid>
CSR 配置文件
然后将此 CSR 配置传递给DSCert::runOpenssl,执行以下命令:
openssl req config /home/runtime/tmp/csrconf.<pid> -new -utf8 -out /home/runtime/tmp/csr.<pid>
DSCert::runOpenssl
根据OpenSSL 文档中的记录,配置中可以传递各种字段。但是,攻击者感兴趣的是引擎选项,它允许用户指定要使用的任意“引擎”。如此处所述,引擎 API 提供了一个用于“添加加密原语的替代实现”的接口,并且已在 OpenSSL 3.0 中被提供程序 API 取代。
从攻击者的角度来看,此功能本质上允许我们提供外部库的路径,OpenSSL 将尝试从该路径加载指定的引擎。如果攻击者可以将此选项注入配置文件,那么他们可以在加载引擎时获得任意代码执行。
CRLF 注入
如前所述,在将用户输入传递到配置文件之前,仅对其进行了有限的验证。因此,攻击者可以在其中一个参数中注入 CRLF 字符,POST以将自己的部分添加到配置文件中,从而指定任意引擎路径。
为了确认 CRLF 注入是可行的,我们可以做一个简单的测试。首先,我们发出一个请求,将 CRLF 序列注入localityName参数,在值后面加上 CRLF 序列,然后是值[foo]。如果成功,并且证书不包含[foo]在本地,那么这是一个好兆头,表明 CRLF 注入正在起作用,并且该[foo]值被忽略,因为它被解释为一个空部分:
CRLF 注入测试
正如所怀疑的那样,这是成功的,并且局部性显示该[foo]值被忽略了。
CSR 详细信息中显示的地点值
接下来,我们可以尝试注入一个新的引擎部分,并且应该会出现错误,因为我们将传递一个不存在的引擎库的路径。
如下所示,这会导致错误,因为该/tmp/test.so文件在磁盘上不存在:
CSR 生成失败
这证实服务器容易受到 CRLF 注入的攻击。
概念验证
为了确认是否可以利用此问题来获得远程代码执行,我们需要创建一个 OpenSSL“引擎”有效负载(它只是一个共享对象文件)。
Ivanti Connect Secure 设备基于 Centos 6.4,它使用的内核和glibc版本相当老旧。我们使用 x86 Docker 镜像编译了测试负载ubuntu:xenial。
再次查看我们的 PoC 请求,我们将注入一个带有虚假引擎路径的 CRLF 序列,如下所示:
[default]
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
foo = foo_section
[foo_section]
engine_id = foo
dynamic_path = /tmp/test.so
init = 0
但是,我们首先需要克服一个问题。该dynamic_path选项必须引用磁盘上的共享对象文件。这意味着我们需要找到一种方法将文件放到目标服务器上,以便可以在 OpenSSL 配置中引用它。
有趣的是,OpenSSL 似乎并不介意:
-
为 下引用的文件分配了哪些权限dynamic_path。它不需要是可执行的。
-
文件的扩展名。它不需要以结尾.so。
Ivanti Connect Secure 设备包含一项名为“客户端日志上传”的功能,允许 VPN 客户端和/或 Java Applet 的用户上传客户端日志以用于诊断目的。
当用户上传客户端日志时,这些日志将存储在文件夹中/home/runtime/uploadlog/,文件名包含时间戳并以 结尾.zip,例如:log-20240115-035029.zip。这些文件是通过/dana/uploadlog/uploadlog.cgiCGI 脚本上传的。
该 CGI 不会验证客户端日志内容是否有效,也不会验证文件本身是否是 ZIP 文件。
ZIP 文件处理
以下屏幕截图显示了POST用于上传日志文件的请求:
上传日志 POST 请求
然后,生成的.zip文件名会显示在响应中:
ZIP 文件上传成功
因此,为了将我们的有效载荷发送到服务器上已知的本地路径,我们只需通过上传虚假的客户端日志即可uploadlog.cgi。然后我们可以查找文件名并推断路径。然后可以在我们的注入配置中引用它,例如:
..
[foo_section]
engine_id = foo
dynamic_path = /home/runtime/uploadlog/log-20240115-035029.zip
init = 0
注意:必须先启用客户端日志,并使用低权限用户帐户上传日志。但是,假设攻击者拥有 Web 应用程序的管理权限,则攻击者可以直接满足这两个先决条件(即,通过启用客户端日志上传和/或根据需要添加本地低权限用户)。客户端日志可以在以下位置启用:Users -> User Roles -> Users (Role) -> General -> Session Options -> Enable Upload
现在我们可以发出包含 CRLF 和 OpenSSL 有效负载的请求。如下面的屏幕截图所示,这将导致成功利用,并建立在用户POST下运行的反向 shell :root
反向 Shell-以 root 用户身份运行
原文始发于微信公众号(Ots安全):刚刚发布了 CVE-2024-37404 通报,一个有趣的 CRLF ,导致 RCE!
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论