CVE-2022-33938
A format string injection vulnerability exists in the ghome_process_control_packet functionality of Abode Systems, Inc. iota All-In-One Security Kit 6.9Z and 6.9X. A specially-crafted XCMD can lead to memory corruption, information disclosure and denial of service. An attacker can send a malicious XML payload to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
abode systems, inc. iota All-In-One Security Kit 6.9X
abode systems, inc. iota All-In-One Security Kit 6.9Z
iota All-In-One Security Kit - https://goabode.com/product/iota-security-kit
8.2 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H
CWE-134 - Use of Externally-Controlled Format String
The iota All-In-One Security Kit is a home security gateway containing an HD camera, infrared motion detection sensor, Ethernet, Wi-Fi and Cellular connectivity. The iota gateway orchestrates communications between sensors (cameras, door and window alarms, motion detectors, etc.) distributed on the LAN and the Abode cloud. Users of the iota can communicate with the device through mobile application or web application.
The iota
device generates a significant volume of diagnostic logs, which it displays on its read-only physical UART console. These logs are formatted and put on the serial line inside of a function (located at offset 0xA3270
) which we refer to simply as log
. The log
function operates as a wrapper to vsnprintf
and puts
with the added functionality of prefixing supplied log messages with severity and task strings. The log
function is variadic and crafts the final log message by passing the supplied format
and variadic arguments to vsnprintf
. If an attacker can inject content into the format
parameter, they could potentially leak stack memory and write arbitrary memory.
/* Examples:
log(6, 13, "Initialized SSL"); -> [DBG!][NET ]Initialized SSL
log(3, 13, "SSL init error: %d", error); -> [ERR!][NET ]SSL init error: {error}
*/
void log(unsigned int severity, unsigned int task, const char *format, ...)
{
char log_buffer[520];
va_list var_args;
va_start(var_args, format);
if ( severity <= g_LOG_LEVEL && ((g_TASK_LOGGING_ENABLED_BITFIELD >> task) & 1) != 0 )
{
// Prefix the message with the SEVERITY tag
if ( severity >= MAX_SEVERITY )
severity = MAX_SEVERITY;
memcpy(log_buffer, g_SEVERITY_PREFIX[severity], 6u);
// Prefix the message with the TASK tag
if ( task >= MAX_TASK )
task = MAX_TASK;
memcpy(&log_buffer[6], g_TASK_PREFIX[task], 0xCu);
// Populate remainder of message with format and var_args
vsnprintf(&log_buffer[12], 499u, format, var_args);
// Put crafted message on to UART
puts(log_buffer);
}
}
It is important to note that all output from format string injections stemming from misuse of the log
function will only be available to a physically present attacker who has partially disassembled the device and connected to the UART console.
This vulnerable instance of the log
function occurs within the ghome_process_control_packet
function located at offset 0x1D27B0
in the hpgw
binary included in firmware version 6.9Z. An annotated decompilation of this function is included, for reference, below.
int __fastcall ghome_process_control_packet(
ghome_struct_t ghome_packet,
const struct sockaddr addr,
socklen_t addr_len)
{
char *payload;
int sock_fd;
char *cmd_offset;
int result;
char *host;
const char *v8;
const char *v9;
xstrbuf_t xcmd_result;
char cmd[64];
char id[64];
char log_msg[280];
payload = ghome_packet.payload;
ghome_packet.payload[ghome_packet.payload_len] = 0;
sock_fd = ghome_packet.sock_fd;
log(7u, 0x10u, "GHome recv ctrl len=%d\n%s", ghome_packet.payload_len, ghome_packet.payload);
cmd_offset = strstr(payload, "<cmd");
memset(cmd, 0, sizeof(cmd));
memset(id, 0, sizeof(id));
result = (int)cmd_offset;
if ( cmd_offset )
{
// [1] Extract the `a=` and `id=` fields from the GHOME packet into the `cmd` and `id` variables
xml_fetch_value(cmd_offset, "a=", cmd);
xml_fetch_value(cmd_offset, "id=", id);
if ( !strcmp(id, g_PREV_ID) )
{
return 1;
}
else
{
strncpy_0(g_PREV_ID, id, 63);
log(7u, 0x10u, "\x1B[33mGHome cmd=%s, id=%s\x1B[0m", cmd, id);
memset(log_msg, 0, 0x100u);
xstrbuf(&xcmd_result);
xcmd_run(1, payload, 0, &xcmd_result);
host = inet_ntoa(*(struct in_addr *)&addr.sa_data[2]);
// [2] Construct a log message using the attacker-supplied `cmd` and `id` variables
snprintf(
log_msg,
0xFFu,
"reply '%s' id=%s to %s:%d",
cmd,
id,
host,
(unsigned __int16)(*(_WORD *)addr.sa_data << 8) | (unsigned __int16)(unsigned __int8)addr.sa_data[1]);
// [3] Make the vulnerable call to `log` passing the `log_msg` variable as the `format` parameter
log(7u, 0x10u, log_msg);
...
This function is called on every UDP payload received on port 55050. The function expects that the payload will be an XML formatted payload, though it is not particularly strict in its parsing. At [1]
the function parses out the a
and id
fields of the cmd
tag and uses them at [2]
to craft a log message. After the attacker-supplied values have been injected into the log message buffer, the buffer is used as the format
parameter of the log
function. Supplying a cmd
tag with the a
and id
attributes set to %x.%x.%x.%x.%x.%x.%x.%x
will result in the following log message:
[DBG ][FIND]reply '714be54c.714be4b8.714bf958.e6ab.0.0.482a40.200' id=102.252e7825.78252e78.2e78252e.252e7825.78252e78.78252e.0.0.0 to 10.1.1.207:59051
2022-07-20 - Vendor Disclosure
2022-09-19 - Vendor Patch Release
2022-10-20 - Public Release
Discovered by Matt Wiseman of Cisco Talos.