Revert url decoding+simplifying before matching of mod_rewrite/mod_redirect

- Lot of regressions (we forgot to reencode the result)
  - Generic problem: after decode and rewrite "a?b?c": which '?' was the path?query seperator?
  - Possible solution: only decode printable characters (without '?'), and encode the result; do not encode the '%' of a not decoded character.
  - Still a problem with path simplifying, it seems many people use urls like this: http://server1/http%3a//server2/xxx
    and rewrite the path into the querystring.
  - Probably only usable with an extra config option

  => Do NOT use rewrite/redirect to protect specific urls.


git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2362 152afb58-edef-0310-8abb-c4023f1b3aa9
This commit is contained in:
Stefan Bühler 2008-12-07 15:22:42 +00:00
parent a64e7cd46b
commit 36f74e5d23
9 changed files with 82 additions and 49 deletions

5
NEWS
View File

@ -20,6 +20,7 @@ NEWS
* Fixed fix for round-robin in mod_proxy (forgot to increment the index) (#1715)
* Fix fastcgi-authorizer handling; Status: 200 is now accepted as the doc requests
* Compare address family in inet_ntop_cache
* Revert CVE-2008-4359 (#1720) fix "encoding+simplifying urls for rewrite/redirect": too many regressions.
- 1.4.20 - 2008-09-30
@ -67,7 +68,7 @@ NEWS
* allow digits in [s]cgi env vars (#1712)
* fixed dropping last character of evhost pattern (#161)
* print helpful error message on conditionals in global block (#1550)
* decode url before matching in mod_rewrite (#1720)
* decode url before matching in mod_rewrite (#1720) -- (reverted for 1.4.21)
* fixed conditional patching of ldap filter (#1564)
* Match headers case insensitive in response (removing of X-{Sendfile,LIGHTTPD-*}, catching Date/Server) [2281]
* fixed bug with case-insensitive filenames in mod_userdir (#1589), spotted by "anders1" (CVE-2008-4360)
@ -82,7 +83,7 @@ NEWS
* fix auth.backend.ldap.bind-dn/pw problems (only read from global context for temporary ldap reconnects, thx ruskie)
* fix memleak in request header parsing (#1774, thx qhy) (CVE-2008-4298)
* fix mod_rewrite memleak/endless loop detection (#1775, thx phy - again!)
* use decoded url for matching in mod_redirect (#1720) (CVE-2008-4359)
* use decoded url for matching in mod_redirect (#1720) (CVE-2008-4359) -- (reverted for 1.4.21)
- 1.4.19 - 2008-03-10

View File

@ -39,3 +39,9 @@ url.redirect
$HTTP["host"] =~ "^www\.(.*)" {
url.redirect = ( "^/(.*)" => "http://%1/$1" )
}
Warning
=======
Do NOT use mod_redirect to protect specific urls, as the original url passed from the client
is matched against your rules, for example strings like "/abc/../xyz%2f/path".

View File

@ -43,6 +43,12 @@ url.rewrite-repeat
The options ``url.rewrite`` and ``url.rewrite-final`` were mapped to ``url.rewrite-once``
in 1.3.16.
Warning
=======
Do NOT use mod_rewrite to protect specific urls, as the original url passed from the client
is matched against your rules, for example strings like "/abc/../xyz%2f/path".
Examples
========

View File

@ -178,11 +178,7 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
mod_redirect_patch_connection(srv, con, p);
buffer_copy_string_buffer(p->match_buf, con->uri.path);
if (con->uri.query->used > 0) {
buffer_append_string_len(p->match_buf, CONST_STR_LEN("?"));
buffer_append_string_buffer(p->match_buf, con->uri.query);
}
buffer_copy_string_buffer(p->match_buf, con->request.uri);
for (i = 0; i < p->conf.redirect->used; i++) {
pcre *match;

View File

@ -350,11 +350,7 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) {
if (!p->conf.rewrite) return HANDLER_GO_ON;
buffer_copy_string_buffer(p->match_buf, con->uri.path);
if (con->uri.query->used > 0) {
buffer_append_string_len(p->match_buf, CONST_STR_LEN("?"));
buffer_append_string_buffer(p->match_buf, con->uri.query);
}
buffer_copy_string_buffer(p->match_buf, con->request.uri);
for (i = 0; i < p->conf.rewrite->used; i++) {
pcre *match;

View File

@ -232,29 +232,6 @@ handler_t http_response_prepare(server *srv, connection *con) {
}
/* build filename
*
* - decode url-encodings (e.g. %20 -> ' ')
* - remove path-modifiers (e.g. /../)
*/
if (con->request.http_method == HTTP_METHOD_OPTIONS &&
con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
/* OPTIONS * ... */
buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
} else {
buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
buffer_urldecode_path(srv->tmp_buf);
buffer_path_simplify(con->uri.path, srv->tmp_buf);
}
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- sanatising URI");
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path);
}
/**
*
* call plugins
@ -276,6 +253,29 @@ handler_t http_response_prepare(server *srv, connection *con) {
break;
}
/* build filename
*
* - decode url-encodings (e.g. %20 -> ' ')
* - remove path-modifiers (e.g. /../)
*/
if (con->request.http_method == HTTP_METHOD_OPTIONS &&
con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
/* OPTIONS * ... */
buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
} else {
buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
buffer_urldecode_path(srv->tmp_buf);
buffer_path_simplify(con->uri.path, srv->tmp_buf);
}
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- sanatising URI");
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path);
}
/**
*
* call plugins

View File

@ -8,13 +8,23 @@ BEGIN {
use strict;
use IO::Socket;
use Test::More tests => 6;
use Test::More tests => 9;
use LightyTest;
my $tf_real = LightyTest->new();
my $tf_proxy = LightyTest->new();
my $t;
my $php_child = -1;
my $phpbin = (defined $ENV{'PHP'} ? $ENV{'PHP'} : '/usr/bin/php-cgi');
$ENV{'PHP'} = $phpbin;
SKIP: {
skip "PHP already running on port 1026", 1 if $tf_real->listening_on(1026);
skip "no php binary found", 1 unless -x $phpbin;
ok(-1 != ($php_child = $tf_real->spawnfcgi($phpbin, 1026)), "Spawning php");
}
## we need two procs
## 1. the real webserver
@ -26,9 +36,9 @@ $tf_real->{CONFIGFILE} = 'lighttpd.conf';
$tf_proxy->{PORT} = 2050;
$tf_proxy->{CONFIGFILE} = 'proxy.conf';
ok($tf_real->start_proc == 0, "Starting lighttpd") or die();
ok($tf_real->start_proc == 0, "Starting lighttpd") or goto cleanup;
ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or goto cleanup;
$t->{REQUEST} = ( <<EOF
GET /index.html HTTP/1.0
@ -46,6 +56,31 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'Apache 1.3.29' } ];
ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
SKIP: {
skip "no PHP running on port 1026", 1 unless $tf_real->listening_on(1026);
$t->{REQUEST} = ( <<EOF
GET /rewrite/all/some+test%3axxx%20with%20space HTTP/1.0
Host: www.example.org
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/some+test%3axxx%20with%20space' } ];
ok($tf_proxy->handle_http($t) == 0, 'rewrited urls work with encoded path');
}
ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
ok($tf_real->stop_proc == 0, "Stopping lighttpd");
SKIP: {
skip "PHP not started, cannot stop it", 1 unless $php_child != -1;
ok(0 == $tf_real->endspawnfcgi($php_child), "Stopping php");
$php_child = -1;
}
exit 0;
cleanup:
$tf_real->endspawnfcgi($php_child) if $php_child != -1;
die();

View File

@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
use Test::More tests => 8;
use Test::More tests => 7;
use LightyTest;
my $tf = LightyTest->new();
@ -35,7 +35,7 @@ EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '' } ];
ok($tf->handle_http($t) == 0, 'valid request');
$t->{REQUEST} = ( <<EOF
GET /rewrite/foo?a=b HTTP/1.0
Host: www.example.org
@ -52,14 +52,6 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'bar&a=b' } ];
ok($tf->handle_http($t) == 0, 'valid request');
$t->{REQUEST} = ( <<EOF
GET %2Frewrite/f%6Fo?a=b HTTP/1.0
Host: www.example.org
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'a=b' } ];
ok($tf->handle_http($t) == 0, 'valid request with url encoded characters');
ok($tf->stop_proc == 0, "Stopping lighttpd");
}

View File

@ -122,7 +122,8 @@ url.access-deny = ( "~", ".inc")
url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
"^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
"^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1",
"^/rewrite/all(/.*)$" => "/indexfile/rewrite.php?$1" )
expire.url = ( "/expire/access" => "access 2 hours",
"/expire/modification" => "access plus 1 seconds 2 minutes")