Palo Alto Global Protect 网关设备格式化字符串漏洞(CVE-2019-1579)

iso60001  1887天前

22.png

背景

在文章开始前,我想明确声明,我与Palo Alto Networks没有任何关联,以下所有图片都是合法的。

最近,我在红队的一次例行交流中,遇到了几个没有打补丁的Palo Alto防火墙设备。这些设备位于公网上,承担着网关的作用(配置为Global Protect gateway)。作为红队的一名新手,我经常被客户要求证明我所报告漏洞的可利用性,这也是获得漏洞赏金的要求之一(我个人认为这只是厂商在驱使免费劳动力,漏洞通过平台审核就应该被承认)。

DEVCORE团队成员Orange Tsai(@orange8361)和Meh Chang(@mehqq)最近发表的一篇博客文章引起了我对Palo Alto Global Protect gateway的注意。他们发现了一个格式化字符串漏洞(CVE-2019-1579),而Palo Alto在一年前(2018年6月)就悄悄地修补了这个漏洞,他们还提供了漏洞说明和一个通用POC。

虚拟设备与物理设备

根据那篇文章的说法,“利用起来很容易”,只要知道PLT(Procedure Linkage Table)和GOT(Global Offset Table)中的正确偏移量,并且假设堆栈在不同版本之间能一致对齐即可。然而,在现实中,我发现获得这些偏移量并区分出版本差异是很困难的。

Palo Alto目前正推广下一代防火墙部署,大致分为物理或虚拟两类。而本文中重点是虚拟实现,涉及AWS等云服务。那么,如何确定正在研究的目标是虚拟的还是物理的呢?根据我的经验,一个最简单的方法是基于IP地址来判断。通常,公司不会为虚拟实例设置反向DNS记录。如果某个IP/DNS属于一个主要的云服务商,那么它很可能是一个虚拟设备。

33.jpg

如果确定防火墙是AWS实例,则转到AWS marketplace,启动一个Palo Alto VM。首先需要注意的是,你只能使用8.0.x,8.1 x,9.0.x的最新版本。

44.jpg

不要担心,进入web管理界面后可以升级和降级固件,前提是拥有该设备的有效许可证。但是,如果你启动了9.0.x,会有一些细微差别,它只能降级到8.1.x。另一个非常重要的细节是必须选择一个“m4”实例,否则当你降级到8.x.x时,AWS实例将不可使用。而对于物理设备,可以在这里找到相关固件。

55.jpg

获得有效可证的难度和价格各不相同。如果你正在使用AWS防火墙软件包,则里面自带许可。如果是物理设备,则很复杂且昂贵。如果你从授权经销商购买新设备,则可以激活试用许可证。如果你通过Ebay之类的网站购买设备,请确保卖家将许可转让给你。

一旦设备启动并正常运行,你将需要在其中一个接口上安装一个Global Protect gateway。youtube上有几个视频介绍了一些安装步骤,基本上你只需要一步一步跟随完成就行。Palo Alto也提供了一些文档,如果遇到问题,可以作为参考。预计安装难点是为Global Protect gateway安装SSL证书,这里最简单的解决方法是生成一个自签名证书并导入。你可以在这里找到简单的说明。

如果你正在设置AWS实例,则需要更改网络接口上的密钥设置,否则Global Protect gateway将不可访问。跳转到AWS中用于Global Protect gateway的网络接口,右击并选择Change Source/Dest Check,将值更改为Disabled,如下所示。

66.jpg

利用

在以上设置全部完成后,当通过SSH连接到设备时,你会发现处于一个受限制的shell中,功能非常有限。

77.jpg

为了获得内存偏移量,我们需要访问sslmgr二进制文件,这很难在一个受限制的shell中实现。之前已有研究人员发现了应对方法,但似乎已被修复。如果其他方法有效,那么就可以开始攻击了。

但如果找不到这样的办法,我们该怎么办?事实证明,我们或许可以利用该设备的一些管理功能以及漏洞来实现目标。这个受限制的shell的特性之一是能够增加关键服务生成的日志的冗长性,它还能让我们实时查看每个服务的日志文件。考虑到这次讨论的漏洞是一个格式字符串漏洞,那我们是否可以将内存泄漏到日志中,然后再将其读取出来?让我们看看这个漏洞。

88.jpg

紧接着,就是我们想要利用的代码。今天一定是我们的幸运日。

99.jpg

是的,只要填充了这四个参数,就可以通过格式字符串操作符将内存从进程转储到日志。这意味着我们可以从内存中转储整个二进制文件,检索利用时所需的偏移量。在此之前,首先需要识别出每个参数的堆栈缓冲区偏移量。我开发了一个脚本(你可以从Github上获得),它将定位堆栈上的指定参数,并打印出相关的偏移量。

