Lucene search

K
hackeroneZ2_H1:1269242
HistoryJul 19, 2021 - 6:20 p.m.

curl: CVE-2021-22945: UAF and double-free in MQTT sending

2021-07-1918:20:56
z2_
hackerone.com
102

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%

Vulnerability Description

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

  1. Sending the metadata of the freed chunk over the network via mqtt_send
  2. Freeing mq->sendleftovers multiple times

mq->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:

  1. Supply an mqtt:// URL to curl
  2. Have some successfull transmissions with mqtt_send
  3. At some point have an unsuccessfull transmission such that not all bytes of the write-buffer can be sent.
    This causes mq->sendleftovers and mq->nsend to be set.
  4. Have another invocation of mqtt_doing. The code mentioned above gets executed. mq->sendleftovers gets freed.
    If mqtt_send could send all remaining bytes successfully mq->sendleftovers and mq->nsend don’t get reset.
  5. Have another invocation of mqtt_doing. Since mq->nsend didn’t change curl tries to send the leftover bytes again, triggering the vulnerabilities

How to reproduce the bug

  1. Checkout tag curl-7_77_0 in the curl repository
  2. Apply the following patch that artificially creates a scenario as described above:
diff --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;

  1. Rebuild curl
  2. Start a simple netcat session with: nc -lp 5678
  3. Invoke curl with: 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.

Impact

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%