Lucene search

K
talosTalos IntelligenceTALOS-2021-1396
HistoryFeb 01, 2022 - 12:00 a.m.

Sealevel Systems, Inc. SeaConnect 370W HandleSeaCloudMessage out-of-bounds write vulnerabilities

2022-02-0100:00:00
Talos Intelligence
www.talosintelligence.com
29
mqtt payload
buffer overflow
wi-fi device

CVSS2

6.8

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

CVSS3

8.1

Attack Vector

NETWORK

Attack Complexity

HIGH

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

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

EPSS

0.003

Percentile

66.1%

Summary

Two out-of-bounds write vulnerabilities exists in the HandleSeaCloudMessage functionality of Sealevel Systems, Inc. SeaConnect 370W v1.3.34. A specially-crafted MQTT payload can lead to an out-of-bounds write. An attacker can perform a man-in-the-middle attack to trigger these vulnerabilities.

Tested Versions

Sealevel Systems, Inc. SeaConnect 370W v1.3.34

Product URLs

SeaConnect 370W - <https://www.sealevel.com/product/370w-a-wifi-to-form-c-relays-digital-inputs-a-d-inputs-and-1-wire-bus-seaconnect-multifunction-io-edge-module-powered-by-seacloud/&gt;

CVSSv3 Score

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

CWE

CWE-120 - Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’)

Details

The SeaConnect 370W is a Wi-Fi connected IIoT device offering programmable cloud access and control of digital and analog I/O and a 1-wire bus.

This device offers remote control via several means including MQTT, Modbus TCP and a manufacturer-specific protocol named “SeaMAX API”.

The device is built on top of the TI CC3200 MCU with built-in Wi-Fi capabilities.

One of the role of the SeaConnect 370W is as MQTT client. Different functionality is supported and controlled remotely from the “Sealevel SeaCloud”. When a message is pushed, in the SeaConnect 370W’s subscribed topic, it receive the message, parses it and performs the related action based on the message content.

A specially-crafted MQTT payload can lead to out-of-bound write due to a missing size check.

The HandleIncomingSeaCloudMessage function is responsible for parsing the MQTT message. The message should be in the following form:

{
    "name": "&lt;functionality&gt;",
    "payload": "&lt;data&gt;"
}

Here is the HandleIncomingSeaCloudMessage function:

void HandleIncomingSeaCloudMessage(incoming_message_struct *param_1)

{
  [...]

  puVar1 = read_volatile_4(fname);
  dVar6 = param_1-&gt;topic_element-&gt;element_content;
  Report(s_FSeaConnect_%s_topic_%.*s:_%.*s_2000ecbf + 1,(dword)puVar1,
         param_1-&gt;topic_element-&gt;element_size,dVar6);
  ppcVar2 = (char **)read_volatile_4(p_incomingTopic);
  memset(*ppcVar2,0,0x81);
  ppcVar3 = (char **)read_volatile_4(p_incomingMessage);
  memset(*ppcVar3,0,0x201);
  p_name_ = read_volatile_4(p_name);
  memset(p_name_,0,0x80);
  p_payload_ = read_volatile_4(p_payload);
  memset(p_payload_,0,0x100);
  topic_elem = param_1-&gt;topic_element;
  if ((int)topic_elem-&gt;element_size &lt; 0x80) {
    size = topic_elem-&gt;element_size;
  }
  else {
    size = 0x80;
  }
  strncpy(*ppcVar2,(char *)topic_elem-&gt;element_content,size);
  message_elem = param_1-&gt;message_element;
  size = 0x201;
  if (*(uint *)&message_elem-&gt;element_size &lt; 0x201) {                                                   [1]
    size = *(size_t *)&message_elem-&gt;element_size;
  }
  strncpy(*ppcVar3,(char *)message_elem-&gt;element_content,size);                                         [2]
  Report(aSeaconnectSGIn,(dword)puVar1,(dword)*ppcVar2,dVar6);
  incoming_message = *ppcVar3;
  Report(aSeaconnectSGIn_0,(dword)puVar1,(dword)incoming_message,dVar6);
  json_incoming_message_parser_ = json_parser_init(&jParser,*ppcVar3);
  if (json_incoming_message_parser_ == -1) {
    Report(aErrorSeaconnec_2,(dword)puVar1,(dword)incoming_message,dVar6);
  }
  else {
    puVar4 = read_volatile_4(pPrintCallback);
    json_parser_dump(&jParser,puVar4);
    is_error_ = json_object_get_string(&jParser,json_incoming_message_parser_,aName,p_name_);           [3]
    if ((is_error_ != 0) &&
       (payload_string_ = p_payload_,
       iVar5 = json_object_get_string(&jParser,json_incoming_message_parser_,aPayload,p_payload_),      [4]
       iVar5 != 0)) {
      Report(aSNameS,(dword)puVar1,(dword)p_name_,(dword)payload_string_);
      Report(s_F%s_payload:_%s_2000ed4f + 1,(dword)puVar1,(dword)p_payload_,(dword)payload_string_);
      HandleSeaCloudPayload(p_name_,p_payload_);
    }
    json_parser_deinit(&jParser);
  }
  return;
}

The function only copies at most 0x201 element from the MQTT message. This is guaranteed with the combination of the condition at [1] and the strncpy at [2]. The HandleIncomingSeaCloudMessage function extracts the function name and the payload data respectively at [3] and [4] using the function json_object_get_string.

Here is the function json_object_get_string:

char * json_object_get_string(jsonParser *jParser, jsonObj jObj, char *tagName, char *str)
{
      char 		*cmpStr;
      int   	cmpStrLen = 0;
      jsonString	jString;

      jString = (jsonString)get_object_by_type(jParser, jObj, tagName, JSON_STRING_OBJECT);
      if(jString == JSON_INVALID_OBJECT)
      {
          return NULL;
      }
      else
      {
          cmpStr = jParser-&gt;jsonStream + jParser-&gt;tokenList[jString].start;
          cmpStrLen = jParser-&gt;tokenList[jString].end - jParser-&gt;tokenList[jString].start;
          strncpy(str, cmpStr, cmpStrLen);
          str[cmpStrLen] = '\0';
          return str;
      }
}

This function will fill the str variable with the value corresponding to the key specified in tagName. So, at 3 it will fill str with the value corresponding to the name key, and at [4] with the one corresponding to payload.

CVE-2021-21969 - json payload key value out-of-bound write

The HandleIncomingSeaCloudMessage function uses at [4] the json_object_get_string to populate the p_payload global variable. The p_payload is only 0x100 bytes long, and the total MQTT message could be up to 0x201 bytes. Because the function json_object_get_string will fill str based on the length of the json’s value and not the actual str size, this would result in a possible out-of-bounds write.

CVE-2021-21970 - json name key value out-of-bound write

The HandleIncomingSeaCloudMessage function uses at [3] the json_object_get_string to populate the p_name global variable. The p_name is only 0x80 bytes long, and the total MQTT message could be up to 0x201 bytes. Because the function json_object_get_string will fill str based on the length of the json’s value and not the actual str size, this would result in a possible out-of-bounds write.

Timeline

2021-10-26 - Vendor disclosure
2022-02-01 - Public Release

CVSS2

6.8

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

CVSS3

8.1

Attack Vector

NETWORK

Attack Complexity

HIGH

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

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

EPSS

0.003

Percentile

66.1%

Related for TALOS-2021-1396