一、文件上传漏洞靶场练习第12关
1. 查看源码
- 白名单机制:通过检查文件扩展名实现安全控制,仅允许特定类型文件上传
- 路径参数:使用save_path参数控制文件保存位置,该参数值可从请求中修改
2. 抓包分析
1)save_path参数的作用
- 参数位置:出现在POST请求的URL参数中
- 功能说明:控制上传文件的存储路径和文件名
- 安全风险:前端参数可被修改,导致路径可控漏洞
2)Content-Disposition字段
- 主要用途:
- 响应头中:指定下载文件的默认名称
- 请求头中:定义表单数据的字段名和文件名
- 示例说明:服务端可通过该字段指定下载文件名为"1.txt"
- 实际应用:在本次请求中用于指定上传文件的字段名和原始文件名
3)文件名截断技术
- 基本原理:利用特殊字符使程序提前终止字符串处理
- 实现方式:
- 在期望文件名后添加截断字符(如NULL字节)
- 再拼接合法后缀绕过检查
- 双重作用:既绕过黑名单检查,又确保服务器保存预期文件名
- 跨语言特性:该技术在PHP、Java等多种语言中均有效
4)URL编码与截断字符
- 关键字符:NULL字节(ASCII 0)作为截断标志
- 编码形式:在URL中需编码为%00
- 处理机制:服务器解码后遇到该字符即停止后续处理
- 实际应用:构造shell.php%00.png形式实现绕过
5)文件上传与验证绕过
- 白名单校验:检查文件扩展名是否在允许列表(jpg/png/gif)
- 路径拼接:将save_path与随机生成的文件名组合
- 绕过方法:
- 修改上传文件名为图片格式(如.png)
- 在保存路径参数中添加截断字符
- 确保最终保存的文件名为.php扩展名
6)访问上传的文件
- 存储位置:默认保存在PHP study的upload目录
- 访问验证:通过浏览器直接访问上传的PHP文件
- 结果确认:文件可正常执行,证明绕过成功
- 安全影响:攻击者可借此上传webshell控制服务器
3. 文件命名截断绕过上传路径控制
1)抓包分析
- Content-Disposition作用:在HTTP应答中指示内容展示形式(内联或附件下载),在multipart/form-data类型中用于定义子部分字段信息
- 关键参数限制:HTTP场景仅允许使用form-data、name和filename三个参数
- 白名单验证:代码检查文件扩展名是否在array('jpg','png','gif')中
- 重命名机制:使用随机数+时间戳生成新文件名,如rand(10,99).date("YmdHis").".$file_ext
- 二进制检测:通过读取文件头2字节判断真实类型(255216-jpg/13780-png/7173-gif)
- 安全措施:即使绕过扩展名检查,未知文件类型仍会被拦截
2)截断技术实现
- 路径存储位置:第13关将保存路径放在Content-Disposition字段而非URL中
- 编码差异:需要改用16进制00截断而非URL编码的%00
- 操作步骤:
- 在filename后添加占位符(如+号)
- 切换Hex视图将2B改为00
- 同时修改显示文件名为合法扩展名(如.jpg)
- 验证要点:需确保截断后无残留内容影响路径拼接
- 兼容性:同一漏洞在不同位置(URL/header)需要采用不同编码方式的截断字符
3)技术原理总结
- 核心原理:利用
chr(0)\operatorname{chr}(0)chr(0)
截断文件路径处理流程 - 两种实现:
- URL编码形式:filename=test.php%00.txt
- 16进制形式:在Content-Disposition字段插入\x00
- 防御建议:
- 严格校验文件头与扩展名的匹配
- 过滤所有位置的空字符
- 使用不可预测的存储路径
4. 文件头知识讲解
1)php版本切换
- 版本要求:使用PHP study默认最新的nts 7.3.4版本
- 操作步骤:切换版本后需要重启服务才能生效
2)查看源码
- 检查原理:通过读取文件前两个字节判断文件类型
- 255216 → JPG
- 13780 → PNG
- 7173 → GIF
- 文件保存:根据检测到的实际类型进行重命名保存
3)文件头规范
- JPG:FF D8(十六进制)
- PNG:89 50 4E 47(对应ASCII字符".PNG")
- GIF:47 49 46 38 39|37 61(对应"GIF89a"或"GIF87a")
- BMP:42 4D(对应"BM")
- CLASS文件:CA FE BA BE(十六进制但形成有意义的英文单词)
4)制作图片码命令
- Windows命令:
- Linux命令:
- 验证方法:
- 图片查看器能正常打开
- 文本编辑器能看到尾部包含恶意代码
5)文件包含漏洞
- 原理:通过include函数动态包含其他文件内容
- 危险点:未限制包含路径时可能执行恶意代码
- 利用方法:
6)新函数的应用
- getimagesize函数
- 功能:获取图像尺寸并验证文件有效性
- 支持格式:GIF/JPG/PNG/SWF/PSD/TIFF等
- 返回值:无效图像返回false并报错
- exif_imagetype函数
- 功能:读取文件第一个字节检查签名
- 与文件头检查区别:自动完成文件头验证
- 返回值:返回对应的图像类型常量
7)例题:图片码上传
- 题目解析
- 解题步骤:
- 制作包含muma的图片码
- 上传图片码文件
- 通过文件包含漏洞执行代码
- 关键点:
- 必须保持图片文件头有效
- 需要配合文件包含漏洞使用
- 防御方法:
- 严格限制包含文件路径
- 禁用危险函数
- 解题步骤:
二、exif_imagetype函数说明
1. 函数功能
- 功能: 读取图像的第一个字节并检查其签名(文件头)
- 用途:
- 避免在不支持的文件类型上调用其他exif函数
- 与$_SERVER['HTTP_ACCEPT']结合检查浏览器是否支持显示特定图像
- 参数: 接受一个字符串参数$filename,表示被检查的图像文件名
2. 实现原理
- 签名本质: 实际检查的是文件的文件头信息
- 验证机制: 将文件扩展名与实际文件内容进行对比验证
- 例如:扩展名为.gif的文件,会检查实际内容是否符合GIF格式标准
- 如果强行修改文件扩展名但内容不符,函数会返回错误
3. 使用注意事项
- 依赖模块: 需要开启php_exif模块才能正常使用
- 配置修改: 本质是通过修改php.ini配置文件来启用该功能
- 版本兼容性: 某些PHP版本可能不包含该扩展,强行启用会导致报错
三、实际应用与测试
1. 环境配置
- 版本选择: 建议使用线程安全的PHP 7.4.22版本
- 模块启用: 需要确保php_exif扩展已正确启用
- 配置验证: 修改配置后需要重启Apache服务
2. 测试方法
- 测试要点:
- 保证上传后的图片马包含完整的恶意代码
- 使用文件包含漏洞运行图片马中的代码
- 需要使.jpg、.gif、.png三种格式都上传成功
- 验证逻辑: 函数会严格检查文件实际内容与扩展名的匹配性
3. 常见问题
- 版本差异: 不同PHP版本对exif扩展的支持程度不同
- 错误处理: 在不支持的版本中强行启用扩展会导致服务报错
- 调试建议: 可尝试多个PHP版本找到兼容的配置方案
4. 实用技巧
- 测试策略: 当遇到问题时,可尝试以下方法:
- 切换不同PHP版本进行测试
- 检查php.ini配置是否正确
- 确认Apache服务已正常重启
- 验证php_exif模块是否真正加载成功
四、知识小结
知识点 |
核心内容 |
考试重点/易混淆点 |
难度系数 |
文件上传漏洞(第12关) |
利用save_path参数控制上传路径,通过文件名截断(%00)绕过白名单校验 |
%00截断原理与URL编码格式 |
⭐⭐⭐ |
文件上传漏洞(第13关) |
截断字符从URL参数移至Content-Disposition字段,需通过16进制编辑器修改为0x00 |
非URL场景下的截断字符实现方式 |
⭐⭐⭐⭐ |
文件头校验(第14关) |
检测文件前两字节(如FFD8=JPEG),需制作图片码(图片+恶意代码) |
常见文件头标志(JPEG/PNG/GIF) |
⭐⭐⭐ |
文件包含漏洞 |
通过include.php动态包含图片码中的恶意代码 |
协议缺失导致连接失败 |
⭐⭐⭐⭐ |
图片码制作 |
copy /b命令合并图片与木马文件,生成可显示且含代码的图片 |
Linux下使用cat命令 |
⭐⭐ |
函数检测绕过(第15关) |
getimagesize()函数验证文件是否为有效图片 |
仅校验基础属性,不深度检测内容 |
⭐⭐ |
扩展依赖(第16关) |
exif_imagetype()需开启PHP的exif扩展 |
版本兼容性问题(如TS/NTS版本差异) |
⭐⭐⭐⭐ |