一次白名单绕过分析
字数 1209 2025-08-05 11:39:45
白名单绕过技术分析与实战教学
0X00 前言
文件上传漏洞是Web安全中常见的高危漏洞,主要分为黑名单和白名单两种防护机制:
黑名单机制
- 定义:明确禁止上传特定后缀的文件
- 探测方法:上传不存在的后缀文件(如
1.jpgsssss) - 常见绕过方式:
- 利用黑名单遗漏的可执行后缀(如ASP.NET中的
.aspx、.ashx、.asmx等) - Windows系统特性(如
%00截断,PHP 5.2.x版本有效) - 特殊字符引发报错获取上传路径
- 上传
web.config文件(如果未被限制) - 结合中间件解析漏洞(IIS6.0、IIS7.5、Nginx配置不当、Apache畸形解析)
- 利用黑名单遗漏的可执行后缀(如ASP.NET中的
白名单机制
- 定义:只允许上传特定后缀的文件
- 安全性:相对黑名单更安全,但并非绝对安全
- 绕过思路:结合中间件特性或特定环境条件
0X01 白名单绕过实战分析
漏洞发现过程
- 初始测试遇到登录框难以突破
- 通过FOFA批量收集使用相同系统的站点
- 批量扫描备份文件获取
bin.zip进行灰盒测试
代码审计关键点
分析MyUpload类的ProcessRequest方法:
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
string val = request["hash"];
int count = request.Files.Count;
string text = string.Empty;
if (val.IsNullOrEmpty())
{
if (count > 0)
{
text = this.CommonSave(context); // 常规保存
}
}
else
{
text = this.SliceSave(context); // 分片保存
}
// 后续处理...
}
1. CommonSave方法分析(常规上传)
- 获取文件名和后缀
- 严格检查后缀是否在白名单中
- 无直接绕过可能
2. SliceSave方法分析(分片上传)
关键漏洞点:
- 获取
hash参数并拼接.yqdata后缀 - 检查
fileName和hash的后缀是否在白名单中 - 文件最终重命名逻辑:
其中string text7 = text6.Substring(0, text6.LastIndexOf(".")) + extension;extension来自fileName参数的后缀
绕过原理
- 构造
hash参数为11111.asp.(注意结尾的点) - 系统处理:
Path.GetExtension(text)获取后缀时,结尾的点不被识别为有效后缀- 绕过白名单检查
- 最终文件名为
11111.asp(系统自动去除结尾的点)
漏洞利用步骤
- 确保
hash参数不为空 - 设置
hash=malicious.asp.(恶意文件名加结尾点) - 设置
ok=1确保进入文件重命名流程 - 上传文件最终会被保存为
malicious.asp
0X02 防御建议
-
严格后缀检查:
- 实现真正的白名单机制
- 检查文件名前后是否有异常字符(如结尾的点)
-
文件重命名:
- 上传文件统一使用系统生成的随机名
- 不保留用户提供的任何文件名信息
-
参数校验:
// 改进后的后缀检查 if (!IsValidExtension(Path.GetExtension(text).Trim('.'))) { return "errorFile"; } -
文件内容检查:
- 对上传文件进行内容验证(如图片文件的魔数检查)
-
权限控制:
- 上传目录设置为不可执行
- 使用单独的子域处理文件上传
附录:完整漏洞代码
// 漏洞关键代码片段
private string SliceSave(HttpContext context)
{
// 获取并检查fileName参数
string fileName = Path.GetFileName(context.Request["fileName"]);
if (!fileName.IsNullOrEmpty())
{
string sextenName = Path.GetExtension(fileName);
if (!PageClass.GetDocumentType().Any((string x) => x.Equals(sextenName, StringComparison.CurrentCultureIgnoreCase)))
{
return "errorFile";
}
}
// 获取并检查hash参数(漏洞点)
string text = context.Request["hash"];
if (!text.IsNullOrEmpty())
{
string sextenName = Path.GetExtension(text);
if (!sextenName.IsNullOrEmpty() && !PageClass.GetDocumentType().Any((string x) => x.Equals(sextenName, StringComparison.CurrentCultureIgnoreCase)))
{
return "errorFile";
}
}
// 文件保存和重命名逻辑
string text2 = text + ".yqdata";
// ...省略中间代码...
if (File.Exists(text6))
{
text2 = context.Request["fileName"];
string extension = Path.GetExtension(text2);
string text7 = text6.Substring(0, text6.LastIndexOf(".")) + extension; // 最终文件名拼接
// ...省略后续代码...
}
}
总结
本案例展示了即使采用白名单机制,由于文件名处理逻辑的不严谨,仍然可能导致安全漏洞。关键在于:
- 结尾的点字符处理异常
- 文件名检查与最终命名的逻辑分离
- 缺乏对异常文件名的全面校验
安全开发应当遵循"不信任任何用户输入"的原则,对所有上传文件进行多重校验和严格处理。