前言
专门把第28关单拿出来,是因为在做题时遇到了一些问题,就拿出来单写一篇博客。
ps.整理了关于sqli-labs靶场的博客,将分散的几篇整合了起来。
less-28
先讲解题思路。通过标题提示与源码的分析,我们知道这题除了过滤注释符与空格之外,还将连续的union select
给过滤了:
1 | $id= preg_replace('/[\/\*]/',"", $id); //strip out /* |
过滤是相当严格的,不过我们已经学习了这么多注入方法,既然联合注入语句内容被过滤,我们可以使用盲注法来注入(由于报错不会回显因此不考虑报错注入)。但是我们要练习的就是绕过过滤的方法,因此我们依然采用联合查询进行注入。
关于注释符与空格的绕过上篇博客已经介绍过了,这里来介绍如何绕过对union select的过滤(单引号+括号注入):
1 | ?id=0')unionunion%0aselect%0aselect%0a1,database(),3;%00 |
这种方法是双写绕过,我们发现输入后页面在hint部分回显内容都为正常的联合查询语句,原理都是让union%0aselect被过滤,剩下的内容刚好构成一个新的union%0aselect,从而进行联合查询,当然这里的%a0可以替换为其他不可打印字符代替。
到这里我们就可以进行爆库操作了。
关于%a0分析
这道题其实已经解完了,但是我们在回顾源码中关于union select的过滤语句:$id= preg_replace('/union\s+select/i',"", $id);
union的后面有一个\s+,这就意味着所有的空格、空白符以及换行符在这里全部都被过滤了,而这个加号意味着多次匹配,因此我们也不能通过双写空格的方式来绕过。但在这其中,有一个例外:%a0
注意到这个玩意也是我发现其他人构建了一句这样的语句:?id=0')union%a0select(1),(database()),(3);%00
%a0是经过URL编码的不可打印字符,代表的是空格,按道理来说是应该要被过滤掉的,但是居然没有,相当神奇。不过我们在linux下跑php7靶场时,发现了问题:
我们想要的数据库名称居然没有正常回显,看下hint的显示,union与select之间居然出现了一个奇怪的符号,这就相当离谱了,我们回主机的靶场上跑:
翻译翻译什么叫惊喜,这就叫惊喜,hint语句出来是一样的,但是主机靶场就是不讲道理地回显了数据库名。这里我们开始做推测:
- linux系统下读取解析%a0结果与windows系统下结果不同,导致在linux系统下出现语法错误
- php版本不同导致%a0解析结果不同
在此之前,我们首先了解到了这个%a0在此处被解析出的结果,它是空格,但又不完全是,因为如果是空格的话,例如我们使用%0a替换%a0,hint回显应该是连union select一起被过滤了,很显然这里却没有,但是在主机靶场中这个%a0又起到了空格的作用。
通过在主机另外搭建了一个php7的靶场测试,发现hint是一样的,但是没有数据库名的回显,这证明了php版本是肯定有问题的,但是第一点暂时没有证明,因为现在的linux系统只能安装php7及以上版本。
通过资料我们发现,%a0解析成空格只有在php5.2.17版本可以通过成功,目前看来应该是php版本的问题。28a采用盲注就行了,甚至28a连空格和注释符都没过滤。