Summary
Product | Singtel WI-FI 6 ROUTER RT5703W |
---|---|
Vendor | Singtel/Askey |
Severity | High - Adversaries may exploit software vulnerabilities to execute arbitrary commands on the underlying OS with root privileges. |
Affected Versions | V1.6.4-5194 (latest version as of writing) |
Tested Versions | V1.6.4-5194 (latest version as of writing) |
Internal Identifier | STAR-2023-0098 |
CVE Identifier | TBD |
CVE Description | OS command injection vulnerability in net.cgi in Singtel WI-FI 6 ROUTER RT5703W V1.6.4-5194 allows an authenticated attacker on LAN to execute arbitrary OS commands via the /cgi-bin/login endpoint. |
CWE Classification(s) | CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’) |
CAPEC Classification(s) | CAPEC-88: OS Command Injection |
CVSS3.1 Scoring System
Base Score: 8.8 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Metric | Value |
---|---|
Attack Vector (AV) | Local |
Attack Complexity (AC) | Low |
Privileges Required (PR) | Low |
User Interaction (UI) | None |
Scope (S) | Changed |
Confidentiality (C) | High |
Integrity (I) | High |
Availability (A) | High |
Product Overview
Singtel WI-FI 6 ROUTER RT5703W is a router provided by Singtel to their customers, manufactured by Askey Computer Corp.
Vulnerability Summary
There is an post-authenticated OS Command Injection vulnerability in Singtel WI-FI 6 ROUTER RT5703W at /cgi-bin/SetLoginPwd
, allowing an adversary to execute arbitrary OS commands on the underlying OS with root privileges.
Vulnerability Details
It is discovered that in the password changing process of the admin panel via https://cap.singtel/1.6.4/cgi-bin/SetLoginPwd, the user-supplied new password value is inserted into a string that is later executed as a system command. Below is the code snippet related to the vulnerability within the change_pwd
function, located at address 11aaac
.
undefined4 change_pwd(char *username, char *encrypted_password, undefined4 *param_3)
{
...
do {
...
if (...) {
if (...) {
...
des_decrypt_password(encrypted_password, decrypted_password, 0x80); // [1]
memset(cmd, 0, 0x400);
sprintf(cmd, "smbpasswd %s %s", username, decrypted_password); // [2]
do_cmd(cmd); // [3] popen wrapper
At [1]
, the function argument is decrypted with DES. Then, at [2]
, the decrypted_password
value is appended to the end of a command string, which is passed to do_cmd
at [3]
, which is a wrapper function that calls popen
. Therefore, this function is potentially vulnerable to command injection, depending on how the argument is handled by its callers.
The function change_pwd
is called by SetLoginPwd
(located at fcae8
), which can be accessed via the /SetLoginPwd
endpoint. Below is the code snippet related to the vulnerability.
int setloginpwd(undefined4 param_1,undefined4 param_2,undefined4 *param_3,undefined4 param_4)
{
...
request_json = json_tokener_parse(request_data);
...
if (...) {}
else {
..
json_object_object_get_ex(request_json, "NewPwd", &newpwd_obj);
if (newpwdobj == 0) { ... }
else {
newpwd = (char *)0x0;
newpwd_decrypted = (char *)0x0;
newpwd_enc_str = (char *)json_object_get_string(newpwd_obj);
newpwd_enc_len = strlen(newpwd_enc_str);
if (newpwd_enc_len < 0x81) {
newpwd_dec = (char *)malloc(local_24 * 4 + 2);
res = dataDecryption(newpwd, newpwd_dec);
if (res == 0) {
strcpy(newpwd, newpwd_dec);
urldecode(newpwd, newpwd_dec);
newpwd_dec_len = strlen(newpwd_dec);
if ((newpwd_dec_len < 0x11) && (newpwd_dec_len = strlen(newpwd_dec), newpwd_dec_len > 3)) {
res2 = spec_char_check(newpwd_decrypted,"\"'"); // [4]
if (res2 == 0) {
des_encrypt_pwd(newpwd_dec, newpwd_encrypted, 0x100); //[5]
free(newpwd_decrypted);
res3 = change_pwd(login_user, newpwd_encrypted, &res); // [6]
...
}
At various parts in this function, the user-supplied password is decrypted then encrypted. We focus our attention on [5]
, where the password is encrypted with DES, right before passing it to change_pwd
at [6]
, which is shown earlier to be potentially vulnerable to command injection.
At [4]
, spec_char_check
is called to check if the user-supplied new password contains quotes ("'
), so that change_pwd
is only called if no quotes are present in the string. However, this is not sufficient to prevent command injection shown in [2]
earlier. A new password string that contains shell metacharacters such as &
, ;
, or |
allows an attacker to execute arbitrary OS commands.
Exploit Conditions
This vulnerability can be exploited when the attacker is connected to the router’s LAN, and has valid credentials for the admin panel.
Proof-of-Concept
We have tried our best to make the PoC as portable as possible. This report includes a functional exploit written in Python3 that exploits the OS command injection vulnerability to start a telnet service at port 31337, running as the console
user with uid=0
.
Requirements
- Python3
- Python
requests
library- To install, run
pip3 install requests
- To install, run
- Node.js
- telnet
- To install, run
sudo apt install -y telnet
.
- To install, run
Reproduction Steps
- Open
poc.py
and change thePASSWORD
constant to the router’s admin password, e.g.PASSWORD = "adminpassword"
. - Run
python3 poc.py
. The exploit will take a few seconds to complete. - Run
telnet cap.singtel 31338
to get a shell.
Exploit Details
The command injection can be exploited by setting the POST request field NewPwd
to &<ANY COMMAND HERE>
in its encrypted form.
Firstly, the DES encryption performed by the web application needs to be replicated locally. It is implemented in des.js attached along with this report. Next, the DES key and token needs to be retrieved from the server, as they are required for crafting requests such as /SetLoginPwd
. These are done in steps 2 and 3 in the poc.py
script.
Overall, the attached poc.py
script performs the following steps:
- Login with valid credentials via https://cap.singtel:443/1.6.4/cgi-bin/Login.
- Obtain the DES key via https://cap.singtel:443/1.6.4/cgi-bin/GetInitInfo.
- Obtain the token via https://cap.singtel:443/1.6.4/cgi-bin/GetToken.
- Exploit the vulnerable endpoint at https://cap.singtel:443/1.6.4/cgi-bin/SetLoginPWD.
As the exploit requires modifying the admin password, after completing the exploit, the script will reset the password back to its original value.
In this script, the command cmd_exec telnetd -l sh -p 31338
is executed to start a telnet service listening on port 31338. cmd_exec
starts the service in the context of the console
user (uid=0
).
Suggested Mitigations
Ensure that commands are executed as an argument list using functions like execve
, instead of concatenating user input together and executing the command string.
Specifically, the following change should be made.
- sprintf(cmd, "smbpasswd %s %s", username, password);
- do_cmd(cmd);
+ execve("/usr/sbin/smbpasswd", (char*[]){ "smbpasswd", username, password, 0 }, 0);
Detection Guidance
It is possible to detect the exploitation of this vulnerability by checking the server’s access logs for all POST requests made to /cgi-bin/SetLoginPwd
and manually verifying if the NewPwd
field contains suspicious records (e.g. fuzzing, newline characters, OS commands). Note that the NewPwd
field is encrypted so it will be less straightforward to check its contents.
Credits
Daniel Lim Wee Soong (@daniellimws) of STAR Labs SG Pte. Ltd. (@starlabs_sg)