Why is column-less injection needed?
Our commonly used SQL injection method is information_schema
implemented through this default database, but have you ever thought that if the database is filtered, we cannot use this library to find out the table names and column names. However, we can find out the table name in two ways:
-
InnoDb engine
Starting from MYSQL5.5.8, InnoDB becomes its default storage engine. In versions above MYSQL 5.6, inndb adds two tables, innodb_index_stats and innodb_table_stats (
mysql.innodb_table_stats
). Both tables store information about the database and its data tables, but do not store column names. In higher versions of mysql, table structures are recorded in INNODB_TABLES and INNODB_COLUMNS. -
sys database
In MYSQL 5.7 and above, the sys database is added. The basic data of this database comes from information_schema and performance_chema, and it does not store data itself. The table name can be obtained through schema_auto_increment_columns(
sys.schema_auto_increment_columns
).
However, the above two methods can only find the table name, but not the column name. In this case, we will use column-less injection. Column-less injection, as the name suggests, is an injection that can inject data without column names.
No column name injection usage conditions
Injection without column names is mainly suitable for situations where the data table has been obtained but the columns cannot be queried. In most CTF questions, the information_schema library is filtered, and this method is used to obtain column names.
No column name injection principle
The principle of column-less injection is actually very simple, that is, joint query creates virtual data. It can be seen as aliasing the column names we don't know, and performing data query while taking the alias, so the number of query fields must be the same. If the fields we query are more than the columns in the data table, an error will occur. Report an error.
Practical demonstration:
The data in the normal query user table isselect * from user;
Use a joint query to check the data in the table select 1,2,3 union select * from user;
. It is obvious that dummy data (virtual field value 123 and virtual table) is created, and the column name in the virtual table becomes 123.
If we only check the field value of one column, we can use:
To explain, xxx is the table name of the virtual table named by yourself, which can be customized. This sql statement creates virtual table xxx and virtual columns 1, 2, and 3 in a joint query and simultaneously queries the data in the second column of the virtual table.
select `2` from (select 1,2,3 union select * from user)xxx;
Check multiple columns at the same time
select concat(`2`,`3`) from (select 1,2,3 union select * from user)xxx;
However, sometimes ` will also be filtered. At this time, we have to use the alias (as) operation again and change the column names, so that the column names do not need backticks when querying the data.
select 1 as a,2 as b,3 as c union select * from user;
select b from (select 1 as a,2 as b,3 as c union select * from user)xxx;
Another method is to use JOIN
injection without column names to establish an inner connection between two tables through JOIN. That is to say, adding up the column names of the two tables may reveal the same column names. We use It is this feature that makes the list pop up.
select * from (select * from user as a join user as b)xxx;
After getting the first column name id
, the following payload will echo us the data of the second column.
select * from (select * from user as a join user as b using(id))xxx;
And so on for the rest.
select * from (select * from user as a join user as b using(id,username))xxx;
The actual payload of the first level of sqli-labs:
?id=-1' union all select * from (select * from users as a join users as b)as c--+