打开环境,是个登录框:
注册账号,登录后,有个广告发布,随便输入后查看详情后会回显:
一下子就会想到是xss,于是我试了一下,果然还真存在xss:
但是后来才知道没用,是个SQL题,注入点在标题那:
按照步骤来,发现or,#都被过滤,空格会被消除,空格简单,用/**/就能绕过,但order by和information_schema都不能用,那咋判断字段数,不会要用union select一个个试吧(那这个题可能要搞傻),其实还可以用group by:
1'/**/group/**/by/**/22,'3
(注释符#用,'3
代替,数字随便,这里的'
相当于闭合了输入语句里参数的右引号,变成'3'
字符串,此时整个语句没有注释符)
判断出有22个字段,接着用联合注入:
1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
得到数据库名:web1
接着报表名,information_schena不能用,此处要用到其他知识:
我们知道infromation_schema库的作用无非就是可以获取到table_schema,table_name,column_name这些数据库内的信息,下面两种方法能绕过:
1.InnoDb引擎
从MYSQL5.5.8开始,InnoDB成为其默认存储引擎。而在MYSQL5.6以上的版本中,mysql数据库中inndb增加了innodb_index_stats和innodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名。其利用方式是:mysql.innodb_index_stats和mysql.innodb_table_stats
2.sys数据库
在5.7以上的MYSQL中,新增了sys数据库,该库的基础数据来自information_schema和performance_chema,其本身不存储数据。可以通过其中的schema_auto_increment_columns来获取表名。其用法是sys.schema_auto_increment_columns
经过尝试第一种方法可行:
1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
注意: 这个地方一定要在前面可显示的位置2,3用select查出表名,因为union select查的是当前数据库中的内容,且有22个字段,如果将from/**/mysql.innodb_table_stats写在数字后面就查不出。
得到了5张表,但是用上面的InnoDb引擎方法没法查出列名,因为其中没有存储列名,这里就要用到无列名注入了。
先来了解一下原理:
正常的查询是这样的:
当我们select 1,2,3的时候。这个就像是一个虚拟的表。列名为1,2,3
我们将列名为1,2,3然后查询数据
第一行是我们查询的1,2,3后面跟着表中的数据
这就相当于改了表的列名。之后。我们将某一列取出来即可
select `2` from (select 1,2,3 union select * from user)a;
将select 1,2,3的结果拼接到select * from user 的结果,然后将第二列取出来。select 1,2,3要根据表的字段而定,也就是说进行查询时语句的字段数必须和指定表中的字段数一样,不能多也不能少,不然就会报错。语句最后一个字母是别名。像这样就可以查询第二列的数据,在虚拟表中,列名都是1,2,3,所以我们在查询语句中要用 `2` 而不能直接用 2,这就获取到了列名!!
有些时候程序还会过滤反引号,语句就不能正常执行了。但我们还可以通过别名替代反引号
as 取别名。将select 1,2,3 union select * from user中要查询的一列取别名为b。个人感觉就像是赋值给变量差不多:
这里都是分列的。可以通过group_concat来拼接字符串一起输出:
晓得了原理后回到这个题,尝试后答案在users表中,在可以用下面的payload:
1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
至于为什么有三列(select/**/1,2,3),mysql数据库一般第一列是编号,第二列一般是user之类的,第三列一般都是password: