curl · Report #4127756
urlapi: CURLUPART_HOST accepts text after an IPv6 zone ip and URL round trip changes the host
How it was found
Summary:
[six or fewer sentences describing the issue in your own human voice and optionally a short proof-of-concept script] An app can set a host from untrusted input from CURLUPART_HOST, as the docs allow, and rely on curl to reject bad hosts. curl accepts [fe80::1%25eth0]@evil.example/x as a valid IPv6 host. The URL it then builds has evil.example as its host. Any code that uses that URL string goes to evil.example. libcurl also sends the follow-up request there after a relative redirect from the IPv6 server. An attack needs an app that sets untrusted hosts this way, and i do not know of one.
Affected version
[Which curl/libcurl version are you using to reproduce? On which platform? curl -V typically generates good output to include]
curl 8.10.0 through 8.23.0
Steps To Reproduce:
[add details for how we can reproduce the issue]
Paste this: 1. Build libcurl 8.10.0 or later (I tested 8.10.0, 8.23.0, and master c4b341c).
2. Save the program from the report as repro.c.
3. Compile it:
cc repro.c -I<curl>/include -L<curl>/lib -lcurl -o repro
- Run
./repro.
Expected: curl_url_set() rejects the host, the same way it rejects [::1]junk with CURLUE_BAD_HOSTNAME.
Actual:
set host: rc=0
host: [fe80::1%25eth0]@evil.example/x
url: http://[fe80::1%25eth0]@evil.example/%25eth0]/
reparse: rc=0 host=evil.example
Redirect case
- Start an HTTP server on
[::1]:18934that answers302withLocation: /next. - Start any HTTP server on
127.0.0.1:18933. - Set the host to
[::1%25lo0]@127.0.0.1:18933/xand the port to18934. On Linux, useloin place oflo0. - Pass the handle with
CURLOPT_CURLU, setCURLOPT_FOLLOWLOCATIONto1, and run the transfer. - The first request goes to
[::1]:18934. The second request goes to127.0.0.1:18933.
Again: there is no bug-bounty for curl. We do not offer any rewards, only proper credits.
Impact
Summary:
curl accepts [fe80::1%25eth0]@evil.example/x as a valid IPv6 host. curl_url_get(CURLUPART_URL) then gives a URL whose host is evil.example. Any code that logs, stores, or fetches that URL uses the wrong host. With CURLOPT_CURLU and CURLOPT_FOLLOWLOCATION, libcurl sends the first request to the IPv6 address. A relative redirect from that server sends the next request to the other host and port. An attack needs an app that passes untrusted hosts to CURLUPART_HOST