php文件上传之白名单00截断实验

发布时间 2023-06-12 13:49:09作者: 晨风晓曦

%00截断

介绍:

0x00,%00,/00 在url中 %00 表示ascll码中的 0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。但是所谓的if拦截仍会读取后面的后缀达到绕过白名单的效果。

当前版本环境:

PHP版本低于5.4.24,或者PHP版本在5.5.8到5.6.0之间,且GPC关闭(php.in中"magic.quotes gpc"选项设置为0ff) ,则可能存在PHP文件上传时被00截断的问题,此后的PHP版本中,该问题已经得到修复,同时不再需要关闭GPC

image-20230612103240511

前端界面:

image-20230612103000796

源码:

<?php
// 允许上传的图片后缀
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
echo $_FILES["file"]["size"];
$extension = end($temp);     // 获取文件后缀名

var_dump($extension);
var_dump($_FILES["file"]["name"]);


if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800000)
&& in_array($extension, $allowedExts))
{
        if ($_FILES["file"]["error"] > 0)
        {
                echo "错误:: " . $_FILES["file"]["error"] . "<br>";
        }
        else
        {
                echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
                echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
                echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
                echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "<br>";

                // 判断当期目录下的 upload 目录是否存在该文件
                // 如果没有 upload 目录,你需要创建它,upload 目录权限为 777
                if (file_exists("upload/" . $_FILES["file"]["name"]))
                {
                        echo $_FILES["file"]["name"] . " 文件已经存在。 ";
                }
                else
                {
                        // 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
                        move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
                        echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];
                }
        }
}
else
{
        echo "非法的文件格式";
}
?>

源代码中:

正常%00截断上传流程:

image-20230612102615117

8635edd7df6153fdd97e13c36c90af4

获取的后缀是.php所以绕不过第一个if白名单的检测。

更改之后的代码:

<?php
// 允许上传的图片后
$savepath=$_GET["savepath"];
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $savepath);
echo $_FILES["file"]["size"];
var_dump($temp);
$extension = end($temp);     // 获取文件后缀名
echo $extension;
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800000)
&& in_array($extension, $allowedExts))
{
        if ($_FILES["file"]["error"] > 0)
        {
                echo "错误:: " . $_FILES["file"]["error"] . "<br>";
        }
        else
        {
                echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
                echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
                echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
                echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "<br>";

                // 判断当期目录下的 upload 目录是否存在该文件
                // 如果没有 upload 目录,你需要创建它,upload 目录权限为 777
                if (file_exists("upload/" . $_FILES["file"]["name"]))
                {
                        echo $_FILES["file"]["name"] . " 文件已经存在。 ";
                }
                else
                {
                        // 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
                        move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $savepath);
                        echo "文件存储在: " . "upload/" . $savepath;
                }
        }
}
else
{
        echo "非法的文件格式";
}
?>

使用$savepathPOST传递文件名称参数,$extension = end($temp)=123.php%00.jpg=jpg,从而绕过白名单的检测,最后的move_uploaded_file保存$_FILES["file"]["tmp_name"]使用截断绕过避免生成生成静态文件123.php%00.jpg。image-20230612103713065

结果:

image-20230612104400348

参考:

http://www.admintony.com/关于上传中的00截断分析.html