[bug/56965] Redirect fails with directory traversal

Correct invalid r10536 with a boolean flag.  Note that this fix for the bug will not actually correct the redirects, it will only prevent phpBB from redirecting outside $phpbb_root_path when redirect()'s third argument is not provided.
This commit is contained in:
Josh Woody 2010-03-17 23:24:34 -05:00
parent ac32927566
commit eca2db4afe

View file

@ -2297,6 +2297,8 @@ function redirect($url, $return = false, $disable_cd_check = false)
{ {
global $db, $cache, $config, $user, $phpbb_root_path; global $db, $cache, $config, $user, $phpbb_root_path;
$failover_flag = false;
if (empty($user->lang)) if (empty($user->lang))
{ {
$user->add_lang('common'); $user->add_lang('common');
@ -2344,66 +2346,70 @@ function redirect($url, $return = false, $disable_cd_check = false)
if (!file_exists($pathinfo['dirname'])) if (!file_exists($pathinfo['dirname']))
{ {
// fallback to "last known user page" // fallback to "last known user page"
// at least this way we know the user does not leave the phpBB root
$url = generate_board_url() . '/' . $user->page['page']; $url = generate_board_url() . '/' . $user->page['page'];
break; $failover_flag = true;
} }
} }
// Is the uri pointing to the current directory? if (!$failover_flag)
if ($pathinfo['dirname'] == '.')
{ {
$url = str_replace('./', '', $url); // Is the uri pointing to the current directory?
if ($pathinfo['dirname'] == '.')
// Strip / from the beginning
if ($url && substr($url, 0, 1) == '/')
{ {
$url = substr($url, 1); $url = str_replace('./', '', $url);
}
if ($user->page['page_dir']) // Strip / from the beginning
{ if ($url && substr($url, 0, 1) == '/')
$url = generate_board_url() . '/' . $user->page['page_dir'] . '/' . $url; {
$url = substr($url, 1);
}
if ($user->page['page_dir'])
{
$url = generate_board_url() . '/' . $user->page['page_dir'] . '/' . $url;
}
else
{
$url = generate_board_url() . '/' . $url;
}
} }
else else
{ {
// Used ./ before, but $phpbb_root_path is working better with urls within another root path
$root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path)));
$page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
$intersection = array_intersect_assoc($root_dirs, $page_dirs);
$root_dirs = array_diff_assoc($root_dirs, $intersection);
$page_dirs = array_diff_assoc($page_dirs, $intersection);
$dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
// Strip / from the end
if ($dir && substr($dir, -1, 1) == '/')
{
$dir = substr($dir, 0, -1);
}
// Strip / from the beginning
if ($dir && substr($dir, 0, 1) == '/')
{
$dir = substr($dir, 1);
}
$url = str_replace($pathinfo['dirname'] . '/', '', $url);
// Strip / from the beginning
if (substr($url, 0, 1) == '/')
{
$url = substr($url, 1);
}
$url = (!empty($dir) ? $dir . '/' : '') . $url;
$url = generate_board_url() . '/' . $url; $url = generate_board_url() . '/' . $url;
} }
} }
else
{
// Used ./ before, but $phpbb_root_path is working better with urls within another root path
$root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path)));
$page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname'])));
$intersection = array_intersect_assoc($root_dirs, $page_dirs);
$root_dirs = array_diff_assoc($root_dirs, $intersection);
$page_dirs = array_diff_assoc($page_dirs, $intersection);
$dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
// Strip / from the end
if ($dir && substr($dir, -1, 1) == '/')
{
$dir = substr($dir, 0, -1);
}
// Strip / from the beginning
if ($dir && substr($dir, 0, 1) == '/')
{
$dir = substr($dir, 1);
}
$url = str_replace($pathinfo['dirname'] . '/', '', $url);
// Strip / from the beginning
if (substr($url, 0, 1) == '/')
{
$url = substr($url, 1);
}
$url = (!empty($dir) ? $dir . '/' : '') . $url;
$url = generate_board_url() . '/' . $url;
}
} }
// Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2 // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2