【代码审计】某CMS-sql注入漏洞审计过程
字数 1302 2025-08-09 22:00:43
某CMS SQL注入漏洞审计过程详解
1. 漏洞背景
本文档详细分析某CMS系统中存在的一个SQL注入漏洞的审计过程,通过完整的代码审计流程展示如何发现、分析和验证该漏洞。
2. 审计环境准备
- 获取目标CMS源码
- 本地搭建测试环境
- 进入后台寻找可能存在漏洞的功能模块
3. 漏洞发现过程
3.1 功能点定位
在后台功能中发现一个SQL语句输入框,初步测试发现存在输入过滤:
- 输入测试内容后返回"非法操作"错误
- 通过报错信息在源码中搜索关键词"非法操作"
3.2 代码定位
通过搜索发现相关代码位于同一PHP文件中,关键参数包括:
titlelimitsordersisallsqls(对应SQL输入框)
通过抓包确认参数传递:
- 在功能块点击保存并抓包
- 确认请求中包含上述参数,特别是
sqls参数
4. 代码审计分析
4.1 关键过滤函数分析
系统使用frparam函数处理参数,函数调用形式:
frparam('go', 1)
frparam函数定义分析:
- 获取URL参数值
- 将前端所有数据赋值给
$data - 检查参数是否存在
- 最终调用
format_param($value,$int,$default)进行格式化
4.2 参数过滤机制
format_param函数分析:
- 根据
$int值进行不同处理 - 当
$int=1时调用SafeFilter函数进行过滤
SafeFilter函数分析:
- 过滤XSS攻击
- 使用
preg_replace移除危险字符 - 过滤基本JS语句
- 使用
- 对输入值进行HTML实体编码
- PHP版本判断:
- ≥7.4版本:使用
addslashes转义双引号 - 其他版本:检查魔术引号设置,未开启则使用
addslashes
- ≥7.4版本:使用
4.3 SQL语句过滤机制
对sqls参数的特殊过滤:
if(stripos($sqls,'update')!==false || stripos($sqls,'delete')!==false
|| stripos($sqls,'insert')!==false || stripos($sqls,'drop')!==false
|| stripos($sqls,'truncate')!==false){
// 抛出"非法操作"错误
}
过滤特点:
- 使用
stripos查找危险SQL关键字 - 禁止的关键字包括:update、delete、insert、drop、truncate
- 只要包含任一关键字即报错
4.4 漏洞点分析
漏洞成因:
- 虽然对危险SQL关键字进行了过滤
- 但未对SELECT语句进行限制
- 过滤后的SQL语句直接带入执行
执行流程:
- 绕过关键字检测(不使用被过滤的关键字)
- 构造合法SQL语句
- 系统直接执行该语句
5. 漏洞验证方法
5.1 构造Payload要点
- 避免使用被过滤的关键字:
- update、delete、insert、drop、truncate
- 可使用SELECT语句进行注入
- 利用系统未过滤的其他SQL功能
5.2 自动化验证
可使用sqlmap工具进行自动化验证:
- 定位存在漏洞的参数
- 构造绕过过滤的Payload
- 进行注入测试
6. 漏洞修复建议
- 完善SQL关键字过滤列表,增加SELECT等关键字检测
- 使用预处理语句(PDO或mysqli预处理)
- 实施最小权限原则,限制数据库账户权限
- 增加输入内容白名单验证
- 对输出进行适当编码
7. 审计经验总结
- 通过报错信息定位关键代码
- 分析自定义过滤函数的行为
- 关注过滤机制的完整性
- 注意过滤规则的绕过可能性
- 验证过滤后的语句执行方式
8. 附录:关键代码片段
// 参数获取函数
function frparam($str, $int=0, $default=''){
$data = $this->_data;
if(empty($str) || !array_key_exists($str,$data)){
return $default;
}
$method = isset($this->_method) ? $this->_method : '';
$value = $data[$str];
return format_param($value,$int,$default);
}
// SQL语句过滤检测
if(stripos($sqls,'update')!==false || stripos($sqls,'delete')!==false
|| stripos($sqls,'insert')!==false || stripos($sqls,'drop')!==false
|| stripos($sqls,'truncate')!==false){
// 抛出"非法操作"错误
}