[深入學習Web安全](5)詳解MySQL注射

weixin_34236869發表於2016-08-17

來源:http://bbs.ichunqiu.com/thread-10222-1-1.html?from=ch

作者:萬年死宅

首發:i春秋社群

註明:轉載請務必註明i春秋社群(bbs.ichunqiu.com)

0x00 目錄

0x00 目錄

0x01 MySQL注射的簡單介紹

0x02 對於information_schema庫的研究

0x03 注射第一步——確定查詢語句的查詢物件個數0x04 注射第二步——UNION聯合查詢

0x05 注射第三步——MySQL基礎資訊收集

0x06 注射第四步——通過利用點GET敏感表及列

0x07 注射第五步——通過已知表、列GET資料

0x01 MySQL注射的簡單介紹

MySQL的注射,我們已經在第4篇文章的演示過了,我們就來簡單的總結下,我們MySQL注射的利用點。

首先,我們先來說下現在幾乎沒什麼網站用的Access資料庫吧,在最早期的Web安全技術的學習中,我們最早接觸到的工具相信都是啊D和明小子,而這兩款工具正是針對與Access資料庫的注射漏洞的利用工具。

而提到Access的注射,相信大家都能想到兩個字“爆破”或者是“猜解”。對,這就是Access資料庫存在SQL注射漏洞時的利用點,而我們第4篇文章中所演示的MySQL注射的利用點,自然不是“猜解”。(順便說一下,我說的只是針對於MySQL5及以上版本)這種注射的利用點是information_schema這個預設資料庫,這裡面記錄了該MySQL資料庫所儲存的所有資料。

所以,針對於MySQL資料庫的注射都是利用提取information_schema庫裡的資訊來獲取表名與列名的。

0x02對於information_schema庫的研究

既然這類注射的利用點在於information_schema這個預設庫,那麼自然,我們就應該增進對於這個庫的一些瞭解,接下來,我們就來研究下這個information_schema庫。

首先,我們啟動MySQL服務,並且登入MySQL:

2590180-b917746053cf09df.jpg

然後,我們還是來看下存在的資料庫:

2590180-2357aebb923e6288.jpg

我們看到了information_schema資料庫,也就證明了我安裝的MySQL版本大於5,我們可以來看下具體版本:

2590180-910070ce45c37e7b.jpg

我們可以看到版本是5.6.17。接著,我們進入information_schema庫:

2590180-08db140cc3aed7ac.jpg

接著,我們來show一下表:

2590180-bd4130f1b04cd36c.jpg

可以看到,這個庫裡面有很多表,而我們獲取其他資料庫裡的表、列名情況所利用的是一個叫tables的表,如下圖:

2590180-55859f42eb990408.jpg

我們看看這個tables表裡存在那些column:

2590180-c475d5476aabf2c2.jpg

可以看到,tables表裡情況複雜。。。我們所需要學習的只是其中幾個,包括table_name、colum_name、table_schema,如圖:

2590180-a655d601ba167382.jpg

還有一個沒圈到,可能是在下面,也可能是我眼睛不好。。。。我先來了解下table_schema這個列:

2590180-dad9f5ebe5317b80.jpg

這裡麵包含了所有我們安裝在這個MySQL上的資料庫的db_name,會有很多重複,接著,我們來看下table_name裡的情況:

2590180-30d07ca01d4f599f.jpg

這個表裡則包含了該MySQL安裝過的表的名字,好了,關於這個infromation_schema的庫,我就寫到這裡,because我們的主題不是這個。

0x03 注射第一步——確定查詢語句的查詢物件個數

我們在第4篇的通用注射方式裡的第一步就是確定原查詢語句的查詢物件的個數,什麼意思呢?

其實很簡單,我們還是使用第4篇的栗子,我把MySQL切換到sqli資料庫:

2590180-8d0a006975e2b78f.jpg

然後,用上節課的SQL模型,如下:

2590180-1781e0c7b818764e.jpg

這個X的位置,便是我們能夠注射的位置,這個查詢物件是什麼意思呢?

其實,在這裡查詢物件就是data,個數就是1。這樣或許大家還是不能理解,那我們舉如下栗子:

2590180-ca1d6983f1ec47ac.jpg

這次查詢物件就變為了*,但是長度卻改變了,因為*代表的是ALL的意思,那我們就來看看在news表中到底有幾個物件:

2590180-b82c5ed5636b441a.jpg

我們能看到,news表中有兩個列,所以,這次的查詢物件個數就是2。

但是,我們進行SQL注射只能控制SQL語句的一個部分,而不能知道原本的查詢語句啊,那怎麼辦?

這時,我們就只能勞靠order by了,我們來看如下的栗子(還是一樣的SQL模型):

2590180-ee13496608dbe447.jpg

我們在上面的栗子中可以看到,第一次查詢是正常的查詢,返回正常的查詢結果,而第二次查詢則是加了order by 1,達到的效果就是返回正常查詢結果,因為原SQL模型的查詢物件個數就是1,而第三次查詢則使用了order by 2,而原查詢語句的查詢物件個數是1,而不是2,所以產生了錯誤。

