本文复现了D-Link DIR878型号当中存在的一个命令执行漏洞,漏洞编号CVE-2019-8316,漏洞链接。
本文分为以下几个部分:
1.环境搭建
2.固件解密解压
3.漏洞分析
4.动态测试
一、环境搭建
本文章的实验环境:win10主机,firefox浏览器设置代理,BurpSuiteCommunity实现抓包以及修改报文,逆向分析工具ghidra;Linux虚拟机,版本1804,安装binwalk以及7z。
我手头上有DIR878型号的路由器,所以我直接通过无线网络连接到路由器上,内网地址:192.168.0.1。如果没有路由器的朋友可以参考qemu搭建模拟环境的这个链接,不过非常的繁琐我自己也没有搭建完成。
虚拟机上首先安装qemu组件,执行命令:sudo apt install qemu-utils(注:我不是要用qemu来模拟路由器,只是后面的解密固件需要用到qemu)。安装完成后查看组件,执行命令:ls /usr/bin,查看是否有qemu-mipsel-static组件,有则说明可以正常使用了。
二、固件解密解压
固件的解密参考了解密链接,我结合链接当中的过程,描述一下自己的解密过程以及遇到的问题。
DIR878型号的路由器采用链接当中提到的第一种形式,最初几个版本不加密,从中间某个版本之后开始加密,而解密文件存放在开始加密的前一个版本,也就是最后一个不加密的版本,878型号当中的这个固件版本是1.04,可以在官网根据路由器型号查找到各个版本的固件。如图所示,我们采用的固件版本是最新的1.20,包含解密文件的版本是1.04,放在和第一个加密版本1.10一起。
我们首先尝试解压1.20的固件,可以发现没有任何的输出,可以判定固件已经被加密了。
所以首先提取包含解密文件的旧版本1.04,在固件目录下输入命令:binwalk -Me xxxx
接下来进入提取出来的路径,提取文件系统:binwalk -e A0,在cpio-root路径下就可以看到整个文件系统,熟悉Linux的朋友可能很快就发现和Linux的目录结构是一样的。
进入bin目录,可以发现存在一个imgdecrypt,可以用来解密固件的文件。
返回主目录cpio-root,在第一步当中提到的qemu-mispel-static,把这个文件复制到./usr/bin目录下,执行命令:cp /usr/bin/qemu-mispel-static ./usr/bin,此处踩坑:
查阅资料其实是因为存储空间不够,按道理来说我的虚拟机存储空间是非常大的,绝对不可能出现这种情况,所以怀疑是解压过程当中解压完压缩文件,原文件仍旧保留,所以我把上级目录下的其他文件都删除了,只保留了cpio-root这个文件系统,再尝试就成功了
然后复制需要解密的固件到主目录,命令:cp /home/test/Desktop/firmare/1_20/DIR_878_FW120B05.BIN .
接下来利用qemu,启动mips虚拟执行环境,进入busybox,命令:chroot . /bin/sh
然后利用解密文件解密,可以看到解密成功,输出了key。
利用binwalk开始对解密完的固件解压,(注:此处有坑)
报错显示解压失败,我们进到目录里面也只能看到7z文件,根本看不到解压出来的文件系统,原因是系统没有安装7z工具,平时解压的时候压缩软件都带着解压7z的功能,所以我们误认为系统中带有7z的解压命令,其实不然,可以在命令行输入7z尝试一下就会发现并没有这个工具,跟据他的输入提示,安装7z工具,然后就可以在命令行用7z命令了。
可以看到现在解压成功了,后续提取文件系统也是和之前一样的操作。
三、漏洞分析
根据漏洞编号CVE-2019-8316当中的介绍,命令注入存在于站点过滤功能,把分析定位到这个方向。
首先利用ghidra进行反编译,这里提一下,IDA的可视化功能非常强大,可以看到程序流图,但是只支持ARM架构,如果要分析本路由器的话需要安装别的插件,ghidra的反编译功能则比较强大,可以反编译成C程序,可读性更高,我采用的是ghidra。ghidra新建项目后,把librcm.so文件拉入工程中进行反编译,首先定位到站点过滤函数:
可以看到大部分的处理时文件读写,涉及到的也只是常量,唯一值得怀疑的时FUN_0002fef0函数,后面8位代表地址,进入这个函数分析:
这个函数比较大,有两百多行,(这里剧透一下这个函数有问题),然后查看一下这个函数被哪些函数调用以及调用了哪些函数
可以发现出了刚刚的add_url_filter_iptables_rule函数还有别的函数调用,所以后面测试的时候发现有两个地方可以注入命令,都是利用这同一个漏洞。
查看本函数的调用函数,发现twsystem这种系统调用函数,显然只要注入的命令能被这个系统函数调用就可以实现命令注入,所以我们来详细分析这个函数在内部时怎么调用系统函数的:
这里我用vscode作为编辑器,平时用的多比较习惯,我只截取关键部分,前面的功能我概括一下,就是对用户输入的url进行预处理,提取出域名,然后执行系统函数来实现站点过滤,我们仔细分析这一部分,被系统函数执行的参数一个是常数1,另一个是变量acStack544,只有这个变量是可能被注入的,回溯一下164行对acStack544进行初始化置零,后面进行了很多操作,大部分都是常量字符串来拼接,出现的变量仅有183行的local_268和188行的local_264,这两个变量就是我前面说的预处理得到的域名,url的处理主要根据/ ? 等特殊字符来进行切割的,感兴趣的朋友可以自己读函数。
经过我们的分析,可以发现这里对url的处理并不能过滤命令注入,所以twsystem函数会执行用户注入的命令,接下来开始动态测试来验证我们的分析。
四、动态测试
首先来到站点过滤的地方,尝试在前端直接注入命令,发现不行这里有对特殊字符的限制,没办法直接注入命令。
所以只能采用burpsuite抓包改报文的方式来实现命令注入,首先随意输入一个合法的url,此处已www.baidu.com为例,保存设置,截下前端发送的报文:
对报文当中的url字段进行修改,注入命令:$(telnetd -l sh -p 1337 -b 0.0.0.0),开放路由器的1337端口等待他人连接
注意:此处踩坑,之前采用的命令是telnetd -l /bin/sh -p 1337 -b 0.0.0.0,我们提到了url的预处理过程,函数会根据/来截取域名,例如https://github.com/projectxxx,协议后面有两个/,域名结束后也存在/,如果我们注入的命令存在/,就会被处理掉,所以后面注入命令采用我上面写的那条命令。
改完报文发送过去之后,就可以看到我们的设置成功了,也就是注入的命令被执行了
我们前面静态分析的时候提到了,还有其他函数调用了漏洞函数,在 禁止客户端存取下列清单中的网站选项那里,还可以选择另外一个选项,然后和我们上面一样的步骤,也能够顺利注入命令,因为这两个函数都调用了分析的漏洞函数。
接下来在主机尝试telnet连接路由器,验证一下我们注入的命令被成功执行:
可以看到此时已经成功控制了路由器的shell。
*本文作者:黄培扬payoung,转载请注明来自FreeBuf.COM
来源:freebuf.com 2020-06-16 09:00:37 by: 黄培扬payoung
请登录后发表评论
注册