Vulnerabilities > CVE-2017-2892 - Integer Overflow or Wraparound vulnerability in Cesanta Mongoose 6.8

047910
CVSS 7.5 - HIGH
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
PARTIAL
Integrity impact
PARTIAL
Availability impact
PARTIAL
network
low complexity
cesanta
CWE-190

Summary

An exploitable arbitrary memory read vulnerability exists in the MQTT packet parsing functionality of Cesanta Mongoose 6.8. A specially crafted MQTT packet can cause an arbitrary out-of-bounds memory read and write potentially resulting in information disclosure, denial of service and remote code execution. An attacker needs to send a specially crafted MQTT packet over the network to trigger this vulnerability.

Vulnerable Configurations

Part Description Count
Application
Cesanta
1

Common Weakness Enumeration (CWE)

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Forced Integer Overflow
    This attack forces an integer variable to go out of range. The integer variable is often used as an offset such as size of memory allocation or similarly. The attacker would typically control the value of such variable and try to get it out of range. For instance the integer in question is incremented past the maximum possible value, it may wrap to become a very small, or negative number, therefore providing a very incorrect value which can lead to unexpected behavior. At worst the attacker can execute arbitrary code.

Seebug

bulletinFamilyexploit
description### Summary An exploitable arbitrary memory read vulnerability exists in the MQTT packet parsing functionality of Cesanta Mongoose 6.8. A specially crafted MQTT packet can cause an arbitrary out-of-bounds memory read and write potentially resulting in information disclosure, denial of service and remote code execution. An attacker needs to send a specially crafted MQTT packet over network to trigger this vulnerability. ### Tested Versions Cesanta Mongoose 6.8 ### Product URLs https://cesanta.com/ ### 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-190: Integer Overflow or Wraparound ### Details Mongoose is a monolithic library implementing a number of networking protocols, including HTTP, MQTT, MDNS and others. It is designed with embedded devices in mind and as such is used in many IoT devices and runs on virtually all platforms. While parsing an MQTT packet with variable length header no check is performed to assure the calculated payload length corresponds to the actual received packet. An arbitrary length is used in pointer arithmetic leading to arbitrary memory access. Variable payload length in mqtt packet is encoded by 7 bit fields with 8th bit in a byte being used as continuation bit. The following code from the `parse_mqtt` function decodes this: ``` /* decode mqtt variable length */ do len += (*p & 127) << 7 * (p - &io->buf[1]); while ((*p++ & 128) != 0 && ((size_t)(p - io->buf) <= io->len)); ``` In the above code, no check is performed on the calculated `len` value which can be arbitrarily large. By the MQTT standard, the largest MQTT packet can be at most 256 megabytes. Further, a following check is performed: ``` end = p + len; if (end > io->buf + io->len + 1) return -1; ``` In the above code, `end` should point to the end of message, and the `if` tries to check if it’s in bounds of the buffer, but since the check is comparing pointers, an integer overflow can cause `end` to wrap around and point before the start of message buffer, while still having huge `len` value calculated before. This can cause further memory corruption down the line when actually handling the commands sent in the packet. For example, this can be exploited by sending a “PUBLISH” command, which ends up notifying all the clients subscribed to a certain topic. Still in the `parse_mqtt` function we see: ``` case MG_MQTT_CMD_PUBLISH: { if (MG_MQTT_GET_QOS(header) > 0) mm->message_id = getu16(p); p += 2; p = scanto(p, &mm->topic); mm->payload.p = p; mm->payload.len = end - p; break; ``` The above code deals with the “PUBLISH” command and uses the `end` pointer and `p` to calculate the length, due to the previous integer overflow , `end` can point to before `p` leading to a large `payload.len` value which is later used when sending the notification to subscribed clients. With precise memory layout control, this can be abused to cause an arbitrary write which could lead to remote code execution. On the other hand, there is a potential to abuse this vulnerability to leak large amount of data from the process as the overflown value is used when sending data to clients. The vulnerability can be triggered by sending the supplied proof of concept packet to sample `mqtt_broker` application supplied with the library. It should be noted that depending on memory layout, the proof of concept packet might not crash the application, but it does trigger the bug. ### Crash Information ``` Valgrind output: ==118470== Memcheck, a memory error detector ==118470== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==118470== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==118470== Command: ../../../vanilla/mongoose/examples/mqtt_broker/mqtt_broker ==118470== MQTT broker started on 0.0.0.0:8113 ffff==118470== Invalid read of size 1 ==118470== at 0x4C3236C: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403E95: mbuf_insert (mongoose.c:1073) ==118470== by 0x40EB8D: mg_mqtt_prepend_header (mongoose.c:9824) ==118470== by 0x40ECCA: mg_mqtt_publish (mongoose.c:9843) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== by 0x40A712: mg_handle_tcp_read (mongoose.c:3376) ==118470== by 0x40AC8A: mg_mgr_handle_conn (mongoose.c:3501) ==118470== Address 0x5ce0796 is 6 bytes inside a block of size 10 free'd ==118470== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x4C2FDB7: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40ECA4: mg_mqtt_publish (mongoose.c:9841) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== Block was alloc'd at ==118470== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40EC51: mg_mqtt_publish (mongoose.c:9836) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== ==118470== Invalid write of size 1 ==118470== at 0x4C32372: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403E95: mbuf_insert (mongoose.c:1073) ==118470== by 0x40EB8D: mg_mqtt_prepend_header (mongoose.c:9824) ==118470== by 0x40ECCA: mg_mqtt_publish (mongoose.c:9843) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== by 0x40A712: mg_handle_tcp_read (mongoose.c:3376) ==118470== by 0x40AC8A: mg_mgr_handle_conn (mongoose.c:3501) ==118470== Address 0x5ce0798 is 8 bytes inside a block of size 10 free'd ==118470== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x4C2FDB7: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40ECA4: mg_mqtt_publish (mongoose.c:9841) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== Block was alloc'd at ==118470== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40EC51: mg_mqtt_publish (mongoose.c:9836) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== ==118470== Invalid write of size 2 ==118470== at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403EBE: mbuf_insert (mongoose.c:1075) ==118470== by 0x40EB8D: mg_mqtt_prepend_header (mongoose.c:9824) ==118470== by 0x40ECCA: mg_mqtt_publish (mongoose.c:9843) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== by 0x40A712: mg_handle_tcp_read (mongoose.c:3376) ==118470== by 0x40AC8A: mg_mgr_handle_conn (mongoose.c:3501) ==118470== Address 0x5ce0790 is 0 bytes inside a block of size 10 free'd ==118470== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x4C2FDB7: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40ECA4: mg_mqtt_publish (mongoose.c:9841) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== Block was alloc'd at ==118470== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40EC51: mg_mqtt_publish (mongoose.c:9836) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ==118470== ==118470== Syscall param socketcall.sendto(msg) points to unaddressable byte(s) ==118470== at 0x54F799D: send (send.c:26) ==118470== by 0x40A40E: mg_write_to_socket (mongoose.c:3316) ==118470== by 0x40ACC2: mg_mgr_handle_conn (mongoose.c:3508) ==118470== by 0x40B6C9: mg_socket_if_poll (mongoose.c:3694) ==118470== by 0x407935: mg_mgr_poll (mongoose.c:2232) ==118470== by 0x4022A6: main (mqtt_broker.c:43) ==118470== Address 0x5ce0790 is 0 bytes inside a block of size 10 free'd ==118470== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x4C2FDB7: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40ECA4: mg_mqtt_publish (mongoose.c:9841) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== Block was alloc'd at ==118470== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==118470== by 0x403F74: mbuf_insert (mongoose.c:1080) ==118470== by 0x404055: mbuf_append (mongoose.c:1096) ==118470== by 0x409E83: mg_socket_if_tcp_send (mongoose.c:3167) ==118470== by 0x408158: mg_send (mongoose.c:2463) ==118470== by 0x40EC51: mg_mqtt_publish (mongoose.c:9836) ==118470== by 0x40F9A2: mg_mqtt_broker_handle_publish (mongoose.c:10104) ==118470== by 0x40FAF4: mg_mqtt_broker (mongoose.c:10136) ==118470== by 0x40E648: mqtt_handler (mongoose.c:9712) ==118470== by 0x4071B6: mg_call (mongoose.c:2051) ==118470== by 0x408362: mg_recv_common (mongoose.c:2505) ==118470== by 0x408393: mg_if_recv_tcp_cb (mongoose.c:2509) ``` ### Timeline * 2017-08-30 - Vendor Disclosure * 2017-10-31 - Public Release
idSSV:96835
last seen2017-11-19
modified2017-11-09
published2017-11-09
reporterRoot
titleCesanta Mongoose MQTT Payload Length Remote Code Execution(CVE-2017-2892)

Talos

idTALOS-2017-0399
last seen2019-05-29
published2017-10-31
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0399
titleCesanta Mongoose MQTT Payload Length Remote Code Execution