第壹節,SQL註入原理
先說壹個網站www.19cn.com(註:本文在發表前已經得到站長的認可,大部分是真實數據)。
網站首頁有壹個名為“IE不開新窗口的各種解決方案”的鏈接,地址:。com/showdetail.asp?Id=49,我們在該地址後加上單引號',服務器將返回以下錯誤消息:
Microsoft JET數據庫引擎錯誤“80040e14”
字符串的語法錯誤在查詢表達式“ID=49”中。
/showdetail.asp,第8行
我們可以從這個錯誤提示中看到以下幾點:
1.網站使用Access數據庫,通過JET引擎而不是ODBC連接數據庫。
2.程序沒有判斷客戶端提交的數據是否符合程序要求。
3.此SQL語句查詢的表中有壹個名為ID的字段。
從上面的例子我們可以知道,SQL註入的原理是從客戶端提交專門的代碼來收集程序和服務器的信息,從而獲得妳想要的信息。
第二節,判斷SQL註入是否可以進行
看完第壹節,有人會想:我經常測試能不能這樣註射,不是很簡單嗎?其實這並不是最好的辦法。為什麽?
首先,每臺服務器的IIS不壹定會向客戶端返回特定的錯誤提示。如果將cint(參數)之類的語句添加到程序中,SQL註入將不會成功,但服務器也會報告壹個錯誤。特定提示信息是服務器處理URL時出現的錯誤。請聯系系統管理員。
其次,壹些稍微了解SQL註入的程序員認為過濾掉單引號是安全的,這種情況並不少見。如果用單引號測試,就檢測不到註入點。
那麽,什麽樣的測試方法更準確呢?答案如下:
① .com/showdetail.asp?id=49
② .com/showdetail.asp?id=49和1=1
③ .com/showdetail.asp?id=49和1=2
這就是1=1和1=2的經典測試方法。如何判斷?看看以上三個網站返回的結果:
可以註入的性能:
①正常顯示(這是不可避免的,否則程序有錯誤)
②正常顯示,內容與①基本相同。
(3)提示BOF或EOF(程序未作任何判斷時),或提示找不到記錄(判斷rs.eof時),或顯示內容為空(程序已添加on error resume next)。
如果不能註射就更容易判斷了。①也正常顯示。②、③壹般有程序定義錯誤提示或提示類型轉換錯誤。
當然,這只是傳入參數為數值時的壹種判斷方法。實際應用中會有字符參數和搜索參數,我會在中級章節的“SQL註入的壹般步驟”中分析。
第三節,判斷數據庫類型和註入方法
不同數據庫的功能和註入方式是不壹樣的,所以在註入之前,我們要判斷數據庫的類型。壹般ASP最常用的數據庫是Access和SQLServer,互聯網上99%以上的網站都是其中之壹。
程序怎麽能告訴妳它用的是什麽數據庫?讓我們看看:
SQLServer有壹些系統變量。如果服務器IIS提示沒有關閉,並且SQLServer返回壹個錯誤提示,您可以直接從錯誤消息中獲得它。該方法如下:
。com/showdetail.asp?id=49且用戶& gt0
這句話很簡單,卻包含了SQLServer獨特註入方式的精髓。我自己也是在壹次無意的測試中發現了這個高效的猜測方法。我來看看是什麽意思:首先,前面的說法很正常,側重於和用戶>;0,我們知道,user是SQLServer的內置變量,它的值是當前連接的用戶名,類型是nvarchar。將nvarchar的值與int的數字0進行比較,系統將首先嘗試將nvarchar的值轉換為int類型。當然,在轉換的過程中也會出現錯誤。SQLServer的錯誤提示是將nvarchar“ABC”的值轉換為數據類型為int的列時出現語法錯誤。呵呵,abc就是變量user的值,這樣就可以不費吹灰之力獲得數據庫的用戶名。在接下來的幾頁中,妳會看到許多使用這種方法的句子。
順便說壹下,我們都知道,SQLServer的用戶sa是壹個相當於Adminstrators權限的角色。有了sa權限,幾乎可以肯定他能拿到主機的管理員。上面的方法可以很容易的測試妳是否用sa登錄。需要註意的是,如果用sa登錄,提示是將“dbo”轉換為int的列有錯誤,而不是“sa”。
如果服務器IIS不允許返回錯誤提示,如何確定數據庫類型?我們可以從Access和SQLServer的區別開始。Access和SQLServer都有自己的系統表,例如用於存儲數據庫中所有對象的表。Access在系統表[msy objects]中,但是在Web環境下讀取這個表會提示“無權限”,SQLServer在表[sysobjects]中,在Web環境下可以正常讀取。
當確認可以註射時,使用以下語句:
。com/showdetail.asp?id=49且(select count(*) from sysobjects)>0
。com/showdetail.asp?id=49且(select count(*)from msy objects)>0
如果數據庫是SQLServer,那麽第壹個URL的頁面與原始頁面相同。com/showdetail.asp?Id=49大致相同;第二個URL將提示壹個錯誤,因為找不到表msysobjects。即使程序有容錯,頁面也和原頁面完全不同。
如果數據庫使用Access,情況就不同了。第壹個URL的頁面與原始頁面完全不同。第二個網站,取決於數據庫設置是否允許讀取系統表,壹般是不允許的,所以和原網站完全不同。大多數情況下,用第壹個URL就可以知道系統使用的數據庫類型,第二個URL只是在打開IIS錯誤提示時作為驗證使用。
第壹節,SQL註入的壹般步驟
首先判斷環境,找到註入點,判斷數據庫類型,在入門文章裏已經提到了。
其次,根據註入參數類型,在腦海中重構SQL語句的原貌,根據參數類型主要分為以下三種:
(A) ID=49註入的參數是數值型的,SQL語句的原始外觀大致如下:
Select * from字段=49的表名
註入的參數是ID=49和[查詢條件],即生成的語句:
Select * from表名,其中字段=49和[查詢條件]
(B) Class= Series註入的參數是字符型的,SQL語句原來的樣子大致如下:
Select * from表名,其中field =' series '
註入的參數是Class= series '和[查詢條件]和' ' =' = ',即生成的語句:
Select * from表名,其中field =' series '和[查詢條件]以及' ' ='' = ' '
(c)如果搜索時沒有篩選參數,例如keyword= keyword,則原始SQL語句如下所示:
Select * from表名,其中字段如' % keyword% '
註入的參數是keyword= '和[查詢條件]和' % 25' = ',即生成的語句:
Select * from表名,其中字段如“%”、[查詢條件]和“%”=“%”
然後,用SQL語句替換查詢條件,並猜測表名,例如:
ID=49且(從Admin中選擇Count(*))>=0
如果頁面與ID=49的頁面相同,則附加條件成立,即表Admin存在,否則不存在(請記住這個方法)。依此類推,直到猜出表名。
猜出表名後,用Count(字段名)代替Count(*),用同樣的原理猜出字段名。
有人會說:這裏有些偶然的成分。如果手表的名字很復雜,沒有規律,那就根本不用玩了。沒錯。這個世界上沒有100%成功的黑客技術。蒼蠅不叮無縫的蛋。黑客再高明,也是因為別人的程序寫得不好或者用戶保密意識不夠,才會下手。
有點跑題了。另壹方面,程序仍然有辦法告訴我們SQLServer庫的表名和字段名,我們將在高級文章中介紹。
最後,在成功猜測出表名和列名之後,通過使用SQL語句獲得字段的值。這裏介紹壹種最常用的方法——Ascii逐字解碼法。這個方法雖然慢,但肯定是可行的。
例如,我們知道用戶名字段存在於表Admin中。首先,我們獲取第壹條記錄並測試其長度:
。com/showdetail.asp?id=49且(從Admin中選擇top 1 len(用戶名)>;0
先說明原理:如果top 1的用戶名長度大於0,則條件成立;然後是> 1 、>;2、gt;3這樣測試,直到條件不成立,如> 7成立,> 8不成立,即len(username)=8。
當然,沒有人會傻到從0,1,2,3開始壹個壹個的測試,如何讓它更快,就看自己的發揮了。得到用戶名的長度後,用mid(username,N,1)截取第N個字符,再用asc(mid(username,N,1))得到ASCII碼,例如:
id=49且(select top 1 ASC(mid(username,1,1)) from Admin)>0
類似地,1字符的ASCII碼是通過逐漸縮小範圍獲得的。註意英文和數字的ASCII碼在1-128之間,可以用來加快猜測的速度。如果寫成程序測試,效率會大大提高。
第2節,SQL註入常用函數
有SQL語言基礎知識的人在SQL註入的成功率比不熟悉的人高很多。我們有必要提高自己的SQL水平,尤其是壹些常用的函數和命令。
Access:asc(字符)SQLServer:unicode(字符)
函數:返回字符的ASCII碼。
Access:chr(數字)SQLServer:nchar(數字)
函數:與asc相反,根據ASCII碼返回字符。
Access:mid (string,N,L N,L) SQLServer:substring (string,N,L)
函數:從N個字符中返回長度為L的子串,即介於N和N+L之間的字符串。
訪問:abc(數字)SQLServer:abc(數字)
函數:返回壹個數字的絕對值(猜測漢字時使用)
訪問:B和C之間的A SQL server:B和C之間的A
作用:判斷A是否在B和c之間。
第三節,中文處理方法
打針遇到漢字是常事,有的人壹遇到漢字就想打退堂鼓。其實只要對中文編碼有所了解,“中文恐懼癥”很快就能克服。
先說壹點常識:
在Access中,中文ASCII碼中可能有負數。取出負數後,用abs()取絕對值,漢字不變。
在SQLServer中,中文ascii是正數,但是因為是UNICODE的雙位編碼,所以不能使用函數ASCII()來獲取ASCII碼。必須使用函數unicode()返回unicode值,然後使用nchar函數獲取相應的中文字符。