2

考虑以下代码

<?php
// warning: this code is unsafe and for demonstrational purposes only,
// do not use in a production environment
$filename = $_GET['filename']; 
$extension = 'txt';
$path = '/absolute/path';
$fullFilename = sprintf('%s/%s.%s', $path, $filename, $extension);
echo file_get_contents($fullFilename);

我们都知道(至少我希望如此)预先设置绝对路径绝不是防止离开给定路径的充分方法——人们可以简单地../在查询字符串中插入一个或多个 " " 以到达文件上的任何路径系统。

我的问题是:与给定的示例类似,$_GET['filename']也可以通过绕过给定扩展后缀的方式进行操作,即回显 .txt 以外的文件?我特别想到了某些控制字符,它们../以与前缀相同的方式绕过附加的文件扩展名。

我尝试在查询字符串中添加一些控制字符(例如用于删除的 ASCII 代码 127)或使用&&,|或连接两个文件名>,但都无济于事,我想知道是否存在这种可能性。

(顺便说一句,我想补充一点,这个问题并不是为了利用系统而提出的。这纯粹是我最近想到的一个假设性问题。)

4

1 回答 1

2

当然,nullbyte, \0(或者%00如果您想在查询字符串中进行测试)将file_get_contents()在遇到该字符串时停止处理该字符串。

因此,如果$_GET['filename']../../../../../etc/passwd%00(例如your_page.php?filename=../../../../etc/passwd%00),file_get_contents()将永远不会看到结尾.txt(它会看到它,但不会处理它)。

可悲的是,sprintf在构建字符串时不会剥离 nullbyte。我不确定其他控制字符,但如果有的话 - 我总是建议剥离空字节。但是,更直观的方法是建立允许字符的白名单preg_match()并对输入执行 a。

在那个上一个,您可以realpath()在构建的字符串上使用 PHP,它将确定真正被访问的完整路径。所以,/absolute/path/../../../../etc/passwd\0.txt传递给realpath()将返回/etc/passwd。然后,您可以对返回的值进行进一步验证(例如,扩展是否仍然存在.txt或是否在指定/必需的目录中)。

于 2012-10-04T16:26:01.533 回答