remote file name path traversal in curl tool for Windows
Project curl Security Advisory, January 27th 2016 - Permalink
curl does not sanitize colons in a remote file name that is used as the local file name. This may lead to a vulnerability on systems where the colon is a special path character. Currently Windows is the only OS where this vulnerability applies.
curl offers command line options --remote-name (also usable as -O) and --remote-header-name (also usable as -J). When both of those options are used together (-OJ) and the server provides a remote file name for the content, curl will write its output to that server-provided file name, as long as that file does not already exist. If it does exist curl will fail to write.
If both options are used together (-OJ) but the server does not provide a remote file name, or if -O is used without -J, curl will write output to a file name based solely on the remote file name in the URL string provided by the user, regardless of whether or not that file already exists.
In either case curl does not sanitize colons in the file name. As a result in Windows it is possible and unintended behavior for curl to write to a file in the working directory of a drive that is not the current drive (ie outside the current working directory), and also possible to write to a file's alternate data stream.
For example if curl -OJ and the server sends filename=f:foo curl will incorrectly write foo to the working directory for drive F even if drive F isn't the current drive. For a more detailed explanation see the 'MORE BACKGROUND AND EXAMPLE' section towards the end of this advisory.
Though no known exploit is available for this issue, writing one would be undemanding and could be serious depending on the name of the file and where it ends up being written.
This flaw only affects the curl command line tool as this is a feature not present or provided by libcurl.
The Common Vulnerabilities and Exposures (CVE) project has assigned the name CVE-2016-0754 to this issue.
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
In the case of using a remote file name provided by the user (-O without -J), the feature has existed since inception.
In the case of using a remote file name provided by the server (-OJ), the feature was added in 7.20.0 and didn't exist before then.
- Affected versions (-OJ): curl 7.20.0 to and including 7.46.0
- Not affected versions (-OJ): curl < 7.20.0 and curl >= 7.47.0
curl built for Cygwin is partially affected (-O): curl <= 7.47.0. Please refer to the CYGWIN addendum at the end of this advisory. (Added 2016-02-07)
Starting in curl 7.47.0 the curl tool in Windows will replace all colons in a remote file name with underscores. For example if
f:foo::$DATA is the remote file name it will be sanitized as
A patch is available at:
https://curl.se/CVE-2016-0754_v3_curl-7.24.0_to_7.39.0.patch https://curl.se/CVE-2016-0754_v3_curl-7.40.0_to_7.46.0.patch https://curl.se/CVE-2016-0754_v3_curl-7.47.0.patch
The patch also includes two fixes not present in 7.47.1 for accessing paths using the literal path prefix
\\?\ and accessing reserved dos device names without using the device prefix
If you have applied an older version of the patch revert it and then apply v3. There is no patch for curl < 7.24.0, see RECOMMENDATIONS for alternatives.
Exercise judicious use of the -J option. The -J option when combined with -O lets the server choose the file name. Do you trust the server you are using the -J option on? Is your connection to the server vulnerable to a man-in-the-middle attack? Have you enabled location redirects and the server may send you somewhere untrustworthy? In any of these cases, even with this vulnerability fixed know that if you use the -J option it will still be possible for a rogue server to send you the name of a DLL or other file that could possibly be loaded automatically by Windows or some third party software.
We suggest you take one of the following actions immediately, in order of preference:
A - Upgrade curl and libcurl to version 7.47.1.
B - Apply the patch to your version and rebuild.
C - If you cannot do (A) or (B) it is suggested you do not use -J on Windows. If you choose to continue to use -O without -J it is your responsibility to check that the URL you pass does not have a remote file name that could be exploited.
Regardless of which action you take, exercise judicious use of the -J option as described in THE SOLUTION.
It was first reported to the curl project on November 30 2015. We contacted distros@openwall on January 21 2016.
curl 7.47.0 was released on January 27 2016, coordinated with the publication of this advisory.
curl 7.47.1 was released the week of February 8, 2016 to address over-sanitization of an --output path caused by the first revision of the patch for this issue; and additionally to not allow curl built for Cygwin to write outside the current working directory when a backslash is in the remote file name (-O).
Reported and patched by Ray Satiro (Jay).
Thanks a lot!
MORE BACKGROUND AND EXAMPLE
In Windows if a colon is used to specify a drive letter for a path and there is a slash or backslash (hereafter path separator) that proceeds the colon it means start from the root of the drive, but if that slash is omitted it means start from the current working directory of the drive.
- C:\foo => Windows looks for foo in the root directory of drive C.
- C:foo => Windows looks for foo in the working directory of drive C.
A process in Windows on its creation may inherit a list of drives and their working directories from its parent, and one of those is the current working directory.
For example a command prompt is open and has these working directories:
- Drive C, Path \bar\baz\
- Drive D, Path \
- Drive E, Path \qux\ <-- Current
- Drive F, Path \
Assume other drives were not accessed which means they default to their root.
A user running curl from that command prompt would expect that their file will be output to the current working directory, E:\qux\ in this example. However that may not happen if there is a colon in the filename.
curl has a function which will strip the path to get the file name by removing the last path separator and everything that precedes it. In the case of a colon without a path separator that comes after it, it is not removed from the file name.
Following this example:
In the case of -O without -J recall that the filename is parsed from the user- supplied URL, and is written regardless of whether the file already exists.
curl -O http://somewhere/f:foo => curl writes output to f:\foo
curl -O http://somewhere/c:foo => curl writes output to c:\bar\baz\foo
In the case of -O with -J recall that the file name is parsed from the server's "Content-Disposition:" header if one is given (eg
Content-Disposition: attachment; filename=abc) and in that case the file is written only if it does not already exist.
curl -OJ http://somewhere/somefile => Server sends filename=f:foo curl writes output to f:\foo
curl -OJ http://somewhere/somefile => Server sends filename=c:foo curl writes output to c:\bar\baz\foo
(Added 2016-02-07) Since the original publishing of this advisory it has been determined that curl built for Cygwin is partially vulnerable.
By default Cygwin will sanitize colons and other banned filename characters by replacing them with Unicode characters. However Cygwin does not do this for the backslash and in such a case may not map a colon that precedes a backslash to a Unicode character. In curl <= 7.47.0 built for Cygwin it is possible to write outside the current working directory by specifying a remote file name with backslashes.
curl -O 'http://example.com/F:\foo' will save to F:\foo.
curl built for Cygwin is not vulnerable to an (-OJ) rogue server attack, therefore the scope of this vulnerability as it applies to Cygwin is limited to unchecked user input, such as if you have a script that is passing an untrusted URL to curl built for Cygwin.
curl 7.47.1 checks for backslashes for all operating systems: A remote file name is parsed from the URL by removing anything up to and including the last forward slash or back slash of the URL's path segment.