一、文件上传漏洞
1. 文件上传漏洞六大关
1)文件上传漏洞之第六关
- 第六关和第四关源码对比
- 黑名单机制:第六关依然采用黑名单机制,禁用了包括".php"、".php5"、".php4"、".php3"、".htaccess"等扩展名。
- 关键差异:与第四关相比,第六关源码缺少了将扩展名统一转换为小写的处理步骤(
fileext=strtolower(file_ext=strtolower(fileext=strtolower(
file_ext))。 - 防御漏洞:由于没有大小写转换处理,导致系统对扩展名大小写敏感,为绕过黑名单提供了可能。
- 处理步骤对比:
- 删除文件名末尾的点:两关都有实现(
filename=deldot(file_name=deldot(filename=deldot(
file_name)) - 去除字符串"::SDATA":两关都有实现(str_ireplace)
- 首尾去空格:两关都有实现(trim)
- 唯一区别:第六关缺少大小写转换处理
- 删除文件名末尾的点:两关都有实现(
- 利用文件名大小写敏感的问题
- 绕过原理:由于系统未对扩展名进行大小写转换,可以使用".PHP"等变体绕过黑名单检测。
- 测试过程:
- 将webshell文件扩展名改为大写的".PHP"
- 成功上传后测试连接
- 验证webshell可正常执行
- 防御思路:
- 黑名单机制必须配合大小写统一处理
- 文件上传功能应实现完整的扩展名规范化处理
- 防御的关键在于识别系统未做的处理,并针对性利用
- 实战技巧:
- 在Windows系统中无法同时存在大小写不同的同名文件
- 上传前需删除之前测试用的小写php文件
- 连接测试时注意观察响应状态
2)文件上传漏洞之第七关
- 第七关和第六关源码对比
- 源码关键处理:
- 转换为小写
- 去除点号
- 未进行首尾去空格处理
- 绕过思路:在文件名前后添加空格可以绕过黑名单检测
- 原理说明:黑名单中没有包含带空格的文件名格式,而系统未做空格处理
- 源码关键处理:
- 利用WINDOWS操作系统特性问题
- Windows特性:
- 自动去除文件名中的空格
- 但上传时可以通过抓包修改原始文件名
- 实际操作步骤:
- 使用Burp Suite拦截上传请求
- 在文件名后添加空格(如"shell.php ")
- 转发修改后的请求
- 环境要求:
- 需要使用PHP 5.2.17非线程安全版本
- 其他版本可能无法成功
- 验证方法:
- 上传后检查文件是否保留空格
- 尝试连接上传的webshell
- 注意事项:
- 不同PHP版本处理方式可能不同
- 需要重启Apache服务使版本更改生效
- 上传路径需要正确配置
- 技术要点总结:
- 利用系统未处理的空格特性
- 通过抓包工具修改原始请求
- 环境配置对漏洞利用成功至关重要
- 需要实际测试验证绕过效果
- Windows特性:
3)文件上传漏洞之第八关
- 第八关和第七关源码对比
- 过滤机制差异:
- 第七关仅去除文件名末尾空格
- 第八关新增deldot()函数删除文件名末尾的点
- 两者都包含大小写转换和::$DATA字符串处理
- 黑名单扩展:
- 第八关黑名单更全面,包含.php各种变体和.asp、.jsp等
- 使用strtolower()统一转为小写进行匹配
- 过滤机制差异:
- 利用文件名最后有点和空格的问题
- Windows系统特性
- 空格处理:
- Windows不允许文件名末尾出现空格
- 上传时带空格的文件名会被自动去除空格
- 导致黑名单校验时扩展名不匹配
- 点号处理:
- Windows不允许纯点号结尾的文件名
- 上传shell.php.会被自动去除末尾点
- 实际保存为shell.php绕过校验
- 空格处理:
- 漏洞利用方法
- 攻击步骤:
- 使用Burp拦截上传请求
- 在文件名后添加点或空格(如shell.php.)
- 服务器处理时会自动去除特殊字符
- 实际保存为可执行文件
- 环境依赖:
- 需要Windows服务器环境
- PHP版本影响成功率(测试中7.3.4和5.2.17表现不同)
- 需关闭代理拦截进行测试
- 攻击步骤:
- 防御措施
- 代码层面:
- 使用trim()去除首尾空白
- 实现deldot()处理末尾点号
- 结合str_ireplace()处理特殊字符串
- 系统层面:
- 限制上传目录执行权限
- 使用随机文件名存储
- 设置文件内容类型检查
- 代码层面:
- Windows系统特性
4)文件上传漏洞之第九关
- 第九关和第八关源码对比
- 数据管理设置:展示了URL地址、IP地址、创建时间等关键字段,其中包含多个上传成功的PHP文件记录
- 版本信息:Apache版本为2.4.39,MySQL版本为8.1.1.3
- 目录特征:包含Pass-01到Pass-21的测试目录,其中Pass-08和Pass-09被重点标注
- 文件类型:展示了多种上传文件类型包括.php、.jpg、.htaccess等
- 利用文件名加上日期符号的问题
- 关键处理步骤:
- $file_name = deldot($file_name):删除文件名末尾的点
- $file_ext = strtolower($file_ext):转换为小写
- $file_ext = str_ireplace('::$DATA','',$file_ext):去除字符串::$DATA
- $file_ext = trim($file_ext):首尾去空
- 黑名单设置:包含.php、.php5、.phtml等17种禁止上传的扩展名
- 环境配置:显示使用phpstudy环境,PHP版本包括5.1.6、7.4.22等多个版本
- 路径信息:上传文件存储在E:/dev_runApp/phps路径下
- 测试文件:包含202110202234451136.php、shell.php等多个测试文件
- 目录结构:显示上传文件存储在upload目录下
- 防御措施:
- 删除文件名末尾的点
- 转换为小写
- 去除特殊字符串
- 首尾去空
- 上传逻辑:使用move_uploaded_file函数实现文件移动
- 请求特征:
- 使用multipart/form-data格式
- 文件名包含特殊字符"shell.php.."
- 包含PHP代码@eval($_POST['wuya'])
- 成功条件:当文件扩展名不在黑名单中时,返回"上传成功"消息
- 路径构造:使用UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext生成最终存储路径
- 关键技巧:
- 版本选择:使用PHP 7.4.22版本测试成功
- 文件名处理:Windows系统会自动去除文件名中的特殊符号
- 测试方法:需要同时尝试带特殊符号和不带特殊符号的文件名进行访问
- 拦截时机:在文件扩展名检查通过后,实际移动文件前进行拦截修改
- 连接验证:通过http://localhost/upload-labs/upload/202110202243304373.php成功连接
- 环境确认:最终使用PHP 7.3.4版本演示成功
- 关键处理步骤:
5)文件上传漏洞之第十关
- 第十关和第九关源码对比
- 处理顺序:先删除文件名末尾的点,再删除空格,然后转换为小写,最后去除字符串"::$DATA"
- 黑名单机制:使用数组$deny_ext定义禁止上传的文件扩展名,包括".php",".php5"等多种变体
- 文件重命名:使用date("YmdHis")和rand(1000,9999)生成随机文件名
- 利用文件名加一个点和一个空格的问题
- 绕过原理:通过构造"点空格点"的文件名(如shell.php. .),利用处理顺序的漏洞
- 第一步删除末尾点:shell.php.
- 第二步删除空格:shell.php.
- 最终保留的点会被操作系统自动删除
- 版本差异:
- PHP 7.3.4版本可以成功上传但连接不上
- PHP 5.2.17版本可以完全绕过
- 实战步骤:
- 构造文件名如"shell.php. "
- 使用Burp Suite拦截修改上传请求
- 多次forward测试不同版本效果
- 注意事项:
- 需要尝试不同PHP版本环境
- 部分版本会保留date时间戳导致连接失败
- 文件名处理顺序是关键突破口
- 绕过原理:通过构造"点空格点"的文件名(如shell.php. .),利用处理顺序的漏洞
- 第十关特殊绕过技巧
- 核心函数:仅使用str_ireplace进行简单替换
- 与第九关区别:缺少删除点、转换大小写等处理步骤
- 测试发现:传统绕过方法在本关无效,需要寻找新的利用点
二、文件上传漏洞利用技术
1. 利用文件名包含黑名单特性
- 黑名单替换机制: 使用
strireplace()str_ireplace()strireplace()
函数将黑名单中的扩展名替换为空字符串,如上传"shell.php"会被处理为"shell" - 黑名单内容: 包含常见Web脚本扩展名如
".php",".php5",".html",".jsp",".asp"".php", ".php5", ".html", ".jsp", ".asp"".php",".php5",".html",".jsp",".asp"
等 - 处理流程:
- 获取文件名
filename=trim(file_name = trim(filename=trim(
_FILES['upload_file']['name'])$ - 替换黑名单扩展名
filename=strireplace(file_name = str_ireplace(filename=strireplace(
deny_ext,"",filename)file_name)filename)
- 移动临时文件到目标路径
- 获取文件名
2. 应用案例
1)例题:webshell文件上传
2)题目解析
- 绕过方法: 使用双写扩展名如"shell.pphphp",第一次替换后剩余"shell.php"
- 实现原理:
- 系统仅执行单次替换,不会递归处理
- 匹配到第一个".php"后替换为空,保留后续字符
- 验证过程:
- 上传"shell.pphphp"文件
- 服务器处理后得到有效".php"文件
- 通过中国蚁剑成功连接验证
- 关键代码段:
denyext=array("php","php5","php4","php3","php2");deny_ext = array("php","php5","php4","php3","php2"); denyext=array("php","php5","php4","php3","php2");
file_name = str_ireplace(
denyext,"",deny_ext,"",denyext,"",
file_name);
- **注意事项**: - 需要确保服务器不会对文件名进行递归处理 - 上传路径必须存在且可写 - 该方法仅适用于简单的字符串替换型黑名单 #### 三、知识小结 | 知识点 | 核心内容 | 考试重点/易混淆点 | 难度系数 | |--------|----------|--------------------|----------| | 文件上传漏洞-黑名单绕过 | 利用系统特性绕过黑名单检测(大小写敏感、空格处理、点处理等) | **大小写敏感绕过**(PHP→pHp)、**空格绕过**(需特定PHP版本)、**点绕过**(Windows自动去除末尾点) | ★★★☆ | | 第六关绕过技巧 | 未统一转换为小写的黑名单校验漏洞 | 上传`.PHP`扩展名文件(系统大小写敏感) | ★★☆☆ | | 第七关绕过技巧 | 未处理首尾空格的黑名单校验漏洞 | **抓包修改**添加空格(需PHP 5.2.17环境) | ★★★☆ | | 第八关绕过技巧 | 未处理末尾点的黑名单校验漏洞 | 文件名末尾添加点(如`shell.php.`) | ★★☆☆ | | 第九关绕过技巧 | 未过滤`::$DATA`流特性 | 文件名添加`::$DATA`(Windows NTFS特性) | ★★★★ | | 第十关绕过技巧 | 多重删除逻辑漏洞 | **点+空格+点组合**(`. .`)触发系统自动处理 | ★★★★ | | 第十一关绕过技巧 | 单次替换过滤漏洞 | **双写绕过**(如`pphphp`→处理后保留`php`) | ★★☆☆ | | 环境版本影响 | PHP版本差异导致漏洞复现结果不同 | **关键版本**:PHP 5.2.17非线程安全版 vs PHP 7.3.4 | ★★★★ |