隨着Web應用的高速發展和技術的不斷成熟,對Web開發相關職位的需求量也越來越大,越來越多的人加入了Web開發的行列。但是由於程序員的水平 參差不齊或是安全意識太低,很多程序員在編寫代碼時僅考慮了功能上的實現,很少或是根本沒有考慮應用的安全性問題。這就導致了很多應用都存在不同程度的安 全漏洞。SQL注入便是其中的一種。
SQL注入作為一種很流行的攻擊手段,一直以來都受到網絡安全研究者和黑客們的廣泛關注。那什么是 SQL注入呢?SQL注入是這樣一種攻擊技術:攻擊者通過把惡意SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串中,來達到欺騙服務器執行惡意 的SQL命令的一種攻擊方式。
SQL注入攻擊概述
SQL注入(SQL Injection)定義
SQL注入是攻擊者通過把惡意SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串中,來達到欺騙服務器執行惡意的SQL命令的一種攻擊方式。
SQL注入攻擊危害
利 用SQL注入漏洞,攻擊者可以操縱數據庫的數據(如得到數據庫中的機密數據、隨意更改數據庫中的數據、刪除數據庫等等),在得到一定權限后還可以掛馬,甚 至得到整台服務器的管理員權限。由於SQL注入是通過網站正常端口(通常為80端口)來提交惡意SQL語句,表面上看起來和正常訪問網站沒有區別,如果不 仔細查看WEB日志很難發現此類攻擊,隱蔽性非常高。一旦程序出現SQL注入漏洞,危害相當大,所以我們對此應該給予足夠的重視。
SQL注入漏洞原理
SQL注入的本質是惡意攻擊者將SQL代碼插入或添加到程序的參數中,而程序並沒有對傳入的參數進行正確處理,導致參數中的數據會被當做代碼來執行,並最終將執行結果返回給攻擊者。
我們來看一個例子,當訪問http://www.a.com/cms/new.php?id=3時,在頁面上會顯示一篇id號為3的文章,在服務器端實際上會執行如下一段代碼,如圖1所示:
圖1
上面的過程中實際執行的SQL語句如下:
Select * from news where id=3
現在我們在URL(http://www.a.com/cms/new.php?id=3)后面添加" and 1=1",此時實際執行的SQL語句是:
Select * from news where id=3 and 1=1
由於這個條件永遠成立,所以返回的頁面和正常頁面相同。
當添加“ and 1=2”時,會執行如下SQL語句:
Select * from news where id=3 and 1=2
由於這個條件永遠不成立,所以返回的頁面和正常頁面不同。
現在我們可以控制參數id的值來影響程序的返回結果。我們來分析一下圖1中的代碼,通過GET方式取的參數id的值后,直接用來構造動態SQL語句,並執行SQL查詢。整個過程沒有對變量id的值作任何處理,導致SQL注入漏洞的產生。
SQL注入典型流程
1.判斷Web系統使用的腳本語言,發現注入點,並確定是否存在SQL注入漏洞
2.判斷Web系統的數據庫類型
3.判斷數據庫中表及相應字段的結構
4.構造注入語句,得到表中數據內容
5.查找網站管理員后台,用得到的管理員賬號和密碼登錄
6.結合其他漏洞,想辦法上傳一個Webshell
7.進一步提權,得到服務器的系統權限
(注:以上為一般流程,根據實際情況,情況可能會有所不同。)
PHP+Mysql注入實例
為了方便測試,我們在本地搭建了一個Web系統環境,以攻擊者的角度來滲透網站,讓讀者理解php+mysql注入的完整流程。URL是http://www.a.com/cms/index.php,網站首頁截圖如圖2所示:
圖2
手工注入篇
1.查找注入點,判斷網站是否存在SQL注入漏洞
首先打開網站,選擇“企業新聞”的鏈接,隨便選擇一篇新聞,如圖3所示。通過此URL(http://www.a.com/cms/new.php?id=3),我們可以確定此處存在一個參數為id,它的值等於3。
圖3
現 在我們在http://www.a.com/cms/new.php?id=3后面加一個單引號,會發現返回一個和正常頁面不同的頁面,如圖4所示,這說 明我們添加的單引號影響了程序的運行結果。此處很可能存在注入點,但有時僅用添加單引號的方法判斷是否存在注入點並不准確。因為有的程序員認為只要簡單過 濾了單引號就可以避免SQL注入,所以在程序參數中只是簡單過濾了單引號,並沒有做其他處理。這時用添加單引號的方法去探測程序是否存在SQL注入漏洞 時,是探測不到的;但實際上仍然存在SQL注入漏洞,可以通過其他方法探測到。
接着我們在http://www.a.com/cms/new.php?id=3后面添加" and 1=1"和“ and 1=2”,會發現當添加and 1=1時返回的頁面和正常頁面是一致的,如圖5所示。
圖5
當添加and 1=2時返回的頁面和正常頁面不一致,如圖6所示。
圖6
現在我們可以確定此處是一個SQL注入點,程序對帶入的參數沒有做任何處理,直接帶到數據庫的查詢語句中。可以推斷出在訪問http://www.a.com/cms/new.php?id=3時數據庫中執行的SQL語句大概是這樣的:
Select * from [表名] where id=3
添加and 1=1后的SQL語句:
Select * from [表名] where id=3 and 1=1 由於條件and 1=1永遠為真,所以返回的頁面和正常頁面是一致的
添加and 1=2后的SQL語句:
Select * from [表名] where id=3 and 1=2 由於條件1=2永遠為假,所以返回的頁面和正常頁面不一致
2.通過SQL注入,得到我們感興趣的信息
上面我們確定了此系統存在SQL注入漏洞,下面就讓我們來體驗下SQL注入強大的威力吧。我們先來判斷一下數據庫類型以及版本,構造如下語句:
http://www.a.com/cms/new.php?id=3 and ord(mid(version(),1,1))>51
發現返回正常頁面,說明數據庫是mysql,並且版本大於4.0,支持union查詢,反之是4.0以下版本或者其他類型數據庫。
接着我們再構造如下語句來暴表中字段:
a. http://www.a.com/cms/new.php?id=3 order by 10 返回錯誤頁面,說明字段小於10
b. http://www.a.com/cms/new.php?id=3 order by 5 返回正常頁面,說明字段介於5和10之間
c. http://www.a.com/cms/new.php?id=3 order by 7 返回錯誤頁面,說明字段大於5小於7,可以判斷字段數是6。下面我們再來確認一下
d. http://www.a.com/cms/new.php?id=3 order by 6 返回正常頁面,說明字段確實是6
這里采用了“二分查找法”,這樣可以減少判斷次數,節省時間。如果采用從order by 1依次增加數值的方法來判斷,需要7次才可以確定字段數,采用“二分查找法”只需要4次就夠。當字段數很大時,二分查找法的優勢更加明顯,效率更高。
下面我們構造如下的語句來確定哪些字段可以用來顯示數據:
http://www.a.com/cms/new.php?id=0 union select 1,2,3,4,5,6
圖7
根據返回信息,我們可以確定字段3,4,5,6可以用來顯示數據,如圖7所示。那么我們來構造下面的語句來得到一些數據庫信息:
http://www.a.com/cms/new.php?id=0 union select 1,2,database(),version(),user(),6
圖8
根據如圖8所示的頁面返回信息,我們可以得到如下信息:
數據庫名:cms
數據庫版本:5.1.51-community
用戶名:root@localhost,並且Web系統和數據庫在同一台服務器上
我 們還可以構造別的語句來得到其他信息,如操作系統和數據庫路徑等等,這里可以自由發揮。根據上面的信息我們得知數據庫為5.0以上版本。在 mysql5.0以上版本中增加了一個系統庫,叫information_schema,利用它我們可以直接暴庫、表、字段。在5.0以下的版本中只能通 過暴力猜解的方式去獲得表名和字段名。下面我們來構造SQL語句暴出表名和字段名:
暴表名
http://www.a.com/cms/new.php?id=0 union select 1,2,table_name,4,5,6 from information_schema.tables where table_schema=0x636D73 limit 0,1
注:table_schema=[庫名],庫名要轉換成16進制。Limit 0,1中的0表示查詢庫中第一個表,依此類推。
一直暴到第十二個表,發現一個表名為root的表,懷疑是管理員表。接着暴出這個表中的字段,構造如下SQL語句:
http://www.a.com/cms/new.php?id=0 union select 1,2,column_name,4,5,6 from information_schema.columns where table_name=0x726F6F74 limit 0,1
最終確認此表存在三個字段,分別是root_id、root_name和root_pass。初步判斷此表應該是保存管理員賬號和密碼的。現在我們已經得到root表和其相應的字段名稱。
暴表中的內容
構造如下SQL語句:
http://www.a.com/cms/new.php?id=0 union select 1,2,root_id,root_name,root_pass,6 from cms.root
圖9
如 圖9所示,我們得到了管理員的賬號和密碼,密碼是經過MD5加密的,經過解密后為123456。我們現在得到了管理員的賬號和密碼,只要找到管理員登錄頁 面,就可以登錄進入后台了。很快我們就找到了網站的后台地址:http://www.a.com/cms/isadmin/login.php
我們登錄進去看下,如圖10所示。
圖10
現在我們有了網站管理員的權限,可以隨意更改網站的信息(如添加、刪除文章等),還可以結合其他漏洞上傳一個Webshell,進一步提權獲得服務器的系統權限。此處可以充分發揮自己的想像力。因為本文主要講述SQL注入,所以關於提權的問題請查閱其他資料。
工具注入篇
通 過上面的介紹和手工注入實例,我們對SQL注入漏洞的原理和漏洞利用過程有了一個完整的了解。讀者可能也發現手工注入比較繁瑣,效率比較低,而且容易出 錯。但是手工注入能夠加深對漏洞原理和漏洞利用過程的理解。當我們對這些都非常了解以后,我們可以利用工具來提高效率。現在有很多非常優秀的工具供我們選 擇,下面就演示一下利用工具進行SQL注入。這里選用業界非常著名的Havij來做演示。首先,打開Havij軟件,界面如圖11所示:
圖11
一切設置完畢后,選擇“Analyze”,很快就返回了結果,如圖12和圖13所示。
圖12
SQL注入攻擊防御
上面我們對SQL注入的原理和危害進行了講解,並以攻擊者的角度對SQL注入漏洞的利用過程進行了演示。下面我們以管理者的身份,從防御的角度來談一下SQL防注入。
通過SQL注入的原理我們得知,要想成功利用SQL注入漏洞,需要同時滿足兩個條件,一是攻擊者可以控制用戶的輸入,二是注入的代碼要被成功執行。下面的內容主要圍繞這兩個方面來展開。
首先,我們需要對從其他地方傳遞過來的參數在進入數據庫之前進行正確的處理。主要有以下幾個方面:
1.使用預編譯語句,綁定變量。
2. 對傳入的參數進行驗證,確保符合應用中定義的標准。主要有白名單和黑名單兩種方法來實現。從理論上來講,白名單的安全性要比黑名單高,因為它只允許在白名 單中定義的數據通過,其他數據都會被過濾掉。黑名單只會過濾定義在黑名單中的數據(比如SQL注入中的一些危險字符),通常使用正則表達式來實現。但需要 注意的是,由於黑名單不可能包含所有的危險字符,所以可能會出現黑名單被繞過的情況。例如在mysql注入中,當在黑名單中過濾了空格字符,我們可以使 用"/*(mysql中注釋符)"和"+"來代替空格,繞過黑名單的限制繼續注入,因此我們應該盡量多使用白名單。
除了對用戶的輸入進行了 驗證之外,有時因為程序員的安全意識和技術問題,也可能只是一個小小的疏忽,都有可能產生SQL注入漏洞。還有一種情況是,我們發現了SQL注入漏洞,但 是由於條件所限或者其他原因,不能從代碼層來修復漏洞。比如在某一企業中有一套Web系統是由A程序員開發的,過了一段時間A離職了。后來,發現這套系統 存在SQL注入漏洞,這時再讓A程序員回來修復漏洞幾乎是不可能的。而其他程序員由於對這套系統不熟悉或是因為技術問題沒有能力修復這個漏洞。這種情況在 中小企業更為普遍。這時我們雖然不能從代碼層修復漏洞,但我們可以采用一些其他方式來阻止漏洞被利用成功,把面臨的風險降到最低。如可以布署 WAF(Web應用防火牆)來阻斷SQL注入攻擊,雖然有些攻擊者可以繞過WAF的限制,但畢竟是少數。對於絕大多數的攻擊WAF都是可以檢測到並阻斷。 即便是高水平的攻擊者,在布署WAF以后,也會明顯使漏洞利用變得困難。
最后,在數據庫方面,應該使用“最小權限原則”,避免Web應用使用高權限賬戶直接連接數據庫。如果有多個不同的應用使用同一數據庫,則應該為每個應用分配不同的賬戶,並且只賦予必要的權限。
轉載:http://www.rising.com.cn/newsletter/news/2012-05-24/11580.html