Talos Vulnerability Report

TALOS-2023-1787

Yifan YF325 httpd manage_post stack-based buffer overflow vulnerabilities

October 11, 2023
CVE Number

CVE-2023-35965,CVE-2023-35966

SUMMARY

Two heap-based buffer overflow vulnerabilities exist in the httpd manage_post functionality of Yifan YF325 v1.0_20221108. A specially crafted network request can lead to a heap buffer overflow. 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.

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

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

CWE

CWE-190 - Integer Overflow or Wraparound

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 router provides a series of APIs. Many of those APIs, which expect to receive a POST request, use the manage_post function to manage the received POST data:

void manage_post(undefined4 param_1,FILE **fd,int content_length)

{
  [...]
  if (post == 1) {
    if (POST_DATA == (char *)0x0) {
      POST_DATA = (char *)malloc(content_length + 1U);                                                          [1]
    }
    else {
      POST_DATA = (char *)realloc(POST_DATA,content_length + 1U);                                               [2]
    }
    if ((POST_DATA != (char *)0x0) &&
       (data_end = wfread(POST_DATA,1,content_length,fd), [...])) {                                             [3]
      [...]
    }
  }
  [...]
}

The first thing checked, after confirming that the request is actually a POST, is if the POST_DATA global variable has already been initialized. Based on the answer, a malloc or a realloc is called to accommodate the actual request’s Content-Length.

The Content-Length is parsed in the manage_request function:

void manage_request(void)
{
  [... receive and parse the request until the start of the headers ...]
  [... peforms some checks and parse on the received data ... ]
  
  while( true ) {
    [... tmp_buff is a buffer just after current_header buffer ...]
    read_len = wfgets(current_header,(int)tmp_buff - (int)current_header,(char *)CLIENT_REQUEST_FD);
    if (((is_equal == 0) || (is_equal = strcmp(current_header,"\n"), is_equal == 0)) ||
        (is_equal = strcmp(current_header,"\r\n"), is_equal == 0)) break;
    is_equal = strncasecmp(current_header,"Authorization:",0xe);
    if (is_equal == 0) {
      [...]
    }
    else {
      is_equal = strncasecmp(current_header,"Referer:",8);
      if (is_equal == 0) {
        [...]
      }
      else {
        is_equal = strncasecmp(current_header,"Host:",5);
        if (is_equal == 0) {
          [...]
        }
        else {
          is_equal = strncasecmp(current_header,"Content-Length:",0xf);                                         [4]
          if (is_equal == 0) {
            content_length_value_ptr = current_header + 0xf;
            [...]
            content_length_empty_space = strspn(content_length_value_ptr," \t");
            content_length = content_length_value_ptr + content_length_empty_space;
            CONTENT_LENGTH = strtoul(content_length,(char **)0x0,0);
    [...]
  while( true ) {                                                                                               [5]
    URL_path_pattern = (code *)API_entry_cursor->URL_path_pattern;
    [... find the correct API entry based on the URL path pattern ...]
  }
  [...]
  post = 0;
  is_equal = strcasecmp(request_method,"post");
  if (is_equal == 0) {
    post = 1;
  }
  if ((code *)API_entry_cursor->manage_request_data != (code *)0x0) {
    (*(code *)API_entry_cursor->manage_request_data)
              (request_URL+1,CLIENT_REQUEST_FD,CONTENT_LENGTH,boundary);                                        [6]
  }
  [...]
}

The function will eventually parse, at [4], the Content-Length. Then, at [5], based on the URL path, the correct API entry struct to use is located. At [6], the manage_request_data function of the located API entry, if not null, is called. The manage_request_data struct field, for several APIs, corresponds to the manage_post function.

CVE-2023-35965 - malloc integer overflow

Many API URL paths will eventually call the manage_post function. At [1] for the malloc function the requested size is content_length + 1. The + 1 is used to ensure there is enough space for the null terminator. Because the content_length value is never checked, it could correspond to the max unsigned integer, so, an integer overflow vulnerability exists at [1] that can lead to a heap buffer overflow at [3].

CVE-2023-35966 - realloc integer overflow

Many API URL paths will eventually call the manage_post function. At [2] for the realloc function the requested size is content_length + 1. The + 1 is used to ensure there is enough space for the null terminator. Because the content_length value is never checked, it could correspond to the max unsigned integer, so, an integer overflow vulnerability exists at [2] that can lead to a heap buffer overflow at [3].

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.