浅谈路由器漏洞挖掘
前言
去年公司买了个华硕路由器,型号为AC86U,我闲来无事尝试挖掘了下,一个月内,从路由器漏洞挖掘零基础到混了三个CVE。在此分享我一些漏洞挖掘思路。
前期准备
首先了解我们的路由器,做一些基础工作。
登录路由器后台了解基本的一些功能,比如能不能开启ssh连接等等。访问官网看看能不能下到固件等,如果不能下载到固件,则需要考虑硬件dump或者网络截取的方法来获取固件。
华硕的路由器是可以直接开启ssh登录的,这里打开系统管理有一个服务选项,其中有一个启用SSH的功能。
登录之后就可以做一些基础准备了。
确定挖掘目标
使用netstat -anpt命令,查看路由器有哪些开放的端口,哪些是可以通过外网访问到的,而哪些是只有本地访问到的。
tcp 0 0 0.0.0.0:5152 0.0.0.0:* LISTEN 294/envrams
tcp 0 0 0.0.0.0:5473 0.0.0.0:* LISTEN 1846/u2ec
tcp 0 0 0.0.0.0:18017 0.0.0.0:* LISTEN 1043/wanduck
tcp 0 0 0.0.0.0:36098 0.0.0.0:* LISTEN 1928/miniupnpd
tcp 0 0 0.0.0.0:3394 0.0.0.0:* LISTEN 1846/u2ec
tcp 0 0 192.168.50.1:515 0.0.0.0:* LISTEN 1847/lpd
tcp 0 0 192.168.50.1:1990 0.0.0.0:* LISTEN 1155/wps_monitor
tcp 0 0 127.0.0.1:47753 0.0.0.0:* LISTEN 1912/mcpd
tcp 0 0 192.168.50.1:16363 0.0.0.0:* LISTEN 2111/uuplugin
tcp 0 0 192.168.50.1:9100 0.0.0.0:* LISTEN 1847/lpd
tcp 0 0 0.0.0.0:7788 0.0.0.0:* LISTEN 1733/cfg_server
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN 1644/httpd
tcp 0 0 192.168.50.1:80 0.0.0.0:* LISTEN 1644/httpd
tcp 0 0 127.0.0.1:38770 0.0.0.0:* LISTEN 2111/uuplugin
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 1635/dnsmasq
tcp 0 0 192.168.50.1:53 0.0.0.0:* LISTEN 1635/dnsmasq
tcp 0 0 192.168.50.1:22 0.0.0.0:* LISTEN 1764/dropbear
tcp 0 0 127.0.0.1:38746 0.0.0.0:* LISTEN 2117/uuplugin
tcp 0 0 192.168.50.1:3838 0.0.0.0:* LISTEN 1847/lpd
使用iptables命令查看规则。众所周知漏洞修复的手法多种多样,常见手法例如,直接修复程序上的漏洞,砍掉整个功能(可怜的公式编辑器),添加防火墙规则。有些的修复手法就是通过添加规则挡掉外部流量来做的。
使用iptables -nvL --line-number命令来查看规则。
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 118K 7060K DROP tcp -- lo * 127.0.0.1 127.0.0.1 tcp dpt:38770
2 0 0 ACCEPT tcp -- br0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:16363
3 0 0 ACCEPT 2 -- eth0 * 0.0.0.0/0 0.0.0.0/0
4 826 188K INPUT_PING icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
5 1846K 433M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
6 1770 85622 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 state INVALID
7 4429K 973M PTCSRVWAN all -- !br0 * 0.0.0.0/0 0.0.0.0/0
8 202K 22M PTCSRVLAN all -- br0 * 0.0.0.0/0 0.0.0.0/0
9 34 1768 DROP tcp -- !lo * 0.0.0.0/0 0.0.0.0/0 tcp dpt:5152
10 202K 22M ACCEPT all -- br0 * 0.0.0.0/0 0.0.0.0/0 state NEW
11 4429K 973M ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 state NEW
12 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp spt:67 dpt:68
13 0 0 INPUT_ICMP icmp -- * * 0.0.0.0/0 0.0.0.0/0
14 378 96645 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
可以看到有的端口的包是完全丢弃掉的,比如5152端口。
在剩余的程序中,通过百度或者其他搜索引擎了解它是干什么的,一般来讲应用较广身经百战的项目漏洞比较少且难以发现,并且在网上都是可以查到他是干什么的,例如这里面的miniupnpd,dnsmasq等。而查不到的则很有可能是厂商自己实现的功能也就是我们的目标,其中功能越多越容易出现漏洞。
环境准备
在路由器上安装编译好的gdb,这里我是直接从github上下载编译好的,在本地使用python搭建下载服务,在路由器上使用wget下载下来,需要注意的是,路由器重启之后所有下载的文件就会消失,需要我们重新下载到路由器上,因此非必要的情况下不要重启路由器。
漏洞挖掘
这里以我挖掘危害较轻的一个漏洞为例。这里我选择的是cfg_server。
由于程序代码量很大,因此我们需要找到最关键的部分,也就是数据处理的部分,这里通过调试对recv,listen,accept等函数下断点,通过跟踪数据流来找到程序处理数据的位置。
这里是根据输入数据的前四字节走入不同的处理函数。
变量dword_A2F90存放对应功能码以及处理函数。
例如94 8e 05 00地址对应的是功能码1的处理函数。
定位之后继续对该程序代码分析,发现其实一个TLV格式的报文,TLV 的意思就是Type 类型,Length 长度,Value 值。接下来就是对每个功能进行分析,来找出其中是否存在漏洞,这里需要耐心以及对功能的理解。
这里以0x1对应的功能为例,正常交互时,会输出程序的公钥。如下图。
当我们设置长度为0xfffffff4的时候会导致服务端出现逻辑错误,进而无限循环不停向客户端发送公钥,此时如果关闭客户端的连接就会导致程序产生SIGPIPE信号进而退出。
该漏洞的漏洞点在于没有对输入的长度进行验证,也就是说不会验证TLV中的L与V的长度是否相等。另一个则是程序的信号处理不够完善,导致程序退出。至此一个简单的拒绝服务漏洞就出现了。
而官方通过添加验证数据长度的代码进行修复漏洞。
总结
对我而言整个流程总体来说,确定目标,环境准备,漏洞挖掘。其中花的时间大部分在对程序的逆向分析上,一个程序实现的功能越多越复杂就越可能出现漏洞。最终拿了三个CVE,总体而言华硕的漏洞提交体验还是不错的。