Skip to content

Commit 2bde0e4

Browse files
authored
Merge pull request #163 from todb/mongoose-2905
Add disclosure for CVE-2023-2905
2 parents e43c9aa + a7128bf commit 2bde0e4

File tree

2 files changed

+152
-1
lines changed

2 files changed

+152
-1
lines changed

cve.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ When we publish CVEs, we will tend to use this [template], adjusted to taste.
107107
| [CVE-2023-0666] | 0x00c7 | **Wireshark RTPS Parsing Buffer Overflow** |
108108
| [CVE-2023-0667] | 0x00c7 | **Wireshark MSMMS parsing buffer overflow** |
109109
| [CVE-2023-0668] | 0x00c7 | **Wireshark IEEE-C37.118 parsing buffer overflow** |
110+
| [CVE-2023-2905] | 0x00c8 | **Cesanta Mongoose MQTT Message Parsing Heap Overflow** |
110111

111112
## Reserved CVEs
112113

113114
We've reserved the following CVEs for upcoming publication.
114115

115116
| CVE | Meeting |
116117
| ------------- | --------- |
117-
| CVE-2023-2905 | 0x00c8 |
118118
| CVE-2023-2906 | 0x00c8 |
119119

120120
### Contact
@@ -134,3 +134,4 @@ Vulnerabilities involving other parties must be either (1) presented at a regula
134134
[CVE-2023-0666]: /cves/CVE-2023-0666.html
135135
[CVE-2023-0667]: /cves/CVE-2023-0667.html
136136
[CVE-2023-0668]: /cves/CVE-2023-0668.html
137+
[CVE-2023-2905]: /cves/CVE-2023-2905.html

