Pikachu靶场-unsafe upfileupload
不安全的文件上传漏洞防御与对抗方式对照表
防御方式 | 防御实现 | 攻击者对抗方式 | 对抗原理 |
文件类型白名单验证 | 仅允许指定扩展名(如 .jpg, .png) if (!in_array($ext, ['jpg', 'png'])) { die(); } | 伪造文件类型: 1. 修改文件头(如GIF89a) 2. 使用双扩展名(如 shell.php.jpg) 3. 大小写混淆(如 SHELL.PHP) | 绕过扩展名检查,利用服务器解析漏洞执行恶意代码。 |
文件内容检测 | 检查文件内容的MIME类型或魔术字节: $finfo = new finfo(FILEINFO_MIME); $mime = $finfo->file($_FILES['file']['tmp_name']); | 在合法文件中嵌入恶意代码: 1. 图片木马(如Exif注释注入PHP代码) 2. 利用文件解析漏洞(如CVE-2021-44228) | 伪装成合法文件,利用解析器漏洞触发代码执行。 |
文件重命名 | 上传后重命名文件为随机哈希值: $new_name = md5(uniqid()) . '.' . $ext; | 1. 预测哈希算法生成文件名 2. 结合文件包含漏洞直接调用哈希名 3. 上传.htaccess覆盖解析规则 | 通过预测或间接利用其他漏洞获取文件路径,或强制服务器解析特定文件类型。 |
目录权限隔离 | 设置上传目录不可执行: chmod(upload_dir, 0755); 禁用上传目录的PHP解析: nginx: location ~* ^/uploads/.*\.php$ { deny all; } | 1. 利用服务器配置错误(如未禁用PHP解析) 2. 上传.htaccess文件修改解析规则: AddType application/x-httpd-php .jpg | 绕过目录执行限制,强制服务器将非PHP文件解析为代码。 |
文件大小限制 | 限制上传文件大小: php.ini: upload_max_filesize=2M <input type="hidden" name="MAX_FILE_SIZE" value="2097152"> | 分片上传绕过: 1. 通过多部分上传拼接文件 2. 利用HTTP请求篡改绕过前端校验 | 突破大小限制上传WebShell或大文件。 |
文件名过滤 | 过滤危险字符: $filename = str_replace(['../', '%00'], '', $_FILES['file']['name']); | 编码绕过: 1. URL编码(如 %2e%2e%2f 代替 ../) 2. Unicode编码(如 ..%u2216) 3. 空字节截断(如 shell.php%00.jpg) | 绕过路径遍历过滤,实现任意目录上传。 |
病毒扫描 | 调用杀毒引擎扫描上传文件: system("clamscan $uploaded_file"); | 1. 混淆恶意代码(如代码加密、多态变形) 2. 利用免杀技术(如反射型WebShell) | 逃避静态特征检测,使恶意文件不被识别。 |
客户端校验 | 前端JS校验文件类型: <input type="file" accept=".jpg,.png"> | 直接修改HTTP请求: 1. 使用Burp Suite篡改Content-Type和文件名 2. 删除前端校验代码 | 绕过客户端限制,上传任意类型文件。 |
日志与监控 | 记录所有上传行为: log_upload($user_ip, $filename); 部署WAF检测异常请求 | 1. 慢速攻击(低频上传) 2. 伪装正常流量(如图片缩略图+隐藏代码) | 避免触发告警规则,延长攻击潜伏时间。 |
防御与对抗关键点总结
安全代码示例(PHP)
// 1. 白名单验证 // 2. 内容检测 // 3. 重命名并存储 // 4. 设置权限 |
client check
1,所谓客户端检查就是前端的javascript代码在检查上传文件的后缀名
<script> // 检查上传文件扩展名 function checkFileExt(filename) { let isAllowed = false; // 记录是否符合要求 const allowedExts = ["jpg", "png", "gif"]; // 取出上传文件的扩展名(不含点) const dotIndex = filename.lastIndexOf("."); const ext = filename.substring(dotIndex + 1).toLowerCase(); // 校验扩展名 for (let i = 0; i < allowedExts.length; i++) { if (ext === allowedExts[i]) { isAllowed = true; break; // 找到匹配项后立即退出循环 } } // 如果不符合要求,给出提示并刷新页面 if (!isAllowed) { alert("上传的文件不符合要求,请重新选择!"); location.reload(true); } } </script> |
上传shell.php,果然弹窗告警不能上传.php文件
2,绕过方式,临时删除这段代码发现不行,禁用javascript可以。那就再使用burpsuite改后缀名试试
3,上传文件成功,使用蚁剑连接即可
server check(MIME type)
1,改包修改Content-Type为image/png,然后shell.png改成shell.php
2,上传文件成功,使用蚁剑连接即可
getimagesize()
文件上传功能防御措施分析
一、已实现的防御措施
二、潜在安全风险
防御措施 | 风险描述 | 攻击示例 |
扩展名白名单 | 未过滤双扩展名(如 shell.php.jpg),可能被特定服务器解析为PHP文件。 | 上传 evil.php.jpg,利用Apache配置漏洞解析为PHP代码。 |
MIME类型校验 | 依赖客户端提交的 Content-Type,可被Burp Suite等工具篡改。 | 修改请求头为 Content-Type: image/png 上传PHP文件。 |
getimagesize()验证 | 无法检测图片中嵌入的恶意代码(如Exif注释注入)。 | 在图片元数据中插入 <?php system($_GET['cmd']); ?>。 |
路径泄露 | 上传成功后返回文件存储路径: <p>文件保存的路径为:{$upload['save_path']}</p> | 攻击者直接访问路径执行恶意文件: http://example.com/uploads/2023/10/05/evil.jpg。 |
三、攻击验证方法
- 修改上传请求的 Content-Type 为 image/png,上传PHP文件。
- MIME类型伪造
- 使用ExifTool插入PHP代码到图片注释:
exiftool -Comment='<?php system($_GET["cmd"]); ?>' normal.jpg - 图片马注入
- 上传 shell.php.jpg,利用服务器解析漏洞(如配置 AddType application/x-httpd-php .jpg)。
- 双扩展名绕过
- 按日期分目录存储,降低目录遍历风险。
- 目录隔离与路径隐藏
$save_path = 'uploads'.date('/Y/m/d/'); // 按日期生成存储路径 - 防止上传大体积WebShell或恶意文件。
- 文件大小限制
upload('uploadfile','512000',...); // 限制文件大小为500KB - 使用 getimagesize() 检测文件是否为真实图片,防止伪装图片的恶意文件(如包含PHP代码的图片马)。
- 图片内容验证
// uploadfunction.php 中可能调用 getimagesize() 验证图片有效性 - 通过 $_FILES['uploadfile']['type'] 验证文件类型。
- MIME类型校验
$mime = array('image/jpg','image/jpeg','image/png');
// 检查上传文件的MIME类型 - 仅允许上传 .jpg, .jpeg, .png 文件。
- 扩展名白名单验证
$type = array('jpg','jpeg','png'); // 限制文件扩展名 - 防御方需关注新型攻击手法(如Polyglot文件、反序列化漏洞利用)
- 攻击方会持续探索逻辑漏洞(如条件竞争上传)
- 对抗升级:
- 禁用危险函数(如 putenv(), proc_open())
- 定期更新中间件(修复解析漏洞如Apache Tomcat CVE-2020-1938)
- 纵深防御:需组合使用白名单、内容检测、重命名、权限控制等多层防护,单一措施易被绕过。
- 输入不可信原则:所有用户输入(包括文件名、文件内容、HTTP头)均需严格过滤。
- 服务器加固: