Talos Vulnerability Report

TALOS-2023-1767

Yifan YF325 validate.so diag_ping_start command execution vulnerability

October 11, 2023
CVE Number

CVE-2023-32632

SUMMARY

A command execution vulnerability exists in the validate.so diag_ping_start functionality of Yifan YF325 v1.0_20221108. 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.

Yifan YF325 v1.0_20221108

PRODUCT URLS

YF325 - https://yifanwireless.com/entry-level-wifi-router/yf325-series-gprs/3g/4g-wifi-router-with-sim-card-slot.html

CVSSv3 SCORE

8.8 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-284 - Improper Access Control

DETAILS

The Yifan YF325 is an industrial cellular router. This device is designed for M2M and IOT applications, allowing remote management, offering several VPN services and many other features.

The YF325 offers several APIs, several of which are managed by the same httpd’s cgi_handler function:

int cgi_handler(undefined mime,char *URL_path,int fd,char *query_string)

{
  [...]

  if (post == 1) {
    request_data = POST_DATA;
  }
  else {
    request_data = URL_path;
    URL_path_ = strsep(&request_data,"?");
    if (URL_path_ != (char *)0x0) {
      URL_path = URL_path_;
    }
    init_cgi(request_data);
  }
  [...]
  need_reboot = (char *)websGetVar(fd,"need_reboot","0");
  need_rebot_value = atoi(need_reboot);
  change_action = (char *)websGetVar(fd,"change_action","");
  if ((change_action != (char *)0x0) && (is_gozila = strcmp(change_action,"gozila_cgi"), is_gozila == 0)) {
    gozila_cgi(fd,0,URL_path);
    [...]
  }
  [...]
}

If the request’s change_action parameter is equal to gozila_cgi then the cgi_handler will call the gozila_cgi function:

int gozila_cgi(int fd,undefined param_2,char *URL_path)

{
    [...]

    nvram_set("gozila_action","1");
    my_next_page = '\0';
    submit_button = websGetVar(fd,"submit_button",0);                                                           [1]
    submit_type = websGetVar(fd,"submit_type",0);                                                               [2]
    godzila_ptr = (godzila_object *)handle_gozila_action(submit_button,submit_type);
    if (godzila_ptr == (godzila_object *)0x0) {
        [...]
    }
    else {
        [...]
        if (godzila_ptr->validate_function_name != (undefined *)0x0) {
            start_gozila(godzila_ptr->validate_function_name,fd);                                               [3]
        }
        [...]
    }
}

This function will fetch at [1] and [2] the request’s submit_button and submit_type parameters. These two are used in the handle_gozila_action function to fetch the correct gozila_object struct into the godzila_ptr variable. The fetched struct is used at [3] to call the start_gozila function using the godzila_ptr->validate_function_name value. The godzila_ptr->validate_function_name value is a string representing, in most of the cases, a function defined in the validate.so library.

If the submit_button is equal to Ping and submit_type is equal to start then the godzila_ptr->validate_function_name would be the string diag_ping_start. Following the validate.so’s diag_ping_start function:

void diag_ping_start(int fd)

{
  char *ping_ip;

  ping_ip = (char *)(*UwebsGetVar)(fd,"ping_ip",0);                                                             [4]
  if ((ping_ip != (char *)0x0) && (*ping_ip != '\0')) {
    unlink("/tmp/ping.log");
    nvram_set("ping_ip",ping_ip);
    setenv("PATH","/sbin:/bin:/usr/sbin:/usr/bin",1);
    sysprintf("alias ping='ping -c 3'; eval \"%s\" > %s 2>&1 &",ping_ip,"/tmp/ping.log");                     [5]
    return;
  }
  return;
}

The diag_ping_start function will fetch at [4] the request’s ping_ip parameter, which is used at [5] to execute the alias ping='ping -c 3'; eval "<ping_ip>" > /tmp/ping.log 2>&1 &. Despite the name of the functionality, which would suggest to only be used for performing ping operations, this code path is used to implement the “Diagnostic” page in the web server and execute command shell. But, because it is possible to reach the code at [5] without authentication, this becomes a security issue that could allow a potential attacker to execute arbitrary shell command.

TIMELINE

2023-06-28 - Initial Vendor Contact
2023-07-06 - Vendor Disclosure
2023-10-11 - Public Release
2023-10-24 - Vendor Patch Release

Credit

Discovered by Francesco Benvenuto of Cisco Talos.