cves/CVE-2023-2905.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
layout: default
3+
title: cve-template
4+
categories: nav
5+
showinnav: false
6+
---
7+
8+
# CVE-2023-2905: Cesanta Mongoose MQTT Message Parsing Heap Overflow
9+
10+
[AHA!] has discovered an issue with Mongoose from Cesanta, and is publishing this disclosure in accordance with AHA!’s standard [disclosure policy](https://takeonme.org/cve.html) today, on Tuesday, August 8, 2023. [CVE-2023-2905] has been assigned to this issue.
11+
12+
Any questions about this disclosure should be directed to **cve@takeonme.org**.
13+
14+
# Executive Summary
15+
16+
Due to a failure in validating the length of a provided a `MQTT_CMD_PUBLISH` parsed message with a variable length header, the dual-licensed [Cesanta Mongoose](https://github.com/cesanta/mongoose) embeddable web server version 7.10 is susceptible to a heap-based buffer overflow vulnerability in the default configuration. [CVE-2023-2905] appears to be an instance of [CWE-122](https://cwe.mitre.org/data/definitions/122.html). Version 7.9 and prior does not appear to be vulnerable.
17+
18+
# Technical Details
19+
20+
Below is the code used to parse mqtt messages with lines 365-370 being used to ensure that the variable length portion of the buffer is not larger than 4 bytes and breaking out of the loop if `lc & 0x80` evaluates to false (based on the MSB).
21+
22+
src/mqtt.c
23+
```
24+
352 int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version,
25+
353 struct mg_mqtt_message *m) {
26+
354 uint8_t lc = 0, *p, *end;
27+
355 uint32_t n = 0, len_len = 0;
28+
356
29+
357 memset(m, 0, sizeof(*m));
30+
358 m->dgram.ptr = (char *) buf;
31+
359 if (len < 2) return MQTT_INCOMPLETE;
32+
360 m->cmd = (uint8_t) (buf[0] >> 4);
33+
361 m->qos = (buf[0] >> 1) & 3;
34+
362
35+
363 n = len_len = 0;
36+
364 p = (uint8_t *) buf + 1;
37+
365 while ((size_t) (p - buf) < len) {
38+
366 lc = *((uint8_t *) p++);
39+
367 n += (uint32_t) ((lc & 0x7f) << 7 * len_len);
40+
368 len_len++;
41+
369 if (!(lc & 0x80)) break;
42+
370 if (len_len >= 4) return MQTT_MALFORMED;
43+
371 }
44+
```
45+
46+
Then lines 393-406 show the code path to the vulnerable function `decode_variable_length`, containing the remaining to be read mqtt buffer after additions to the `p` pointer on lines 394, 397, 402.
47+
48+
src/mqtt.c
49+
```
50+
393 case MQTT_CMD_PUBLISH: {
51+
394 if (p + 2 > end) return MQTT_MALFORMED;
52+
395 m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
53+
396 m->topic.ptr = (char *) p + 2;
54+
397 p += 2 + m->topic.len;
55+
398 if (p > end) return MQTT_MALFORMED;
56+
399 if (m->qos > 0) {
57+
400 if (p + 2 > end) return MQTT_MALFORMED;
58+
401 m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]);
59+
402 p += 2;
60+
403 }
61+
404 if (p > end) return MQTT_MALFORMED;
62+
405 if (version == 5 && p + 2 < end) {
63+
406 m->props_size = decode_variable_length((char *) p, &len_len);
64+
```
65+
66+
The below shows the buffer from the crash file showing a 10 byte mqtt message with the 8th byte having the MSB set.
67+
68+
```
69+
Thread 1 "fuzzer" hit Breakpoint 7, LLVMFuzzerTestOneInput (data=0xffffb4500790 "5\b", size=10) at test/fuzz.c:38
70+
71+
38 mg_mqtt_parse(data, size, 5, &mm);
72+
(gdb) x/12bx data
73+
0xffffb4500790: 0x35 0x08 0x00 0x01 0x00 0x00 0x5a 0x8a
74+
0xffffb4500798: 0xff 0xff 0x00 0x00
75+
```
76+
77+
This results in a variable length header being detected but only containing 3 bytes, as can be seen below
78+
79+
```
80+
Thread 1 "fuzzer" hit Breakpoint 8, mg_mqtt_parse (buf=<optimized out>, len=<optimized out>, version=<optimized out>, m=<optimized out>) at src/mqtt.c:415
81+
415 m->props_size = decode_variable_length((char *) p, &len_len);
82+
(gdb) x/10x p
83+
0xffffb0b00797: 0x8a 0xff 0xff 0x00 0x00 0x00 0x00 0x00
84+
0xffffb0b0079f: 0x00 0x02
85+
```
86+
87+
And finally, the `decode_variable_length` function code, which contains no bounds checks on the size of the buffer being read.
88+
89+
src/mqtt.c
90+
```
91+
92 static uint32_t decode_variable_length(const char *buf,
92+
93 uint32_t *bytes_consumed) {
93+
94 uint32_t value = 0, multiplier = 1, offset;
94+
95
95+
96 for (offset = 0; offset < 4; offset++) {
96+
97 uint8_t encoded_byte = ((uint8_t *) buf)[offset];
97+
98 value += (encoded_byte & 0x7F) * multiplier;
98+
99 multiplier *= 128;
99+
100
100+
101 if (!(encoded_byte & 0x80)) break;
101+
102 }
102+
103
103+
104 if (bytes_consumed != NULL) *bytes_consumed = offset + 1;
104+
105
105+
106 return value;
106+
107 }
107+
```
108+
109+
This allows for a read primitive of 1-3 bytes from a heap overflow.
110+
111+
# Payload
112+
113+
A base64 encoded blob of the payload needed to trigger the vulnerability can be found below.
114+
115+
```
116+
NQgAAQAAWor//w==
117+
```
118+
119+
120+
# Attacker Value
121+
122+
Cesanta Mongoose is an embedded webserver library commonly used to add web server functionality to devices with vendor provided integrations. According to the project's [README](https://github.com/cesanta/mongoose), "Mongoose is used by hundreds of businesses, from Fortune500 giants like Siemens, Schneider Electric, Broadcom, Bosch, Google, Samsung, Qualcomm, Caterpillar to the small businesses." Because it is an embedded software, often implemented in the context of IOT/ICS (Internet of Things / Industrial Control Systems), its presence may be difficult for affected end-users to audit for.
123+
124+
If an attacker has the capability of sending an MQTT message to the webserver (which would require direct network access to the network hosting the device), that attacker could use the above primitive in a chain to obtain remote code execution on an embedded device. The level of access would depend on the parent process that runs Mongoose. In most IOT/ICS contexts, this would typically result in the total compromise of the webserver, and, if it is not running in a privilege-restricted context, total compromise of the hosting device.
125+
126+
# Remediation
127+
128+
[PR2274](https://github.com/cesanta/mongoose/pull/2274) fixes the issue on the main branch of the open source repository; the vendor has further advised that Mongoose [Version 7.11](https://github.com/cesanta/mongoose/releases/tag/7.11) available for downstream users and implementors addresses the issue.
129+
130+
# Credit
131+
132+
This issue is being disclosed through the AHA! CNA and is credited to: [zenofex](https://mastodon.social/@zenofex) and [WanderingGlitch](https://infosec.exchange/@WanderingGlitch)
133+
134+
# Timeline
135+
136+
* 2023-05-25 (Thu): Initial findings presented at AHA! Meeting 0xffff
137+
* 2023-06-22 (Thu): PoC validated and this disclosure drafted.
138+
* 2023-06-22 (Thu): Disclosed to the vendor via email at support@cesanta.com.
139+
* 2023-06-23 (Fri): Vendor acknowledged the vulnerability.
140+
* 2023-06-27 (Tue): Vendor fixed `master` branch with [PR2274](https://github.com/cesanta/mongoose/pull/2274).
141+
* 2023-08-07 (Mon): Reached out to vendor for a status update.
142+
* 2023-08-08 (Tue): Vendor advised publishing this disclosure of [CVE-2023-2905].
143+
144+
<br/>
145+
146+
----
147+
148+
[CVE-2023-2905]: https://takeonme.org/cves/CVE-2023-2905-YYYY.html
149+
[disclosure policy]: https://takeonme.org/cve.html
150+
[AHA!]: https://takeonme.org/

0 commit comments

Comments
 (0)