9.1 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
NONE
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H
5.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
NONE
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:N/A:P
0.003 Low
EPSS
Percentile
63.8%
libcurl version 7.77.0 has a Use-After-Free and a Double-Free in lib/mqtt.c
in the function mqtt_doing
on lines 556 - 563:
if(mq->nsend) {
/* send the remainder of an outgoing packet */
char *ptr = mq->sendleftovers;
result = mqtt_send(data, mq->sendleftovers, mq->nsend);
free(ptr);
if(result)
return result;
}
As can be seen in the code above mq->sendleftovers
gets freed in line 560 but not set to NULL
. If mqtt_doing
gets called repeatedly and the values of mq->nsend
and mq->sendleftovers
don’t change this can result in
mqtt_send
mq->sendleftovers
multiple timesmq->nsend
and mq->sendleftovers
get set in the function mqtt_send
if Curl_write
cannot send all bytes in the write-buffer at once. This can e.g. happen if write()
returns EAGAIN
or EWOULDBLOCK
. Then Curl_write
sets the number of written bytes to 0
and returns CURLE_OK
.
This can trigger the vulnerabilities as follows:
mqtt://
URL to curlmqtt_send
mq->sendleftovers
and mq->nsend
to be set.mqtt_doing
. The code mentioned above gets executed. mq->sendleftovers
gets freed.mqtt_send
could send all remaining bytes successfully mq->sendleftovers
and mq->nsend
don’t get reset.mqtt_doing
. Since mq->nsend
didn’t change curl tries to send the leftover bytes again, triggering the vulnerabilitiescurl-7_77_0
in the curl repositorydiff --git a/lib/sendf.c b/lib/sendf.c
index e41bb805f..773d4b5b6 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -294,6 +294,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
* If the write would block (CURLE_AGAIN), we return CURLE_OK and
* (*written == 0). Otherwise we return regular CURLcode value.
*/
+static int CUSTOM_blocked = 0;
CURLcode Curl_write(struct Curl_easy *data,
curl_socket_t sockfd,
const void *mem,
@@ -322,8 +323,13 @@ CURLcode Curl_write(struct Curl_easy *data,
}
#endif
bytes_written = conn->send[num](data, num, mem, len, &result);
+ if(!CUSTOM_blocked) {
+ bytes_written = 0;
+ CUSTOM_blocked = 1;
+ }
*written = bytes_written;
+
if(bytes_written >= 0)
/* we completely ignore the curlcode value when subzero is not returned */
return CURLE_OK;
nc -lp 5678
curl mqtt://127.0.0.1:5678/
The output:
free(): double free detected in tcache 2
[1] 199104 abort (core dumped) ./curl mqtt://127.0.0.1:5678
And in the terminal where netcat was launched it can be seen
that the content of the freed heap chunk was sent.
Since double frees of tcache chunks are not detected until glibc version 2.29
this vulnerability is perfectly exploitable for operationg systems using an older
glibc. Causing write()
to return EAGAIN
is more difficult but not impossible
to manage, e.g. this can always be the case if the peer is not reading as fast as
the curl client is writing (source).
At minimum this can be used to leak heap metadata which can help in exploitation.
9.1 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
NONE
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H
5.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
NONE
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:N/A:P
0.003 Low
EPSS
Percentile
63.8%