From ecee0926868d138312e9608531b232f697e50cad Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Apr 2022 16:24:33 +0200 Subject: [PATCH 1/4] connect: store "conn_remote_port" in the info struct To make it available after the connection ended. Upstream-commit: 08b8ef4e726ba10f45081ecda5b3cea788d3c839 Signed-off-by: Kamil Dudka --- lib/connect.c | 1 + lib/urldata.h | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/connect.c b/lib/connect.c index 64f9511..7518807 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -619,6 +619,7 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn, data->info.conn_scheme = conn->handler->scheme; data->info.conn_protocol = conn->handler->protocol; data->info.conn_primary_port = conn->port; + data->info.conn_remote_port = conn->remote_port; data->info.conn_local_port = local_port; } diff --git a/lib/urldata.h b/lib/urldata.h index f92052a..5218f76 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1167,7 +1167,11 @@ struct PureInfo { reused, in the connection cache. */ char conn_primary_ip[MAX_IPADR_LEN]; - int conn_primary_port; + int conn_primary_port; /* this is the destination port to the connection, + which might have been a proxy */ + int conn_remote_port; /* this is the "remote port", which is the port + number of the used URL, independent of proxy or + not */ char conn_local_ip[MAX_IPADR_LEN]; int conn_local_port; const char *conn_scheme; -- 2.34.1 From 12c129f8d0b165d83ed954f68717d88ffc1cfc5f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Apr 2022 16:24:33 +0200 Subject: [PATCH 2/4] 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 Upstream-commit: 620ea21410030a9977396b4661806bc187231b79 Signed-off-by: Kamil Dudka --- lib/transfer.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/transfer.c b/lib/transfer.c index 1f8019b..752fe14 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1641,10 +1641,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) { -- 2.34.1 From 83bf4314d88cc16469afeaaefd6686a50371d1b7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Apr 2022 16:24:33 +0200 Subject: [PATCH 3/4] tests: verify the fix for CVE-2022-27774 - Test 973 redirects from HTTP to FTP, clear auth - Test 974 redirects from HTTP to HTTP different port, clear auth - Test 975 redirects from HTTP to FTP, permitted to keep auth - Test 976 redirects from HTTP to HTTP different port, permitted to keep auth Upstream-commit: 5295e8d64ac6949ecb3f9e564317a608f51b90d8 Signed-off-by: Kamil Dudka --- tests/data/Makefile.inc | 1 + tests/data/test973 | 88 +++++++++++++++++++++++++++++++++++++++++ tests/data/test974 | 87 ++++++++++++++++++++++++++++++++++++++++ tests/data/test975 | 88 +++++++++++++++++++++++++++++++++++++++++ tests/data/test976 | 88 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 tests/data/test973 create mode 100644 tests/data/test974 create mode 100644 tests/data/test975 create mode 100644 tests/data/test976 diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index 7ae2cf8..175fc43 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -116,6 +116,7 @@ test936 test937 test938 test939 test940 test941 test942 test943 test944 \ test945 test946 test947 test948 test949 test950 test951 test952 test953 \ test954 test955 test956 test957 test958 test959 test960 test961 test962 \ test963 test964 test965 test966 test967 test968 test969 test970 test971 \ +test973 test974 test975 test976 \ \ test980 test981 test982 test983 test984 test985 test986 \ \ diff --git a/tests/data/test973 b/tests/data/test973 new file mode 100644 index 0000000..6ced107 --- /dev/null +++ b/tests/data/test973 @@ -0,0 +1,88 @@ + + + +HTTP +FTP +--location + + + +# +# Server-side + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER0002 + + + +data + to + see +that FTP +works + so does it? + + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER0002 + +data + to + see +that FTP +works + so does it? + + + + +# +# Client-side + + +http +ftp + + +HTTP with auth redirected to FTP w/o auth + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -u joe:secret + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Authorization: Basic am9lOnNlY3JldA== +User-Agent: curl/%VERSION +Accept: */* + +USER anonymous +PASS ftp@example.com +PWD +CWD a +CWD path +EPSV +TYPE I +SIZE %TESTNUMBER0002 +RETR %TESTNUMBER0002 +QUIT + + + diff --git a/tests/data/test974 b/tests/data/test974 new file mode 100644 index 0000000..ac4e641 --- /dev/null +++ b/tests/data/test974 @@ -0,0 +1,87 @@ + + + +HTTP +--location + + + +# +# Server-side + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: http://firsthost.com:9999/a/path/%TESTNUMBER0002 + + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 4 +Connection: close +Content-Type: text/html + +hey + + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: http://firsthost.com:9999/a/path/%TESTNUMBER0002 + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 4 +Connection: close +Content-Type: text/html + +hey + + + + +# +# Client-side + + +http + + +HTTP with auth redirected to HTTP on a diff port w/o auth + + +-x http://%HOSTIP:%HTTPPORT http://firsthost.com -L -u joe:secret + + + +# +# Verify data after the test has been "shot" + + +GET http://firsthost.com/ HTTP/1.1 +Host: firsthost.com +Authorization: Basic am9lOnNlY3JldA== +User-Agent: curl/%VERSION +Accept: */* +Proxy-Connection: Keep-Alive + +GET http://firsthost.com:9999/a/path/%TESTNUMBER0002 HTTP/1.1 +Host: firsthost.com:9999 +User-Agent: curl/%VERSION +Accept: */* +Proxy-Connection: Keep-Alive + + + + diff --git a/tests/data/test975 b/tests/data/test975 new file mode 100644 index 0000000..85e03e4 --- /dev/null +++ b/tests/data/test975 @@ -0,0 +1,88 @@ + + + +HTTP +FTP +--location-trusted + + + +# +# Server-side + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER0002 + + + +data + to + see +that FTP +works + so does it? + + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER0002 + +data + to + see +that FTP +works + so does it? + + + + +# +# Client-side + + +http +ftp + + +HTTP with auth redirected to FTP allowing auth to continue + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --location-trusted -u joe:secret + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Authorization: Basic am9lOnNlY3JldA== +User-Agent: curl/%VERSION +Accept: */* + +USER joe +PASS secret +PWD +CWD a +CWD path +EPSV +TYPE I +SIZE %TESTNUMBER0002 +RETR %TESTNUMBER0002 +QUIT + + + diff --git a/tests/data/test976 b/tests/data/test976 new file mode 100644 index 0000000..c4dd61e --- /dev/null +++ b/tests/data/test976 @@ -0,0 +1,88 @@ + + + +HTTP +--location-trusted + + + +# +# Server-side + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: http://firsthost.com:9999/a/path/%TESTNUMBER0002 + + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 4 +Connection: close +Content-Type: text/html + +hey + + + +HTTP/1.1 301 redirect +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 +Connection: close +Content-Type: text/html +Location: http://firsthost.com:9999/a/path/%TESTNUMBER0002 + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 4 +Connection: close +Content-Type: text/html + +hey + + + + +# +# Client-side + + +http + + +HTTP with auth redirected to HTTP on a diff port --location-trusted + + +-x http://%HOSTIP:%HTTPPORT http://firsthost.com --location-trusted -u joe:secret + + + +# +# Verify data after the test has been "shot" + + +GET http://firsthost.com/ HTTP/1.1 +Host: firsthost.com +Authorization: Basic am9lOnNlY3JldA== +User-Agent: curl/%VERSION +Accept: */* +Proxy-Connection: Keep-Alive + +GET http://firsthost.com:9999/a/path/%TESTNUMBER0002 HTTP/1.1 +Host: firsthost.com:9999 +Authorization: Basic am9lOnNlY3JldA== +User-Agent: curl/%VERSION +Accept: */* +Proxy-Connection: Keep-Alive + + + + -- 2.34.1 From 443ce415aa60caaf8b1c9b0b71fff8d26263daca Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Apr 2022 17:59:15 +0200 Subject: [PATCH 4/4] openssl: don't leak the SRP credentials in redirects either Follow-up to 620ea21410030 Reported-by: Harry Sintonen Closes #8751 Upstream-commit: 139a54ed0a172adaaf1a78d6f4fff50b2c3f9e08 Signed-off-by: Kamil Dudka --- lib/http.c | 10 +++++----- lib/http.h | 6 ++++++ lib/vtls/openssl.c | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/http.c b/lib/http.c index 0791dcf..4433824 100644 --- a/lib/http.c +++ b/lib/http.c @@ -776,10 +776,10 @@ output_auth_headers(struct Curl_easy *data, } /* - * allow_auth_to_host() tells if autentication, cookies or other "sensitive - * data" can (still) be sent to this host. + * Curl_allow_auth_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. */ -static bool allow_auth_to_host(struct Curl_easy *data) +bool Curl_allow_auth_to_host(struct Curl_easy *data) { struct connectdata *conn = data->conn; return (!data->state.this_is_a_follow || @@ -864,7 +864,7 @@ Curl_http_output_auth(struct Curl_easy *data, /* 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) + if(Curl_allow_auth_to_host(data) || conn->bits.netrc) result = output_auth_headers(data, conn, authhost, request, path, FALSE); else @@ -1917,7 +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 */ - !allow_auth_to_host(data)) + !Curl_allow_auth_to_host(data)) ; else { #ifdef USE_HYPER diff --git a/lib/http.h b/lib/http.h index 07e963d..9000bae 100644 --- a/lib/http.h +++ b/lib/http.h @@ -317,4 +317,10 @@ Curl_http_output_auth(struct Curl_easy *data, bool proxytunnel); /* TRUE if this is the request setting up the proxy tunnel */ +/* + * Curl_allow_auth_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_allow_auth_to_host(struct Curl_easy *data); + #endif /* HEADER_CURL_HTTP_H */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 1bafe96..97c5666 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2857,7 +2857,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif #ifdef USE_OPENSSL_SRP - if(ssl_authtype == CURL_TLSAUTH_SRP) { + if((ssl_authtype == CURL_TLSAUTH_SRP) && + Curl_allow_auth_to_host(data)) { char * const ssl_username = SSL_SET_OPTION(username); infof(data, "Using TLS-SRP username: %s\n", ssl_username); -- 2.34.1