HexBrain

curl · Report #2236133

CVE-2023-46219: HSTS long file name clears contents

Validstatus
lowseverity
27upvotes
8 Dec 2023disclosed

How it was found

Summary:

I've discovered a significant security flaw in cURL's file handling, particularly affecting the HSTS (HTTP Strict Transport Security) database when handling long filenames.

Vulnerability Description

cURL erroneously creates temporary files with names potentially exceeding the filesystem's maximum filename length (typically 255 bytes for ext4, etc.). If a filename used in the HSTS database is longer than 243 bytes (255 bytes minus 9 for the random suffix and 4 for the '.tmp' extension), an unexpected security error occurs, leading to the HSTS database being overwritten.

Affected Code

File: curl/lib/fopen.c

CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, FILE **fh, char **tempname) {
  CURLcode result = CURLE_WRITE_ERROR;
  unsigned char randsuffix[9]; // Random suffix generation <=======
  ...
  tempstore = aprintf("%s.%s.tmp", filename, randsuffix); // Temporary filename creation <=======
  if(!tempstore) {
    result = CURLE_OUT_OF_MEMORY;
    goto fail;
  }
}

File: curl/lib/hsts.c

result = Curl_fopen(data, file, &out, &tempstore);
...
if(!result && tempstore && Curl_rename(tempstore, file)) // Attempt to rename temp file to actual file <======
  result = CURLE_WRITE_ERROR;

if(result && tempstore)
  unlink(tempstore); // Remove temp file if error occurs

Steps To Reproduce:

First let’s check the correct behaviour. I’ve created simple hsts file for cxsecurity.com domain

$ cat ok.hsts.txt
# Your HSTS cache. https://curl.se/docs/hsts.html
# This file was generated by libcurl! Edit at your own risk.
cxsecurity.com "20241031 12:12:12"
                                                                                                                                                  
$ curl --hsts ok.hsts.txt http://cxsecurity.com -v
* Switched from HTTP to HTTPS due to HSTS => https://cxsecurity.com/
*   Trying 188.114.97.1:443...
…


So works great. Let’s try update the database and add Facebook

$ curl --hsts ok.hsts.txt https://facebook.com -v 
*   Trying 31…
* Connected to facebook.com …
…
< Strict-Transport-Security: max-age=15552000; preload
…
                                                                                                                                                                  
$ cat ok.hsts.txt                                
# Your HSTS cache. https://curl.se/docs/hsts.html
# This file was generated by libcurl! Edit at your own risk.
cxsecurity.com "20241031 12:12:12"
facebook.com "20240430 00:11:44"

The file has been successfully updated. 


Let’s see what will happen if the user will define filename longer that 243 (let’s use the content from previous file)

$ cp ok.hsts.txt hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt 

Let’s validate the file size as it will be important to prove security issue.

$ ls -la hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt          
-rw-r--r-- 1 cx cx 179 Nov  1 19:14 hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt

we have 179 bytes.

If the user will use such file, curl will reset the content due to improper rename action

$ cat hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt
# Your HSTS cache. https://curl.se/docs/hsts.html
# This file was generated by libcurl! Edit at your own risk.
cxsecurity.com "20241031 12:12:12"
facebook.com "20240430 00:11:44"

$ curl --hsts hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt https://facebook.com -v 
*   Trying …
* Connected to facebook.com …
…

Let’s check the file size again..

$ ls -la hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt 
-rw-r--r-- 1 cx cx 0 Nov  1 19:17 hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.hsts.txt

Now the HSTS database is empty!

Tested on

#curl 8.4.1-DEV (Linux) libcurl/8.4.1-DEV OpenSSL/3.0.10 zlib/1.2.13

Possible solutions:

  • Check the max length of supported file and create shortcut eg by using “~”
  • Create random short file name at /tmp/

I believe addressing this vulnerability is crucial for maintaining the integrity of the HSTS database in cURL, and I'm keen to assist in any way possible to resolve this issue. Looking forward to your response.

Impact

Bypass HSTS

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original