Headline
CVE-2022-41991: TALOS-2022-1639 || Cisco Talos Intelligence Group
A heap-based buffer overflow vulnerability exists in the m2m DELETE_FILE cmd functionality of Siretta QUARTZ-GOLD G5.0.1.5-210720-141020. A specially-crafted network request can lead to a heap buffer overflow. An attacker can send a network request to trigger this vulnerability.
SUMMARY
A heap-based buffer overflow vulnerability exists in the m2m DELETE_FILE cmd functionality of Siretta QUARTZ-GOLD G5.0.1.5-210720-141020. A specially-crafted network request can lead to a heap buffer overflow. An attacker can send a network 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.
Siretta QUARTZ-GOLD G5.0.1.5-210720-141020
PRODUCT URLS
QUARTZ-GOLD - https://www.siretta.com/products/industrial-routers/4g-lte-router/gigabit-ethernet-small-footprint-lte-router-eu/
CVSSv3 SCORE
9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE
CWE-122 - Heap-based Buffer Overflow
DETAILS
The Siretta QUARTZ-GOLD is an industrial router with several functionalities and services, such as: SSH, UPNP, VPN, SNMP and many others.
The QUARTZ-GOLD offers a feature called M2M. When enabled, the device will execute the m2m binary and offer different network services. One of the services the m2m binary offers handles several commands. To communicate with this service the client must send a specific UDP packet format.
Following is the portion of m2m binary that manages the DELETE_FILE command:
[...]
cmdid_provided_LB = UDP_data_buff.cmd_id >> 8;
if (cmdid_provided == 0x15) {
syslog(5,"M2M Command(%02x) DELETE_FILE!!!",0x15);
m2m_UDP_packet_resp.cmd_id._0_1_ = 0x80;
m2m_UDP_packet_resp.cmd_id._1_1_ = cmdid_provided_LB;
[... set base_folder variable ...]
base_folder_length = strlen(base_folder);
for (current_entry_off = 0; current_entry_off < (actual_data_len_recv - 0x22);
current_entry_off = current_entry_off + __bswap_16(previous_data_len)){
current_data_len = __bswap_16(*(UDP_data_buff.entries[0].data_len + current_entry_off));
if ((( __bswap_16(*(UDP_data_buff.fix_word + data_idx)) != 0x12)) ||
(((actual_data_len_recv - 0x22) - current_entry_off) < current_data_len) ||
(command_string = calloc(current_data_len + base_folder_length + 0xc,1),
command_string == 0x0)) { [1]
[... invalid state ...]
}
sprintf(command_string,"rm -rf %s/%s &",base_folder,&UDP_data_buff.entries[0].data + current_entry_off
); [2]
syslog(6,"Deleting file :%s",command_string + 7);
system(command_string);
free(command_string);
previous_data_len = *(UDP_data_buff.entries[0].data_len + current_entry_off); [3]
[...]
Following whe will briefly explain the packet composition for this command:
struct M2M_data_entry{
uint16_t fix_word;
uint16_t data_len;
char data[];
};
struct M2M_packet{
uint16_t packet_len;
uint16_t cmd_id;
uint32_t pkd_id;
uint16_t version;
M2M_data_entry entries[];
};
The UDP packet received, which can contain at most 0x251c bytes, is casted to an M2M_packet. This is a variable length structure. Indeed, inside of it there is an array of M2M_data_entry structure that is a variable length struct. To seek the various entries the variable current_entry_off is used. It starts with value 0 and then, at [4], the value M2M_data_entry.data_len of the just-parsed entry is added to seek, in the next loop, the next entry.
The DELETE_FILE command will execute the command rm -rf <base_folder>/<M2M_data_entry.data> & for each entry in the UDP M2M_packet packet it received.
At [1] several checks are performed. One related to the entry size is particular interesting: (((actual_data_len_recv - 0x22) - current_entry_off) < current_data_len) where actual_data_len_recv is the total size of the UDP packet that the service received, and current_data_len is the current data entry length. Basically, this checks if the total size of the received packet minus the header (0x22 bytes) minus the current_entry_off is lower than the current_data_len. If true, the packet is invalid; otherwise a string is allocated.
The string is allocated as follow: calloc(current_data_len + base_folder_length + 0xc,1). It takes into account the base_folder length, the M2M_data_entry.data_len length of the current entry and the other characters in the format string.
The execution will reach [2] and compose the command that will then be executed. The problem is that the allocation takes into account the size provided, but then the composition of the string will use the string until the first null byte. So if the provided size is lower than the actual M2M_data_entry.data string size, a heap-based buffer overflow would occur.
Crash Information
──── registers ────
$r0 : 0x00093ff8 → 0x41414141 ("AAAA"?)
$r1 : 0x7ee94168 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$r2 : 0x14d
$r3 : 0x41414141 ("AAAA"?)
$r4 : 0x41414141 ("AAAA"?)
$r5 : 0x41414141 ("AAAA"?)
$r6 : 0x7ee932b2 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$r7 : 0x1000
$r8 : 0x0
$r9 : 0x7ee931c8 → 0x7e0000d0
$r10 : 0xd
$r11 : 0x0
$r12 : 0x41414141 ("AAAA"?)
$sp : 0x7ee93018 → 0x7ee931c8 → 0x7e0000d0
$lr : 0x41414141 ("AAAA"?)
$pc : 0x2acb5bfc → stmia r0!, {r3, r4, r5, r12}
$cpsr: [negative zero CARRY overflow interrupt fast thumb]
──── stack ────
0x7ee93018│+0x0000: 0x7ee931c8 → 0x7e0000d0 ← $sp
0x7ee9301c│+0x0004: 0x00001000
0x7ee93020│+0x0008: 0x00093155 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x7ee93024│+0x000c: 0x2acaf35c → <__stdio_fwrite+72> ldr r3, [r4, #16]
0x7ee93028│+0x0010: 0x00001000
0x7ee9302c│+0x0014: 0x0000000b
0x7ee93030│+0x0018: 0x7ee932b2 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
0x7ee93034│+0x001c: 0x00000000
──── code:arm:ARM ────
0x2acb5bf0 orr r5, r5, r12, lsl #24
0x2acb5bf4 lsr r12, r12, #8
0x2acb5bf8 orr r12, r12, lr, lsl #24
→ 0x2acb5bfc stmia r0!, {r3, r4, r5, r12}
0x2acb5c00 subs r2, r2, #16
0x2acb5c04 bge 0x2acb5bd8
0x2acb5c08 pop {r4, r5}
0x2acb5c0c adds r2, r2, #12
0x2acb5c10 blt 0x2acb5c2c
──── threads ────
[#0] Id 1, Name: "m2m", stopped 0x2acb5bfc in ?? (), reason: SIGSEGV
──── trace ────
[#0] 0x2acb5bfc → stmia r0!, {r3, r4, r5, r12}
TIMELINE
2022-10-14 - Initial Vendor Contact
2022-10-20 - Vendor Disclosure
2022-11-24 - Vendor Patch Release
2023-01-26 - Public Release
Discovered by Francesco Benvenuto of Cisco Talos.
Related news
Given the privileged position these devices occupy on the networks they serve, they are prime targets for attackers, so their security posture is of paramount importance.
Francesco Benvenuto of Cisco Talos discovered these vulnerabilities. Cisco Talos recently discovered several vulnerabilities in the Siretta Quartz-Gold router. Talos also discovered vulnerabilities in FreshTomato while investigating the Siretta router. The Siretta Quartz-Gold is an industrial cellular router with several features and services, such as: SSH, UPNP, VPN, SNMP and