From vuln-reproduce
Detects framework-level input sanitization mechanisms (MyBB clean_variables, WordPress absint, Laravel casts) to prevent SQL injection false positives in vuln audits.
npx claudepluginhub Clouditera/AI-Vuln-Reproduce --plugin vuln-reproduce> **Owner**: 分析师 (vuln-analyst) > **适用角色**: vuln-analyst, api-reproducer > **核心原则**:很多框架在请求到达业务代码之前就已经对输入进行了类型转换或清理,必须检查这些全局机制 --- ```yaml 原始报告声称: - Source: $_GET['tid'] 用户输入 - Sink: $db->simple_select('threads', 'fid', "tid = '{$mybb->input['tid']}'") - 结论: SQL 注入漏洞 实际代码分析: - MyBB 框架在初始化时调用 clean_input() - tid 在 $clean_variables['int'] 数组中 - 任何非数字输入都被强制转换为 0 - 用户输入 "1' OR '1'='1" → 变成整数 0 - 结论...Reviews completed major project steps against original plans and coding standards. Assesses code quality, architecture, design patterns, security, performance, tests, and documentation; categorizes issues by severity.
Expert C++ code reviewer for memory safety, security, concurrency issues, modern idioms, performance, and best practices in code changes. Delegate for all C++ projects.
Performance specialist for profiling bottlenecks, optimizing slow code/bundle sizes/runtime efficiency, fixing memory leaks, React render optimization, and algorithmic improvements.
Owner: 分析师 (vuln-analyst) 适用角色: vuln-analyst, api-reproducer
核心原则:很多框架在请求到达业务代码之前就已经对输入进行了类型转换或清理,必须检查这些全局机制
原始报告声称:
- Source: $_GET['tid'] 用户输入
- Sink: $db->simple_select('threads', 'fid', "tid = '{$mybb->input['tid']}'")
- 结论: SQL 注入漏洞
实际代码分析:
- MyBB 框架在初始化时调用 clean_input()
- tid 在 $clean_variables['int'] 数组中
- 任何非数字输入都被强制转换为 0
- 用户输入 "1' OR '1'='1" → 变成整数 0
- 结论: 框架级防护,SQL 注入不可利用 → 误报
根本原因:
- 只看到 sink(SQL 拼接)就判定漏洞存在
- 没有检查框架的全局输入清理机制
- 代码审计只分析了业务代码,忽略了框架初始化流程
在判定 SQL 注入存在前,必须检查框架是否有全局输入清理机制:
def check_framework_sanitization(framework_type, param_name):
"""
检查框架是否对指定参数进行了全局清理
Returns:
{
'sanitized': bool,
'sanitization_type': str, # int_cast | filter | whitelist | none
'location': str, # 清理代码位置
'evidence': str
}
"""
if framework_type == 'mybb':
# 检查 clean_variables 数组
clean_vars = find_clean_variables_config()
if param_name in clean_vars.get('int', []):
return {
'sanitized': True,
'sanitization_type': 'int_cast',
'location': 'inc/class_core.php:clean_input()',
'evidence': f'{param_name} 在 clean_variables["int"] 中,被强制转换为整数'
}
elif framework_type == 'wordpress':
# 检查是否使用了 absint/intval
if check_global_sanitization(param_name, ['absint', 'intval']):
return {
'sanitized': True,
'sanitization_type': 'int_cast',
'location': 'wp-includes/functions.php',
'evidence': f'{param_name} 经过 absint/intval 处理'
}
elif framework_type == 'laravel':
# 检查 Form Request 验证和 $casts
if check_form_request_rules(param_name) or check_model_casts(param_name):
return {
'sanitized': True,
'sanitization_type': 'validation',
'location': 'App\\Http\\Requests\\*',
'evidence': f'{param_name} 有 Form Request 验证规则'
}
return {
'sanitized': False,
'sanitization_type': 'none',
'location': None,
'evidence': '未发现框架级输入清理'
}
| 框架 | 清理机制 | 检查位置 | 关键代码 |
|---|---|---|---|
| MyBB | $clean_variables 数组 | inc/class_core.php | $clean_variables['int'] |
| WordPress | 全局清理函数 | wp-includes/functions.php | absint(), intval(), sanitize_*() |
| Laravel | Form Request + Casts | app/Http/Requests/* | $rules, $casts |
| CodeIgniter | Input 类自动过滤 | system/core/Input.php | $this->input->get() 的 XSS 过滤 |
| Symfony | ParamConverter | config/services.yaml | @ParamConverter 注解 |
| Yii2 | 验证规则 | Model::rules() | [['id'], 'integer'] |
| 框架 | 清理机制 | 检查位置 | 关键代码 |
|---|---|---|---|
| Express | 中间件验证 | middleware/*.js | express-validator |
| NestJS | 管道验证 | *.dto.ts | @IsInt(), ValidationPipe |
| Fastify | Schema 验证 | 路由定义 | schema: { params: {...} } |
| 框架 | 清理机制 | 检查位置 | 关键代码 |
|---|---|---|---|
| Spring | @Valid + 类型绑定 | Controller | @PathVariable Long id |
| Struts2 | 类型转换器 | struts.xml | <param name="..." type="long"/> |
特别关注以下类型强转模式,这些会使 SQL 注入无效:
PHP 类型强转:
- (int)$value
- intval($value)
- (float)$value
- floatval($value)
- abs($value) # 返回数值
JavaScript 类型强转:
- parseInt(value, 10)
- parseFloat(value)
- Number(value)
- +value # 一元加号转数值
Java 类型强转:
- Integer.parseInt(value)
- Long.parseLong(value)
- Integer.valueOf(value)
Go 类型强转:
- strconv.Atoi(value)
- strconv.ParseInt(value, 10, 64)
Python 类型强转:
- int(value)
- float(value)
发现 SQL 拼接点 (sink)
↓
识别输入参数名 (如 tid, pid, uid)
↓
检测项目使用的框架
↓
┌─────────────────────────────────────┐
│ 框架是否有全局输入清理机制? │
├─────────────────────────────────────┤
│ 是 → 检查该参数是否在清理列表中 │
│ ├─ 在列表中 → 检查清理类型 │
│ │ ├─ int/float 强转 → 不可利用│
│ │ ├─ 字符串过滤 → 需分析过滤 │
│ │ └─ 白名单 → 检查白名单完整性│
│ └─ 不在列表中 → 继续常规分析 │
│ 否 → 继续常规数据流分析 │
└─────────────────────────────────────┘
↓
发送真实请求验证
↓
对比正常请求与注入请求的响应差异
// inc/class_core.php
class MyBB {
public $clean_variables = array(
"int" => array(
"tid", // 帖子 ID
"pid", // 回复 ID
"uid", // 用户 ID
"fid", // 论坛 ID
"eid", // 事件 ID
"pmid", // 私信 ID
// ... 更多
),
"a]int" => array(
"forum_read", // 数组元素转整数
),
"pos" => array(
"page", // 必须为正整数
),
);
function clean_input() {
foreach($this->clean_variables as $type => $vars) {
foreach($vars as $var) {
if($type == "int") {
// 强制转换为整数
$this->input[$var] = (int)$this->input[$var];
}
// ...
}
}
}
}
# 检查 MyBB 的 clean_variables 配置
grep -A 50 'clean_variables' inc/class_core.php | grep -E '"int"|"pos"|"a\]int"' -A 10
# 检查特定参数是否被清理
grep -r 'tid|pid|uid|fid' inc/class_core.php | grep clean_variables
即使代码分析发现框架清理机制,仍必须通过真实请求验证:
# 1. 正常请求(基准)
curl "http://target/showthread.php?tid=1" -o normal.html
NORMAL_SIZE=$(wc -c < normal.html)
# 2. 注入请求
curl "http://target/showthread.php?tid=1'+OR+'1'='1" -o inject.html
INJECT_SIZE=$(wc -c < inject.html)
# 3. 无效参数请求(对照)
curl "http://target/showthread.php?tid=0" -o invalid.html
INVALID_SIZE=$(wc -c < invalid.html)
# 4. 分析结果
echo "正常请求: $NORMAL_SIZE bytes"
echo "注入请求: $INJECT_SIZE bytes"
echo "无效请求: $INVALID_SIZE bytes"
# 判定逻辑
if [ "$INJECT_SIZE" == "$INVALID_SIZE" ] && [ "$INJECT_SIZE" != "$NORMAL_SIZE" ]; then
echo "注入请求响应 = 无效参数响应 ≠ 正常响应"
echo "结论: 输入被清理/转换,SQL 注入不可利用"
fi
| 正常响应 | 注入响应 | 无效响应 | 判定 |
|---|---|---|---|
| 20KB | 20KB | 10KB | 可能存在注入(返回了数据) |
| 20KB | 10KB | 10KB | 输入被清理,不可利用 |
| 20KB | 错误页 | 错误页 | 输入被拒绝,不可利用 |
| 20KB | 更多数据 | 10KB | 可能存在注入(UNION成功) |
## 框架输入清理检测报告
### 框架信息
- **框架类型**: {framework_name}
- **版本**: {version}
- **清理机制**: {mechanism_type}
### 参数检测
- **参数名**: {param_name}
- **是否在清理列表**: {yes/no}
- **清理类型**: {int_cast/filter/whitelist/none}
- **清理位置**: {file:function}
### 真实请求验证
- **正常请求响应**: {size} bytes, HTTP {status}
- **注入请求响应**: {size} bytes, HTTP {status}
- **无效请求响应**: {size} bytes, HTTP {status}
### 判定结果
- **框架防护有效**: {yes/no}
- **SQL 注入可利用**: {yes/no}
- **判定依据**: {reason}
原流程:
1. 发现 SQL 拼接点
2. 追溯输入来源
3. 检查直接路径上的过滤
4. 判定漏洞
新流程:
1. 发现 SQL 拼接点
2. 识别项目使用的框架
3. **[新增] 检查框架级输入清理机制**
- 查找框架的全局清理配置
- 检查目标参数是否在清理列表中
- 识别清理类型(类型强转/过滤/白名单)
4. 追溯输入来源
5. 检查直接路径上的过滤
6. **[新增] 响应差异对比验证**
- 发送正常/注入/无效三组请求
- 对比响应大小和内容
7. 判定漏洞
关键变更:
- 如果参数在框架的 int 类型清理列表中 → 直接标记为不可利用
- 如果注入响应 = 无效响应 → 标记为输入被清理,不可利用
在判定 SQL 注入存在前,必须回答以下问题:
任何一项显示输入被清理或转换,都不能判定为可利用的 SQL 注入漏洞。
最后更新: 2026-01-19 版本: 1.0 触发条件: 所有 SQL 注入漏洞分析