diff options
author | Daniel Stenberg <daniel@haxx.se> | 2022-04-25 16:24:33 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2022-04-25 16:24:33 +0200 |
commit | 620ea21410030a9977396b4661806bc187231b79 (patch) | |
tree | 892977a893b80b90392609b5e8fc0930728e52b3 | |
parent | 08b8ef4e726ba10f45081ecda5b3cea788d3c839 (diff) | |
download | curl-620ea21410030a9977396b4661806bc187231b79.tar.gz |
transfer: redirects to other protocols or ports clear auth
... unless explicitly permitted.
Bug: https://curl.se/docs/CVE-2022-27774.html
Reported-by: Harry Sintonen
Closes #8748
-rw-r--r-- | lib/transfer.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/lib/transfer.c b/lib/transfer.c index 53ef0b03b..315da876c 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1611,10 +1611,57 @@ CURLcode Curl_follow(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } else { - uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0); if(uc) return Curl_uc_to_curlcode(uc); + + /* Clear auth if this redirects to a different port number or protocol, + unless permitted */ + if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) { + char *portnum; + int port; + bool clear = FALSE; + + if(data->set.use_port && data->state.allow_port) + /* a custom port is used */ + port = (int)data->set.use_port; + else { + uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum, + CURLU_DEFAULT_PORT); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + port = atoi(portnum); + free(portnum); + } + if(port != data->info.conn_remote_port) { + infof(data, "Clear auth, redirects to port from %u to %u", + data->info.conn_remote_port, port); + clear = TRUE; + } + else { + char *scheme; + const struct Curl_handler *p; + uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0); + if(uc) { + free(newurl); + return Curl_uc_to_curlcode(uc); + } + + p = Curl_builtin_scheme(scheme); + if(p && (p->protocol != data->info.conn_protocol)) { + infof(data, "Clear auth, redirects scheme from %s to %s", + data->info.conn_scheme, scheme); + clear = TRUE; + } + free(scheme); + } + if(clear) { + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); + } + } } if(type == FOLLOW_FAKE) { |