# Talos Vulnerability Report
### TALOS-2023-1712
## Milesight UR32L vtysh_ubus _get_fw_logs OS command injection vulnerability
##### July 6, 2023
##### CVE Number
CVE-2023-22299
##### SUMMARY
An OS command injection vulnerability exists in the vtysh_ubus _get_fw_logs functionality of Milesight UR32L v32.3.0.5. A specially crafted network request can lead to command execution. An attacker can send a network request to trigger this vulnerability.
##### CONFIRMED VULNERABLE VERSIONS
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Milesight UR32L v32.3.0.5
##### PRODUCT URLS
UR32L –
##### CVSSv3 SCORE
8.8 – CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
##### CWE
CWE-78 – Improper Neutralization of Special Elements used in an OS Command (âOS Command Injectionâ)
##### DETAILS
The Milesight UR32L is an industrial cellular router. The router features include support for multiple VPNs, a router console shell, firewall and many others.
The Milesight router offers several functionalities through the `/cgi` endpoint. The âcoreâ functionality we are considering is called `yruo_debug_firewall`. In this âcoreâ there is a function called âgetâ. The function that manages this functionality is the `vtysh_ubus`âs `fw_logs_get` function:
void fw_logs_get(undefined4 param_1,undefined4 param_2,undefined4 param_3,undefined4 param_4,
undefined4 *data)
{
[… variable declaration …]
[… variable initialization …]
json_msg_output(“!! yruo_fw_logs.get params”,data);
blob_buf_init(b,0);
data_len = __bswapsi2(*data);
blobmsg_parse(fw_logs_get_policy,2,tb,data + 1,(data_len & 0xffffff) – 4); [1]
if (tb[0] != (blob_attr *)0x0) {
base_value_ptr = (char *)blobmsg_get_string(tb[0]);
strncpy(tb_base_value,base_value_ptr,0x20);
system_ptr = (system_base_struct *)get_handler_bybase(&debug_bases,1,tb_base_value); [2]
if (system_ptr != (system_base_struct *)0x0) {
switch_to_enable_node();
_get_fw_logs = (code *)system_ptr->get_func;
if ((_get_fw_logs != (code *)0x0) &&
(_get_fw_logs = (code *)(*_get_fw_logs)(tb,”get”), _get_fw_logs == (code *)0x0)) [3]
[…]
[…]
}
}
}
[…]
}
The data are transmitted through `blobmsg` structures. The two variable that are parsed into the `tb` array, at `[1]`, are: – `base`: this value must be equal to âfirewall_logâ, otherwise no functionality will be performed. The value of this data will be parsed in the `tb[0]` variable. – `command`: this value will be used as argument of the `iptables` shell command. The value of this data will be parsed in the `tb[1]` variable.
At `[2]` the `base` value will be used to get a struct handler that in the code is called `system_ptr`. Because there is only, in this case, one valid value for `base`, we know the struct fetched has as value of the `system_ptr->get_func` the `_get_fw_logs` function pointer. At `[3]` the `_get_fw_logs` function will be called:
void _get_fw_logs(blob_attr **tb, char* type)
{
[… variable declaration …]
[… variable initialization …]
= (undefined4 *)zcalloc(1,8);
if (two_word != (undefined4 *)0x0) {
command = tb[1]; [4]
[…]
if ((command != (blob_attr *)0x0) &&
(command_string = (char *)blobmsg_get_string(command), *command_string != ”)) {
dup_command = zstrdup(1,command_string);
[…]
command_string = (char *)(dup_command + -1);
do {
command_string = command_string + 1;
command_string_cursor = *command_string;
if (command_string_cursor == ”) {
snprintf(iptables_command,0x100,”iptables -w %s”,dup_command); [5]
zlog_debug(“exec fw command(%s)n”,iptables_command);
__stream = popen(iptables_command,”r”); [6]
[…]
}
[…]
}
} while (command_string_cursor != ‘&’ && command_string_cursor != ‘;’);
[…]
}
}
[…]
} This function takes as first argument the `fw_logs_get`’s `tb` variable pointer. Then, at `[4]`, `tb[1]` is used to fetch the `command` argument sent in the `/cgi` API. The `command` variable is used, at `[5]`, to compose the `iptables -w ` string. This is then used at `[6]` as the argument for the `popen` function, effectively executing the `iptables -w ` shell command.
The payload for the `/cgi` API to execute the âgetâ function in the âyruo_debug_firewallâ core would look likes this:
{
“id”:60,
“execute”:10,
“core”:”yruo_debug_firewall”,
“function”:”get”,
“values”:[
{
“base”:”firewall_log”,
“command”:”-S”,
}
]
}
This would execute the `iptables -W -S` command listing all the iptables rules.
Because no exhaustive checks are performed on the `command` parameters until it reaches the `popen` function, this leads to an OS command injection vulnerability.
##### VENDOR RESPONSE
Since the maintainer of this software did not release a patch during the 90 day window specified in our policy, we have now decided to release the information regarding this vulnerability, to make users of the software aware of this problem. See Ciscoâs Coordinated Vulnerability Disclosure Policy for more information: https://tools.cisco.com/security/center/resources/vendor_vulnerability_policy.html
##### TIMELINE
2023-02-14 – Initial Vendor Contact
2023-02-21 – Vendor Disclosure
2023-07-06 – Public Release
##### Credit
Discovered by Francesco Benvenuto of Cisco Talos.
* * *
Vulnerability Reports Next Report
TALOS-2023-1713
Previous Report
TALOS-2023-1706Read More

