文章目錄
個人博客文章:MySQL 數據庫系統表的利用
背景
學習目標:
-
如何利用數據庫的功能讀寫文件,需要什麼樣的條件纔可以讀寫;
-
學習數據庫系統表的功能,如何利用 sql 語句查詢庫名、表名、字段名、內容以及當前用戶等基本信息;
-
嘗試查詢出用戶的 hash,並使用 hashcat 來對獲取的 hash 進行暴力破解。
MySQL 讀寫文件
讀文件
使用 load_file()
函數
load_file(file_name)
函數讀取文件內容,將內容以字符串的形式返回。
前提條件:
secure_file_priv
不爲 NULL,使用select @@secure_file_priv
查看其值,值不爲空字符串時,只能使用該目錄進行文件的讀寫操作, 該值的設置見附錄;- 當前數據庫用戶具有
FILE
權限,使用show grants
查看; - 系統用戶
mysql
對該文件可讀(要考慮系統的訪問控制策略),在Ubuntu-18.04使用 MySQL 時默認的系統用戶是mysql
; - 讀取文件的大小小於
max_allowed_packet
,使用select @@max_allowed_packet
查看; - 文件存在服務器上。
如果上述任一條件不滿足,函數返回 NULL
值。
用法:
select load_file('filename');
**例子:**讀取文件 /mysql/test.csv
mysql> select @@secure_file_priv,@@max_allowed_packet;
+--------------------+----------------------+
| @@secure_file_priv | @@max_allowed_packet |
+--------------------+----------------------+
| | 16777216 |
+--------------------+----------------------+
mysql> show grants;
+----------------------------------------------------------------------------------------------+
| Grants for user101@localhost |
+----------------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, DELETE, CREATE, FILE ON *.* TO 'user101'@'localhost' WITH GRANT OPTION |
+----------------------------------------------------------------------------------------------+
mysql> select load_file('/mysql/test.csv');
+------------------------------+
| load_file('/mysql/test.csv') |
+------------------------------+
| 3,Hack
4,World
5,Surprise!
|
+------------------------------+
**問題:**在設置
secure_file_privilege=''
且目錄權限爲777
後load_file()
無法讀取文件**解決方案:**Ubuntu 自帶的強制訪問控制系統 AppArmor 強制限制了每個程序可使用的資源,它並非針對用戶,而是針對程序的,所以不論用戶是否能訪問某一資源,只要程序被 AppArmor 限制訪問該資源,則程序就不能訪問該資源。因此需要修改 AppArmor 針對於 MySQL 的訪問控制策略,修改文件
/etc/apparmor.d/usr.sbin.mysqld
,在其中添加需要訪問的目錄。**參考:**https://stackoverflow.com/questions/4215231/load-data-infile-error-code-13
使用 LOAD DATA
語句
laod_file()
函數只能從 服務器中讀取文件,LOAD DATA
語句既能讀取服務器的文件,也能讀取 MySQL 客戶機的文件,兩種方式語法上稍有不同。
**前提條件:**和 load_file()
函數使用條件相同,但通過使用 LOCAL
語句從客戶主機讀取文件內容。
用法:
#[] 中的內容爲可選內容
LOAD DATA
[LOW_PRIORITY | CONCURRENT] [LOCAL] #使用 LOCAL 表示從客戶主機讀取文件,要設置 mysqld 中的系統變量 local_infile
INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[CHARACTER SET charset_name] #處理文件的字符集
[{FIELDS | COLUMNS} #描述每一列的格式
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES #描述行的格式,不滿足的行會被略過
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}] #忽略指定行或列
[(col_name_or_user_var
[, col_name_or_user_var] ...)] #寫到數據表中的指定列
[SET col_name={expr | DEFAULT},
[, col_name={expr | DEFAULT}] ...]
**例子:**讀取文件 /mysql/test.csv
到已有的數據表中。CSV文件內容如下:
3,Hack
4,World
5,Surprise!
mysql> select * from test;
+----+------+
| id | name |
+----+------+
| 1 | May |
| 2 | June |
+----+------+
mysql> load data infile '/mysql/test.csv' into table test fields terminated by ',';
Query OK, 3 rows affected (0.00 sec)
mysql> select * from test;
| id | name |
+----+-----------+
| 1 | May |
| 2 | June |
| 3 | Hack |
| 4 | World |
| 5 | Surprise! |
+----+-----------+
5 rows in set (0.00 sec)
寫文件
使用 SELECT INTO OUTFILE 語句
SELECT INTO OUTFILE
和 LOAD DATA
這兩條語句是完全互補的,一個寫文件,一個讀文件,語句的語法也很相似。
前提條件:**
- secure_file_priv
不爲 NULL,使用
select @@secure_file_priv`查看其值,值不爲空字符串時,只能使用該目錄進行文件的讀寫操作, 該值的設置見附錄; - 當前數據庫用戶具有
FILE
權限,使用show grants
查看; - 系統用戶
mysql
對該文件可寫(要考慮系統的訪問控制策略),在Ubuntu-18.04使用 MySQL 時默認的系統用戶是mysql
; - 讀取文件的大小小於
max_allowed_packet
,使用select @@max_allowed_packet
查看; - 文件不存在。
用法:
#[] 中的內容爲可選內容
SELECT select_expr...
INTO OUTFILE 'file_name'
[CHARACTER SET charset_name] #處理文件的字符集
[{FIELDS | COLUMNS} #描述每一列的格式
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES #描述行的格式
[STARTING BY 'string']
[TERMINATED BY 'string']
]
**例子:**寫數據表到 CSV 文件中。
mysql> select * from comments;
+----+---------------------------+
| id | comment |
+----+---------------------------+
| 1 | test |
| 2 | hhhh |
| 3 | Need lots of improvements |
+----+---------------------------+
3 rows in set (0.00 sec)
mysql> select comment from comments where id>1 into outfile '/mysql/comments.csv' fields terminated by ',';
Query OK, 2 rows affected (0.00 sec)
/mysql/comments.csv
內容:
hhhh
Need lots of improvements
注:
使用
SELECT INTO DUMPFILE
可將文件內容寫成一行.mysql> select comment from comments where id>1 into dumpfile '/mysql/comments'; Query OK, 2 rows affected (0.00 sec)
/mysql/comments.csv
內容:hhhhNeed lots of improvements
如果想把遠程數據庫的查詢結果寫到本地主機文件上, 可用:
mysql -h hostname -P portnum -u username -p databsename -e "SELECT ..." > file_name
MySQL 數據庫系統表
MySQL-5.7 默認的系統表/視圖 放在4個數據庫/schema 中,。
在 MySQL 中
schema
和database
是一樣的就不做區分, 但實際上是有區別的,可以參考這篇文章。視圖也稱爲虛表,是爲了便於查詢某些信息,建立在查詢結果之上的表,所以視圖其實就是被保存起來的一次查詢。視圖和表的區別簡單來說就是視圖存儲的是SQL查詢語句執行的結果,以表的形式存在但在數據庫中並沒有這個表。
庫名 | 視圖數量 | 基表數量 |
---|---|---|
information_schema | 61 | 0 |
mysql | 0 | 31 |
performance_schema | 0 | 87 |
sys | 100 | 1(sys_config) |
MySQL 數據庫管理系統中的系統表很多,這裏主要介紹和在SQL 注入中常的幾個表和視圖。
information_schema
數據庫
information_schema
存放着 MySQL 服務器維護的所有數據庫的詳細信息, 包括數據庫名、表名、列名、列的數據類型、訪問權限等等。
常用視圖
在進行 SQL 注入時比較有用的幾個視圖:SCHEMATA
、 COLUMNS
、TABLES
、user_privileges
。
schemata
視圖存放 MySQL 數據管理系統中的所有數據的基本信息,叢中可以獲取所有數據庫名字,數據庫使用的字符集、排序規則(collation,數據庫中數據進行排序時的規則,升序、降序,是否忽略大小寫等)
mysql> select * from schemata;
+--------------+--------------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+--------------------+----------------------------+------------------------+----------+
| def | information_schema | utf8 | utf8_general_ci | NULL |
| def | mysql | latin1 | latin1_swedish_ci | NULL |
| def | performance_schema | utf8 | utf8_general_ci | NULL |
| def | sys | utf8 | utf8_general_ci | NULL |
| def | webdb101 | latin1 | latin1_swedish_ci | NULL |
+--------------+--------------------+----------------------------+------------------------+----------+
columns
視圖存放列相關的信息,常用字段 table_schema
(數據庫名), table_name
(表名),column_name
(列名)。
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 | |
| DATETIME_PRECISION | 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(30) | NO | | | |
| PRIVILEGES | varchar(80) | NO | | | |
| COLUMN_COMMENT | varchar(1024) | NO | | | |
| GENERATION_EXPRESSION | longtext | NO | | NULL | |
+--------------------------+---------------------+------+-----+---------+-------+
tables
存放表相關的信息,常用字段 table_schema
(數據庫名), table_name
(表名)。
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 | | | |
+-----------------+---------------------+------+-----+---------+-------+
21 rows in set (0.00 sec)
user_privileges
存放用戶的權限信息。
mysql> desc information_schema.user_privileges;
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| GRANTEE | varchar(81) | NO | | | | #被授權的用戶名
| TABLE_CATALOG | varchar(512) | NO | | | |
| PRIVILEGE_TYPE | varchar(64) | NO | | | | #權限名,如 SELECT、INSERT 等
| IS_GRANTABLE | varchar(3) | NO | | | | #是否授權,YES/NO
+----------------+--------------+------+-----+---------+-------+
視圖信息利用
用戶權限查詢
- 獲取當前用戶名
selectmysql> select user();
+-------------------+
| user() |
+-------------------+
| user101@localhost |
+-------------------+
- 獲取用戶權限
mysql> select * from information_schema.user_privileges where grantee like '%user101%';
+-----------------------+---------------+----------------+--------------+
| GRANTEE | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE |
+-----------------------+---------------+----------------+--------------+
| 'user101'@'localhost' | def | SELECT | YES |
| 'user101'@'localhost' | def | INSERT | YES |
| 'user101'@'localhost' | def | UPDATE | YES |
| 'user101'@'localhost' | def | DELETE | YES |
| 'user101'@'localhost' | def | CREATE | YES |
| 'user101'@'localhost' | def | FILE | YES |
+-----------------------+---------------+----------------+--------------+
注入時可以利用 information_schema 數據庫進行信息查詢,一般步驟有:
- 獲取數據庫名
mysql> select schema_name from information_schema.schemata;
+--------------------+
| schema_name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| webdb101 |
+--------------------+
- 獲取表名
mysql> select table_name from information_schema.tables where table_schema='webdb101';
+------------+
| table_name |
+------------+
| comments |
| test |
+------------+
- 獲取列名
mysql> select column_name from information_schema.columns where table_name='test';
+-------------+
| column_name |
+-------------+
| id |
| name |
+-------------+
mysql 數據庫
mysql 數據中存放的都是表,常用的表有 user
、db
。
user
表中常用字段有 user
、host
、authentication_string
(存儲密碼的字段,MySQL 版本相關,低一些的版本爲 password
)等。
查詢所有用戶名、連接主機和密碼哈希
mysql> select user,host,authentication_string from mysql.user;
+------------------+-----------+-------------------------------------------+
| user | host | authentication_string |
+------------------+-----------+-------------------------------------------+
| root | localhost | |
| mysql.session | localhost | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.sys | localhost | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| debian-sys-maint | localhost | *962236403F954BF9C92EBDBA0BC04F7CE7FCFB89 |
| user101 | localhost | *6331E4D15433B998EF878BE017AE2A0878316CCC |
+------------------+-----------+-------------------------------------------+
注:
在進行 sql 注入使用常常使用
group_concat(col_name…)
將多個列的信息連成一句話輸出,便於回顯到瀏覽器。如獲取用戶名及其密碼的一條注入語句:
select group_concat(user, authentication_string) from mysql.user
用戶密碼爆破
MySQL 用戶的密碼存儲方式並非明文直接存儲,而是經過 hash 函數加密進行存儲的,從 mysql.user
中獲取到 MySQL 用戶密碼的哈希值後,需要使用工具進行破解。
工具:hashcat
hashcat 號稱最快的高級密碼恢復套機(密碼破解工具),支持多系統(Linux,OS,Windows),多平臺(GPU,CPU,DSP等),支持多達 200 多種的 Hash 類型,支持使用同一系統的不同設備,支持分佈式系統資源等,重要的是開源啊!
下載安裝:
推薦在 Windows 上使用,最好不用虛擬機,這樣安裝最簡單,而且能充分利用 hashcat 支持多設備的特點,在 Linux 上安裝需要安裝很多東西,而且問題特別多,除非特別需要,個人不建議。
使用:
./hashcat64.exe -m 300 -a 3 hashfile -o plaintxt --outfile-format=2 ?a?a?a?a?a?a
參數:
-m 300
:hash 類型,200多種,詳見: hashcat --help
,300 選擇的是 MySQL4/5 的hash
-a 3
:攻擊模式,總共5種,3 表示爆破模式,所有攻擊模式如下表:
值 | 攻擊模式 |
---|---|
0 | Straight:字典模式,從字典內容中依次選擇密碼候選,進行哈希計算,看是否和待破解的哈希值相同 |
1 | Combination:組合模式,將兩個字典的內容組合作爲字典內容,可以通過 -k ,-j 選項爲兩個字典添加額外規則 |
3 | Brute-force:爆破模式/掩碼模式,使用掩碼固定密碼的字符集,減小爆破的候選密碼數,掩碼格式見下文。 |
6 | Hybrid Wordlist + Mask:混合模式(字典+掩碼),通過字典後接掩碼的方式構建最終的密碼候選。 |
7 | Hybrid Mask + Wordlist:混合模式(掩碼+字典),通過掩碼後接字典的方式構建最終的密碼候選,和上面的組合順序相反。 |
-o pliantxt
:破解後輸出到文件 plaintxt
--outfile-format=2
:輸出文件格式,2表示只輸出破解後的內容,所有可用格式如下表
值 | 輸出文件格式 |
---|---|
1 | hash[:salt] |
2 | plain |
3 | hash[:salt]:plain |
4 | hex_plain |
5 | hash[:salt]:hex_plain |
6 | plain:hex_plain |
7 | hash[:salt]:plain:hex_plain |
8 | crackpos |
9 | hash[:salt]:crack_pos |
10 | plain:crack_pos |
11 | hash[:salt]:plain:crack_pos |
12 | hex_plain:crack_pos |
13 | hash[:salt]:hex_plain:crack_pos |
14 | plain:hex_plain:crack_pos |
15 | hash[:salt]:plain:hex_plain:crack_pos |
?a?a?a?a?a?a
:這表示密碼的掩碼,所謂的掩碼就是通過 ?[字符集代號]… 的格式表示密碼的格式,包括密碼的位數和每一位密碼使用的字符集。?a 表示所有的鍵盤上可輸入的字符,6個?a表示密碼有6位。hashcat 內置字符集如下:
字符集代號 | 字符集 |
---|---|
l | abcdefghijklmnopqrstuvwxyz |
u | ABCDEFGHIJKLMNOPQRSTUVWXYZ |
d | 0123456789 |
h | 0123456789abcdef |
H | 0123456789ABCDEF |
s | !"#$%&’()*+,-./:;<=>?@[]^_`{ |
a | ?l?u?d?s |
b | 0x00 - 0xff |
還通過選項自定義字符集,自定以的字符集對應的字符集代號爲 1,2,3,4:
--custom-charset1=CS #同 -1 的短選項
--custom-charset2=CS #同 -2
--custom-charset3=CS #同 -3
--custom-charset4=CS #同 -4
如果得知密碼第一位爲大寫字母且不包含字符的8爲密碼,可自定義掩碼,加快解密過程:
hashcat -m 300 -a 3 -1 ?l?u?d hashfile ?u?1?1?1?1?1?1?1
參考
附錄
MySQLsecure_file_priv
變量
Property | Value |
---|---|
Command-Line Format | --secure-file-priv=dir_name |
System Variable | secure_file_priv |
Scope | Global |
Dynamic | No,表示不能動態使用 set 命令進行設置,只能通過配置文件設置,如在 ~/.my. |
Type | String |
Default Value (>= 5.7.6) | platform specific |
Default Value (<= 5.7.5) | empty string |
Valid Values (>= 5.7.6) | empty string dirname NULL |
Valid Values (<= 5.7.5) | empty string dirname |
該變量限制 MySQL 用戶對文件的讀寫操作,可設置爲以下值:
- 空字符串;
- 特定路徑名;
- NULL,表示不允許文件的讀寫操作;
具體可在 MySQL 啓動配置文件 /etc/mysql/my.cnf
中設置如下:
[mysql_safe] #服務器啓動腳本
[mysqld] #服務器端配置
secure_file_priv = "" #設置讀取文件目錄爲任意目錄
my.cnf
文件中配置格式:
[group] #常用的 group 有 mysqld:MySQL 服務器,client:MySQL 客戶端,mysql_safe:服務器啓動腳本
opt_name #等同命令行中 --opt_name 選項
opt_name=value #等同命令行中 --opt_name=vale
不同平臺的默認值:
INSTALL_LAYOUT Value |
Default secure_file_priv Value |
---|---|
STANDALONE |
empty |
DEB , RPM , SVR4 |
/var/lib/mysql-files |
Otherwise | mysql-files under the CMAKE_INSTALL_PREFIX value |