磕磕绊绊的sql注入漏洞挖掘
字数 1238 2025-08-20 18:18:17
SQL注入漏洞挖掘实战教学文档
0x01 路由信息分析
.NET Web.config 文件解析
- 关键元素:
<httpHandlers>用于配置HTTP处理程序verb:请求方式(GET/POST/*表示任何方式)path:请求文件路径(*表示通配符)validate:是否验证HTTP处理程序type:处理类的完整命名空间路径
请求处理流程示例
POST /A8TOP/CarpaServer/CarpaServer.LoginService.ajax/UserLogin HTTP/1.1
- 请求
.ajax后缀 → 调用Carpa.Web.Ajax.AjaxHandlerFactory GetHandler方法处理请求,附加路径信息作为方法名(如UserLogin)Substring(1)去除路径前的/获取实际方法名
0x02 鉴权机制分析
鉴权核心方法CheckHasLogin
- 两种绕过方式:
!needLogin为真时直接返回true- 从
context获取session判断登录状态
C#特性(Attribute)机制
- 特性作用:为程序元素添加元数据(类似Python装饰器)
- NeedLogin特性:
- 完整类名:
NeedLoginAttribute - 使用时可省略
Attribute后缀([NeedLogin]) - 通过
IsDefined方法检查类/方法是否应用该特性
- 完整类名:
Web服务方法暴露
- 只有标记
[WebMethod]的公共方法才能被外部访问 - 审计重点:查找带有
[WebMethod]但未标记[NeedLogin]的方法
0x03 漏洞审计实战
初步筛选工具
import os
import re
import shutil
def traverse_directory(source_dir, dest_dir):
for root, dirs, files in os.walk(source_dir):
for file_name in files:
file_path = os.path.join(root, file_name)
if not contains_need_login(file_path):
copy_file(file_path, dest_dir)
def contains_need_login(file_path):
with open(file_path, 'r') as file:
for line in file:
if '[NeedLogin]' in line:
return True
return False
def copy_file(file_path, dest_dir):
relative_path = os.path.relpath(file_path, os.getcwd())
dest_path = os.path.join(dest_dir, relative_path)
dest_folder = os.path.dirname(dest_path)
if not os.path.exists(dest_folder):
os.makedirs(dest_folder)
shutil.copy(file_path, dest_path)
SQL执行方式分析
-
安全方式:
this.dbHelper.SelectFirstRow() // 使用参数化查询 -
危险方式A:直接字符串拼接
string sql = "SELECT * FROM users WHERE id=" + userInput; dbHelper.Select(sql); -
危险方式B:字符串格式化
string.Format("SELECT * FROM users WHERE id={0}", userInput);
正则匹配模式
# 直接拼接检测
pattern1 = r'string sql = ".+?"[\s]*\+'
# 字符串格式化检测
pattern2 = r'string.Format$"SELECT.*?"$'
连接字符串问题
- 常见问题:
AppUtils.CreateDbHelper()从UserInfo获取连接字符串 - 绕过方法:
- 查找调用
CreateDbHelper重载方法(接受database参数) - 查找直接实例化
DbHelper的代码
- 查找调用
改进的筛选函数:
def contains_need_login(file_path):
with open(file_path, 'r', encoding="gb18030", errors='ignore') as file:
for line in file:
if re.findall('new DbHelper$.+?$\)', line):
return False
if re.findall('CreateDbHelper$.+?$\)', line):
return False
return True
实战案例
[WebMethod]
public string GetData(string dbName, string param1, string jsonStr)
{
// json解析获取参数
var etypeid = jsonObj["etypeid"];
var vipcardid = jsonObj["vipcardid"];
// 危险拼接
string sql = "SELECT * FROM table WHERE id=" + etypeid;
return dbHelper.Select(sql);
}
漏洞验证流程
-
未授权验证:
- 不携带任何cookie直接访问
- 确认返回有效数据而非鉴权错误
-
注入验证:
POST /targetEndpoint HTTP/1.1 Host: target.com Content-Type: application/json { "dbName": "testdb", "param1": "value1", "jsonStr": "{\"etypeid\":\"1' AND 1=CONVERT(int,@@version)--\"}" } -
错误处理:
- 观察是否返回数据库错误信息
- 确认是否执行了拼接的SQL语句
防御建议
-
代码层面:
- 对所有数据库操作使用参数化查询
- 避免直接拼接用户输入到SQL语句
-
架构层面:
- 最小权限原则:数据库账户仅需必要权限
- 统一数据库访问层,禁止开发直接拼接SQL
-
审计工具:
- 使用SAST工具扫描SQL拼接模式
- 建立代码审计流程,特别是对
[WebMethod]标记的方法
总结
通过本教学文档,我们系统性地学习了:
- .NET路由处理机制与鉴权绕过方法
- C#特性在权限控制中的应用
- 三种SQL执行方式的区别与风险
- 自动化筛选漏洞代码的技术
- 连接字符串问题的解决方案
- 完整的漏洞验证流程
关键要点:关注未授权+SQL拼接的组合漏洞,特别是使用重载方法绕过鉴权的场景。