Lucene search

K
hackeroneZ2_H1:2604391
HistoryJul 16, 2024 - 2:07 a.m.

curl: CVE-2024-6874: macidn punycode buffer overread

2024-07-1602:07:09
z2_
hackerone.com
33
cve-2024-6874
buffer overread
libcurl
macidn
punycode
url
stack-buffer
uidnainfo
buffer overflow
exploitation

CVSS3

4.3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

LOW

Integrity Impact

NONE

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

AI Score

6.5

Confidence

High

EPSS

0.001

Percentile

35.1%

libcurl at commit 58772b0e082eda333e0a5fc8fb0bc7f17a3cd99c contains a stack-buffer overread in lib/idn.c:75 that can be triggered when the host of a URL is converted to punycode.

The root cause of the bug is in the function mac_idn_to_ascii():

static CURLcode mac_idn_to_ascii(const char *in, char **out)
{
    // --- snip ---
    
    UIDNAInfo info = UIDNA_INFO_INITIALIZER;
    char buffer[256] = {0};
    (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
        sizeof(buffer), &info, &err);
    uidna_close(idna);
    if(U_FAILURE(err)) {
        return CURLE_URL_MALFORMAT;
    }
    else {
        *out = strdup(buffer);
        if(*out)
        return CURLE_OK;
        else
        return CURLE_OUT_OF_MEMORY;
    }
    
    // --- snip ---
}

buffer is supposed to hold the punycode-encoded version of in as a NUL-terminated string. However
the implementation of uidna_nameToASCII_UTF8() leaves the output buffer unterminated when the length of the encoded output is equal to
the capacity of the output buffer (source).
This leaves buffer without a terminating NUL-byte and the subsequent call to strdup(buffer) includes bytes beyond buffer.

PoC

Consider the following dummy application that takes a URL as an argument and prints its punycode-encoded version:

int main (int argc, char** argv) {
    CURLU* url = curl_url();
    curl_url_set(url, CURLUPART_URL, argv[1], 0);
    
    char* encoded_url;
    curl_url_get(url, CURLUPART_URL, &encoded_url, CURLU_PUNYCODE);
    
    printf("%s\n", encoded_url);
}

Then

./dummy "https://ââââââ-À-üxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxâââââââââââââââââüâÀüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüâââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââxx"

results in the over-read:

==77491==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7e649e109750 at pc 0x5852e492c7b5 bp 0x7ffec1daa250 sp 0x7ffec1da9a10
READ of size 257 at 0x7e649e109750 thread T0
    #0 0x5852e492c7b4 in strlen.part.0 asan_interceptors.cpp.o
    #1 0x5852e4a1bf48 in curl_dbg_strdup curl/lib/memdebug.c:198:9
    #2 0x5852e4a43e13 in mac_idn_to_ascii curl/lib/idn.c:75:14
    #3 0x5852e4a4331f in idn_decode curl/lib/idn.c:244:12
    #4 0x5852e4a43158 in Curl_idn_decode curl/lib/idn.c:274:21
    #5 0x5852e4a28c6b in curl_url_get curl/lib/urlapi.c:1582:29
    #6 0x5852e4a196ec in main dummy.c:6:4

Note: In order to trigger the vulnerability on a non-apple device, compile curl with -DUSE_APPLE_IDN -licuuc.

Exploitation Scenario

Exploitation of this bug has three strict requirements:

  1. An attacker has control over the URL in curl_url_set()
  2. The application manually calls curl_url_get() with CURLU_PUNYCODE and the attacker-provided URL
  3. The resulting URL is mirrored back to the attacker or used to make a transfer

For any application that fulfills these three requirements this vulnerability can be used to leak pointers in the stackframe of mac_idn_to_ascii().
Depending on what is adjacent to buffer the following information could be leaked:

  • Base address of the stack when the framepointer follows buffer
  • Base address of the application/libcurl when the return address follows buffer (-fomit-frame-pointer)
  • Base address of the heap if the variable UIDNA* idna follows the buffer

Any of these information leaks bring down exploit mitigations like ASLR or PIE and contribute largely to successful exploitation of other memory corruption vulnerabilities.

Patch

I suggest the following patch, inspired by PHP’s handling of uidna_nameToASCII_UTF8():

diff --git a/lib/idn.c b/lib/idn.c
index 8d6bfe7ce..b66e04a64 100644
--- a/lib/idn.c
+++ b/lib/idn.c
@@ -65,13 +65,14 @@ static CURLcode mac_idn_to_ascii(const char *in, char **out)
   else {
     UIDNAInfo info = UIDNA_INFO_INITIALIZER;
     char buffer[256] = {0};
-    (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
+    int n = uidna_nameToASCII_UTF8(idna, in, -1, buffer,
       sizeof(buffer), &info, &err);
     uidna_close(idna);
-    if(U_FAILURE(err)) {
+    if(U_FAILURE(err) || n < 0 || n >= sizeof(buffer)) {
       return CURLE_URL_MALFORMAT;
     }
     else {
+      buffer[n] = 0;
       *out = strdup(buffer);
       if(*out)
         return CURLE_OK;

Impact

The vulnerability

  • does not affect the majority of curl installations
  • has strict requirements to work
  • even then only leads to an information leak and nothing worse

However, leaking memory content is still security-relevant so I suggest severity β€œLow”.

CVSS3

4.3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

LOW

Integrity Impact

NONE

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N

AI Score

6.5

Confidence

High

EPSS

0.001

Percentile

35.1%