低于 22.7R2.1 和 22.7R2.2 的 Ivanti Connect Secure 版本以及低于 22.7R1.1 的 Ivanti Policy Secure 版本包含 CRLF 注入漏洞,经过身份验证的管理员可利用该漏洞以root特权执行任意代码。
虽然该漏洞需要身份验证,但过去的漏洞(如 CVE-2020-8260 和 CVE-2020-8243)也需要身份验证,已被广泛利用。但是,Ivanti 表示,在公开披露之前,他们并不知道此漏洞被广泛利用。
受影响的版本
22.7R2.1 之前的 ICS 版本。
漏洞详情
CSR 生成
Ivanti Connect Secure 为管理用户提供了通过 URL 处的管理 Web 应用程序生成新证书的功能:/dana-admin/cert/admincert.cgi
以下屏幕截图显示了该页面:admincert.cgi
管理员证书生成页面
单击“New CSR”选项时,系统会提示用户填写一些详细信息,这些详细信息将用于通过 CGI 脚本生成 CSR,网址为/dana-admin/cert/admincertnewcsr.cgi
新证书签名申请表
此表单生成的请求如下所示:
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 编写的 的源代码,我们可以看到 main 子例程从请求中获取这些值。admincertnewcsr.cgi
POST
根据正则表达式验证 The ,但其他值似乎没有验证检查:commonName
公用名验证
这些用户控制的值将从 添加到新对象中:。这是一个 Perl 模块,可以在 中找到。此模块包含 Swig 包装器,这些包装器调用以下代码:DSCert::NewCSR()
/home/perl/DSCert.pm
DSCert.so
DSCert::NewCSR
DSCert.so
从 中导入函数 :DSCert::NewCSR::NewCSR
libdsplibs.so
NewCSR 函数
在 中创建 CSR 对象后,它会调用admincertnewcsr.cgi
DSCert::Admin::addCSR
addCSR 函数
由于我们知道这是由 导出的,因此我们可以去 IDA 中反编译代码,看看 CSR 是如何生成的。libdsplibs.so
此函数中对某些参数(例如国家/地区代码)进行了一些额外的验证:
国家/地区代码的验证
但是,许多参数在未过滤的情况下传递,并写入 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 文档中所述,配置中可以传递各种字段。但是,攻击者感兴趣的是 engine 选项,它允许用户指定要使用的任意 “engine”。如此处所述,Engine API 提供了一个用于“添加加密原语的替代实现”的接口,此后在 OpenSSL 3.0 中被 Provider API 取代。
从攻击者的角度来看,此功能实质上允许我们提供指向外部库的路径,OpenSSL 将尝试从中加载指定的引擎。如果攻击者可以将此选项注入配置文件,则他们可以在加载引擎时获得任意代码执行。
CRLF 注射
如前所述,在将用户输入传递到配置文件之前,只对用户输入进行有限的验证。因此,攻击者可以在其中一个参数中注入 CRLF 字符,以将自己的部分添加到配置文件中,并指定任意引擎路径。POST
为了确认 CRLF 注射是可能的,我们可以做一个简单的测试。首先,我们发出一个请求,注入到参数中,在值后面加上一个 CRLF 序列,然后是值 .如果此操作成功,并且证书不包含在局部区域,则表明 CRLF 注入正在运行,并且该值将被忽略,因为它被解释为空部分:localityName
[foo]
[foo]
[foo]
CRLF 注射测试
正如所怀疑的那样,这是成功的,并且 locality 显示该值被忽略了。
CSR 详细信息中显示的 Locality 值
接下来,我们可以尝试注入一个新的 engine 部分,并且应该会引发错误,因为我们将传递一个指向不存在的 engine 库的路径。
如下所示,这会导致错误,因为该文件在磁盘上不存在:/tmp/test.so
CSR 生成失败
这确认了服务器容易受到 CRLF 注入的攻击。
概念验证
为了确认是否可以利用此问题来获得远程代码执行,我们需要创建一个 OpenSSL“引擎”有效负载(它只是一个共享对象文件)。
Ivanti Connect Secure 设备基于 Centos 6.4,该版本使用相当旧的内核和版本。我们使用 x86 Docker 镜像编译了测试有效负载。glibc
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
但是,我们首先需要克服一个问题。该选项必须引用磁盘上的共享对象文件。这意味着我们需要找到一种方法将文件放到目标服务器上,以便可以在 OpenSSL 配置中引用它。dynamic_path
有趣的是,OpenSSL 似乎并不介意:
-
为 下引用的文件分配了哪些权限。它不需要是可执行的。
dynamic_path
-
文件的扩展名。它不需要以 .
.so
Ivanti Connect Secure 设备包括一项名为“客户端日志上传”的功能,该功能允许 VPN 客户端和/或 Java 小程序的用户上传客户端日志以进行诊断。
当用户上传客户端日志时,这些日志将存储在文件夹 中,文件名包含时间戳并以 结尾,例如:。这些文件通过 CGI 脚本上传。/home/runtime/uploadlog/
.zip
log-20240115-035029.zip
/dana/uploadlog/uploadlog.cgi
此 CGI 不会验证客户端日志内容是否有效,也不会验证文件本身是否为 ZIP 文件。
ZIP 文件处理
以下屏幕截图显示了用于上传日志文件的请求:
上传日志 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 负载的请求。如下面的屏幕截图所示,这会导致成功利用,并建立在用户下运行的反向 shell:POST
root
反向 Shell - 以 root 用户身份运行
原文始发于微信公众号(合规渗透):Ivanti Connect Secure 通过 OpenSSL CRLF 注入的RCE CVE-2024-37404
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论