PSV-2020-0211:Netgear R8300 UPnP栈溢出漏洞分析
漏洞简介
PSV-2020-0211
对应Netgear
R8300
型号路由器上的一个缓冲区溢出漏洞,Netgear
官方在2020年7月31日发布了安全公告,8月18日SSD
公开了该漏洞的相关细节。该漏洞存在于设备的UPnP
服务中,由于在处理数据包时缺乏适当的长度校验,通过发送一个特殊的数据包可造成缓冲区溢出。利用该漏洞,未经认证的用户可实现任意代码执行,从而获取设备的控制权。
该漏洞本身比较简单,但漏洞的利用思路值得借鉴,下面通过搭建R8300
设备的仿真环境来对该漏洞进行分析。
漏洞分析
环境搭建
根据官方发布的安全公告,在版本V1.0.2.134
中修复了该漏洞,于是选取之前的版本V1.0.2.130
进行分析。由于手边没有真实设备,打算借助qemu
工具来搭建仿真环境。文章通过qemu system mode
的方式来模拟整个设备的系统,我个人更偏向于通过qemu user mode
的方式来模拟单服务。当然,这两种方式可能都需要对环境进行修复,比如文件/目录缺失、NVRAM
缺失等。
用binwalk
对固件进行解压提取后,运行如下命令启动UPnP
服务。
1 | 添加`--strace`选项, 方便查看错误信息, 便于环境修复 |
运行后提示如下错误,根据对应的目录结构,通过运行命令mkdir -p tmp/var/run
解决。
1 | 18336 open("/var/run/upnpd.pid",O_RDWR|O_CREAT|O_TRUNC,0666) = -1 errno=2 (No such file or directory) |
之后再次运行上述命令,提示大量的错误信息,均与NVRAM
有关,该错误在进行IoT
设备仿真时会经常遇到。NVRAM
中保存了设备的一些配置信息,而程序运行时需要读取配置信息,由于缺少对应的外设,因此会报错。一种常见的解决方案是"劫持"
与NVRAM
读写相关的函数,通过软件的方式来提供相应的配置。
网上有很多类似的模拟NVRAM
行为的库,我个人经常使用Firmadyne
框架提供的libnvram
库:支持很多常见的api
,对很多嵌入式设备进行了适配,同时还会解析固件中默认的一些NVRAM
配置,实现方式比较优雅。采用该库,往往只需要做很少的改动,甚至无需改动,就可以满足需求。
参考libnvram
的文档,编译后然后将其置于文件系统中的firmadyne
路径下,然后通过LD_PRELOAD
环境变量进行加载,命令如下。
1 | <extracted squashfs-root>$ sudo chroot . ./qemu-arm-static --strace -E LD_PRELOAD=./firmadyne/libnvram.so.armel ./usr/sbin/upnpd |
运行后提示缺少某个键值对,在libnvram/config.h
中添加对应的配置,编译后重复进行测试,直到程序成功运行起来即可,最终libnvram/config.h
的变化如下。
1 | diff --git a/config.h b/config.h |
需要说明的是,libnvram
还会尝试去定位固件中的全局符号router_defaults
和Nvrams
,并加载其中存在的键值对,对应的代码如下。其中,调用nvram_set_default_*
的顺序为:nvram_set_default_builtin()
,nvram_set_default_table(a)
。也就是说,上面NVRAM_DEFAULTS
中的键值对会先被加载,然后再加载全局符号router_defaults
和Nvrams
中存在的键值对。因此,在libnvram/config.h
中添加的键值对有可能会被覆盖(比如lan_ipaddr
),为了保证自定义的键值对生效,对libnvram/nvram.c
的修改如下。
1 | int nvram_set_default(void) { |
1 | diff --git a/nvram.c b/nvram.c |
程序成功运行效果如下。
1 | <extracted squashfs-root>$ sudo chroot . ./qemu-arm-static -E LD_PRELOAD=./firmadyne/libnvram.so.armel ./usr/sbin/upnpd |
漏洞分析
在upnp_main()
中,在(1)
处recvfrom()
用来读取来自socket
的数据,并将其保存在v55
指向的内存空间中。在(2)
调用ssdp_http_method_check()
,传入该函数的第一个参数为v55
,即指向接收的socket
数据。
1 | int upnp_main() |
在ssdp_http_method_check()
中,在(3)
处调用strcpy()
进行数据拷贝,其中v40
指向栈上的局部缓冲区,v3
指向接收的socket
数据。由于缺乏长度校验,当构造一个超长的数据包时,拷贝时会出现缓冲区溢出。
1 | signed int ssdp_http_method_check(const char *a1, int a2, int a3) |
漏洞利用
upnpd
程序启用的缓解措施如下,可以看到仅启用了NX
机制。另外,由于程序的加载基址为0x8000
,故.text
段地址的最高字节均为\x00
,而在调用strcpy()
时存在NULL
字符截断的问题,因此在进行漏洞利用时需要想办法绕过NULL
字符限制的问题。
1 | checksec --file ./upnpd |
SSD
公开的漏洞细节中给出了一个方案:通过stack reuse
的方式来绕过该限制。具体思路为,先通过socket
发送第一次数据,往栈上填充相应的rop payload
,同时保证不会造成程序崩溃;再通过socket
发送第二次数据用于覆盖栈上的返回地址,填充的返回地址用来实现stack pivot
,即劫持栈指针使其指向第一次发送的payload
处,然后再复用之前的payload
以完成漏洞利用。SSD
公开的漏洞细节中的示意图如下。
实际上,由于recvfrom()
函数与漏洞点strcpy()
之间的路径比较短,栈上的数据不会发生太大变化,利用stack reuse
的思路,只需发送一次数据即可完成利用,示意图如下。在调用ssdp_http_method_check()
前,接收的socket
数据包保存在upnp_main()
函数内的局部缓冲区上,而在ssdp_http_method_check()
内,当调用完strcpy()
后,会复制一部分数据到该函数内的局部缓冲区上。通过覆盖栈上的返回地址,可劫持栈指针,使其指向upnp_main()
函数内的局部缓冲区,复用填充的rop gadgets
,从而完成漏洞利用。
另外在调用strcpy()
后,在(4)
处还调用了函数sub_B60C()
。通过对应的汇编代码可知,在覆盖栈上的返回地址之前,也会覆盖R7
指向的栈空间内容,之后R7
作为参数传递给sub_B60C()
。而在sub_B60C()
中,会读取R0
指向的栈空间中的内容,然后再将其作为参数传递给strstr()
,这意味[R0]
中的值必须为一个有效的地址。因此在覆盖返回地址的同时,还需要用一个有效的地址来填充对应的栈偏移处,保证函数在返回前不会出现崩溃。由于libc
库对应的加载基址比较大,即其最高字节不为\x00
,因此任意选取该范围内的一个不包含\x00
的有效地址即可。
在解决了NULL
字符截断的问题之后,剩下的部分就是寻找rop gadgets
来完成漏洞利用了,相对比较简单。同样,SSD
公开的漏洞细节中也包含了完整的漏洞利用代码,其思路是通过调用strcpy gadget
拼接出待执行的命令,并将其写到某个bss
地址处,然后再调用system gadget
执行对应的命令。
在给出的漏洞利用代码中,strcpy gadget
执行的过程相对比较繁琐,经过分析后,在upnpd
程序中找到了另一个更优雅的strcpy gadget
,如下。借助该gadget
,可以直接在数据包中发送待执行的命令,而无需进行命令拼接。
1 | .text:0000B764 MOV R0, R4 ; dest |
补丁分析
Netgear
官方在R8300-V1.0.2.134_1.0.99
版本中修复该漏洞。函数ssdp_http_method_check()
的相关伪代码如下,可以看到,在补丁中调用的是strncpy()
而非原来的strcpy()
,同时还对局部缓冲区&v40
进行了初始化。
1 | signed int ssdp_http_method_check(const char *a1, int a2, int a3) |
小结
本文通过搭建Netgear
R8300
型号设备的仿真环境,对其UPnP
服务中存在的缓冲区溢出漏洞进行了分析。漏洞本身比较简单,但漏洞利用却存在NULL
字符截断的问题,SSD
公开的漏洞细节中通过stack reuse
的方式实现了漏洞利用,思路值得借鉴和学习。
相关链接
- Security Advisory for Pre-Authentication Command Injection on R8300, PSV-2020-0211
- SSD Advisory – Netgear Nighthawk R8300 upnpd PreAuth RCE
- Netgear Nighthawk R8300 upnpd PreAuth RCE 分析与复现
- Firmadyne libnvram
本文首发于安全客,文章链接:https://www.anquanke.com/post/id/217606