脚本输出如下所示。每个偏移量都指向我们控制的堆栈上的缓冲区。现在,我们可以选择一个并使用我们喜欢的内存地址去填充它,然后使用%s格式操作符读取该位置的内存。

100.jpg

通常情况下,我们必须解决一些问题才能获得正确的内存转储。因为某些坏字符会导致意外输出:\x00\x25\x26

因为sprintfstrlen会将空字节识别为字符串的末尾。一种解决方法是使用格式字符串指向一个已知索引的空字节,例如%10$c

此外\x25字符也破坏了转储,因为它表示字符%。我们可以使用两个\x25\x25轻松将其转义。

\x26字符则有点棘手。因为它是用于分割HTTP参数的标记。由于在已知索引的堆栈上不是普遍存在&,所以我们只使用%n将一些符号写入已知索引,然后每当遇到带\x26的地址时引用它。

综上所述,我修改了前面的脚本,将用户提供的地址写入堆栈,使用%s格式操作符对其进行处理,然后将该地址的数据输出到日志中。将这个逻辑封装在一个循环中,再配合我们对特殊字符的处理,就可让我们在任何可读位置转储大量内存。你可以在我们的Github上找到这个脚本的MIPS版本,执行它应该会得到如下输出。

110.jpg

现在,我们终于可以strlen GOT以及需要利用的系统PLT地址。那么,它们在哪里呢??如果没有sslmgr二进制文件,我们如何知道要转储哪些内存地址来获得二进制文件?要知道,64位地址空间是非常大的。

幸运的是,这个受限制的shell为我们提供了另一个中断方法。如果像sslmgr这样的关键服务崩溃,则可以使用scp导出堆栈跟踪,并将崩溃信息转储。我们在任意索引上抛出一些%n格式的操作符,就可以实现。

120.jpg

在这个过程中,我学到了一些关于IDA Pro的新知识。你可以使用它打开ELF内核转储。打开IDA中的分段视图,我们终于可以看到二进制文件在内存中的加载位置。在调试payload时,我们注意另一个有趣的细节,在MIPS物理设备上,ASLR似乎是禁用的,因为二进制文件和加载的库总是在相同的地址加载。

130.jpg

最后,让我们开始导出二进制文件,这样我们就可以得到偏移量。我们大约有0x40000个字节要转储,速度大约是4字节/秒。这可能要几天。有什么捷径呢?我们真正需要的是GOT和PLT中对strlen和system的偏移量。

不幸的是,即使我们确切的知道GOT和PLT是什么,其中也没能显示函数名。那么GDB或IDA Pro如何解析函数名呢?它们使用ELF头。我们应该也能够转储ELF头和二进制文件的一小部分来解析出位置。一两个小时后,我将内存转储文件加载Binary Ninja中。Binary Ninja在分析和处理不完整或损坏的数据的时候是很强的。

对ELF的研究表明,PT_DYNAMIC程序头将保存一个表到其他分区,这个分区记录了可执行二进制文件的相关信息,其中三个表对我们很重要,Symbol Table(dt_symtab-06)、String Table(dt_strtab-05)和Global Offset Table(dt_pltgot-03)。其中Symbol Table表将列出PLT和GOT分区中函数的正确顺序。它也向String Table提供偏移量,以正确标识每个函数名。

140.jpg

通过SYMBOL Table和STRING Table中的偏移量,我们可以正确地解析PLT和GOT中的函数名。我编写了一个脚本来解析symbol table的转储,输出了一个与PLT匹配的重新排序的string table。这也可以用Binary Ninja的api完成。随着symbol table与string table相匹配,我们现在可以用GOT来覆盖它,得到strlen和system需要的偏移量。现在我们有两个选择来转储GOT。我们可以使用前面提及崩溃方法,也可以使用脚本手动转储内存。

150.jpg

为了节省我一点时间,我决定使用崩溃方法。上面的列表显示了GOT中指向PLT(0x1001xxxx地址)的条目和几个已经解析的库函数。结合我们的string table,我们终于可以为strlen和system提取正确的偏移量,并得到最后的PoC。我们的PoC是针对基于MIPS的物理Palo Alto设备,但是脚本应该只需稍作调整就能通用。

注意

虽然sslmgr服务有一个监视器,可以在进程崩溃时重新启动进程,但如果在短时间内崩溃超过3次,则不会重新启动,此时需要手动启动。如果你要针对客户的生产设备进行测试,请记住这一点,否则可能造成极大损失。

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://www.securifera.com/blog/2019/09/10/preauth-rce-on-palo-alto-globalprotect-part-ii-cve-2019-1579/

最新评论

昵称
邮箱
提交评论