Talos Vulnerability Report

TALOS-2023-1867

Peplink Smart Reader web interface mac2name OS command injection vulnerability

April 17, 2024
CVE Number

CVE-2023-39367

SUMMARY

An OS command injection vulnerability exists in the web interface mac2name functionality of Peplink Smart Reader v1.2.0 (in QEMU). A specially crafted HTTP request can lead to arbitrary command execution. An attacker can make an authenticated HTTP 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.

Peplink Smart Reader v1.2.0 (in QEMU)

PRODUCT URLS

Smart Reader - https://www.peplinkworks.com/Smart-Reader.asp

CVSSv3 SCORE

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

CWE

CWE-78 - Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)

DETAILS

The Peplink Smart Reader is the access-control hardware associated with the PepXIM Time-Logging and Security System. It is used to manage access to buildings, workstations and public transit, as well as for employee time management.

The Peplink Smart Reader exposes a web server on ports 80 and 443 intended for local configuration and control of the card reader. One of the endpoints accessible on this web interface is /cgi-bin/api.cgi, backed by the binary located at /web/cgi-bin/api.cgi. A vulnerability exists in the function responsible for handling mac2name requests which allows an authenticated attacker to execute arbitrary commands on the device.

Requests destined for api.cgi are initially passed to a function located at offset 0x437ab0 which we refer to as api_handler. This function extracts four common parameters (option, type, poll_by and mode) from the POST body and further dispatches the request based on the contents of option, type and mode. The vulnerable function is reached when the request is successfully authenticated, the mode parameter is set to info, type is set to json, option is set to xws and func is set to mac2name. With those preconditions, the request will be handled by a function located at 0x438930 which we refer to as xws_handler. This function queries a Peplink API endpoint for the name associated with a particular MAC address. The way this is done is vulnerable to an OS Command injection of the mac parameter. An annotated decompilation of this function is included here for reference.

00438930  int32_t xws_handler(int32_t* arg1)
00438930  {
00438930      // [1] Compare the value of the `func` parameter to "mac2name"
00438988      if (strcmp(SafecgiGetValue("func", ""), "mac2name") == 0)
00438988      {
004389d8          char template_filename[0x19];
004389d8          __builtin_strncpy(&template_filename, "/tmp/_xws_doc_tmp.XXXXXX", 0x19);
00438a04          char url[0x80] = {0};
00438a20          char command[0x100] = {0};
00438a20
00438a60          // [2] Construct a URL (and subsequent OS command) using the attacker-controlled `mac` parameter
    00438a60          snprintf(&url, 0x80, "%s?option=mac2name\&mode=text\&m…", "http://ws.peplink.com/api1/", SafecgiGetValue("mac", ""));
00438a98          snprintf(&command, 0x100, "(%s %s -T %d -O %s) > /dev/null", "/bin/wget_https", &url, 10, &template_filename);
00438a98
00438aa8          // [3] Execute the constructed command with root privileges
00438aa8          system(&command);
00438aa8
00438ac0          // [4] Finalize API response to user
00438ac0          int32_t $v0_4 = load_taglist_ex(&var_38, 1, 0);
00438ad4          unlink(&var_38);
00438adc          if ($v0_4 != 0)
00438adc          {
00438aec              int32_t i = 0;
00438ae8              if (*(uint32_t*)$v0_4 > 0)
00438ae8              {
00438b44                  do
00438b44                  {
00438b00                      int32_t* $v1_2 = *(uint32_t*)(*(uint32_t*)($v0_4 + 0xc) + (i << 2));
00438b04                      i = (i + 1);
00438b34                      json_object_set_new_nocheck(arg1, *(uint32_t*)$v1_2, json_string(escape_html_character($v1_2[1])));
00438b08                  } while (i < *(uint32_t*)$v0_4);
00438b3c              }
00438b50              free_taglist($v0_4);
00438b70              return 1;
00438b70          }
00438aec      }
004389a8      return 1;
004389a8  }

At [1] we see the final precondition being enforced, which is that the func parameter must match mac2name. If that is the case, then a URL is constructed (at [2]) which contains the attacker-controlled POST parameter, mac. It is expected that this parameter will be an appropriately formatted MAC address, but no such checks are conducted. The constructed URL is passed to a system command (at [3]) intended to query the http://ws.peplink.com/api1/ endpoint, but since no validation occurs, it is possible for the value in mac to escape from the expected command and execute arbitrary OS commands with root privileges.

An authenticated attacker can leverage this vulnerability to execute arbitrary commands on the device with root privileges and elevate their access to the vulnerable system.

VENDOR RESPONSE

The vendor links to new firmware versions at the end of their advisory: https://forum.peplink.com/t/peplink-security-advisory-smart-reader-firmware-1-2-0-cve-2023-43491-cve-2023-45209-cve-2023-39367-cve-2023-45744-cve-2023-40146/47256

TIMELINE

2023-11-30 - Vendor Disclosure
2024-04-17 - Vendor Patch Release
2024-04-17 - Public Release

Credit

Discovered by Matt Wiseman of Cisco Talos.