diff options
author | Ingela Anderton Andin <ingela@erlang.org> | 2021-02-18 11:40:16 +0100 |
---|---|---|
committer | Ingela Anderton Andin <ingela@erlang.org> | 2021-02-23 09:10:20 +0100 |
commit | 39f14943f2aaa2c551d6402c73583fe213d6ed87 (patch) | |
tree | 86eb31be8cd8f96ebfba81dc22264e0820bbca77 | |
parent | 5a3d03ee2c12f4c93cf7375abdb3c04f7423f76d (diff) | |
download | erlang-39f14943f2aaa2c551d6402c73583fe213d6ed87.tar.gz |
inets,httpd: Assure relative paths can not be used to bypass server root directory
Use of uri_string:percent_decode in commmit 5f83a9d719afac0718bff524df6654c9fc94aad5
needs to be combined with uri_string:normalize to assure valid paths.
Solves CVE-2021-27563
-rw-r--r-- | lib/inets/src/http_server/mod_alias.erl | 24 | ||||
-rw-r--r-- | lib/inets/test/httpd_SUITE.erl | 45 |
2 files changed, 61 insertions, 8 deletions
diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl index 35da39c53c..cb2d2c1ef4 100644 --- a/lib/inets/src/http_server/mod_alias.erl +++ b/lib/inets/src/http_server/mod_alias.erl @@ -195,22 +195,30 @@ append_index(RealName, [Index | Rest]) -> %% path -path(Data, ConfigDB, RequestURI) -> - InitPath = +path(Data, ConfigDB, RequestURI0) -> case proplists:get_value(real_name, Data) of undefined -> - {Prefix, DocumentRoot} = which_document_root(ConfigDB), - {Path, _AfterPath} = + {Prefix, DocumentRoot} = which_document_root(ConfigDB), + RequestURI = percent_decode_path(RequestURI0), + {Path, _AfterPath} = httpd_util:split_path(DocumentRoot ++ RequestURI), Prefix ++ Path; {Path, _AfterPath} -> Path - end, - case uri_string:percent_decode(InitPath) of - {error, _} -> InitPath; - P -> P end. +percent_decode_path(InitPath) -> + case uri_string:percent_decode(InitPath) of + {error, _} -> + InitPath; + Path0 -> %% Protect against vulnerabilities + case uri_string:normalize(Path0) of + {error, _, _} -> + InitPath; + Path -> + Path + end + end. %% %% Configuration %% diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index e4efeb1b81..027932caa2 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -155,6 +155,7 @@ http_head() -> http_get() -> [alias, get, + bad_dot_paths, %%actions, Add configuration so that this test mod_action esi, bad_hex, @@ -473,6 +474,50 @@ get(Config) when is_list(Config) -> {header, "Date"}, {header, "Server"}, {version, Version}]). + +bad_dot_paths() -> + [{doc, "Do not allow ..-paths to acesse files outside of doc root"}]. +bad_dot_paths(Config) when is_list(Config) -> + Version = proplists:get_value(http_version, Config), + Host = proplists:get_value(host, Config), + Type = proplists:get_value(type, Config), + + BadDotPath0 = "/..%2f..%2f...%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd ", + BadDotPath1 = "/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd ", + BadDotPath2 = "/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd ", + + ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host, + proplists:get_value(port, Config), + transport_opts(Type, Config), + proplists:get_value(node, Config), + http_request("GET " ++ BadDotPath0 , Version, Host), + [{statuscode, 404}, + {header, "Content-Type", "text/html"}, + {header, "Date"}, + {header, "Server"}, + {version, Version}]), + + ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host, + proplists:get_value(port, Config), + transport_opts(Type, Config), + proplists:get_value(node, Config), + http_request("GET " ++ BadDotPath1, Version, Host), + [{statuscode, 404}, + {header, "Content-Type", "text/html"}, + {header, "Date"}, + {header, "Server"}, + {version, Version}]), + + ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host, + proplists:get_value(port, Config), + transport_opts(Type, Config), + proplists:get_value(node, Config), + http_request("GET " ++ BadDotPath2, Version, Host), + [{statuscode, 404}, + {header, "Content-Type", "text/html"}, + {header, "Date"}, + {header, "Server"}, + {version, Version}]). basic_auth_1_1(Config) when is_list(Config) -> basic_auth([{http_version, "HTTP/1.1"} | Config]). |