看起来这个问题在 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';
}
?>