2026-9-29-zip伪协议
zip伪协议
原题 https://www.ctfplus.cn/problem-detail/1836247027114053632/description
极客大挑战2023-web-famale_imp_l0ve
做题步骤
上传提交到 upload_file.php 但是发现一行注释: include.php 已废弃,只接受上传文件 暗示了文件包含点
访问 include.php 直接泄露自身源码(highlight_file):
1 | $file = $_GET['file']; |
上传文件只接受以zip为后缀的文件
漏洞点
include() 支持 zip:// 伪协议,可以直接从 zip 包内读取文件并执行 PHP
include.php 的 .jpg 后缀检查,对伪协议无用:只要让 file 参数末尾是 “.jpg” 就能过
攻击链
zip:///var/www/upload/shell.zip#shell.jpg
构造的zip文件中包含一个webshell
include.php 的 include() 支持 zip:// 伪协议 → ?file=zip:///var/www/upload/xxx.zip%23shell.jpg
末尾 “.jpg” 过了 include 的后缀检查,include 实际执行了 zip 里的 PHP → RCE → 读 /flag
漏洞题目源码
通过RCE拿到
1 |
|
漏洞分析报告
漏洞 1(核心):第 4-5 行 + 第 13 行 —— 只查后缀、不查内容
- 第 4 行 $ext_arr = array(‘zip’) 是白名单,只有 zip。
- 第 5 行取扩展名:strrpos(name, “.”) + 1 拿到最后一个点后面的字符串。
- 第 13 行 in_array($file_ext, $ext_arr) 判断扩展名是不是 zip。
问题:这只是”文件名后缀”检查,完全不看文件真实内容/MIME。而且它还有个隐藏 bug——没做 strtolower,是大小写敏感的(传 .ZIP 会直接进 else 报”必须上传.zip哦”)。这就是出题人嘲讽的”压缩了一定安全”:开发者以为”只让传 zip 就安全了”,但 zip 恰恰能被 zip:// 伪协议包起来执行 PHP。
漏洞 2:第 24 行 —— 文件名用户可控,直接拼进路径
move_uploaded_file($_FILES[“file”][“tmp_name”], “upload/“ . $_FILES[“file”][“name”]);
存储路径用了 $_FILES[“file”]”name”,没有做路径清洗。虽然本题没走到路径穿越,但这是典型的”文件名可控 + 拼接路径”隐患。
漏洞 3(代码质量暴露的烂摊子):第 7-11 行的死代码
- 第 7 行 $file = … $_POST[‘filename’] 引用了前端已经被注释掉的 filename 字段
- 第 9 行 $name = basename($_POST[‘filename’]) —— 此时 $_POST[‘filename’] 根本不存在(表单里没有这个字段),是 undefined
- 第 10 行 $filename_ext 算了也没用
- 第 11 行 $filename = $_FILES[‘file’][‘name’] 才真正赋值
这几行是开发者改了一半留下的残骸:前端注释掉 filename 输入框(“懒得换前端了😋”),后端却还留着处理 filename 的代码,$file/$name/$filename_ext 全是死变量。这本身不是可利用点,但强烈暗示”后端和前端不同步、改得仓促”——这也是 CTF 里常见的出题信号。
三、include.php 的漏洞(上一题已确认,这里补全)
$file = $_GET[‘file’]; if(isset($file) && strtolower(substr($file, -4)) == “.jpg”){ include($file); // ← 第 7 行,任意文件包含 }
include($file) 是任意文件包含;.jpg 后缀检查被 zip:// 伪协议绕过。
四、两洞串联
上传 zip(过 upload_file.php 的后缀白名单)→ include.php 用 zip:///var/www/upload/readsrc.zip#r.jpg 包含(末尾 .jpg 过检查)→ 执行 zip 里的 PHP → RCE。