DIR-816 模拟执行与命令注入漏洞分析

固件安全
2022-08-30 01:04
40116

前言

本文主要想说明当手头没有真机,并且一些已有的一键模拟仿真工具也不好用的时候,该如何来手动模拟固件执行,从而分析和验证我们通过静态分析所挖掘到的漏洞。从本篇文章的标题也能看得出,这次的重点并不是漏洞挖掘或分析,而是如何在现有工具不好用的情况下,一步步的成功将固件中的某一部分功能模拟出来

正文

固件版本:DIR-816

下载链接:http://support.dlink.com.cn:9000/ProductInfo.aspx?m=DIR-816

解包命令:

binwalk -Me DIR-816A2_FWv1.img

解包之后可以看到直接解出了文件系统,并没有什么加密手段

漏洞编号:CVE-2018-17066

首先来说一下我们这次选取的漏洞,是一个比较老的命令注入漏洞,位于/bin/goahead程序中,form2systime.cgi所对应的函数:

程序获取json数据中的datetime,拼接到date命令中,然后放进doSystem执行,而doSystem函数中也没有对所执行的字符串进行任何特殊字符的过滤或者检查:

有一定基础的人肯定能立刻知道这里存在一个命令注入漏洞,可以通过修改datetime字段的值,配合$或者其他特殊字符来实现远程执行命令

简要介绍完漏洞之后,我们来尝试模拟固件执行来验证与调试漏洞,首先肯定是尝试一些自动化的一键模拟仿真工具,这里先试试firmAE,是一个firmadyne的一个wrapper,集成了一些功能,在firmadyne的基础上变得更加的一键化

采用命令:

sudo '/home/iot/tools/FirmAE/run.sh' -r dir '/home/iot/Desktop/D-LINK/DIR-816/DIR-816A2.img'

等了很久很久也没反应,访问web端也访问不到,此时我们考虑,我们需要模拟的功能其实并不多,只需要能够正确执行goahead程序即可,如果要把程序改到能够通过一键模拟仿真脚本,可能需要做大量的patch,能不能直接利用qemu来只执行goahead呢?

首先我们来试试看

命令:

sudo qemu-mipsel -L ../squashfs-root/  ./bin/goahead

可以看到这里一直在等待nvram_daemon启动,每隔几秒打印一个点,一定时间之后程序退出了,显然我们是卡在了一个死循环里,我们呢来分析一下为什么会这样,将goahead程序拖进IDA中

从这里可以看到,这个while循环应该就是卡住我们的地方,从代码逻辑来看也的确对应了我们看到的现象,sleep一秒,然后打印一个点,15个点之后退出程序

可是现在我们显然是没有nvramd.pid这个文件的,那能不能通过动态调试的方式直接将这个v1变量改成1呢,来试一下

将启动命令改成如下:

sudo qemu-mipsel -L ../squashfs-root/  -g 1234 ./bin/goahead

然后ifconfig查看自己的网卡:

修改IDA的debugger设置

然后执行命令,在IDA中点击启动按钮开始动态调试

然后定位到刚才分析的while循环处的逻辑

针对v1的分支判断处的汇编语句打下断点

然后按F9运行到这里,在右上角的寄存器框中将v0寄存器修改为1

然后F9继续运行,结果debugger啪的一下子退出去了

此时到qemu启动终端那里看看log如何

可以看到刚才那里的逻辑确实通过了,但是又因为一些问题退出了,将log里的错误信息复制一下到IDA里搜索一番:

在这里成功定位到了最后出错的位置

走到报错逻辑显然是因为v17变量等于-1,而v17是inet_addr的返回值,inet_addr的参数是v14,且报错信息中将v14当做字符串打印了出来,此时可以通过log中,%s的位置为空串判断出,inet_addr返回-1的原因是v14不是一个合法的地址字符串

v14又是来自v13,v13来自nvram_bufget函数获取的lan_ipaddr字段的值,显然我们并没有提供这样的字段,如果这里直接将v17改成0而不是-1,能否绕过这里的检查呢?我们来试试

同样的方法启动qemu,然后把IDA的debugger连上去,不要忘记上一处的逻辑也要修改

修改好了以后按F9,IDA的debugger成功跑起来没有停下

此时我们可以访问web页面试试了

成功访问到了web界面,现在想要调试到位于时间修改界面的漏洞,还需要绕过登录这一关,先访问一下d_wizard_step1_start.asp试试,但是会跳回登录界面,看样子是必须手动绕一下这里了

在IDA中搜索login,找到这里

显然这里应该就是处理登录验证的函数

我们可以大致的来分析一下程序的登录验证逻辑,首先通过nvram_bufget获取到正确的username和password,然后通过websGetVar获取用户登录的时候输入的username和password

然后通过websDecode64分别将username和password解码并存到v10和v11里,这里猜测应该是在登录前端对username和password进行了base64加密后发包给后端。

接下来是两个strcmp函数,用来比较nvram获取的和用户输入的是否一致,这里我们考虑,既然是strcmp函数,且没有检测username和password是否为空,那我直接什么都不输入不是就绕过了吗,尝试一下

发现用户名必须输入,由前端js代码决定的,密码可以不输入,这里改前端或者动态调试改寄存器应该都可以,我是选择的在IDA中下断点手动将username修改成0来绕过

这意味着我们启动之前要在IDA中下好三处断点,前两处用来启动环境,第三处用来绕过登录验证,再来试一下

首先进到登录界面,然后输入用户名aaaa,点击登录,到IDA中看断点状态

可以看到成功断了下来,v0显然是strcmp的返回值,我们手动将v0改成0,理论上来说就可以绕过那段逻辑,修改过后继续F9,然后试着访问一下

可以看到现在已经成功进入了后台,接下来进入漏洞功能处

这种简单的命令注入想要验证的话直接抓个包就行,如何做呢,可以在dosystem里的system函数打个断点,然后抓包修改datetime进行命令注入,最后在system函数执行的时候查看是否成功注入即可

本次的文章就到这里,感谢阅读!

分享到

参与评论

0 / 200

全部评论 2

zebra的头像
学习大佬思路
2023-03-19 12:14
Hacking_Hui的头像
学习了
2023-02-01 14:20
投稿
签到
联系我们
关于我们