突破SQL注入语义分析算法的黑魔法
引言
当下,语义分析算法因其轻规则、低误漏报、更贴合业务场景等优势被广泛应用于各类型的安全防护产品中,并取得了较好的效果,但现阶段依旧存在一些方法能够有效突破传统语义分析防护,本文会介绍部分SQL注入场景下突破语义分析算法的黑魔法。
语义\词法分析概述
词法分析
现阶段,SQL注入的词法分析主流分为两类:
1.基于弱规则词法黑名单
2.基于词法Token变化
其中基于弱规则词法黑名单的算法被用于大家熟知的Libinjection,主要通过将用户的输入进行Token化,然后再去匹配一份维护好了的SQL注入黑名单规则库,从而有效发现SQL注入问题。
其中各种输入对应词法如下,
检测SQL注入的流程如下,
而基于Token变化的检测算法,规则比上述算法更弱,只需计算用户的输入是否横跨了多个Token,如果横跨了多个Token则判断为存在SQL注入,
语义分析
和词法分析相比,语义分析会做的更加细致,它不仅仅关注SQL的Token,更会去关注用户的输入对具体的SQL结构造成了怎样的改变,这样能够更大程度的解决词法分析仅仅基于Token造成的误报问题。
对于一些运行时安全防护产品而言,由于运行在应用中,可以直接获取到完整的SQL语句,语义分析的准确率往往较高,而对于传统流量型安全防护产品而言,由于只能获取到流量中的用户输入参数,无法知道真实运行的SQL语句是什么样的,就需要额外的工作,大体分为两类:
- SQL片段分析:需要基于 Context Free Grammer ,最大的挑战是时间复杂度和准确率。
- 构造完整的SQL语句:主流安全产品会假设用户输入参数为 数字型、字符型 两种场景,将参数拼接到简化的SQL语句中构成完整的SQL语句,进而进行语义分析。但很多时候会出现关键字拼接参数(如IN、GROUP BY、ORDER BY等)的场景,这种情况下语义分析准确率就会下降,而如果尽可能的穷举了用户参数的拼接场景,则会造成性能的不可控。
绕过思路
预期外的SQL特性
原理
语义分析会面临的一个最大的难题就是:虽然大部分的数据库语法都比较相似,但不同数据库之间又都有自己独有的一些特性在里面,这样如果攻击者对某一款数据库足够了解,就可能通过一些特殊的SQL特性进行SQL注入,而语义分析之前又未能兼容该特性,从而导致语义分析引擎报错,失去检测能力。
巧用ODBC
ODBC是一个大部分SQL都支持的特性,官方介绍如下
1 | {identifier expr} is ODBC escape syntax and is accepted for ODBC compatibility. The value is expr. The { and } curly braces in the syntax should be written literally; they are not metasyntax as used elsewhere in syntax descriptions. |
由于ODBC本身的自由性,可以构造出很多非常复杂的SQL语句,从而导致语义分析很难进行识别,
psql并不认识转义字符
几乎大部分主流语义分析引擎、主流数据库都将 \ 理解为转义字符,但PSQL并不这么理解,对 \ 理解上的差异使得绕过PSQL变得十分容易,
神奇的科学计数法
科学符号,特别是 e 符号,已被集成到包括 SQL 在内的许多编程语言中。目前还不清楚这是否是所有 SQL 实现的一部分,但它是 MySQL/MariaDB 实现的一部分。当e符号在无效的上下文中使用的时候,并不会导致SQL报错,而是会被SQL自行忽略,这就导致了SQL注入时的Payload可以通过大量无效科学符号来影响语义分析引擎对SQL语句的解析。
1 | select last_name from students where student_id = '1' union select concat 5.e(1.e(flag 10.2e)3.e,'***'6.e) from test 1.e.flag-- |
注释欺骗的艺术
原理
大部分语义分析往往都是能够识别出注释,并在分析时省略注释后面语句的分析,从而实现更好的性能,那么如果攻击者能够成功构造出语义分析引擎认为是注释而实际数据库并不认为是注释的特殊关键字,再把攻击的Payload隐藏在注释之后,就能成功欺骗语义分析,光明正大的进行SQL注入。
万能注释 //
存在不少语义分析引擎,在解析数据流的时候,会将 // 作为注释处理,忽视后面的内容,而大部分主流数据库,并不将 // 作为注释。
注释结束符的差别
语义分析引擎往往认为 \r \n 都是注释的结束符,但很多数据库(MYSQL\ORACLE等)只认为 \n 是注释结束符,利用注释结束符理解的差异可以构造绕过
mybatis眼中的#
JAVA的mybatis框架会对用户输入的参数做一些特殊的处理,尤其针对形如 #{param} 这种写法的数据的额外处理,会对语义分析造成极强的欺骗性
巧用特殊关键字
原理
除去让很多开发、安全人员熟知的关键字外,不少数据库也拥有一些较为冷门的关键字,这些关键字在语义分析或词法分析时很可能未能兼容,从而导致防护失效。因此,寻找冷门且有效的关键字也是绕过语义分析引擎的一种有效手段,尤其是针对新版本的数据库,往往会出现一些新的关键字,这些关键字极有可能未被兼容。
handle替代select
MySQL除了可以使用 select 查询表中的数据,也可使用 handler 语句,这条语句使我们能够一行一行的浏览一个表中的数据。它是MySQL专用的语句,并没有包含到SQL标准中。handler语句由于可以查询数据,因此也是SQL注入中一个十分方便且鲜为人知的关键字。
MEMBER OF函数
MEMBER OF()是一个MySQL8高版本特性,官方定义它是一个函数,但是这个函数的函数名中间还包含空格,十分具有欺骗性,虽然它对于注出数据并没有什么帮助,但是放在注入Payload的前段以促使语义分析引擎解析失败报错却是一个很不错的选择。
1 | SELECT last_name FROM students WHERE student_id = '1' and (select substr((SELECT flag from flag), 1, 1) MEMBER OF('["a","b","t"]'))=1; |
附录
该篇文章内容为笔者在2023年4月1日阿里先知白帽大会上的分享议题PPT《让SQL注入无所遁形》的分享。内容中删去了防御者视角下的探索,主要展示攻击者如何去绕过使用语义分析算法的安全设备,具体内容详见PPT。