某次实战代码审计出sql注入漏洞记录
字数 1602 2025-08-10 08:28:27
ASP.NET SQL注入漏洞审计实战分析
漏洞背景
在某次实战项目中,审计人员对一套ASP.NET开发的CMS系统进行代码审计时,发现了多处SQL注入漏洞。本文详细记录其中一处较为典型的注入漏洞的发现和分析过程。
系统环境分析
- 系统架构:ASP.NET运行环境
- 关键文件:
Global.asax:提供全局可用代码,包括应用程序事件处理程序web.config:基于XML的配置文件,存储数据库连接字符串等
- URL重写机制:系统使用URL Rewrite将请求重定向到处理程序(如
/api/a/b/c请求会被转发到/api/a/b/c.ashx)
漏洞定位过程
-
API目录结构分析:
/api/user:需要登录/api/manager:需要登录/api/common:公开访问(最终漏洞点)
-
漏洞文件定位:
- 在
/api/common/search.ashx中发现漏洞 - 后端代码位于
xxxxcms.web.dll中
- 在
代码审计分析
1. 请求处理流程
-
ProcessRequest()方法:- 获取URL中
action参数值 - 当
action=search_tip时调用GetsearchTip()方法
- 获取URL中
-
GetsearchTip()方法处理逻辑:// 获取并处理POST请求中的val参数 string val = PostTagValue(context.Request, "val"); val = UnEscape(val); // 设置默认types值 string types = PostTagValue(context.Request, "types"); if (string.IsNullOrEmpty(types)) types = "content"; // 将val参数拼接到condition数组 string[] condition = new string[] { types, val }; // 执行查询 ResultSet(condition); -
ResultSet方法最终调用SelectRecords存储过程执行SQL查询
2. 关键安全缺陷
-
过滤与解码顺序问题:
- 先使用
PostTagValue()过滤危险字符 - 然后使用
UnEscape()进行解码处理 - 这种顺序导致可以绕过过滤
- 先使用
-
PostTagValue()过滤函数:- 过滤单引号等大量危险字符
- 但过滤后的数据会被
UnEscape()解码
-
UnEscape()函数功能:- 处理两种编码格式:
- Unicode编码(
%u开头的编码) - URL编码(
%后跟两个十六进制数字)
- Unicode编码(
- 将编码后的字符解码为原始字符
- 处理两种编码格式:
漏洞利用原理
-
绕过过滤的方法:
- 将SQL注入payload先进行编码(URL编码+Unicode编码)
- 将Unicode编码中的
\u替换为%u - 这样能绕过
PostTagValue()的过滤 - 然后被
UnEscape()解码为原始注入语句
-
不同Content-Type的处理差异:
application/x-www-form-urlencoded:- 后端会先自动URL解码一次
- 需要将payload双重URL编码
- 上传格式(如multipart/form-data):
- 不会自动URL解码
- 只需单次编码即可
漏洞复现步骤
-
构造恶意请求:
POST /api/common/search.ashx?action=search_tip HTTP/1.1 Content-Type: application/x-www-form-urlencoded val=%25%37%35%25%36%66%25%36%39%25%36%65%25%36%34%25%36%36%25%37%35%25%36%65%25%36%33%25%37%34%25%36%39%25%36%66%25%36%65%25%32%38%25%32%39%25%32%64%25%32%64 -
编码解释:
- 原始payload:
unionfunction()-- - 第一次URL编码:
%75%6f%6e%69%6f%6e%66%75%6e%63%74%69%6f%6e%28%29%2d%2d - 第二次URL编码(针对application/x-www-form-urlencoded):对每个%再次编码为%25
- 原始payload:
-
multipart/form-data方式:
- 只需将payload进行一次URL编码+Unicode编码
- 将
\u替换为%u
修复建议
-
代码层面:
- 调整过滤顺序,先解码再过滤
- 使用参数化查询或ORM框架
- 对用户输入进行严格类型检查
-
架构层面:
- 实施最小权限原则
- 使用Web应用防火墙(WAF)
- 定期进行安全审计和代码审查
经验总结
-
审计重点:
- 关注用户输入的完整处理流程
- 特别注意编码/解码与过滤的顺序
- 注意不同Content-Type的处理差异
-
开发启示:
- 安全措施应该放在数据处理的最早阶段
- 不要依赖单一的安全控制
- 对用户输入保持零信任原则
-
扩展思考:
- 类似问题可能存在于其他解码场景(如base64、HTML实体编码等)
- 审计时应关注所有数据处理管道中的每个环节