SQL 截斷攻擊和防御方法_第1頁
SQL 截斷攻擊和防御方法_第2頁
SQL 截斷攻擊和防御方法_第3頁
SQL 截斷攻擊和防御方法_第4頁
SQL 截斷攻擊和防御方法_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

新型SQL截斷攻擊和防御方法本文討論: 本文使用了以下技術(shù):SQLServer分隔標(biāo)識符和字符串實用的T-SQL函數(shù)截斷和修改攻擊找出Bug和漏洞目錄利用SQL注入方法的漏洞攻擊已經(jīng)引起了廣泛關(guān)注,因為這些漏洞能夠穿過防火墻和入侵檢測系統(tǒng),從而破壞您的數(shù)據(jù)層。無論是第一級還是第二級注入攻擊,如果您看一下基本的代碼模式它與其他任何注入攻擊問題都類似,即您在構(gòu)造語句時都使用了不受信任的數(shù)據(jù)。大多數(shù)開發(fā)人員已經(jīng)開始通過在后端使用參數(shù)化SQL查詢和存儲過程來減少Web前端的這些漏洞,但有些情況下,開發(fā)人員仍使用動態(tài)構(gòu)建的SQL,例如根據(jù)用戶輸入或為C/C++編寫的應(yīng)用程序構(gòu)造數(shù)據(jù)定義語言(DDL)語句時。在本文中我將討論一些新觀點(diǎn),其結(jié)果可能會修改SQL語句或注入SQL代碼,即使代碼對分隔字符進(jìn)行了轉(zhuǎn)義。我首先介紹一些構(gòu)建分隔標(biāo)識符和SQL字符串的最佳實踐,然后我將介紹攻擊者注入SQL代碼的幾種新方法,以幫助您保護(hù)您的應(yīng)用程序。分隔標(biāo)識符和字符串在SQLServer中,有兩種字符串變量:唯一可識別SQL對象(如表、視圖和存儲過程)的SQL標(biāo)識符,以及用于表示數(shù)據(jù)的字符串。分隔SQL標(biāo)識符的方法與分隔數(shù)據(jù)字符串的方法不同。我們將討論需要使用這些數(shù)據(jù)變量的動態(tài)SQL構(gòu)建方法的最佳實踐。如果SQL對象名使用了關(guān)鍵字,或者對象名中包含了特殊字符,則您需要使用分隔標(biāo)識符。假如您需要刪除my_dbreader登錄名,則可以執(zhí)行以下語句:復(fù)制代碼DROPLOGINmy_dbreader如果您試著刪除一個使用DROP作為其名稱(也是關(guān)鍵字)的登錄名會怎樣?如果您使用以下SQL語句,SQLServer會返回一個語法錯誤。復(fù)制代碼DROPLOGINDROP如果您要刪除像my][dbreader這樣的登錄名又會怎樣?這也會引發(fā)語法錯誤。在上面兩個例子中,由于登錄名為關(guān)鍵字或包含特殊字符,因此您需要提供一些開始和結(jié)束標(biāo)記,以便SQLServer可以識別SQL語句中的對象名。您可以使用雙引號或方括號作為SQL標(biāo)識符的分隔符,而在QUOTED_IDENTIFIER設(shè)置(一種基于連接的設(shè)置)啟用時您可以只使用雙引號。為簡便起見,最好始終使用方括號。要成功刪除DROP登錄名,您可以使用方括號來構(gòu)造您的SQL語句:復(fù)制代碼DROPLOGIN[DROP]但以下語句會怎樣?復(fù)制代碼DROPLOGIN[my][dbreader]在這種特殊情況下,由于登錄名my][dbreader中包含分隔字符,因此SQL會認(rèn)為[my]是登錄名,因為它被包含在方括號內(nèi)。由于[dbreader]跟在登錄名后面,因此該語句并不構(gòu)成正確的SQL語句,會導(dǎo)致語法錯誤。您可以通過用另一個右方括號對上面的右方括號進(jìn)行轉(zhuǎn)義來解決這一問題。因此,如果您執(zhí)行以下語句,SQLServer將成功刪除my][dbreader登錄名:復(fù)制代碼DROPLOGIN[my]][dbreader]轉(zhuǎn)義機(jī)制只是使右方括號的出現(xiàn)次數(shù)增加了一倍。您無需改動其他字符,包括左方括號。準(zhǔn)備分隔字符串與準(zhǔn)備分隔SQL標(biāo)識符類似,主要區(qū)別就是需要使用的分隔字符。在介紹與構(gòu)建分隔字符串相似的規(guī)則之前,先來看以下幾個例子。假設(shè)您希望創(chuàng)建dbreader登錄名,密碼是P@$$w0rd。您會使用以下SQL語句:復(fù)制代碼CREATELOGIN[dbreader]WITHPASSWORD='P@$$w0rd'在該語句中,P@$$w0rd是由單引號分隔的字符串?dāng)?shù)據(jù),因此SQL知道該字符串從哪里開始,到哪里結(jié)束。但如果字符串?dāng)?shù)據(jù)中包含單引號會怎樣?SQLServer會引發(fā)一個錯誤,因為該語句為無效語句:復(fù)制代碼CREATELOGIN[dbreader]WITHPASSWORD='P@$$'w0rd'您需要對字符串中出現(xiàn)的所有單引號進(jìn)行轉(zhuǎn)義,構(gòu)造有效的SQL語句:復(fù)制代碼CREATELOGIN[dbreader]WITHPASSWORD='P@$$''w0rd'當(dāng)您執(zhí)行該語句時,SQLServer將創(chuàng)建dbreader登錄名,密碼為P@$$'w0rd。您還可以使用雙引號作為分隔符,但正如我前面提到的,這種方法是否成功完全取決于QUOTED_IDENTIFIER設(shè)置是否已開啟。因此,最好始終使用單引號作為字符串的分隔符。T-SQL函數(shù)可以看出,處理標(biāo)識符和字符串的規(guī)則相對比較簡單,如果您預(yù)先知道該字符串,可以手動對其進(jìn)行分隔。但如果您要根據(jù)用戶輸入構(gòu)建動態(tài)的T-SQL語句,該怎么辦?您需要通過自動的方法來完成。兩種T-SQL函數(shù)可幫您準(zhǔn)備分隔字符串,它們是QUOTENAME和REPLACE。QUOTENAME會返回一個Unicode字符串,并添加了分隔符,以使該輸入字符串成為有效標(biāo)識符。QUOTENAME函數(shù)使用以下語法:復(fù)制代碼QUOTENAME('string'[,'delimiter'])您可以將要分隔的字符串和一個用作分隔符的單字符字符串傳給QUOTENAME。分隔符可以是方括號、單引號或雙引號。此函數(shù)主要用于準(zhǔn)備分隔SQL標(biāo)識符,因此它只接受sysname類型,在SQLServer中為nvarchar(128)。您還可以使用此函數(shù)準(zhǔn)備分隔SQL字符串,但由于參數(shù)長度的限制,因此它支持的字符串長度最多為128個字符(在這一點(diǎn)上,REPLACE函數(shù)可發(fā)揮其用途)。圖1顯示了sp_addlogin如何使用QUOTENAME來準(zhǔn)備分隔登錄名和密碼字符串??梢钥闯?,由于@loginname和@passwd均為sysname類型,因此可使用QUOTENAME函數(shù)準(zhǔn)備分隔SQL標(biāo)識符和分隔字符串。因此,即使有人傳遞的是@loginname='my[]dbreader'和@passwd='P@$$''w0rd',也不會有任何SQL注入機(jī)會,因為QUOTENAME對分隔字符進(jìn)行了適當(dāng)轉(zhuǎn)義:復(fù)制代碼createlogin[my[]]dbreader]withpassword='P@$$''w0rd'Figure1DelimitingStringswithQUOTENAMEREPLACE函數(shù)會將某個給定字符串的所有出現(xiàn)之處全部替換為指定的替代字符串。QUOTENAME不同,REPLACE函數(shù)對其接受的參數(shù)沒有長度限制:復(fù)制代碼REPLACE('stringl','string2','string3')REPLACE帶有三個字符串:stringl是要編輯的表達(dá)式,string2是stringl中要被替換的項,string3是用于取代string2的項。任何字符串表達(dá)式都可由字符或二進(jìn)制數(shù)據(jù)組成。要準(zhǔn)備分隔SQL字符串,您可以使用REPLACE使單引號的出現(xiàn)次數(shù)增加一倍,但您需要手動添加分隔符(開始和結(jié)束的單引號)。圖2顯示了sp_attach_single_file_db如何使用此函數(shù)準(zhǔn)備一個文件的已轉(zhuǎn)義的物理名稱。由于@physname是nvarchar(260),因此您無法使用QUOTENAME準(zhǔn)備分隔字符串,這就是為何要使用REPLACE的原因。因此,即使有人傳遞帶單引號的字符串,他們也無法打破SQL語句,注入任何SQL代碼。Figure2DelimitingStringswithREPLACESQL注入漏洞接下來介紹存儲過程,它可在驗證了當(dāng)前密碼后更改用戶帳戶的密碼(參圖3)。Figure3ChangingaPassword快速瀏覽存儲過程,會發(fā)現(xiàn)沒有任何參數(shù)對單引號進(jìn)行轉(zhuǎn)義,這同樣容易受至SQL注入攻擊。攻擊者可以傳遞幾個特定的參數(shù),并將SQL語句修改為:復(fù)制代碼updateUserssetpassword='NewP@ssw0rd'whereusername='admin'--'andpassword='dummy'結(jié)果是,無需實際密碼即可設(shè)置管理員帳戶(或任何已知的帳戶)的密碼。在T-SQL函數(shù)中,您可以通過使用REPLACE或QUOTENAME函數(shù)修復(fù)此代碼。圖4顯示了使用REPLACE函數(shù)后正確的代碼。Figure4UsingREPLACEtoAvoidInjection可以看出,REPLACE會將參數(shù)中所有單引號的出現(xiàn)次數(shù)都增加一倍。因此,如果攻擊者傳遞相同的參數(shù),該語句會變?yōu)椋簭?fù)制代碼updateUserssetpassword='NewP@ssw0rd'whereusername='admin''--'andpassword='dummy'這樣就不容易受到通常的SQL注入問題的影響了。通過截斷進(jìn)行修改如果您仔細(xì)留意上面顯示的存儲過程,您會發(fā)現(xiàn)@command變量只能存放100個字符,但當(dāng)25個字符都為單引號時,這些字符的每個變量經(jīng)過REPLACE函數(shù)處理后可返回50個字符。如果變量沒有足夠大的緩沖區(qū),SQLServer2000SP4和SQLServer2005SP1會自行截斷數(shù)據(jù)。這就為攻擊者提供了截斷命令字符串的機(jī)會。在此例中,如果有人可以在username='username'表達(dá)式后截斷命令,那么無需知道已知用戶的當(dāng)前密碼,就可更改其帳戶的密碼。假設(shè)攻擊者知道administrator用戶名存在于Web應(yīng)用程序中(這可以是任何用戶帳戶)。攻擊者需要提供長度為41個字符的新密碼,以使命令的長度足以被適當(dāng)截斷一之所以是41個字符,是因為在用于命令的100個字符中,27個字符用于更新語句,17個字符用于where子句,13個字符用于"administrator”,2個字符用于新密碼前后的單引號。攻擊者只能傳遞25個字符作為新密碼。但他可以通過傳遞單引號避開這一限制,因為REPLACE函數(shù)會使單引號數(shù)量增加一倍。因此,通過傳遞18個單引號、1個大寫字母、1個符號、2個小寫字母和1個數(shù)字,攻擊者就可以截斷whereusername='administrator'表達(dá)式后面的命令了。如果攻擊者將 !Abb1傳遞給@new參數(shù),并將administrator作為用戶名參數(shù),那么@command就會變成:復(fù)制代碼updateUserssetpassword=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,!Abb1,whereusername='administrator'圖5使用QUOTENAME而非REPLACE。上面的例子和此例的唯一不同在于,在上例中,開發(fā)人員為用戶名、新密碼和舊密碼添加了單引號分隔符,而在此例中,股UOTENAME函數(shù)添加。由于用戶提供的數(shù)據(jù)沒有變化,因此上例中使用的同一攻擊字符串仍然可以被攻擊者利用圖6是在中間層應(yīng)用程序中編寫的C/C++函數(shù)的縮寫版本,可實現(xiàn)相同功能。它容易受到相同的攻擊。Figure6TruncationProblemsinC++Figure5UsingQUOTENAMEtoAvoidInjection通過截斷進(jìn)行SQL注入圖7顯示了相同代碼的另一變體,但可使用單獨(dú)的變量進(jìn)行修復(fù)。可以看出,此代碼將轉(zhuǎn)義后的字符串存放在單獨(dú)的變量中,而且@command有足夠的緩沖區(qū)來存放整個字符串。@escaped_username、@escaped_oldpw和@escaped_newpw被聲明為varchar(25),但如果@username、@old和@new中的所有字符是25個單引號,則它們需要存放50個字符。這就為截斷已轉(zhuǎn)義的字符串創(chuàng)造了機(jī)會。Figure7UsingSeperateVariablestoAvoidInjection攻擊者可以傳遞123...n'作為新密碼,其中n是第24個字符,使@escaped_newpw也成為123...n'(REPLACE函數(shù)返回的第二個單引號字符會被截斷),使最后的查詢?nèi)缦滤?,攻擊者可以通過用戶名字段注入代碼,從而利用此查詢:復(fù)制代碼updateuserssetpassword=T23...n''whereusername='<SQLInjectionhereusingUsername>這種代碼模式更危險,因為這為注入SQL代碼(而不僅僅是截斷現(xiàn)有SQL)提供了機(jī)會。圖8提供了使用QUOTENAME函數(shù)而非REPLACE的同一變體的另一個例子。由于QUOTENAME函數(shù)要添加分隔符,因此負(fù)載會有所不同,但仍舊容易受到SQL注入攻擊。Figure8UsingQUOTENAMEwithSeperateVariables在此例中,代碼將分隔后的字符串存放在單獨(dú)的變量中,而且@command有足夠的緩沖區(qū)來存放整個命令字符串。正如上例所示,問題在于被引用的變量@quoted_username、@quoted_oldpw和@quoted_newpw。它們都被聲明為varchar(25),但如果@username、@old和@new中的所有字符是25個單引號,則它們需要存放52個字符(QUOTENAME還將添加開始和結(jié)束的分隔符。)這就為攻擊者截斷已分隔的字符串創(chuàng)造了機(jī)會。攻擊者可以傳遞123...n(其中n是第24個字符)作為新密碼,使@escaped_newpw也成為'123...n(開始的單引號由QUOTENAME添加),使最后的查詢?nèi)缦滤?,攻擊者可以通過用戶名字段注入代碼,從而利用此查詢:復(fù)制代碼updateuserssetpassword='123...nwhereusername='<SQLInjectionhereusingUsername>圖9是C/C++中此代碼的縮寫版本,可實現(xiàn)相同功能。它同樣容易受到相同攻擊。Figure9VariableTruncationIssuesinC++盡管我在演示中使用的是T-SQL代碼,但實際上您不需要使用動態(tài)SQL來構(gòu)造數(shù)據(jù)操作語言(DML)語句,因此大多數(shù)包含DML代碼的應(yīng)用程序不易受到這些問題的困擾。下面,我們來看看另一個根據(jù)用戶輸入構(gòu)造動態(tài)DDL語句的例子,如圖10所示。就像前面的例子一樣,以下語句也存在截斷問題:復(fù)制代碼set@escaped_oldpw=quotename(@old,'''')set@escaped_newpw=quotename(@new,'''')攻擊者通過傳遞@new='123...'(其中從第127個字符(無單引號)開始是@old=';SQLInjection'),會使SQL語句如下所示:復(fù)制代碼alterlogin[loginname]withpassword='123...old_password=';SQLInjectionFigure10CreatingaDynamicDDLStatement盡管存儲過程更可能出現(xiàn)這些問題,但并非所有存儲過程都會導(dǎo)致安全漏洞。接下來介紹哪些存儲過程需要仔細(xì)審查。在SQLServer中,默認(rèn)情況下,所有存儲過程都在調(diào)用方的環(huán)境下執(zhí)行。因此,即使某個過程存在SQL注入問題,對該過程具有執(zhí)行權(quán)限的惡意的本地用戶也無法提高其權(quán)限,并且注入的代碼會在其環(huán)境下執(zhí)行。但是如果您有內(nèi)部維護(hù)腳本,作為計算機(jī)所有者或某個特定用戶可以執(zhí)行該腳本,那么調(diào)用方就可以在不同用戶環(huán)境下執(zhí)行代碼,并將其權(quán)限提升為該用戶的權(quán)限。所有截斷問題肯定都是Bug,但它們不一定是安全漏洞。但最好還是修復(fù)這些問題,因為您并不知道將來誰會找出這些問題并對其加以利用。您可以采取其他措施減少您的SQL代碼中的注入漏洞。首先,在存儲過程中避免使用動態(tài)SQL來構(gòu)造DML語句。如果您無法避免使用動態(tài)SQL,那么可以使用sp_executesql。第二,正如本文所舉的例子中說明的,您需要正確計算緩沖區(qū)的長度。最后,在C/C++代碼中,檢查字符串運(yùn)算返回值,并查看字符串是否已截斷,如果已截斷,則相應(yīng)的結(jié)果錯誤。參見提要懦洞檢測方法”,了解您可以采取的措施的摘要。通過截斷檢測注入要利用自動化工具通過截斷問題檢測SQL注入,需要對所有會產(chǎn)生截斷可能性的代碼模式有非常清楚的了解。您可以針對不同的特定代碼模式使用不同的字符串?dāng)?shù)據(jù)。在下述情形中,假定?是輸入緩沖區(qū)的長度。要檢測QUOTENAME分隔問題,首先假設(shè)使用QUOTENAME(或C/C++應(yīng)用程序采用的類似函數(shù))來準(zhǔn)備分隔標(biāo)識符或字符串,并且分隔字符串緩沖區(qū)大小小于2*n+2。當(dāng)分隔字符串緩沖區(qū)長度等于n時,要捕獲這些問題,可傳遞未分隔的長字符串。尾部分隔符將被截斷,利用其他某個輸入變量,您將獲得注入機(jī)會。當(dāng)分隔緩沖區(qū)長度為奇數(shù)時,要捕獲這些問題,可傳遞單引號字符或右方括號或雙引號)的長字符串。由于QUOTENAME會將所有分隔符出現(xiàn)的次數(shù)增加一倍,并添加開始的分隔字符,因此當(dāng)已轉(zhuǎn)義的字符串緩沖區(qū)只能存放奇數(shù)個字符時,尾部分隔符會被截斷。當(dāng)分隔緩沖區(qū)長度為偶數(shù)時,要捕獲這些問題,可傳遞像1'、1''、1'''、1''''等這樣的字符串,每次迭代時使單引號(或右方括號)數(shù)量遞增。由于QUOTENAME會使所有單引號的出現(xiàn)次數(shù)增加一倍,因此在返回的字符串中會有偶數(shù)個單引號,加上開始的分隔符和1,最終會有偶數(shù)個字符。因此,尾部的分隔符會被截斷。如果使用REPLACE(或C/C++應(yīng)用程序采用的類似函數(shù))來準(zhǔn)備已轉(zhuǎn)義的字符串,并且當(dāng)已轉(zhuǎn)義的字符串緩沖區(qū)大小小于2勺時,您也可以檢測出上述問題。當(dāng)已轉(zhuǎn)義的字符串緩沖區(qū)長度等于?時,要捕獲這些問題,可傳遞像1'、12'、123'和123...n'等這樣的字符串,每次迭代時使輸入字符串的長度遞增。在這種情況下,如果您達(dá)到合適的長度,那么REPLACE函數(shù)就會將最后一個單引號字符再增加一個。由于已轉(zhuǎn)義的字符串變量不具備足夠的緩沖區(qū)空間因此最后一個單引號會被截斷,并在傳遞時保存起來,從而為打破SQL語句提供了機(jī)會。當(dāng)已轉(zhuǎn)義的緩沖區(qū)長度為奇數(shù)時,要通過REPLACE捕獲問題,可傳遞長度逐漸遞增的單引號字符串,如’'、’'’和’'''...’(或者只傳遞單引號字符的長字符串)。在這種情況下,REPLACE將使所有單引號的出現(xiàn)次數(shù)增加一倍。但是由于有的緩沖區(qū)長度是奇數(shù),因此最后一個單引號會被截斷這就為打破語句提供了機(jī)會。當(dāng)已轉(zhuǎn)義緩沖區(qū)長

溫馨提示

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

評論

0/150

提交評論