1From f6eba3638f9b25adfe85f3570f9a0fb2ceb09c2b Mon Sep 17 00:00:00 2001 2From: Daniel Stenberg <daniel@haxx.se> 3Date: Mon, 25 Apr 2022 13:05:40 +0200 4Subject: [PATCH] http: avoid auth/cookie on redirects same host diff port 5 6CVE-2022-27776 7 8Reported-by: Harry Sintonen 9Bug: https://curl.se/docs/CVE-2022-27776.html 10Closes #8749 11 12Upstream-Status: Backport [https://github.com/curl/curl/commit/6e659993952aa5f90f48864be84a1bbb047fc258] 13Signed-off-by: Robert Joslyn <robert.joslyn@redrectangle.org> 14--- 15 lib/http.c | 34 ++++++++++++++++++++++------------ 16 lib/urldata.h | 16 +++++++++------- 17 2 files changed, 31 insertions(+), 19 deletions(-) 18 19diff --git a/lib/http.c b/lib/http.c 20index 799d4fb..0791dcf 100644 21--- a/lib/http.c 22+++ b/lib/http.c 23@@ -775,6 +775,21 @@ output_auth_headers(struct Curl_easy *data, 24 return CURLE_OK; 25 } 26 27+/* 28+ * allow_auth_to_host() tells if autentication, cookies or other "sensitive 29+ * data" can (still) be sent to this host. 30+ */ 31+static bool allow_auth_to_host(struct Curl_easy *data) 32+{ 33+ struct connectdata *conn = data->conn; 34+ return (!data->state.this_is_a_follow || 35+ data->set.allow_auth_to_other_hosts || 36+ (data->state.first_host && 37+ strcasecompare(data->state.first_host, conn->host.name) && 38+ (data->state.first_remote_port == conn->remote_port) && 39+ (data->state.first_remote_protocol == conn->handler->protocol))); 40+} 41+ 42 /** 43 * Curl_http_output_auth() setups the authentication headers for the 44 * host/proxy and the correct authentication 45@@ -847,17 +862,14 @@ Curl_http_output_auth(struct Curl_easy *data, 46 with it */ 47 authproxy->done = TRUE; 48 49- /* To prevent the user+password to get sent to other than the original 50- host due to a location-follow, we do some weirdo checks here */ 51- if(!data->state.this_is_a_follow || 52+ /* To prevent the user+password to get sent to other than the original host 53+ due to a location-follow */ 54+ if(allow_auth_to_host(data) 55 #ifndef CURL_DISABLE_NETRC 56- conn->bits.netrc || 57+ || conn->bits.netrc 58 #endif 59- !data->state.first_host || 60- data->set.allow_auth_to_other_hosts || 61- strcasecompare(data->state.first_host, conn->host.name)) { 62+ ) 63 result = output_auth_headers(data, conn, authhost, request, path, FALSE); 64- } 65 else 66 authhost->done = TRUE; 67 68@@ -1905,10 +1917,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, 69 checkprefix("Cookie:", compare)) && 70 /* be careful of sending this potentially sensitive header to 71 other hosts */ 72- (data->state.this_is_a_follow && 73- data->state.first_host && 74- !data->set.allow_auth_to_other_hosts && 75- !strcasecompare(data->state.first_host, conn->host.name))) 76+ !allow_auth_to_host(data)) 77 ; 78 else { 79 #ifdef USE_HYPER 80@@ -2084,6 +2093,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) 81 return CURLE_OUT_OF_MEMORY; 82 83 data->state.first_remote_port = conn->remote_port; 84+ data->state.first_remote_protocol = conn->handler->protocol; 85 } 86 Curl_safefree(data->state.aptr.host); 87 88diff --git a/lib/urldata.h b/lib/urldata.h 89index 03da59a..f92052a 100644 90--- a/lib/urldata.h 91+++ b/lib/urldata.h 92@@ -1329,14 +1329,16 @@ struct UrlState { 93 char *ulbuf; /* allocated upload buffer or NULL */ 94 curl_off_t current_speed; /* the ProgressShow() function sets this, 95 bytes / second */ 96- char *first_host; /* host name of the first (not followed) request. 97- if set, this should be the host name that we will 98- sent authorization to, no else. Used to make Location: 99- following not keep sending user+password... This is 100- strdup() data. 101- */ 102+ 103+ /* host name, port number and protocol of the first (not followed) request. 104+ if set, this should be the host name that we will sent authorization to, 105+ no else. Used to make Location: following not keep sending user+password. 106+ This is strdup()ed data. */ 107+ char *first_host; 108+ int first_remote_port; 109+ unsigned int first_remote_protocol; 110+ 111 int retrycount; /* number of retries on a new connection */ 112- int first_remote_port; /* remote port of the first (not followed) request */ 113 struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ 114 long sessionage; /* number of the most recent session */ 115 struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ 116