来自GRIMM的安全研究人员Adam Nichols和来自越南互联网服务提供商VNPT 的研究人员d4rkn3ss分析报告了一个影响Netgear路由器的严重的栈缓存溢出远程代码执行漏洞,漏洞CVSS 评分为8.8分,漏洞影响79种不同型号的Netgear路由器的758种固件版本,受影响的固件中最早的版本是2007年发布的。远程攻击者利用该漏洞可以以root权限执行代码,并接管设备。
影响路由器:
AC1450
D6220
D6300
D6400
D7000v2
D8500
DC112A
DGN2200
DGN2200v4
DGN2200M
DGND3700
EX3700
EX3800
EX3920
EX6000
EX6100
EX6120
EX6130
EX6150
EX6200
EX6920
EX7000
LG2200D
MBM621
MBR624GU
MBR1200
MBR1515
MBR1516
MBRN3000
MVBR1210C
R4500
R6200
R6200v2
R6250
R6300
R6300v2
R6400
R6400v2
R6700
R6700v3
R6900
R6900P
R7000
R7000P
R7100LG
R7300
R7850
R7900
R8000
R8300
R8500
RS400
WGR614v8
WGR614v9
WGR614v10
WGT624v4
WN2500RP
WN2500RPv2
WN3000RP
WN3100RP
WN3500RP
WNCE3001
WNDR3300
WNDR3300v2
WNDR3400
WNDR3400v2
WNDR3400v3
WNDR3700v3
WNDR4000
WNDR4500
WNDR4500v2
WNR834Bv2
WNR1000v3
WNR2000v2
WNR3500
WNR3500v2
WNR3500L
WNR3500Lv2
XR300
1. 关键点:Netgear R7000,版本1.0.11.100_10.2.100及之前,未认证绕过获取到ROOT权限。
2. PoC代码参见:https://github.com/grimm-co/NotQuite0DayFriday/tree/master/2020.06.15-netgear
版本 V1.0.11.208_10.2.101(已经修复):http://support.netgear.cn/Upfilepath/R7000-V1.0.11.208_10.2.101.chk
版本 V1.0.11.100_10.2.100(存在漏洞):https://www.downloads.netgear.com/files/GDC/R7000/R7000-V1.0.11.100_10.2.100.zip
调试的程序:httpd
1. 静态分析:IDA
2. 获取文件系统:binwalk
3. 程序调试工具:gdbserver、IDA
4. 串口调试工具:Hyper Terminal软件、TTL转USB转接板
Netgear R7000路由器真机测试,可以在某宝上或者某鱼上购买,价格不贵(学到的知识是无价的)。
1. Netgear R7000路由器自身带有串口引脚,所以就没必要太过于费劲寻找串口引脚。如下图所示,是已经连接好的串口。
2. 如下图是USB转TTL转接板,本人为什么先把这个工具插入到USB口,而不是USB转TTL转接板连接杜邦线(正常是提前连接杜邦线,USB转TTL转接板连接USB口,再打开Hyper Terminal,最后开启路由器,数据就会在Hyper Terminal显示),再去连接USB口,是有原因的,主要是因为,如果提前连接好杜邦线,再插入到USB口,那就获取不到信息(不信可以自行尝试,本人之前也遇到过类似的坑,脱坑后一直想着这个点)。
3. 打开Hyper Terminal软件,调整好信息(Netgear R7000路由器使用默认信息即可,不用修改信息),点击确定。
4. 开启路由器,等待几秒钟,再将杜邦线插入到TTL转USB转接板上(按着GND-GND、RXD-TXD、TXD-RXD的接法接),如下图所示。
5. 此时就会在Hyper Terminal上打印信息。当打印启动完成后,获取到ROOT权限,便可以进行下一步的调试工作。
1. 进入到路由器后,使用wget下载gdbserver程序进行调试(由于Netgear R7000是arm架构,所以需要下载arm架构的gdbserver)。
2. 根据网上曝光的poc来看,漏洞点是在如下图的地址所示,只要能控制v9的大小,便可以溢出s的值。但是想触碰到漏洞点,必须要绕过 strcmp(src,"*#$^") ,而 src 必须是*#$^,否则无法绕过,src是我们可以控制的数据,所以绕过这个函数并不难。只要在 *#$^ 数据的后面放入00便可以轻松绕过。
3. 想要到达漏洞点,还有两个点需要绕过,s1(全部的数据) 必须存在name="mtenFWUpload",而且name="mtenFWUpload"的数据之后需要存在 \r\n\r\n,所以在构造数据的时候必须是name="mtenFWUpload" ... \r\n\r\n。
4. 可以看到R1寄存器(src的值)的值是我们控制的长度,而且这个长度是可以溢出到返回值地址处。
5. 没有执行memcpy之前R0的值(s的值)是没有数据的,执行之后,就覆盖了构造好的数据。
6. 运行到POP处,此时的SP的地址是0XBE911E54,就是已经被覆盖成了BBBB,由于ARM架构的特性,它会先将BBBB...IIII的数据存放到R4-R11的寄存器中,真正复制给PC的值是0X003D000,所以最终的返回值地址是0X003D000。
7. 经过构造,程序会跳转到0X003D000地址处,将SP(此时的SP已经是0xBE911E78,所以是utelnetd -p 8888 -l /bin/sh的值)赋值给R0,并传给system函数执行命令,达到任意命令执行漏洞的效果。
1. 图7.1(V1.0.11.208_10.2.101)是已经打过补丁的,限制了v9的长度,而图7.2(V1.0.11.100_10.2.100)并没有对v9的长度进行限制,才导致溢出漏洞。
图 7.1
图 7.2
这个漏洞原理相对来说比较简单,挺适合入门的大白。
1. 串口调试时要注意TTL转USB转接板接入。
2. 构造的poc中必须有*#$^,而且后面必须跟00,否则无法绕过strcmp。
3. 0X003D000是很好的执行点,不需要跳转到libc库中,相对来说利用还是比较简单的。
4. 导致溢出的原因,没有限制用户数据的长度。