Loading HuntDB...

CVE-2020-8177: curl overwrite local file with -J

Medium
C
curl
Submitted None
Reported by snsn

Vulnerability Details

Technical details and impact analysis

Improper Input Validation
## Summary: curl supports the `Content-disposition` header, including the `filename=` option. By design, curl does not allow server-provided local file override by verifying that the `filename=` argument does not exist before opening it. However, the implementation contains 2 minor logical bugs that allow a server to override an arbitrary local file (without path traversal) when running curl with specific command line args (-OJi) This bug can trigger a logical RCE when curl is used from the user's home dir (or other specific directories), by overriding specific files (e.g. ".bashrc"), while keeping the user completely uninformed of the side effects. The 2 bugs are: 1. `curl -iJ` is not supported however `curl -Ji` is available - 2. The standard `Content-disposition` handling flow does not allow opening existing files: https://github.com/curl/curl/blob/master/src/tool_cb_wrt.c#L54, however by using `-OJi` it is possible to reach a flow that overrides a local file with the response headers, without verification: https://github.com/curl/curl/blob/master/src/tool_cb_hdr.c#L196 ## Steps To Reproduce: 1. Return the following http response form a server : ``` HTTP/1.1 200 OK <PAYLOAD> Content-disposition: attachment; filename=".bashrc" ``` Where `<PAYLOAD>` is the bash payload, e.g. `echo pwn` 2. Run `curl -OJi` from the user's home dir **Note that curl falsely claims that `.bashrc` was refused to be overwritten.** ## Supporting Material/References: First bug: ```c case 'i': config->show_headers = toggle; /* show the headers as well in the general output stream */ break; ... case 'J': /* --remote-header-name */ if(config->show_headers) { warnf(global, "--include and --remote-header-name cannot be combined.\n"); return PARAM_BAD_USE; } config->content_disposition = toggle; break; ``` Second bug: ```c if(filename) { if(outs->stream) { int rc; /* already opened and possibly written to */ if(outs->fopened) fclose(outs->stream); outs->stream = NULL; /* rename the initial file name to the new file name */ rc = rename(outs->filename, filename); if(rc != 0) { warnf(per->config->global, "Failed to rename %s -> %s: %s\n", outs->filename, filename, strerror(errno)); } if(outs->alloc_filename) Curl_safefree(outs->filename); if(rc != 0) { free(filename); return failure; } } ``` ## Impact Local file override without path traversal, possibly leading to an RCE or loss of data.

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Bounty

$700.00

Submitted

Weakness

Improper Input Validation