這就是利用order by來獲取未知查詢語句的查詢物件個數。

0x04 注射第二步——UNION聯合查詢

好滴,接下來,我們就要使用聯合查詢了,這個union到底是拿來幹啥的啊,很不解對吧,那我們就先來學習一下union。

我們先來執行如下SQL語句,並檢視結果:

2590180-ac818db179c60004.jpg

可以看到select什麼就是什麼,接著,我們來看一下下面這個圖(別閒枯燥,都是為了後面做鋪墊):

2590180-b60509dc9ecb9323.jpg

這就是news表裡的全部資料,我們想一下,我們有如下程式:

2590180-fd58b5684d698985.jpg

這個程式,我們假設它叫test.php吧,關於getData()函式,圖上有註釋,我們想,當id為1~9的時候,這個程式確實沒任何問題,但是試想,當id等於10的時候,就沒法查詢出結果,說不定還會報錯,這樣很影響使用者體驗。

所以,有時,可以使用union來解決這種問題,例如如下SQL模型就能解決這種問題:

2590180-30140a6875a77b10.jpg

X的位置就是剛才那個程式的id引數的拼接處,這樣就解決了剛才說的問題,不信我們來看:

2590180-7844236f65643abc.jpg

可以看到,在第一次查詢時id為1,的確存在這個資料,於是正常返回查詢結果,其實也不完全正常,因為還多了個Error,但是這個很好處理,直接在mysql_fetch_array()之後的返回值裡取陣列的[0]就可以了。

而第二次查詢,id為10,不存在這條資料,於是,語句錯誤了,所以查詢結果就變成了Error。

Ok,就是這樣,這就是UNION的基礎用法,但是還沒轉過彎來的同學可能還會問那剛才為什麼要order by?

其實,這也怪我,沒講清楚,我們來看如下栗子:

2590180-103bfc43219abb4d.jpg

很明瞭吧,嘿嘿,好了。我們最後在說一個問題,當我們有原語句出現錯誤時,我們的union的內容就會替換掉查詢結果,其實類似於如下等式:

select * from news where id=10 union select 'Error',1000;

=

select 'Error',1000;

好了,接著就是下一個內容了。

0x05 注射第三步——MySQL基礎資訊收集

Ok,基礎的東西終於嘮完了,我們就來玩玩吧,我們先看下面這樣一個列表:

database()  當前資料庫

version() 資料庫版本

user() 當前使用者

就這樣三個基礎資訊吧,我們先直接查詢下:

2590180-5f67fd3a5f8e6afc.jpg

我們可以看到如下幾個基礎資訊,根據我們0x04裡最後提的等式,可以構造出如下SQL語句來GET這些資訊:

2590180-b1fc2609925c8d25.jpg

OK,長話短說了我們試試吧,首先是GET當前庫:

2590180-9977d5afb27b8697.jpg

接著是資料庫版本:

2590180-e4a2830a2051d39a.jpg

最後是當前使用者:

2590180-faef5fd188955942.jpg

OK,就這麼簡單,其實注射並不難,只是缺少系統性的資料以及各種資料的“質量”參差不齊才導致有很多朋友覺得SQL注射很難學。

0x06 注射第四步——通過利用點GET敏感表及列

好滴,接著,我們來到了0x06,真心寫得好累,阿西吧,神吶。。。好了,利用點自然是information_schema庫。

我們首先想獲取的自然是當前庫裡的所有表,大家還記得吧,在0x02的地方,我曾說過information_schema庫裡的tables表裡存著我們想要的資訊,首先table_schema裡存的是啥?是所有資料庫名吧,那table_name裡存的啥?是所有表名吧,既然如此,只需要將select database()查出來的當前庫名對應一下,自然就能得到所有屬於當前庫的表名了哎。

所以,我們來先正常嘗試一下(額,對了跨庫的話就“from 庫名.表名”就行了):

2590180-9f498b77b8984b0c.jpg

可以看到,確實獲取了屬於sqli庫的所有表名,此時一看,哪個敏感一幕瞭然啊,嘿嘿,讓我們猥瑣的繼續:

2590180-cc44c9d9eba9c3fd.jpg

就這麼簡單,通過前面那個等式,大家就能夠通過這兩個語句直接構造攻擊的Payload了吧,嘿嘿(容我猥瑣的笑會兒~~)

0x07 注射第五步——通過已知表、列GET資料

好了,最後,我們就能通過已知的表、列GET想要的資料了,例如:

2590180-049f11edcb540516.jpg

但是例如php程式在處理查詢結果時有點坑咋辦?就例如mysql_fetch_array()後只取了[0]咋辦?難道一個一個查?那不累死?

所以還是用第4篇裡講到過的group_concat()函式來解決吧,如下例:

2590180-99478b76c53fbb6b.jpg

好了,這篇paper就到這裡了,接下來還會有更多更高階的SQL注射技巧等著大家~~

作者:萬年死宅

首發:i春秋社群

註明:轉載請務必註明i春秋社群(bbs.ichunqiu.com)

相關文章