draytek漏洞分析

分析复现一下几个draytek的漏洞

1.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.

我这里选取Vigor2960 1.5.0版本的固件和1.5.1版本的固件作为对比。
首先提取固件:

固件是ubi类型的,需要使用ubi_reader这个工具进行提取,提取出来之后就是一个完整的文件系统。

lighttpd是一个轻量级的web服务器,一般会有cgi文件作为支持,在./etc/lighttpd/lighttpd.conf中可以看到服务器的各个配置项,在分析固件之前可以先查看一下服务器的配置文件,这样有助于我们确定分析目标。
根据漏洞通告,问题出现在cgi-bin目录下的mainfunction.cgi程序。
那么我们就来分析这个文件,IDA打开,看到main函数:

在33行中获取到PATH_INFO这个环境变量,这个环境变量表示紧接在CGI程序名之后的其他路径信息,它常常作为CGI程序的参数出现。比如:http://192.168.0.1:80/cgi-bin/mainfunction.cgi/webrestore,
那么PATH_INFO=/webrestore.
一直看到最下面:

除了通过PATH_INFO来确定要访问的路径,main函数还通过action参数来确定要执行的动作,跟进sub_B44C函数中
在0x4240c地址处有一张函数表:

遍历函数表名,并且和用户传入的action的值进行比较来确定要执行的函数。
main函数的逻辑大概理清楚了,接下来开始分析漏洞。
漏洞点在登录时的keyPath参数中,通过搜索字符串定位到函数,并且这个函数位于上面的函数表中,函数名为login:

这也是为什么这个漏洞能够导致未认证的命令注入,因为是发生在登录过程中的命令注入。


首先是获取keypath的值,然后进行对这个值进行check,check函数如下:

