绕过PHP中的目录遍历过滤器?

信息安全 php 目录遍历
2021-09-01 01:56:06

我有一个旧的 PHP 应用程序,它的代码类似于:

<?php

$doc = $_GET['doc'];

if (preg_match('#\.\./#', $doc)) {
  header("HTTP/1.1 403 Forbidden");
  die();
}

$content = file_get_contents("/home/example/src/docs/" . $doc);

echo $content;

过滤器对我来说看起来有点过于简单。我试过对它进行各种攻击,它似乎阻止了它们。谁能想到绕过这个过滤器的方法?

3个回答

确实是太简单了。您可以使用反斜杠字符绕过它。在我的 IIS 服务器上绕过它的方法示例: http://example.com/index.php?doc=..\/index.php

它检查“../”,而为了使其“更安全”,它应该检查“..”或者根本不允许任何点,并确保它只包含在请求的文件的扩展名中。

虽然除了 Technidev 已经描述的逃逸之外,我在 Linux/POSIX 系统上想不出任何东西,但这并不是说没有。如果是我,我会相信 realpath() 能够正确处理路径字符串的语义,而不管底层操作系统如何......

$basedir="/home/example/src/docs/";
$target=realpath("/home/example/src/docs/" . $_GET['doc']);
if (substr($target, 0, strlen($basedir)) != $basedir || !file_exists($target)) {
   header("HTTP/1.1 403 Forbidden");
   exit -1;
}

输入过滤和旁路

过滤器作为额外的安全层总是很棒,但它们不应该是您唯一的防线,因为通常过滤器缺少上下文,因此无法实现 100% 安全过滤。

例如,您的过滤器对底层操作系统一无所知。它接受\作为目录分隔符吗?如果是这样,..\可能会工作。@Technidev 提到了另一个问题..\/根据操作系统的不同,其他攻击也可能起作用(例如,在处理路径时可能会忽略一个字符,但在过滤时不会;我尝试%00了一个示例,但它不起作用)。不过,不应该有一个独立于操作系统工作的通用旁路。

一个更好但可能过于严格的过滤器会过滤...

适当的防御

您隐含的问题似乎是此代码是否安全,或者如何使其更安全。

如果您不需要路径,只需使用basename,它将返回一个文件名。

如果您确实需要路径,但它应该在 docs 目录中,请解析路径并将其与基本路径进行比较