看来这个问题在 PHP 5.3 中已修复 https://bugs.php.net/bug.php?id=39863
由于 PHP 使用底层 C 函数进行与文件系统相关的操作,它可能会以意想不到的方式处理空字节。由于空字节在 C 中表示字符串的结尾,因此包含空字节的字符串将不会被完全识别,而只识别到第一个空字节出现的位置。以下示例展示了一个容易受到空字节攻击的代码,它演示了这个问题
示例 #1 易受空字节攻击的脚本
<?php
$file = $_GET['file']; // "../../etc/passwd\0"
if (file_exists('/home/wwwrun/'.$file.'.php')) {
// file_exists 将返回 true,因为文件 /home/wwwrun/../../etc/passwd 存在
include '/home/wwwrun/'.$file.'.php';
// 将包含文件 /etc/passwd
}
?>
因此,在文件系统操作中使用的任何受污染的字符串都应该始终进行适当的验证。以下是前一个示例的改进版本
示例 #2 正确验证输入
<?php
$file = $_GET['file'];
// 白名单可能的值
switch ($file) {
case 'main':
case 'foo':
case 'bar':
include '/home/wwwrun/include/'.$file.'.php';
break;
default:
include '/home/wwwrun/include/main.php';
}
?>