F-Secure Internet Gatekeeper 中的堆溢出漏洞
2020年2月3日 - 作者:Kevin Joensen
F-Secure Internet Gatekeeper 堆溢出漏洞详解
这篇博客文章阐述了我们发现的F-Secure Internet Gatekeeper应用程序中的一个漏洞。它展示了简单错误如何导致可被利用的未授权远程代码执行漏洞。
复现环境设置
所有测试应在CentOS虚拟机中复现,至少需要1个处理器和4GB RAM。
需要安装F-Secure Internet Gatekeeper。过去可以从https://www.f-secure.com/en/business/downloads/internet-gatekeeper下载。据我们所知,供应商不再提供易受攻击的版本。
原始受影响包的SHA256哈希值为: 1582aa7782f78fcf01fccfe0b59f0a26b4a972020f9da860c19c1076a79c8e26。
安装步骤:
(1) 如果使用x64版本的CentOS,执行 yum install glibc.i686
(2) 使用 rpm -I
现在你可以使用GHIDRA/IDA或你喜欢的反汇编器/反编译器开始逆向工程Internet Gatekeeper!
目标
正如F-Secure所描述,Internet Gatekeeper是"在企业网络网关级别提供高效且易于管理的保护解决方案"。
F-Secure Internet Gatekeeper包含一个运行在9012/tcp端口的管理面板。这可用于控制产品中所有可用的服务和规则(HTTP代理、IMAP代理等)。这个管理面板通过用C语言编写的fsikgwebui二进制文件在HTTP上提供服务。实际上,整个Web服务器都是用C/C++编写的;有一些对civetweb的引用,表明可能使用了定制版本的CivetWeb。
它用C/C++编写的事实引导我们寻找内存破坏漏洞,这在这种语言中通常很常见。
通过使用Fuzzotron(使用Radamsa作为底层引擎)对管理面板进行模糊测试,很快就发现了本文描述的问题。fuzzotron具有内置的TCP支持,便于模糊测试网络服务。作为种子,我们提取了一个有效的POST请求,用于更改管理面板上的语言。此请求可以由未经身份验证的用户执行,这使其成为良好的模糊测试种子。
在分析由radamsa变异的输入时,我们可以很快看到漏洞的根本原因围绕Content-length头。导致软件崩溃的生成测试具有以下头值:Content-Length: 21487483844。这表明由于错误的整数运算导致溢出。
通过gdb运行测试后,我们发现导致崩溃的代码位于fs_httpd_civetweb_callback_begin_request函数中。此方法负责处理传入连接,并根据使用的HTTP动词、路径或cookie将它们分派到相关函数。
为了演示问题,我们将向运行管理面板的9012端口发送POST请求。我们设置一个非常大的Content-Length头值。
|
|
应用程序将解析请求并执行fs_httpd_get_header函数以获取内容长度。随后,内容长度被传递给函数strtoul(字符串到无符号长整型)
以下伪代码提供了控制流的摘要:
|
|
strtoul函数中具体发生的情况可以通过阅读相应的手册页来理解。strtoul的返回值是一个无符号长整型,其最大可能值为2^32-1(在32位系统上)。
strtoul()函数返回转换结果,或者如果有前导减号,则返回转换结果的否定表示为无符号值,除非原始(非否定)值会溢出;在后一种情况下,strtoul()返回ULONG_MAX并将errno设置为ERANGE。strtoull()完全相同(用ULLONG_MAX代替ULONG_MAX)。
由于我们提供的内容长度对于无符号长整型来说太大,strtoul将返回ULONG_MAX值,在32位系统上对应于0xFFFFFFFF。
到目前为止一切顺利。现在出现了实际的错误。当fs_httpd_civetweb_callback_begin_request函数尝试发出malloc请求为我们的数据腾出空间时,它首先向content_length变量加1,然后调用malloc。
这可以在以下伪代码中看到:
|
|
这导致了一个问题,因为值0xFFFFFFFF + 1将导致整数溢出,结果为0x00000000。因此malloc调用将分配0字节的内存。
Malloc确实允许使用0字节参数调用。当调用malloc(0)时,将返回一个指向堆的有效指针,指向最小可能块大小为0x10字节的分配。具体内容也可以在手册页中阅读:
malloc()函数分配size字节并返回指向已分配内存的指针。内存未初始化。如果size为0,则malloc()返回NULL,或返回一个唯一的指针值,该值以后可以成功传递给free()。
如果我们进一步查看Internet Gatekeeper代码,可以看到对mg_read的调用。
|
|
在溢出期间,此代码将在堆上读取任意数量的数据 - 没有任何限制。对于利用来说,这是一个很好的原语,因为我们可以停止向HTTP流写入字节,软件将简单地关闭连接并继续。在这种情况下,我们可以完全控制要写入的字节数。
总之,我们可以利用大小为0x10的Malloc块和任意数据的溢出来覆盖现有的内存结构。以下概念验证证明了这一点。尽管非常原始,它通过翻转标志should_delete_file = true来利用堆上的现有结构,然后随后用我们要删除文件的完整路径喷洒堆。Internet Gatekeeper内部处理程序有一个decontruct_http方法,该方法查找此标志并删除文件。通过利用此漏洞,攻击者获得任意文件删除权限,这足以证明问题的严重性。
|
|
当前漏洞利用的可靠性约为总尝试次数的60-70%,并且我们的漏洞利用PoC依赖于先决条件中列出的特定机器。
获得RCE绝对应该是可能的,因为我们可以控制确切的块大小并在小块上覆盖任意多的数据。此外,应用程序使用多个线程,可以利用这些线程进入干净的堆区域并多次尝试利用。如果你有兴趣与我们合作,请将你的RCE PoC发送到info@doyensec.com ;)
此关键问题被跟踪为FSC-2019-3,并在F-Secure Internet Gatekeeper版本5.40 – 5.50 hotfix 8(2019-07-11)中修复。我们要感谢F-Secure的合作。
堆利用学习资源
漏洞利用演练
- Linux堆利用入门系列:Set you free() – 第1部分
- Linux堆利用入门系列:Set you free() – 第2部分
GLibC演练
- GLibC Malloc for Exploiters - YouTube
- 理解GLibC实现 - 第1部分
- 理解GLibC实现 - 第2部分
工具
- GEF - GDB的附加组件,协助漏洞利用。此外,它还有一些用于堆利用调试的有用命令
- Villoc - 堆的HTML可视化表示
其他相关文章
- !exploitable 第一集 - 破解IoT (2025年2月11日)
- 使用r2pickledec反转Pickles (2023年6月1日)
- Play Framework中的CSRF保护绕过 (2020年8月20日)
- LibreSSL和OSS-Fuzz (2020年4月8日)
- 不要克隆那个仓库:Visual Studio Code^2执行 (2020年3月16日)
- Electron-Updater中导致RCE的签名验证绕过 (2020年2月24日)
- Solo固件的安全分析 (2020年2月19日)
- 凝视聚光灯 (2017年11月15日)