4月12日的是看到 paloaltonetworks 有一个安全公告[1], CVE编号是 CVE-2024-3400, 漏洞是一个命令注入,影响的版本如下:
然后在复现的过程中发现 watchTowr Labs[2] 已经发了他们的分析, 那就顺着他们的分析学习下这洞吧, 这里提下我的复现版本为 10.2.9
环境搭建
由于漏洞公告[1]提到, 该漏洞的影响需要 PAN-OS 配置 GlobalProtect portal 或者 GlobalProtect gateway, 所以我们需要先完整的搭建下我们的环境。
简单说下配置的流程, 我这里的配置是参考 QWB S6 Final Pan 这个题目的环境配置的( 亏我还能找到这个题目的虚拟机), 另外提一句当时强网杯利用的 CVE-2021-3064 这个漏洞还是蛮有意思的。
首先,我的虚拟机有三个网卡,
网卡1是管理口, 网卡2准备用来做门户和网关的网段 ,我这里用的网段是 192.168.100.1/24 。 登陆到管理口的后台后,依次设置
NETWORK->接口
设置以太网接口, 接口类型设置为 3层, 设置 IPV4 的静态 IP
DEVICE->证书管理->证书
, 生成RootCert
再基于RootCert
派发一个gp_cer
DEVICE->证书管理-> SSL/TLS 服务配置文件
依据gp_cert
配置SSL_PROFILE
- 然后到
NETWORK->GlobalProtect->门户
配置门户, 中间可能少了一点东西, 这里贴一下我的配置项, 缺什么补什么就好了
NETWORK->GlobalProtect->网关
网关配置是也是差不多
然后现在在另外一台虚拟机里,也设置上同样的 192.168.100.1/24 网段的网卡, 就可以访问到门户了
由于没有所谓的设备证书, 此次漏洞能命令执行提到的 telemetry
功能是不可用状态
访问 https://192.168.1.101/ssl-vpn/hipreport.esp
就是 https://192.168.1.101/ssl-vpn/hipreport.esp
的返回
shell 和文件系统的获取直接用了当时 QWB时候 Larryxi[3] 大哥提供的方法
- patch vmem获取本地shell
sed -i "s/\/usr\/local\/bin\/cli/\/\/\/\/\/\/\/\/\/\/\/\/bin\/sh/g" PA1029-9aad9851.vmem
sed -i "s/admin:x:1001:1004/admin:x:0000:0000/g" PA1029-9aad9851.vmem
- 查看固件内容方式, 挂载 vmdk 就行
j1
2
3sudo modprobe nbd
sudo qemu-nbd -c /dev/nbd1 /mnt/hgfs/qwb-final/PA-disk1.vmdk
sudo mount /dev/nbd1p2 /mnt/panos/
这样就可以 admin
用户登陆之后是一个 root 权限的 shell , 之后调试之类的也可使用 ssh 登陆
漏洞分析
在[1] 文章就已经提到了漏洞的触发路径, 首先是 gpsvc
文件在处理 Cookie 字段的时候会有一个任意文件写, 其次是 telemetry
功能的定时任务 device_telemetry_send
会用 /usr/local/bin/dt_send
发送数据的时候会拼接文件名到命令中,造成命令注入。
我们依次简单分析下
gpsvc 任意文件写分析
通过 netstat
命令, 我们可以看到 gpsvc
监听在 20277 端口上,
在查看 /etc/nginx/sslvpn/localtion.conf
的配置文件中, 我们看到如下配置
可以看到 ssl-vpn 相关的部分接口为通过 nginx 代理转发到 20177 端口, 就是 gpsvc 程序里处理。
逆向分析
我们把程序拿出来分析, 坏消息是这个程序是 golang 编写的, 好像是有符号, 而且我们已经知道了漏洞大致位置, 可以通过直接找到 main__ptr_SessDiskStore_New
函数
我们在这个函数里可以看到一个通过 Cookie 里的值然后拼接文件名的操作,
比如我们在 146 行下一个断点, 然后使用如下 PoC 触发:
1 | curl -i -s -k -X $'POST' \ |
到达main__ptr_SessDiskStore_New
函数的backtrace如下:
1 | (gdb) bt |
此时可以看到 $rdi->array
存储了我们的 payload 的相关字符: session_/../../../tmp/hacked
, 我们单步走一步走到调用main_loadSessFile
函数的位置
(分析到这,我突然反应过来他是golang 是旧版本的 api 调用 , 搜了下字符串可以知道他的 golang 版本是 1.13.15)
1 | .rodata:0000000000C956F6 aGo11315 db 'go1.13.15' |
可以看到 /../
相关字符被path_filepath_Join
函数处理后已经被去除了,问题来了, 是在哪创建的的文件呢?
我们找到 syscall_Open
函数 , 对其进行引用查找, 找到一条这样的调用链
1 | main_loadSessFile->main_fileLock->syscall_Open |
而此时 main_loadSessFile
的参数就是我们想要创建的文件
open 的定义为 int open(const char *pathname, int flags, mode_t mode);
第二个参数是个 flags, 当值为 0x40 的时候为 O_CREAT
O_CREAT
定义位于 fcntl.h
文件中, 可以在 linux 的内核代码[4]中看到,
1 | #define O_ACCMODE 00000003 |
O_CREAT
的值通常是 0100,这是一个八进制表示的值, 等同于十进制的 64 ,十六进制的 0x40, 通过查找相关资料[5]
例如使用如下 payload 尝试创建 /etc/passwd
的时候
1 | curl -i -s -k -X $'POST' \ |
可以看到 open 是返回了 0
这个漏洞会创建一个任意路径、文件名可控的文件(不能覆盖文件)。那么攻击者是如何将这么一个漏洞再组合成一个命令执行的呢? 这就得提到 telemetry
功能了
telemetry 命令文件分析
根据官网 [5] 的介绍, 该功能是一个定时发送数据到远端的一个功能, 在环境搭建提到的该功能开启需要一个设备证书, 我目前的复现环境是不支持的。 只能分析分析功能了
在 /etc/cron.d
可以看到很多和 telemetry
相关的定时任务
其中 /usr/local/bin/dt_send
看起来是用来发送数据的
该程序由 python 编写, 可以看到简单判断了下功能是不是开启, 然后调用 check_and_send
函数
check_and_send
函数会接着调用 send_file_dirs_all
可以看到 send_file_dirs_all
函数会遍历 DEFAULT_DEVTELEM_OUTPUT_DIR
下的文件, 然后再调用 send_file_dir
而在 send_file_dir
函数中, 用 send_file
函数
在 send_file
函数中, 会将文件名拼接到 send_file_cmd
遍历中
接着调用 cmd_status = techsupport.dosys(send_file_cmd, None)
, 运行 dt_curl
命令, 该命令也是一个 python 程序,
dt_curl
里会调用 send_file
函数
在该函数中就拼接命令, 使用 pansys(curl_cmd, shell=True, timeout=250)
函数调用, 注意这里的 shell=True
这里最后调用到 /opt/plugins/2.0/python-lib/pan/pansys/pansys.py
文件中的 dosys
可以看到这里的shell
参数默认是 False 的 但是由于send_file
调用的是传递进来设置了成了 True, 因此可以命令注入 。
Diff Patch
从日志可以可以看到似乎加了检查 {"level":"error","task":"3-22","time":"2024-04-20T06:28:12.18264473-07:00","message":"ArgFilterCheck: authcookie input is invalid"}
刚好也是这个补丁加的样子, 从编译路径来看
1 | (gdb) bt |
思考
一个空文件创建到命令执行, 想必这个攻击者估计找这个功能了找了不少时间吧,此外该漏洞的利用目前需要开启telemetry
功能, 那么是否还有可以利用这个空文件创建的地方呢? 这么大的一个系统也许还有吧, 有时间可以在仔细看看