CVE-2018-3950
An exploitable remote code execution vulnerability exists in the ping and tracert functionality of the TP-Link TL-R600VPN http server. A specially crafted IP address can cause a stack overflow, resulting in remote code execution. An attacker can send a single authenticated HTTP request to trigger this vulnerability.
TP-Link TL-R600VPN HWv3 FRNv1.3.0 TP-Link TL-R600VPN HWv2 FRNv1.2.3
https://www.tp-link.com/us/products/details/cat-4909_TL-R600VPN.html
7.2 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
CWE-120 - Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)
The TP-Link r600vpn does not properly check the size of the data passed to its ‘ping_addr’ field when performing a ping operation. By sending a large amount of data to this field, it is possible to overflow the stack buffer, causing the device’s HTTP server to crash. It is further possible to craft the data passed through the ‘ping_addr’ field to exploit this vulnerability and gain remote code execution on the device.
[Annotated Disassembly / Decompilation output] The user-supplied ping address is obtained from the environment variable “ping_addr” and placed into the register $s4 toward the beginning of the function PingIframeRpmHtm. LOAD:004773D0 loc_4773D0: LOAD:004773D0 la $a1, dword_520000 LOAD:004773D4 move $a0, $s2 LOAD:004773D8 la $t9, httpGetEnv LOAD:004773DC jalr $t9 ; httpGetEnv LOAD:004773E0 addiu $a1, (aPingAddr - 0x520000) # “ping_addr” LOAD:004773E4 move $a0, $s2 LOAD:004773E8 lw $gp, 0x78+var_60($sp) LOAD:004773EC move $s4, $v0 # holds the user-supplied buffer
The $s4 register is not set again before a call to the function ipAddrDispose, where it is passed as the first argument. LOAD:004777B8 move $a0, $s4 LOAD:004777BC lw $gp, 0x78+var_60($sp) LOAD:004777C0 la $t9, ipAddrDispose LOAD:004777C4 jalr $t9 ; ipAddrDispose LOAD:004777C8 move $s1, $v0
The $a0 register is then moved into the $s2 register for a strlen call in ipAddrDispose. During this same instruction, we see the register $s3 being loaded with a stack address. LOAD:0049B098 move $s0, $zero LOAD:0049B09C la $t9, strlen LOAD:0049B0A0 move $s2, $a0 LOAD:0049B0A4 jalr $t9 ; strlen LOAD:0049B0A8 addiu $s3, $sp, 0x78+var_50
A loop is then entered where each character is loaded into a stack-based buffer one by one.
LOAD:0049B0D4 li $a3, 0x20
LOAD:0049B0D8 addiu $a2, $sp, 0x78+var_60 # load a stack pointer into $a2
LOAD:0049B0DC addu $v0, $s2, $a0
LOAD:0049B0E0
LOAD:0049B0E0 loc_49B0E0:
LOAD:0049B0E0 addiu $a0, 1
LOAD:0049B0E4 lbu $v0, 0($v0)
LOAD:0049B0E8 slt $a1, $a0, $s1
LOAD:0049B0EC beq $v0, $a3, loc_49B0FC
LOAD:0049B0F0 addu $v1, $s0, $a2 # calculate an offset on the stack buffer
LOAD:0049B0F4 addiu $s0, 1
LOAD:0049B0F8 sb $v0, 0x10($v1) # write the byte to the stack buffer
LOAD:0049B0FC
LOAD:0049B0FC loc_49B0FC:
LOAD:0049B0FC bnez $a1, loc_49B0E0
LOAD:0049B100 addu $v0, $s2, $a0
LOAD:0049B104
When the function epilogue is entered, the values for $ra and $s0-$s3 are overwritten with the values from the user-controlled stack buffer. LOAD:0049B2FC loc_49B2FC: LOAD:0049B2FC LOAD:0049B2FC lw $ra, 0x78+var_8($sp) LOAD:0049B300 move $v0, $v1 LOAD:0049B304 lw $s3, 0x78+var_C($sp) LOAD:0049B308 lw $s2, 0x78+var_10($sp) LOAD:0049B30C lw $s1, 0x78+var_14($sp) LOAD:0049B310 lw $s0, 0x78+var_18($sp) LOAD:0049B314 jr $ra LOAD:0049B318 addiu $sp, 0x78 LOAD:0049B318 # End of function ipAddrDispose
[ 18.484000] do_page_fault() #2: sending SIGSEGV to httpd for invalid read access from
[ 18.484000] 42424242 (epc == 42424242, ra == 42424242)
[ 18.508000] Cpu 0
[ 18.520000] $ 0 : 00000000 1000a400 00000000 00000000
[ 18.528000] $ 4 : 0067bc68 00000000 00000000 00000000
[ 18.532000] $ 8 : 00000434 00000001 00000001 00000007
[ 18.540000] $12 : 00000003 00000000 00000002 00000003
[ 18.544000] $16 : 41414141 41414141 41414141 41414141
[ 18.548000] $20 : 0067bc68 00520000 00000040 00000004
[ 18.560000] $24 : 8f055f08 004be740
[ 18.568000] $28 : 00598790 7d9ff8e0 7d9ffa62 42424242
[ 18.572000] Hi : 00000005
[ 18.576000] Lo : 00000000
[ 18.576000] epc : 42424242 0x42424242
[ 18.584000] Not tainted
[ 18.584000] ra : 42424242 0x42424242
[ 18.588000] Status: 0000a413 USER EXL IE
[ 18.592000] Cause : 10800008
[ 18.600000] BadVA : 42424242
[ 18.608000] PrId : 00019300 (MIPS 24Kc)
[ 18.608000] Modules linked in:
[ 18.612000] Process httpd (pid: 9668, threadinfo=8f0cc000, task=8f07e4c0, tls=00000000)
[ 18.624000] Stack : 43434343 43434343 43434343 43434343 43434343 43434343 43434343 43434343
[ 18.628000] 43434343 43434343 43434343 43434343 43434343 43434343 43434343 43434343
[ 18.644000] 43434343 43434343 43434343 43434343 43434343 43434343 43434343 43434343
[ 18.652000] 43434343 43434343 43434343 43434343 43434343 43434343 43434343 43434343
[ 18.660000] 43434343 43434343 43434343 43434343 43434343 43434343 43434343 43434343
[ 18.668000] ...
[ 18.672000] Call Trace:
[ 18.676000]
[ 18.684000]
[ 18.684000] Code: (Bad address in epc)
[ 18.692000]
[ 18.700000] httpd/9668: potentially unexpected fatal signal 11.
[ 18.708000]
[ 18.708000] Cpu 0
[ 18.716000] $ 0 : 00000000 1000a400 00000000 00000000
[ 18.732000] $ 4 : 0067bc68 00000000 00000000 00000000
[ 18.736000] $ 8 : 00000434 00000001 00000001 00000007
[ 18.744000] $12 : 00000003 00000000 00000002 00000003
[ 18.748000] $16 : 41414141 41414141 41414141 41414141
[ 18.752000] $20 : 0067bc68 00520000 00000040 00000004
[ 18.764000] $24 : 8f055f08 004be740
[ 18.772000] $28 : 00598790 7d9ff8e0 7d9ffa62 42424242
[ 18.776000] Hi : 00000005
[ 18.780000] Lo : 00000000
[ 18.780000] epc : 42424242 0x42424242
[ 18.784000] Not tainted
[ 18.784000] ra : 42424242 0x42424242
[ 18.788000] Status: 0000a413 USER EXL IE
[ 18.792000] Cause : 10800008
[ 18.792000] BadVA : 42424242
[ 18.796000] PrId : 00019300 (MIPS 24Kc)
2018-06-28 - Vendor Disclosure
2018-10-09 - Vendor provided beta
2018-10-11 - Patch tested and confirmed fix
2018-11-19 - Public Release
Discovered by Jared Rittle of Cisco Talos