information_schema數(shù)據(jù)庫是MySQL自帶的數(shù)據(jù)庫,MySQL 5.x以下沒有這個數(shù)據(jù)庫,它提供了整個MySQL訪問數(shù)據(jù)庫元數(shù)據(jù)的方式,其中就包含MySQL里面所有的數(shù)據(jù)庫名或表名,列的數(shù)據(jù)類型,或訪問權(quán)限等。也就是說information_schema中保存著關(guān)于MySQL服務器所維護的所有其他數(shù)據(jù)庫的信息。在INFORMATION_SCHEMA中,有數(shù)個只讀表。
```
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| security |
| test |
+--------------------+
mysql> use information_schema;
mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema |
+---------------------------------------+
| CHARACTER_SETS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS |
| COLUMN_PRIVILEGES |
| ENGINES |
| EVENTS |
| FILES |
| GLOBAL_STATUS |
| GLOBAL_VARIABLES |
| KEY_COLUMN_USAGE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
| PROCESSLIST |
| PROFILING |
| REFERENTIAL_CONSTRAINTS |
| ROUTINES |
| SCHEMATA |
| SCHEMA_PRIVILEGES |
| SESSION_STATUS |
| SESSION_VARIABLES |
| STATISTICS |
| TABLES |
| TABLESPACES |
| TABLE_CONSTRAINTS |
| TABLE_PRIVILEGES |
| TRIGGERS |
| USER_PRIVILEGES |
| VIEWS |
| INNODB_BUFFER_PAGE |
| INNODB_TRX |
| INNODB_BUFFER_POOL_STATS |
| INNODB_LOCK_WAITS |
| INNODB_CMPMEM |
| INNODB_CMP |
| INNODB_LOCKS |
| INNODB_CMPMEM_RESET |
| INNODB_CMP_RESET |
| INNODB_BUFFER_PAGE_LRU |
+---------------------------------------+
```
上面顯示的表,實際上是視圖,而不是基本表,在數(shù)據(jù)庫的數(shù)據(jù)保存目錄是看不到這個數(shù)據(jù)庫的實體文件,而數(shù)據(jù)庫的數(shù)據(jù)保存在MySQLdata目錄,mysql、performance_schema、test、security
```
# 查看當前數(shù)據(jù)保存目錄
mysql> select @@datadir;
+-------------------------------------+
| @@datadir |
+-------------------------------------+
| D:phpStudyPHPTutorialMySQLdata |
+-------------------------------------+
```
```
mysql> select schema_name from information_schema.schemata;
+--------------------+
| schema_name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| security |
| test |
+--------------------+
```
可以看到他們的作用是一樣的,都是列出所有數(shù)據(jù)庫,跟我們前面說的一樣,SCHEMA_NAME字段保存了所有的數(shù)據(jù)庫名。
每一個目錄對應數(shù)據(jù)庫中的一個數(shù)據(jù)庫,在數(shù)據(jù)庫中執(zhí)行show databases;的時候,可以看到存在5個數(shù)據(jù)庫,正是少了information_schema這個數(shù)據(jù)庫。
- 在SQL注入中,重點關(guān)注的表有如下幾個,因為主要的時候主要利用這幾個表來獲取數(shù)據(jù):
- SCHEMATA:提供了當前mysql數(shù)據(jù)庫中所有數(shù)據(jù)庫的信息,其中SCHEMA_NAME字段保存了所有的數(shù)據(jù)庫名。show databases的結(jié)果取自此表。
- TABLES:提供了關(guān)于數(shù)據(jù)庫中的表的信息,詳細表述了某個表屬于哪個schema,表類型,表引擎,創(chuàng)建時間等信息,其中table_name字段保存了所有列名信息,show tables from schemaname的結(jié)果取自此表。
- COLUMNS:提供了表中的列信息。詳細表述了某張表的所有列以及每個列的信息,其中column_name保存了所有的字段信息。show columns from schemaname.tablename的結(jié)果取自此表。
```
mysql> desc tables;
+-----------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG | varchar(512) | NO | | | |
| TABLE_SCHEMA | varchar(64) | NO | | | |
| TABLE_NAME | varchar(64) | NO | | | |
| TABLE_TYPE | varchar(64) | NO | | | |
| ENGINE | varchar(64) | YES | | NULL | |
| VERSION | bigint(21) unsigned | YES | | NULL | |
| ROW_FORMAT | varchar(10) | YES | | NULL | |
| TABLE_ROWS | bigint(21) unsigned | YES | | NULL | |
| AVG_ROW_LENGTH | bigint(21) unsigned | YES | | NULL | |
| DATA_LENGTH | bigint(21) unsigned | YES | | NULL | |
| MAX_DATA_LENGTH | bigint(21) unsigned | YES | | NULL | |
| INDEX_LENGTH | bigint(21) unsigned | YES | | NULL | |
| DATA_FREE | bigint(21) unsigned | YES | | NULL | |
| AUTO_INCREMENT | bigint(21) unsigned | YES | | NULL | |
| CREATE_TIME | datetime | YES | | NULL | |
| UPDATE_TIME | datetime | YES | | NULL | |
| CHECK_TIME | datetime | YES | | NULL | |
| TABLE_COLLATION | varchar(32) | YES | | NULL | |
| CHECKSUM | bigint(21) unsigned | YES | | NULL | |
| CREATE_OPTIONS | varchar(255) | YES | | NULL | |
| TABLE_COMMENT | varchar(2048) | NO | | | |
+-----------------+---------------------+------+-----+---------+-------+
```
分別記錄一個表名和一個這個表所屬的庫名。其中TABLE_NAME保存的是表名,而TABLE_SCHEMA保存的是這個表名所在的數(shù)據(jù)庫。我們可以查詢一條記錄看看,在查詢前,先看看有多少條記錄,避免記錄太多查看不方便,執(zhí)行select count(*) from tables;
```
mysql> select count(*) from tables;
+----------+
| count(*) |
+----------+
| 85 |
+----------+
```
說明當前所有數(shù)據(jù)庫中的表數(shù)量為85。查詢?nèi)我庖粭l記錄查看,這里選擇最后一條記錄,SQL語句為:select * from tables limit 141,1G由于在客戶端中,默認查詢結(jié)果顯示不友好,所以,可以把語句后面的分號改成G,他會讓一條記錄顯示一行,看起來不那么亂。G只支持在客戶端中用,在其他連接數(shù)據(jù)庫的軟件中,使用G會報錯。
```
mysql> select * from tables limit 84,1G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: security
TABLE_NAME: users
TABLE_TYPE: BASE TABLE
ENGINE: MyISAM
VERSION: 10
ROW_FORMAT: Dynamic
TABLE_ROWS: 8
AVG_ROW_LENGTH: 24
DATA_LENGTH: 196
MAX_DATA_LENGTH: 281474976710655
INDEX_LENGTH: 2048
DATA_FREE: 0
AUTO_INCREMENT: 9
CREATE_TIME: 2020-08-21 02:13:29
UPDATE_TIME: 2020-08-21 02:13:29
CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
CHECKSUM: NULL
CREATE_OPTIONS:
TABLE_COMMENT:
```
可以看到,最后一條記錄的TABLE_NAME是users,TABLE_SCHEMA為security。查看security數(shù)據(jù)庫中的表,SQL語句為:show tables from security;可以看到確實存在users表。
```
mysql> show tables from security;
+--------------------+
| Tables_in_security |
+--------------------+
| emails |
| referers |
| uagents |
| users |
+--------------------+
```
既然information_schema的TABLES表中的TABLE_SCHEMTA字段是保存的數(shù)據(jù)庫名,而TABLE_NAME保存了表名,那么就可以使用TABLE_SCHEMTA字段作為查詢條件,查詢TABLE_NAME,即可得知所有指定數(shù)據(jù)庫中的所有表名。
比如,我們想要通過information_schema數(shù)據(jù)庫來查詢security數(shù)據(jù)庫中所有的表,那么就可以使用如下SQL語句:select table_name from information_schema.tables where table_schema ='security';
如果當前庫為information_schema,則可以省略不寫,否則跨庫查詢的時候,需要帶上庫名。
```
mysql> select table_name from information_schema.tables where table_schema ='security';
+------------+
| table_name |
+------------+
| emails |
| referers |
| uagents |
| users |
+------------+
```
通過修改 TABLE_SCHEMA 的限制,可以查詢?nèi)我鈹?shù)據(jù)庫中的所有表名,網(wǎng)上的通過注入爆表名便是這個原理。
知道了表名,那么如何獲取表中的字段呢?要知道我們沒有表名的話,會把所有的數(shù)據(jù)查詢出來,而如果注入沒有回顯,不能進行union查詢,那么想要獲取我們的標目數(shù)據(jù),無疑效率極低。
幸運的是,在information_schema數(shù)據(jù)庫中,同樣存在一個表,它保存了整個數(shù)據(jù)中,所有的列名,這個表就是COLUMNS。同樣先查看該表結(jié)構(gòu)。
```
mysql> desc columns;
+--------------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG | varchar(512) | NO | | | |
| TABLE_SCHEMA | varchar(64) | NO | | | |
| TABLE_NAME | varchar(64) | NO | | | |
| COLUMN_NAME | varchar(64) | NO | | | |
| ORDINAL_POSITION | bigint(21) unsigned | NO | | 0 | |
| COLUMN_DEFAULT | longtext | YES | | NULL | |
| IS_NULLABLE | varchar(3) | NO | | | |
| DATA_TYPE | varchar(64) | NO | | | |
| CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES | | NULL | |
| CHARACTER_OCTET_LENGTH | bigint(21) unsigned | YES | | NULL | |
| NUMERIC_PRECISION | bigint(21) unsigned | YES | | NULL | |
| NUMERIC_SCALE | bigint(21) unsigned | YES | | NULL | |
| CHARACTER_SET_NAME | varchar(32) | YES | | NULL | |
| COLLATION_NAME | varchar(32) | YES | | NULL | |
| COLUMN_TYPE | longtext | NO | | NULL | |
| COLUMN_KEY | varchar(3) | NO | | | |
| EXTRA | varchar(27) | NO | | | |
| PRIVILEGES | varchar(80) | NO | | | |
| COLUMN_COMMENT | varchar(1024) | NO | | | |
+--------------------------+---------------------+------+-----+---------+-------+
```
這里面,與注入相關(guān)的存在3個字段,分別是TABLE_SCHEMA、TABLE_NAME以及COLUMN_NAME,不難猜到,如果在該表中查詢一條記錄,TABLE_SCHEMA保存了這條記錄保存的字段所屬的數(shù)據(jù)庫名,而TABLE_NAME保存的是該字段所屬表名,COLUMN_NAME則是一個列名記錄,查詢一條記錄驗證一下,首先確定該表有多少條記錄,執(zhí)行select count(*) from columns;,得知一共有820條記錄。
```
mysql> select count(*) from columns;
+----------+
| count(*) |
+----------+
| 820 |
+----------+
```
獲取最后一條記錄,執(zhí)行select * from columns limit 819,1G
```
mysql> select * from columns limit 819,1G
*************************** 1. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: security
TABLE_NAME: users
COLUMN_NAME: password
ORDINAL_POSITION: 3
COLUMN_DEFAULT: NULL
IS_NULLABLE: NO
DATA_TYPE: varchar
CHARACTER_MAXIMUM_LENGTH: 20
CHARACTER_OCTET_LENGTH: 60
NUMERIC_PRECISION: NULL
NUMERIC_SCALE: NULL
CHARACTER_SET_NAME: utf8
COLLATION_NAME: utf8_general_ci
COLUMN_TYPE: varchar(20)
COLUMN_KEY:
EXTRA:
PRIVILEGES: select,insert,update,references
COLUMN_COMMENT:
```
其中COLUMNS_NAME為password,TABLE_NAME為users,TABLE_SCHEMA為security,這說明,在security這個數(shù)據(jù)中,users表存在一個password的列,也就是我們常說的password字段。
查看security的users表是否存在該字段,執(zhí)行SQL語句:show columns from security.users;
```
mysql> show columns from security.users;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| username | varchar(20) | NO | | NULL | |
| password | varchar(20) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
```
可以看到確實存在該字段。
既然在columns中,TABLE_NAME保存了字段所屬的表名,TABLE_SCHEMA保存了該字段所屬的庫名,與通過TABLES表獲取表名一樣,我們就可以查詢把TABLE_NAME 和TABLE_SCHEMA做為查詢條件,查詢符合條件的COLUMN_NAME,也就是查詢指定數(shù)據(jù)庫中某表中的字段。
比如,我們要通過information_schema數(shù)據(jù)庫的columns表查詢security數(shù)據(jù)庫中user表中所有的字段,可以執(zhí)行如下SQL語句:select column_name from information_schema.columns where table_schema='security' and table_name='users';
```
mysql> select column_name from information_schema.columns where table_schema='security' and table_name='users';
+-------------+
| column_name |
+-------------+
| id |
| username |
| password |
+-------------+
```
查詢結(jié)果與show columns from security.users; 一致。
```
mysql> show columns from security.users;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| username | varchar(20) | NO | | NULL | |
| password | varchar(20) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
```
知道了庫名、表名、字段,如果有回顯且支持聯(lián)合查詢,就可以直接通過在注入點后面注入一個聯(lián)合查詢語句,即可直接獲取數(shù)據(jù),如果不能回顯,則可能需要通過盲注獲取數(shù)據(jù)。