过滤了常用的`;|>$(
空格等命令拼接字符,看起来过滤的很严格,但是问题不大,依然可以绕过
在unix上可以通过如下字符来执行多条命令:

%0a
%0d 
;
&
|
$(shell_command)
`shell_command`
{shell_command,}

;&|被过滤了,可以考虑使用%0a来绕过,而且$(的检测也不对,这里是先检测当前字符是否为$,并且下一个字符得为(才会发生替换,目的是为了检测$(shellcommand)这种类型的命令执行,但并没有过滤单独的$,这样子的话空格就可以使用${IFS}来绕过。
check之后,通过snprintf函数将路径拼接在一起,类似于这样:

/tmp/rsa/private_key_keypath

后面接着再使用一个snprintf函数来将命令拼接:

openssl rsautl -inkey '/tmp/rsa/private_key_keypath' -decrypt -in /tmp/rsa/binary_login

之后将这条命令作为参数传递给run_command函数(这里我自己重名了函数),run_command如下:

使用popen函数执行这条命令,由此便造成了未授权的命令执行。
分析完原理,来实际操作一下,以vigor2960为例:

随便输入用户名和密码,然后抓包:

可以看到以POST方式访问/cgi-bin/mainfunction.cgi,传入的action=login,要执行的动作为login,按照上面分析的,我们修改keypatch的值为:

执行效果如下:

成功地执行了ls。
再换一个需要空格的命令:

执行效果如下:

注意,keypatch的值前面加上'的作用是为了闭合命令中的单引号,因为在单引号包围中的命令是不会执行的。
实际上如果固件版本小于1.4.2.1,在rtick参数中也存在命令注入,这里使用1.4.1版本的固件来说明。
还是在login函数中:

这里会取rtick作为时间戳来生成验证码。
查找rtick或者formcaptcha这两个字符串的交叉引用可以定位到验证码的生成函数:


可以看到这个函数里面直接将rtick的值作为验证码名,然后调用system函数执行,因此只需要修改rtick就可以达成未认证命令执行。
实际操作这一块就跳过了,感兴趣的可以自己尝试。
下面来和1.5.1的版本进行比较,直接定位到login函数:

除了有过滤函数还有一个判断,判断字符是否为十六进制字符,而且check函数也完善了:

再看到rtick那边:

将rtick的值限制在数字之内防止命令注入。

2.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.

在1.5.1版本下,当访问cgi-bin/mainfunction.cgi/cvmcfgupload这个路径时,如果content type为text/x-python-script,则在filename中存在命令注入。
知道了漏洞所在,直接定位过去:

看路径名猜测这个是一个用来上传文件的页面。
getenv("QUERY_STRING"),如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号'?'分隔。
首先获取QUERY_STRING的值,然后判断是否存在session=字符串,如果不存在的话就进入到sub_13450函数中,跟进去看看:

看到了一个system的执行点,但该怎么利用,漏洞通告中的filename并未在这里出现,出现filename的函数又和/cvmcfgupload路径不对应。
结合已有POC继续分析:

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--

/cgi-bin/mainfunction.cgi/cvmcfgupload?1=2
使得getenv("QUERY_STRING")能够获取到值,顺利进入到sub_13450函数;接着看到Content-Type=multipart/form-data; boundary=----WebKitFormBoundary,以及body部分的Content-Disposition等属性,这几个需要说明一下。
这篇文章中介绍了multipart/form-data,在往服务器发送表单数据之前需要对数据进行编码,multipart/form-data的编码规则为不做编码,发送二进制数据。对于multipart/form-data的编码规则有以下规范特征:1.必须以POST方式发送数据;2.Content-Type格式为multipart/form-data; boundary=${boundary}。其中的boundary是长度为16的随机base64字符,浏览器会自动创建,类似下面这样:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary222BPd3etU0TLTOv

不过在这个漏洞利用中,WebKitFormBoundary是我们手动添加的,自然也没必要添加后面的boundary。
然后,这个boundary=----WebKitFormBoundary222BPd3etU0TLTOv
作为数据的起始符、分隔符,终结标记符相比于起始符和分隔符多了--。
数据内容主要包括:Content-Disposition、Content-Type、数据内容等;其中数据内容前面有\n\r标记的空行;Content-Disposition是必选项,其它都是可选项;Content-Disposition 包含了 type 和 一个名字为 name 的 parameter,type 是 form-data,name 参数的值则为表单控件(username)的名字,如果是文件,那么还有一个 filename 参数,值就是文件名。
了解了这些前置知识后再看POC就明白漏洞通告中的filename在哪了,就是我们上传的文件名。
我们看到文件名:

filename="t';id;echo '1_"

双引号之内的就是文件名,t';id;echo '1_,熟悉的单引号,说明了filename会被写到''之中,注意到filename最后还有一个_,经测试之后,发现去掉_的话命令就无法执行成功,说明需要_来起一个引导作用。
根据以上分析,最终确定了漏洞的发生点在上方所给截图的system调用中,接下来继续分析sub_13450函数
先看三个函数:

NAME
cgiGetFiles - Returns a list of CGI file variables
char **cgiGetFiles (s_cgi *parms);

DESCRIPTION
This routine returns a NULL terminated array of names of CGI file variables that are available.

RETURN VALUE
On success a NULL terminated array of strings is returned. The last element is set to NULL. If an error occurred or if no files variables are available NULL is returned.

cgiGetFiles函数返回值为一个数组指针,最后一个元素会被设置为NULL
NAME
cgiGetFile - Return information of a CGI file variable
s_file *cgiGetFile (s_cgi *parms, const char *name);

DESCRIPTION
This routine returns a pointer to a datastructure associated with the value of a CGI file variable. The pointer must not be freed.
The s_file structure is declared as follows:
typedef struct file_s {
    char   *name,
           *type,
           *filename,
           *tmpfile;
} s_file;

cgiGetFile函数返回值为s_file类型的指针
NAME
cgiEscape - HTML escape certain characters in a string
char *cgiEscape (char *string);

DESCRIPTION
This function returns a pointer to a sanitised string. It converts <, & and > into HTML entities so that the result can be displayed without any danger of cross-site scripting in a browser. The result may be passed to free(3) after use. This routine is meant to be called before any user provided strings are returned to the browser.

RETURN VALUE
cgiEscape() returns a pointer to the sanitised string or NULL in case of error.

cgiEscape函数就是防止xss攻击,将<, &和>转换成html实体,返回一个字符串指针

首先先用cgiGetFiles获得一个文件数组指针,然后进入一个循环,使用cgiGetFile获取s_file类型的指针


接着使用cgiEscape将filename进行html转义(filename位于sfile结构体中的第三个,在32位机器下,char*类型的长度为4字节,因此+8就是filename的位置),再从中寻找\,如果可以找到,就进入if代码块,之后就是将html转义之后的filename和/data/%s/%s/拼接,最后再和mkdir -p命令拼接,所以最终形成的命令就是如下所示:

mkdir -p /data/cvm/files/'<filename>'

漏洞分析完毕,来实际测试一下:

另外,在测试中发现传输数据的content-type不是必要的:

这个漏洞也是一个未认证的命令执行。
最后我们再看到1.5.1.2版本的固件是如何修复这个漏洞的:

简单粗暴,直接过滤filename的值。

3.CVE-2020-19664
漏洞通告:

DrayTek Vigor2960 1.5.1 allows remote command execution via shell metacharacters in a toLogin2FA action to mainfunction.cgi.

根据描述,漏洞发生在toLogin2FA 动作中,通过字符串定位到对应函数:

首先获取环境变量,HTTP_COOKIE、REMOTE_ADDR、HTTP_HOST,接着以HTTP_COOKIE作为参数传入sub_12864函数,跟进查看:

如果参数1即HTTP_COOKIE的值存在的话就进入if代码块,假如我们是未认证用户,那么HTTP_COOKIE自然没有,直接返回-10。
然后将sub_12864函数的返回值,也就是-10拷贝到dest中,接着将dest和HTTP_HOST作为参数一并传入sub_273B0函数,跟进查看:

将a2,a3和/sbin/auth_check.sh Interface拼接,其中a2为-10,a3为HTTP_HOST的值,然后将拼接完后的命令传入run_command函数,实现命令执行。

但遗憾的是按照这个思路我无法实现命令执行,可能是思路不对。为了弄清楚到底是哪里出了问题,我选择对比固件查看不同点。
目前最新固件版本为1.5.1.2,所以我使用1.5.1.1和1.5.1.2的固件进行对比,查看哪里进行了修复
由于bindiff不支持高版本IDA,所以我使用diaphora这个IDA插件来进行比较,首先用IDA打开1.5.1.1版本的manfunction.cgi
在IDA中选择File->Script file,然后选择diaphora.py,会弹出一个框:

然后点击确定,会生成一个sqlite数据库文件
再用IDA打开1.5.1.2版本的manfunction.cgi,打开diaphora.py

在diff against那里选择1.5.1.1版本的sqlite数据文件
最终会生成这样的页面:

Ratio表示两个函数的相似度,我们从中找到toLogin2FA 动作要执行的函数:

diff pseudo-code可以查看伪代码对比:

对比很清晰,左边的是1.5.1.2的伪代码,右边的是1.5.1.1的,新版本对HTTP_COOKIE处理函数进行了修改:

如果HTTP_COOKIE的值为空,那么经过处理后传入run_command的第二个则为NULL。
但我依然不清楚该如何利用该漏洞,很可惜。
根据这个GitHub仓库描述的,我的大致方向应该是没问题的,如果有知道如何利用的师傅希望能告知,这里主要是说明一下我的一个思路。

4.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.

在1.5.1.1版本中,formuserphonenumber参数存在栈溢出
通过字符串定位到函数:

获取到formuserphonenumber的值,然后直接拷贝到栈上:

确定了v31的大小之后就可以溢出了,并且经测试之后,vigor2960是没有开启ASLR和NX的,所以可以直接ret2shellcode,动态调试确定下来栈地址之后就能直接利用了。
这个函数在authusersms动作中,利用起来比较麻烦,需要认证,可以看看这篇文章,在这里就不进行利用了。

5.总结
draytek其实爆出来的漏洞不止这些,不过大都是认证后的,最危险的还是CVE-2020-8515和CVE-2020-15415这两个不需要认证的漏洞。
公网上draytek的数量还是很大的,仅仅只是vigor2960就存在两万多条IP。

6.参考链接
https://nosec.org/home/detail/4631.html
https://github.com/CLP-team/Vigor-Commond-Injection
https://blog.netlab.360.com/two-zero-days-are-targeting-draytek-broadband-cpe-devices/
https://baike.baidu.com/item/getenv/935515
https://manpages.debian.org/jessie/cgilib/cgiGetFiles.3.en.html
https://manpages.debian.org/jessie/cgilib/cgiGetFile.3.en.html
https://manpages.debian.org/unstable/cgilib/cgiEscape.3.en.html

本文来源于: https://xz.aliyun.com/t/9317

相关推荐

记某CMS漏洞getshell

记极致CMS漏洞getshell 今天下午比较空闲,就去搜索一些cms,突然对极致CMS感兴趣,而网上已经有一些文章对它进行分析利用,sql注入,xss,后台修改上传后缀名前台getshell等等。 于是就引起了我的兴趣想去测试一下。 信息

CVE-2016-0165 Win32k漏洞分析笔记

CVE-2016-0165 是一个典型的整数上溢漏洞,由于在 win32k!RGNMEMOBJ::vCreate 函数中分配内核池内存块前没有对计算的内存块大小参数进行溢出校验,导致函数有分配到远小于所期望大小的内存块的可能性。而函数本身并

记一次无意的渗透测试

由于最近再写一个web漏洞扫描器,准备在fofa上找网站测试的时候,无意间看到了个标题,xx系统, 点进去一看,好家伙,这不就是我很收悉的,那个xxcms嘛(具体的忘记了) 正好通过这个网站的cms漏洞,测试下我的扫描器,结果,好家伙,

ThinkPHP5.x RCE 复现

ThinkPHP5.x RCE 复现 其实去年开始是复现过这个漏洞的,但是总觉得并没有吃透,分析写得漏洞百出,于是再来审计一遍。 漏洞影响范围 5.x < 5.1.31 5.x < 5.0.23 复现环境 php7.3 thinkphp5.

FastAdmin前台文件上传

漏洞通告 FastAdmin是一款基于ThinkPHP和Bootstrap的极速后台开发框架。 2021年3月28日,360漏洞云漏洞研究员发现,FastAdmin框架存在有条件RCE漏洞,当攻击者具有一定用户权限的前提下,可以实现任意文件

ELK在渗透测试中的利用与安全配置解析

通过此文章,我将提供有关ELK在攻击利用与安全防护。关于利用ELK 的信息在网上非常罕见。因此,这篇文章只是本人在日常工作和学习中的个人笔记,虽不完善,但可作为学习参考。通过这篇文章希望能为你提供一些在渗透测试期间可能有用的方法。 背景 E

记一次简单的审计

前言 上次在逛先知的时候,无意间看到了L4zily师傅的这篇文章:https://xz.aliyun.com/t/9114 ,所以有了这篇,该版本为金微手机商城 V0.3.8版本 正题 我们直接去官方搭建的演示站,直接访问/admin.ph

TP5 漏洞分析

RCE1 影响版本 TP 5.0.7 - 5.0.24 TP 5.1.0 - 5.1.30 payload 5.0 ?s=index/think\config/get&name=database.username // 获取配置信息 ?s=

记一次SSRF->getshell

这个是2个月前的项目,思路也是挺简单的,还是给兄弟们分享分享,首先还是常规的站点,我们进去看看 可以看见这个网站为thinkphp,当然,当时就很开心,因为自己打tp的站打的太多了,然后再进一步细看。 我们可以得知这个web站点的版本为

vulnstack红队一学习

环境搭建 配置网卡 编辑->虚拟网络编辑器 自定义为仅主机模式 配置win7网络 添加两块网卡,一块为VMnet1(仅主机模式),一块为VMnet8(net模式连通外网) 配置VMnet1网卡 (win7) DNS服务器是windows s

Hvv前排查分析

排查分析 这段时间陆陆续续开始hvv,而这里就简单的介绍一下hvv中对应急响应中可能存在问题进行介绍和分析。 windows排查分析 开机启动项 一般情况下,各个木马等恶意程序,都会在计算机开机的时候自动运行。 所以我们就需要排查一下win