| From f6eba3638f9b25adfe85f3570f9a0fb2ceb09c2b Mon Sep 17 00:00:00 2001 |
| From: Daniel Stenberg <daniel@haxx.se> |
| Date: Mon, 25 Apr 2022 13:05:40 +0200 |
| Subject: [PATCH] http: avoid auth/cookie on redirects same host diff port |
| |
| CVE-2022-27776 |
| |
| Reported-by: Harry Sintonen |
| Bug: https://curl.se/docs/CVE-2022-27776.html |
| Closes #8749 |
| |
| Upstream-Status: Backport [https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258] |
| Signed-off-by: Robert Joslyn <robert.joslyn@redrectangle.org> |
| --- |
| lib/http.c | 34 ++++++++++++++++++++++------------ |
| lib/urldata.h | 16 +++++++++------- |
| 2 files changed, 31 insertions(+), 19 deletions(-) |
| |
| diff --git a/lib/http.c b/lib/http.c |
| index 799d4fb..0791dcf 100644 |
| --- a/lib/http.c |
| +++ b/lib/http.c |
| @@ -775,6 +775,21 @@ output_auth_headers(struct Curl_easy *data, |
| return CURLE_OK; |
| } |
| |
| +/* |
| + * allow_auth_to_host() tells if autentication, cookies or other "sensitive |
| + * data" can (still) be sent to this host. |
| + */ |
| +static bool allow_auth_to_host(struct Curl_easy *data) |
| +{ |
| + struct connectdata *conn = data->conn; |
| + return (!data->state.this_is_a_follow || |
| + data->set.allow_auth_to_other_hosts || |
| + (data->state.first_host && |
| + strcasecompare(data->state.first_host, conn->host.name) && |
| + (data->state.first_remote_port == conn->remote_port) && |
| + (data->state.first_remote_protocol == conn->handler->protocol))); |
| +} |
| + |
| /** |
| * Curl_http_output_auth() setups the authentication headers for the |
| * host/proxy and the correct authentication |
| @@ -847,17 +862,14 @@ Curl_http_output_auth(struct Curl_easy *data, |
| with it */ |
| authproxy->done = TRUE; |
| |
| - /* To prevent the user+password to get sent to other than the original |
| - host due to a location-follow, we do some weirdo checks here */ |
| - if(!data->state.this_is_a_follow || |
| + /* To prevent the user+password to get sent to other than the original host |
| + due to a location-follow */ |
| + if(allow_auth_to_host(data) |
| #ifndef CURL_DISABLE_NETRC |
| - conn->bits.netrc || |
| + || conn->bits.netrc |
| #endif |
| - !data->state.first_host || |
| - data->set.allow_auth_to_other_hosts || |
| - strcasecompare(data->state.first_host, conn->host.name)) { |
| + ) |
| result = output_auth_headers(data, conn, authhost, request, path, FALSE); |
| - } |
| else |
| authhost->done = TRUE; |
| |
| @@ -1905,10 +1917,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, |
| checkprefix("Cookie:", compare)) && |
| /* be careful of sending this potentially sensitive header to |
| other hosts */ |
| - (data->state.this_is_a_follow && |
| - data->state.first_host && |
| - !data->set.allow_auth_to_other_hosts && |
| - !strcasecompare(data->state.first_host, conn->host.name))) |
| + !allow_auth_to_host(data)) |
| ; |
| else { |
| #ifdef USE_HYPER |
| @@ -2084,6 +2093,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) |
| return CURLE_OUT_OF_MEMORY; |
| |
| data->state.first_remote_port = conn->remote_port; |
| + data->state.first_remote_protocol = conn->handler->protocol; |
| } |
| Curl_safefree(data->state.aptr.host); |
| |
| diff --git a/lib/urldata.h b/lib/urldata.h |
| index 03da59a..f92052a 100644 |
| --- a/lib/urldata.h |
| +++ b/lib/urldata.h |
| @@ -1329,14 +1329,16 @@ struct UrlState { |
| char *ulbuf; /* allocated upload buffer or NULL */ |
| curl_off_t current_speed; /* the ProgressShow() function sets this, |
| bytes / second */ |
| - char *first_host; /* host name of the first (not followed) request. |
| - if set, this should be the host name that we will |
| - sent authorization to, no else. Used to make Location: |
| - following not keep sending user+password... This is |
| - strdup() data. |
| - */ |
| + |
| + /* host name, port number and protocol of the first (not followed) request. |
| + if set, this should be the host name that we will sent authorization to, |
| + no else. Used to make Location: following not keep sending user+password. |
| + This is strdup()ed data. */ |
| + char *first_host; |
| + int first_remote_port; |
| + unsigned int first_remote_protocol; |
| + |
| int retrycount; /* number of retries on a new connection */ |
| - int first_remote_port; /* remote port of the first (not followed) request */ |
| struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ |
| long sessionage; /* number of the most recent session */ |
| struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ |