一位客戶讓我們針對只有他們企業(yè)員工和顧客能使用的企業(yè)內(nèi)網(wǎng)進(jìn)行滲透測試。這是安全評估的一個(gè)部分,所以盡管我們之前沒有使用過SQL注入來滲透網(wǎng)絡(luò),但對其概念也相當(dāng)熟悉了。最后我們在這項(xiàng)任務(wù)中大獲成功,現(xiàn)在來回顧一下這個(gè)過程的每一步,將它記錄為一個(gè)案例。
“SQL注入”是一種利用未過濾/未審核用戶輸入的攻擊方法(“緩存溢出”和這個(gè)不同),意思就是讓應(yīng)用運(yùn)行本不應(yīng)該運(yùn)行的SQL代碼。如果應(yīng)用毫無防備地創(chuàng)建了SQL字符串并且運(yùn)行了它們,就會(huì)造成一些出人意料的結(jié)果。
我們記錄下了在多次錯(cuò)誤的轉(zhuǎn)折后經(jīng)歷的曲折過程,而一個(gè)更有經(jīng)驗(yàn)的人會(huì)有這不同的 — 甚至更好的 — 方法。但事實(shí)上我們成功以后才明白,我們并沒有完全被誤導(dǎo)。
其他的SQL文章包含了更多的細(xì)節(jié),但是這篇文章不僅展示了漏洞利用的過程,還講述了發(fā)現(xiàn)漏洞的原理。
展現(xiàn)在我們眼前的是一個(gè)完整定制網(wǎng)站,我們之前沒見過這個(gè)網(wǎng)站,也無權(quán)查看它的源代碼:這是一次“黑盒”攻擊?!烫健Y(jié)果顯示這臺(tái)服務(wù)器運(yùn)行在微軟的IIS6上,并且是ASP.NET架構(gòu)。這就暗示我們數(shù)據(jù)庫是微軟的SQL server:我們相信我們的技巧可以應(yīng)用在任何web應(yīng)用上,無論它使用的是哪種SQL 服務(wù)器。
登陸頁有傳統(tǒng)的用戶-密碼表單,但多了一個(gè) “把我的密碼郵給我”的鏈接;后來,這個(gè)地方被證實(shí)是整個(gè)系統(tǒng)陷落的關(guān)鍵。
當(dāng)鍵入郵件地址時(shí),系統(tǒng)假定郵件存在,就會(huì)在用戶數(shù)據(jù)庫里查詢郵件地址,然后郵寄一些內(nèi)容給這個(gè)地址。但我的郵件地址無法找到,所以它什么也不會(huì)發(fā)給我。
對于任何SQL化的表單而言,第一步測試,是輸入一個(gè)帶有單引號(hào)的數(shù)據(jù):目的是看看他們是否對構(gòu)造SQL的字符串進(jìn)行了過濾。當(dāng)把單引號(hào)作為郵件地址提交以后,我們得到了500錯(cuò)誤(服務(wù)器錯(cuò)誤),這意味著“有害”輸入實(shí)際上是被直接用于SQL語句了。就是這了!
我猜測SQL代碼可能是這樣:
$EMAIL 是用戶從表單提交的地址,并且這段查詢在字符串末端$EMAIL上提供了引號(hào)。我們不知道字段或表的確切名字,但是我們了解他們的本質(zhì),這有助于我們做正確的猜測。
當(dāng)我們鍵入steve@unixwiz.net‘ -注意這個(gè)末端的引號(hào) – 下面是這個(gè)SQL字段的構(gòu)成:
當(dāng)這段SQL開始執(zhí)行,SQL解析器就會(huì)發(fā)現(xiàn)多余的引號(hào)然后中斷執(zhí)行,并給出語法錯(cuò)誤的提示。這個(gè)錯(cuò)誤如何清楚的表述給用戶,基于應(yīng)用內(nèi)部的錯(cuò)誤恢復(fù)規(guī)程,但一般來說都不會(huì)提示“郵件地址不存在”。這個(gè)錯(cuò)誤響應(yīng)成了死亡之門,它告訴別人用戶輸入沒有被正確的處理,這就為應(yīng)用破解留下了可乘之機(jī)。
這個(gè)數(shù)據(jù)呈現(xiàn)在WHERE的從句中,讓我們以符合SQL規(guī)范的方式改變輸入試試,看看會(huì)發(fā)生什么。鍵入anything’ OR ‘x’=‘x, 結(jié)果如下:
因?yàn)閼?yīng)用不會(huì)思考輸入 – 僅僅構(gòu)造字符串 - 我們使用單引號(hào)把WHERE從句的單一組成變成了雙組成,’x'=‘x’從句是恒成立的,無論第一個(gè)從句是什么。(有一種更好的方式來確?!笆冀K為真”,我們隨后會(huì)接觸到)。
但與每次只返回單一數(shù)據(jù)的“真實(shí)”查詢不同,上面這個(gè)構(gòu)造必須返回這個(gè)成員數(shù)據(jù)庫的所有數(shù)據(jù)。要想知道在這種情況下應(yīng)用會(huì)做什么,唯一的方法就是嘗試,嘗試,再嘗試。我們得到了這個(gè):
你的登錄信息已經(jīng)被郵寄到了 random.person@example.com.
我們猜測這個(gè)地址是查詢到的第一條記錄。這個(gè)家伙真的會(huì)在這個(gè)郵箱里收到他忘記的密碼,想必他會(huì)很吃驚也會(huì)引起他的警覺。
我們現(xiàn)在知道可以根據(jù)自己的需要來篡改查詢語句了,盡管對于那些看不到的部分還不夠了解,但是我們注意到了在多次嘗試后得到了三條不同的響應(yīng):
前兩個(gè)響應(yīng)是有效的SQL,最后一個(gè)響應(yīng)是無效的SQL:當(dāng)猜測查詢語句結(jié)構(gòu)的時(shí)候,這種區(qū)別非常有用。
第一步是猜測字段名:我們合理的推測了查詢包含“email address”和“password”,可能也會(huì)有“US Mail address”或者“userid”或“phone number”這樣的字段。我們特別想執(zhí)行 SHOW TABLE語句, 但我們并不知道表名,現(xiàn)在沒有比較明顯的辦法可以拿到表名。
我們進(jìn)行了下一步。在每次測試中,我們會(huì)用我們已知的部分加上一些特殊的構(gòu)造語句。我們已經(jīng)知道這個(gè)SQL的執(zhí)行結(jié)果是email地址的比對,因此我們來猜測email的字段名:
目的是假定的查詢語句的字段名(email),來試試SQL是不是有效。我不關(guān)心匹配的郵件地址是啥(我們用了個(gè)偽名’x’),’——’這個(gè)符號(hào)表示SQL注釋的起始。對于去除應(yīng)用末尾提供的引號(hào),這是一個(gè)很有效的方式,我們不用在乎我們屏蔽掉的是啥。
如果我們得到了服務(wù)器錯(cuò)誤,意味著SQL有不恰當(dāng)?shù)牡胤剑⑶艺Z法錯(cuò)誤會(huì)被拋出:更有可能是字段名有錯(cuò)。如果我們得到了任何有效的響應(yīng),我們就可以猜測這個(gè)字段名是正確的。這就是我們得到“email unknown”或“password was sent”響應(yīng)的過程。
我們也可以用AND連接詞代替OR:這是有意義的。在SQL的模式映射階段,我們不需要為猜一個(gè)特定的郵件地址而煩惱,我們也不想應(yīng)用隨機(jī)的泛濫的給用戶發(fā)“這是你的密碼”的郵件 - 這不太好,有可能引起懷疑。而使用AND連接郵件地址,就會(huì)變的無效,我們就可以確保查詢語句總是返回0行,永遠(yuǎn)不會(huì)生成密碼提醒郵件。
提交上面的片段的確給了我們“郵件地址未知”的響應(yīng),現(xiàn)在我們知道郵件地址的確是存儲(chǔ)在email字段名里。如果沒有生效,我們可以嘗試email_address或mail這樣的字段名。這個(gè)過程需要相當(dāng)多的猜測。
接下來,我們猜測其他顯而易見的名字:password,user ID, name等等。每次只猜一個(gè)字段,只要響應(yīng)不是“server failure”,那就意味著我們猜對了。
在這個(gè)過程中,我們找到了幾個(gè)正確的字段名:
無疑還有更多(有一個(gè)線索是表單中的字段名),一陣挖掘后沒有發(fā)現(xiàn)更多了。但是我們依然不知道這些字段名的表名,它們在哪找到的?
尋找數(shù)據(jù)庫表名
應(yīng)用的內(nèi)建查詢指令已經(jīng)建立了表名,但是我們不知道是啥:有幾個(gè)方法可以找到表名。其中一個(gè)是依靠subselect(字查詢)。
一個(gè)獨(dú)立的查詢
返回表里記錄的數(shù)量,如果表名無效,查詢就會(huì)失敗。我們可以建立自己的字符串來探測表名:
我們不關(guān)心到底有多少條記錄,只關(guān)心表名是不是正確。重復(fù)多次猜測以后,我們終于發(fā)現(xiàn)members是這個(gè)數(shù)據(jù)庫里的有效表名。但它是用在這個(gè)查詢里的么?所以我們需要另一個(gè)測試,使用table.field:實(shí)際查詢的部分只工作在這個(gè)表中,而不是只要表存在就執(zhí)行。
當(dāng)返回“Email unknown”時(shí),就意味著我們的SQL注入成功了,并且我們正確的猜測出了表名。這對后面的工作很重要,但是我們暫時(shí)先試試其他的方法。
找用戶賬號(hào)
我們對members表的結(jié)構(gòu)有了一個(gè)局部的概念,但是我們僅知道一個(gè)用戶名:任意用戶都可能得到“Here is your password”的郵件?;叵肫饋恚覀儚奈吹玫竭^信息本身,只有它發(fā)送的地址。我們得再弄幾個(gè)用戶名,這樣就能得到更多的數(shù)據(jù)。
首先,我們從公司網(wǎng)站開始找?guī)讉€(gè)人:“About us”或者“Contact”頁通常提供了公司成員列表。通常都包含郵件地址,即使它們沒有提供這個(gè)列表也沒關(guān)系,我們可以根據(jù)某些線索用我們的工具找到它們。
LIKE從句可以進(jìn)行用戶查詢,允許我們在數(shù)據(jù)庫里局部匹配用戶名或郵件地址,每次提交如果顯示“We sent your password”的信息并且郵件也真發(fā)了,就證明生效了。
警告:這么做拿到了郵件地址,但也真的發(fā)了郵件給對方,這有可能引起懷疑,小心使用。
我們可以查詢email name或者full name(或者推測出來的其他信息),每次放入%通配符進(jìn)行如下查詢:
記住盡管可能不只有一個(gè)“Bob”,但我們只能看到一條信息:建議精煉LIKE從句。
密碼暴力破解
可以肯定的是,我們能在登陸頁進(jìn)行密碼的暴力破解,但是許多系統(tǒng)都針對此做了監(jiān)測甚至防御。可能有的手段有操作日志,賬號(hào)鎖定,或者其他能阻礙我們行動(dòng)的方式,但是因?yàn)榇嬖谖催^濾的輸入,我們就能繞過更多的保護(hù)措施。
我們在構(gòu)造的字符串里包含進(jìn)郵箱名和密碼來進(jìn)行密碼測試。在我們的例子中,我們用了受害者bob@example.com 并嘗試了多組密碼。
這是一條很好使的SQL語句,我們不會(huì)得到服務(wù)器錯(cuò)誤的提示,只要我們得到“your password has been mailed to you”的提示信息,就證明我們已經(jīng)得到密碼了。這時(shí)候受害人可能會(huì)警覺起來,但誰關(guān)心他呢,我們已經(jīng)得到密碼了。
這個(gè)過程可以使用perl腳本自動(dòng)完成,然而,我們在寫腳本的過程中,發(fā)現(xiàn)了另一種方法來破解系統(tǒng)。
迄今為止,我們沒做查詢數(shù)據(jù)庫之外的事,盡管SELECT是只讀的,但不代表SQL只能這樣。SQL使用分號(hào)表示結(jié)束,如果輸入沒有正確過濾,就沒有什么能阻止我們在字符串后構(gòu)造與查詢無關(guān)的指令。
The most drastic example is:
這劑猛藥是這樣的:
第一部分我們準(zhǔn)備了一個(gè)偽造的email地址——‘X’——我們不關(guān)心查詢結(jié)果返回什么:我們想要得到的只是我們自己構(gòu)造的SQL指令。這次攻擊刪除了整個(gè)members表,這就不太好玩了。
這表明我們不僅僅可以切分SQL指令,而且也可以修改數(shù)據(jù)庫。這是被允許的。
我們已經(jīng)了解了members表的局部結(jié)構(gòu),添加一條新紀(jì)錄到表里視乎是一個(gè)可行的方法:如果這成功了,我們就能簡單的用我們新插入的身份登陸到系統(tǒng)了。
不要太驚訝,這條SQL有點(diǎn)長,我們把它分行顯示以便于理解,但它依然是一條語句:
即使我們得到了正確的字段名和表名,但在成功攻擊之前我們還有幾件事需要了解:
在這個(gè)案例里,我們遇到了問題#4或#5,我們無法確定到底是哪個(gè)—— 因?yàn)橛脴?gòu)造好的用戶名登陸進(jìn)去的時(shí)候,返回了服務(wù)器錯(cuò)誤的提示。盡管這就暗示了我們那些沒有構(gòu)造的字段是必須的,但我們沒有辦法正確處理。
一個(gè)可行的辦法是猜測其他字段,但這是一個(gè)勞力費(fèi)神的過程:盡管我們可以猜測其他“顯而易見”的字段,但要想得到整個(gè)應(yīng)用的組織結(jié)構(gòu)圖太難了。
我們最后嘗試了其他方式。
把密碼郵給我
我們意識(shí)到雖然我們無法添加新紀(jì)錄到members數(shù)據(jù)庫里,但我們可以修改已經(jīng)存在的,這被證明是可行的。
從上一步得知 bob@example.com 賬戶在這個(gè)系統(tǒng)里,我們用SQL注入把數(shù)據(jù)庫中的這條記錄改成我們自己的email地址:
運(yùn)行之后,我們自然得到了“we didn’t know your email address”的提示,但這在預(yù)料之中,畢竟我們用了假的email地址。UPDATE操作不會(huì)通知應(yīng)用,因此它悄然執(zhí)行了。
之后,我們使用了“I lost my password”的功能,用我們剛剛更新的email地址,一分鐘后,我們收到了這封郵件:
現(xiàn)在,我們要做的就是跟隨標(biāo)準(zhǔn)的登錄流程進(jìn)入系統(tǒng),這是一個(gè)高等級職員,有高級權(quán)限,比我們INSERT的用戶要好。
我們發(fā)現(xiàn)這個(gè)企業(yè)內(nèi)部站點(diǎn)內(nèi)容特別多,甚至包含了一個(gè)全用戶列表,我們可以合理的推出許多內(nèi)網(wǎng)都有同樣的企業(yè)Windows網(wǎng)絡(luò)賬號(hào),它們可能在所有地方都使用同樣的密碼。我們很容易就能得到任意的內(nèi)網(wǎng)密碼,并且我們找到了企業(yè)防火墻上的一個(gè)開放的PPTP協(xié)議的VPN端口,這讓登錄測試變得更簡單。
我們又挑了幾個(gè)賬號(hào)測試都沒有成功,我們無法知道是否是“密碼錯(cuò)誤”或者“企業(yè)內(nèi)部賬號(hào)是否與Windows賬號(hào)名不同”。但是我們覺得自動(dòng)化工具會(huì)讓這項(xiàng)工作更容易。
在這次特定的滲透中,我們得到了足夠的權(quán)限,我們不需要更多了,但是還有其他方法。我們來試試我們現(xiàn)在想到的但不夠普遍的方法。
我們意識(shí)到不是所有的方法都與數(shù)據(jù)庫無關(guān),我們可以來試試。
調(diào)用xp_cmdshell
微軟的SQLServer支持存儲(chǔ)過程xp_cmdshell有權(quán)限執(zhí)行任意操作系統(tǒng)指令。如果這項(xiàng)功能允許web用戶使用,那webserver被滲透是無法避免的。
迄今為止,我們做的都被限制在了web應(yīng)用和數(shù)據(jù)庫這個(gè)環(huán)境下,但是如果我們能執(zhí)行任何操作系統(tǒng)指令,再厲害的服務(wù)器也禁不住滲透。xp_cmdshell通常只有極少數(shù)的管理員賬戶才能使用,但它也可能授權(quán)給了更低級的用戶。
繪制數(shù)據(jù)庫結(jié)構(gòu)
在這個(gè)登錄后提供了豐富功能應(yīng)用上,已經(jīng)沒必要做更深的挖掘了,但在其他限制更多的環(huán)境下可能還不夠。
能夠系統(tǒng)的繪制出數(shù)據(jù)庫可見結(jié)構(gòu),包含表和它們的字段結(jié)構(gòu),可能沒有直接幫助。但是這為網(wǎng)站滲透提供了一條林萌大道。
從網(wǎng)站的其他方面收集更多有關(guān)數(shù)據(jù)結(jié)構(gòu)的信息(例如,“留言板”頁?“幫助論壇”等?)。不過這對應(yīng)用環(huán)境依賴強(qiáng),而且還得靠你準(zhǔn)確的猜測。
減輕危害
我們認(rèn)為web應(yīng)用開發(fā)者通常沒考慮到“有害輸入”,但安全人員應(yīng)該考慮到(包括壞家伙),因此這有3條方法可以使用。
輸入過濾
過濾輸入是非常重要的事,以確保輸入不包含危險(xiǎn)代碼,無論是SQL服務(wù)器或HTM本身。首先想到的是剝掉“惡意字符”,像引號(hào)、分號(hào)或轉(zhuǎn)義符號(hào),但這是一種不太好的方式。盡管找到一些危險(xiǎn)字符很容易,但要把他們?nèi)页鰜砭碗y了。
web語言本身就充滿了特殊字符和奇怪的標(biāo)記(包括那些表達(dá)同樣字符的替代字符),所以想要努力識(shí)別出所有的“惡意字符”不太可能成功。
換言之,與其“移除已知的惡意數(shù)據(jù)”,不如移除“良好數(shù)據(jù)之外的所有數(shù)據(jù)”:這種區(qū)別是很重要的。在我們的例子中,郵件地址僅能包含如下字符:
允許不正確的字符輸入是沒有任何好處的,應(yīng)該早點(diǎn)拒絕它們 - 可能會(huì)有一些錯(cuò)誤信息 – 不僅可以阻止SQL注入,也可以捕獲一些輸入錯(cuò)誤而不是把它們存入數(shù)據(jù)庫。
某個(gè)特殊的email地址會(huì)讓驗(yàn)證程序陷入麻煩,因?yàn)槊總€(gè)人對于“有效”的定義不同。由于email地址中出現(xiàn)了一個(gè)你沒有考慮到的字符而被拒絕,那真是糗大了。
真正的權(quán)威是RFC 2822(比RFC822內(nèi)容還多),它對于”允許使用的內(nèi)容“做了一個(gè)規(guī)范的定義。這種更學(xué)術(shù)的規(guī)范希望可以接受&和*(還有更多)作為有效的email地址,但其它人 - 包括作者 – 都樂于用一個(gè)合理的子集來包含更多的email地址。
那些采用更限制方法的人應(yīng)當(dāng)充分意識(shí)到?jīng)]有包含這些地址會(huì)帶來的后果,特別是限制有了更好的技術(shù)(預(yù)編譯/執(zhí)行,存儲(chǔ)過程)來避免這些“奇怪”的字符帶來的安全問題。
意識(shí)到“過濾輸入”并不意味著僅僅是“移除引號(hào)”,因?yàn)榧词挂粋€(gè)“正規(guī)”的字符也會(huì)帶來麻煩。在下面這個(gè)例子中,一個(gè)整型ID值被拿來和用戶的輸入作比較(數(shù)字型PIN):
在實(shí)踐中,無論如何這個(gè)方法都有諸多限制,因?yàn)槟軌驈氐着懦形kU(xiǎn)字符的字段實(shí)在太少了。對于“日期”或者“email地址”或者“整型”,上面的辦法是有價(jià)值的,但對于真實(shí)的環(huán)境,我們不可避免地要使用其他方式
來減輕危害。
輸入項(xiàng)編碼/轉(zhuǎn)義
現(xiàn)在可以過濾電話號(hào)碼和郵件地址了,但你不能通過同樣的方法處理“name”字段,要不然可能會(huì)排除掉Bill O’Reilly這樣的名字:對于這個(gè)字段,這里的引號(hào)是合法的輸入。
有人就想到過濾到單引號(hào)的時(shí)候,再加上一個(gè)引號(hào),這樣就沒問題了 – 但是這么干要出事?。?/p>
預(yù)處理每個(gè)字符串來替換單引號(hào):
這個(gè)方法很容易出問題,因?yàn)榇蟛糠謹(jǐn)?shù)據(jù)庫都支持轉(zhuǎn)碼機(jī)制。像MySQL,允許輸入’來替代單引號(hào),因此如果輸入 ‘; DROP TABLE users; — 時(shí),通過兩次引號(hào)來“保護(hù)”數(shù)據(jù)庫,那我們將得到:
比如MySQL的函數(shù)mysql_real_escape_string()和perl DBD 的 $dbh->quote($value)方法,這些方法都是必用的。
參數(shù)綁定 (預(yù)編譯語句)
盡管轉(zhuǎn)義是一個(gè)有用的機(jī)制,但我們?nèi)稳惶幱凇坝脩糨斎氡划?dāng)做SQL語句”這么一個(gè)循環(huán)里。更好的方法是:預(yù)編譯,本質(zhì)上所有的數(shù)據(jù)庫編程接口都支持預(yù)編譯。技術(shù)上來說,SQL聲明語句是用問號(hào)給每個(gè)參數(shù)占位創(chuàng)建的 – 然后在內(nèi)部表中進(jìn)行編譯。
預(yù)編譯查詢執(zhí)行時(shí)是按照參數(shù)列表來的:
Perl中的例子
感謝Stefan Wagner幫我寫了個(gè)java實(shí)現(xiàn):
不安全版
安全版
$email 是從用戶表單獲得的,它作為#1(第一個(gè)問號(hào)標(biāo)記的地方)位置的參數(shù)傳遞過來,在任何情況下這條SQL聲明都可以解析。引號(hào),分號(hào),反斜杠,SQL指令記號(hào) – 任何字符都不會(huì)產(chǎn)生特殊效果,因?yàn)樗鼈儭爸皇菙?shù)據(jù)”而已。這不會(huì)對其他東西造成破壞,因此這個(gè)應(yīng)用很大程度上防范了SQL注入攻擊。
如果預(yù)編譯查詢語句多次(只編譯一次)執(zhí)行,也會(huì)帶來性能上的提升,但是與大量安全方面的巨大提升相比,這顯得微不足道。這可能是我們保證web應(yīng)用安全最重要的一步。
限制數(shù)據(jù)庫權(quán)限和隔離用戶
在這個(gè)案例中,我們觀察到只有兩個(gè)交互動(dòng)作不在登錄用戶的上下文環(huán)境中:“登錄”和“發(fā)密碼給我”。web應(yīng)用應(yīng)該對數(shù)據(jù)庫連接做權(quán)限的限制:對于members表只能讀,并且無法操作其他表。
作用是即使一次“成功的”SQL注入攻擊也只能得到非常有限的成功。噢,我們將不能做有授權(quán)的UPDATE請求,我們要求 助于其他方法。
一旦web應(yīng)用確定登錄表單傳遞來的認(rèn)證是有效的,它就會(huì)切換會(huì)話到一個(gè)有更多權(quán)限的用戶上。
對任何web應(yīng)用而言,不使用sa權(quán)限幾乎是根本不用說的事。
對數(shù)據(jù)庫的訪問采用存儲(chǔ)過程
如果數(shù)據(jù)庫支持存儲(chǔ)過程,請使用存儲(chǔ)過程來執(zhí)行數(shù)據(jù)庫的訪問行為,這樣就不需要SQL了(假設(shè)存儲(chǔ)過程編程正確)。
把查詢,更新,刪除等動(dòng)作規(guī)則封裝成一個(gè)單獨(dú)的過程,就可以針對基礎(chǔ)規(guī)則和所執(zhí)行的商業(yè)規(guī)則來完成測試和歸檔(例如,如果客戶超過了信用卡限額,“添加新記錄”過程可能拒絕訂單)。
對于簡單的查詢這樣做可能僅僅能獲得很少的好處,不過一旦操作變復(fù)雜(或者被用在更多地方),給操作一個(gè)單獨(dú)的定義,功能將會(huì)變得更穩(wěn)健也更容易維護(hù)。
注意:動(dòng)態(tài)構(gòu)建一個(gè)查詢的存儲(chǔ)過程是可以做到的:這么做無法防止SQL注入 – 它只不過把預(yù)編譯/執(zhí)行綁定到了一起,或者是把SQL語句和提供保護(hù)的變量綁定到了一起。
隔離web服務(wù)器
實(shí)施了以上所有的防御措施,仍然可能有某些地方有遺漏,導(dǎo)致了服務(wù)器被滲透。設(shè)計(jì)者應(yīng)該在假定壞蛋已經(jīng)獲得了系統(tǒng)最高權(quán)限下來設(shè)計(jì)網(wǎng)絡(luò)設(shè)施,然后把它的攻擊對其他事情產(chǎn)生的影響限制在最小。
例如,把這臺(tái)機(jī)器放置在極度限制出入的DMZ網(wǎng)絡(luò)“內(nèi)部”,這么做意味著即便取得了web服務(wù)器的完全控制也不能自動(dòng)的獲得對其他一切的完全訪問權(quán)限。當(dāng)然,這么做不能阻止所有的入侵,不過它可以使入侵變的非常困難。
配置錯(cuò)誤報(bào)告
一些框架的錯(cuò)誤報(bào)告包含了開發(fā)的bug信息,這不應(yīng)該公開給用戶。想象一下:如果完整的查詢被現(xiàn)實(shí)出來了,并且指出了語法錯(cuò)誤點(diǎn),那要攻擊該有多容易。
對于開發(fā)者來說這些信息是有用的,但是它應(yīng)該禁止公開 – 如果可能 - 應(yīng)該限制在內(nèi)部用戶訪問。
注意:不是所有的數(shù)據(jù)庫都采用同樣的方式配置,并且不是所有的數(shù)據(jù)庫都支持同樣的SQL語法(“S”代表“結(jié)構(gòu)化”,不是“標(biāo)準(zhǔn)的”)。例如,大多數(shù)版本的MySQL都不支持子查詢,而且通常也不允許單行多條語句(multiple statements):當(dāng)你滲透網(wǎng)絡(luò)時(shí),實(shí)際上這些就是使問題復(fù)雜化的因素。
再強(qiáng)調(diào)一下,盡管我們選擇了“忘記密碼”鏈接來試試攻擊,但不是因?yàn)檫@個(gè)功能不安全。而是幾個(gè)易攻擊的點(diǎn)之一,不要把焦點(diǎn)聚集在“忘記密碼”上。
這個(gè)教學(xué)示例不準(zhǔn)備全面覆蓋SQL注入的內(nèi)容,甚至都不是一個(gè)教程:它僅僅是一篇我們花了幾小時(shí)做的滲透測試的記錄。我們看了其他的關(guān)于SQL注入文章的討論,但它們只給出了結(jié)果而沒有給出過程。
但是那些結(jié)果報(bào)告需要技術(shù)背景才能看懂,并且滲透細(xì)節(jié)也是有價(jià)值的。在沒有源代碼的情況下,滲透人員的黑盒測試能力也是有價(jià)值的。
感謝 David Litchfield 和 Randal Schwartz對本文的貢獻(xiàn),還有Chris Mospaw的排版(? 2005 by Chris Mospaw, used with permission).
聯(lián)系客服