一位客戶讓我們針對(duì)只有他們企業(yè)員工和顧客能使用的企業(yè)內(nèi)網(wǎng)進(jìn)行滲透測(cè)試。這是安全評(píng)估的一個(gè)部分,所以盡管我們之前沒(méi)有使用過(guò)SQL注入來(lái)滲透網(wǎng)絡(luò),但對(duì)其概念也相當(dāng)熟悉了。最后我們?cè)谶@項(xiàng)任務(wù)中大獲成功,現(xiàn)在來(lái)回顧一下這個(gè)過(guò)程的每一步,將它記錄為一個(gè)
一位客戶讓我們針對(duì)只有他們企業(yè)員工和顧客能使用的企業(yè)內(nèi)網(wǎng)進(jìn)行滲透測(cè)試。這是安全評(píng)估的一個(gè)部分,所以盡管我們之前沒(méi)有使用過(guò)SQL注入來(lái)滲透網(wǎng)絡(luò),但對(duì)其概念也相當(dāng)熟悉了。最后我們?cè)谶@項(xiàng)任務(wù)中大獲成功,現(xiàn)在來(lái)回顧一下這個(gè)過(guò)程的每一步,將它記錄為一個(gè)案例。
我們記錄下了在多次錯(cuò)誤的轉(zhuǎn)折后經(jīng)歷的曲折過(guò)程,而一個(gè)更有經(jīng)驗(yàn)的人會(huì)有這不同的 — 甚至更好的 — 方法。但事實(shí)上我們成功以后才明白,我們并沒(méi)有完全被誤導(dǎo)。
其他的SQL文章包含了更多的細(xì)節(jié),但是這篇文章不僅展示了漏洞利用的過(guò)程,還講述了發(fā)現(xiàn)漏洞的原理。
展現(xiàn)在我們眼前的是一個(gè)完整定制網(wǎng)站,我們之前沒(méi)見(jiàn)過(guò)這個(gè)網(wǎng)站,也無(wú)權(quán)查看它的源代碼:這是一次“黑盒”攻擊。‘刺探’結(jié)果顯示這臺(tái)服務(wù)器運(yùn)行在微軟的IIS6上,并且是ASP.NET架構(gòu)。這就暗示我們數(shù)據(jù)庫(kù)是微軟的SQL server:我們相信我們的技巧可以應(yīng)用在任何web應(yīng)用上,無(wú)論它使用的是哪種SQL 服務(wù)器。
登陸頁(yè)有傳統(tǒng)的用戶-密碼表單,但多了一個(gè) “把我的密碼郵給我”的鏈接;后來(lái),這個(gè)地方被證實(shí)是整個(gè)系統(tǒng)陷落的關(guān)鍵。
當(dāng)鍵入郵件地址時(shí),系統(tǒng)假定郵件存在,就會(huì)在用戶數(shù)據(jù)庫(kù)里查詢郵件地址,然后郵寄一些內(nèi)容給這個(gè)地址。但我的郵件地址無(wú)法找到,所以它什么也不會(huì)發(fā)給我。
對(duì)于任何SQL化的表單而言,第一步測(cè)試,是輸入一個(gè)帶有單引號(hào)的數(shù)據(jù):目的是看看他們是否對(duì)構(gòu)造SQL的字符串進(jìn)行了過(guò)濾。當(dāng)把單引號(hào)作為郵件地址提交以后,我們得到了500錯(cuò)誤(服務(wù)器錯(cuò)誤),這意味著“有害”輸入實(shí)際上是被直接用于SQL語(yǔ)句了。就是這了!
我猜測(cè)SQL代碼可能是這樣:
[sql] view plaincopy$EMAIL 是用戶從表單提交的地址,并且這段查詢?cè)谧址┒?EMAIL上提供了引號(hào)。我們不知道字段或表的確切名字,但是我們了解他們的本質(zhì),這有助于我們做正確的猜測(cè)。
當(dāng)我們鍵入 steve@unixwiz.net‘ -注意這個(gè)末端的引號(hào) – 下面是這個(gè)SQL字段的構(gòu)成:
[sql] view plaincopy當(dāng)這段SQL開始執(zhí)行,SQL解析器就會(huì)發(fā)現(xiàn)多余的引號(hào)然后中斷執(zhí)行,并給出語(yǔ)法錯(cuò)誤的提示。這個(gè)錯(cuò)誤如何清楚的表述給用戶,基于應(yīng)用內(nèi)部的錯(cuò)誤恢復(fù)規(guī)程,但一般來(lái)說(shuō)都不會(huì)提示“郵件地址不存在”。這個(gè)錯(cuò)誤響應(yīng)成了死亡之門,它告訴別人用戶輸入沒(méi)有被正確的處理,這就為應(yīng)用破解留下了可乘之機(jī)。
這個(gè)數(shù)據(jù)呈現(xiàn)在WHERE的從句中,讓我們以符合SQL規(guī)范的方式改變輸入試試,看看會(huì)發(fā)生什么。鍵入anything’ OR ‘x’=‘x, 結(jié)果如下:
[sql] view plaincopy因?yàn)閼?yīng)用不會(huì)思考輸入 – 僅僅構(gòu)造字符串 - 我們使用單引號(hào)把WHERE從句的單一組成變成了雙組成,’x'=‘x’從句是恒成立的,無(wú)論第一個(gè)從句是什么。(有一種更好的方式來(lái)確保“始終為真”,我們隨后會(huì)接觸到)。
但與每次只返回單一數(shù)據(jù)的“真實(shí)”查詢不同,上面這個(gè)構(gòu)造必須返回這個(gè)成員數(shù)據(jù)庫(kù)的所有數(shù)據(jù)。要想知道在這種情況下應(yīng)用會(huì)做什么,唯一的方法就是嘗試,嘗試,再嘗試。我們得到了這個(gè):
你的登錄信息已經(jīng)被郵寄到了 random.person@example.com.
我們猜測(cè)這個(gè)地址是查詢到的第一條記錄。這個(gè)家伙真的會(huì)在這個(gè)郵箱里收到他忘記的密碼,想必他會(huì)很吃驚也會(huì)引起他的警覺(jué)。
我們現(xiàn)在知道可以根據(jù)自己的需要來(lái)篡改查詢語(yǔ)句了,盡管對(duì)于那些看不到的部分還不夠了解,但是我們注意到了在多次嘗試后得到了三條不同的響應(yīng):
前兩個(gè)響應(yīng)是有效的SQL,最后一個(gè)響應(yīng)是無(wú)效的SQL:當(dāng)猜測(cè)查詢語(yǔ)句結(jié)構(gòu)的時(shí)候,這種區(qū)別非常有用。
第一步是猜測(cè)字段名:我們合理的推測(cè)了查詢包含“email address”和“password”,可能也會(huì)有“US Mail address”或者“userid”或“phone number”這樣的字段。我們特別想執(zhí)行 SHOW TABLE語(yǔ)句, 但我們并不知道表名,現(xiàn)在沒(méi)有比較明顯的辦法可以拿到表名。
我們進(jìn)行了下一步。在每次測(cè)試中,我們會(huì)用我們已知的部分加上一些特殊的構(gòu)造語(yǔ)句。我們已經(jīng)知道這個(gè)SQL的執(zhí)行結(jié)果是email地址的比對(duì),因此我們來(lái)猜測(cè)email的字段名:
[sql] view plaincopy目的是假定的查詢語(yǔ)句的字段名(email),來(lái)試試SQL是不是有效。我不關(guān)心匹配的郵件地址是啥(我們用了個(gè)偽名’x’),’ ——’這個(gè)符號(hào)表示SQL注釋的起始。對(duì)于去除應(yīng)用末尾提供的引號(hào),這是一個(gè)很有效的方式,我們不用在乎我們屏蔽掉的是啥。
如果我們得到了服務(wù)器錯(cuò)誤,意味著SQL有不恰當(dāng)?shù)牡胤剑⑶艺Z(yǔ)法錯(cuò)誤會(huì)被拋出:更有可能是字段名有錯(cuò)。如果我們得到了任何有效的響應(yīng),我們就可以猜測(cè)這個(gè)字段名是正確的。這就是我們得到“email unknown”或“password was sent”響應(yīng)的過(guò)程。
我們也可以用AND連接詞代替OR:這是有意義的。在SQL的模式映射階段,我們不需要為猜一個(gè)特定的郵件地址而煩惱,我們也不想應(yīng)用隨機(jī)的泛濫的給用戶發(fā)“這是你的密碼”的郵件 - 這不太好,有可能引起懷疑。而使用AND連接郵件地址,就會(huì)變的無(wú)效,我們就可以確保查詢語(yǔ)句總是返回0行,永遠(yuǎn)不會(huì)生成密碼提醒郵件。
提交上面的片段的確給了我們“郵件地址未知”的響應(yīng),現(xiàn)在我們知道郵件地址的確是存儲(chǔ)在email字段名里。如果沒(méi)有生效,我們可以嘗試email_address或mail這樣的字段名。這個(gè)過(guò)程需要相當(dāng)多的猜測(cè)。
接下來(lái),我們猜測(cè)其他顯而易見(jiàn)的名字:password,user ID, name等等。每次只猜一個(gè)字段,只要響應(yīng)不是“server failure”,那就意味著我們猜對(duì)了。
[sql] view plaincopy在這個(gè)過(guò)程中,我們找到了幾個(gè)正確的字段名:
無(wú)疑還有更多(有一個(gè)線索是表單中的字段名),一陣挖掘后沒(méi)有發(fā)現(xiàn)更多了。但是我們依然不知道這些字段名的表名,它們?cè)谀恼业降模?/p>
尋找數(shù)據(jù)庫(kù)表名
應(yīng)用的內(nèi)建查詢指令已經(jīng)建立了表名,但是我們不知道是啥:有幾個(gè)方法可以找到表名。其中一個(gè)是依靠subselect(字查詢)。
一個(gè)獨(dú)立的查詢
[sql] view plaincopy返回表里記錄的數(shù)量,如果表名無(wú)效,查詢就會(huì)失敗。我們可以建立自己的字符串來(lái)探測(cè)表名:
[sql] view plaincopy我們不關(guān)心到底有多少條記錄,只關(guān)心表名是不是正確。重復(fù)多次猜測(cè)以后,我們終于發(fā)現(xiàn)members是這個(gè)數(shù)據(jù)庫(kù)里的有效表名。但它是用在這個(gè)查詢里的么?所以我們需要另一個(gè)測(cè)試,使用table.field:實(shí)際查詢的部分只工作在這個(gè)表中,而不是只要表存在就執(zhí)行。
[sql] view plaincopy當(dāng)返回“Email unknown”時(shí),就意味著我們的SQL注入成功了,并且我們正確的猜測(cè)出了表名。這對(duì)后面的工作很重要,但是我們暫時(shí)先試試其他的方法。
找用戶賬號(hào)
我們對(duì)members表的結(jié)構(gòu)有了一個(gè)局部的概念,但是我們僅知道一個(gè)用戶名:任意用戶都可能得到“Here is your password”的郵件。回想起來(lái),我們從未得到過(guò)信息本身,只有它發(fā)送的地址。我們得再弄幾個(gè)用戶名,這樣就能得到更多的數(shù)據(jù)。
首先,我們從公司網(wǎng)站開始找?guī)讉€(gè)人:“About us”或者“Contact”頁(yè)通常提供了公司成員列表。通常都包含郵件地址,即使它們沒(méi)有提供這個(gè)列表也沒(méi)關(guān)系,我們可以根據(jù)某些線索用我們的工具找到它們。
LIKE從句可以進(jìn)行用戶查詢,允許我們?cè)跀?shù)據(jù)庫(kù)里局部匹配用戶名或郵件地址,每次提交如果顯示“We sent your password”的信息并且郵件也真發(fā)了,就證明生效了。
警告:這么做拿到了郵件地址,但也真的發(fā)了郵件給對(duì)方,這有可能引起懷疑,小心使用。
我們可以查詢email name或者full name(或者推測(cè)出來(lái)的其他信息),每次放入%通配符進(jìn)行如下查詢:
[sql] view plaincopy記住盡管可能不只有一個(gè)“Bob”,但我們只能看到一條信息:建議精煉LIKE從句。
密碼暴力破解
可以肯定的是,我們能在登陸頁(yè)進(jìn)行密碼的暴力破解,但是許多系統(tǒng)都針對(duì)此做了監(jiān)測(cè)甚至防御。可能有的手段有操作日志,帳號(hào)鎖定,或者其他能阻礙我們行動(dòng)的方式,但是因?yàn)榇嬖谖催^(guò)濾的輸入,我們就能繞過(guò)更多的保護(hù)措施。
我們?cè)跇?gòu)造的字符串里包含進(jìn)郵箱名和密碼來(lái)進(jìn)行密碼測(cè)試。在我們的例子中,我們用了受害者bob@example.com 并嘗試了多組密碼。
[sql] view plaincopy這是一條很好使的SQL語(yǔ)句,我們不會(huì)得到服務(wù)器錯(cuò)誤的提示,只要我們得到“your password has been mailed to you”的提示信息,就證明我們已經(jīng)得到密碼了。這時(shí)候受害人可能會(huì)警覺(jué)起來(lái),但誰(shuí)關(guān)心他呢,我們已經(jīng)得到密碼了。
這個(gè)過(guò)程可以使用perl腳本自動(dòng)完成,然而,我們?cè)趯懩_本的過(guò)程中,發(fā)現(xiàn)了另一種方法來(lái)破解系統(tǒng)。
迄今為止,我們沒(méi)做查詢數(shù)據(jù)庫(kù)之外的事,盡管SELECT是只讀的,但不代表SQL只能這樣。SQL使用分號(hào)表示結(jié)束,如果輸入沒(méi)有正確過(guò)濾,就沒(méi)有什么能阻止我們?cè)谧址髽?gòu)造與查詢無(wú)關(guān)的指令。
The most drastic example is:
這劑猛藥是這樣的:
[sql] view plaincopy第一部分我們準(zhǔn)備了一個(gè)偽造的email地址——‘X’——我們不關(guān)心查詢結(jié)果返回什么:我們想要得到的只是我們自己構(gòu)造的SQL指令。這次攻擊刪除了整個(gè)members表,這就不太好玩了。
這表明我們不僅僅可以切分SQL指令,而且也可以修改數(shù)據(jù)庫(kù)。這是被允許的。
我們已經(jīng)了解了members表的局部結(jié)構(gòu),添加一條新紀(jì)錄到表里視乎是一個(gè)可行的方法:如果這成功了,我們就能簡(jiǎn)單的用我們新插入的身份登陸到系統(tǒng)了。
不要太驚訝,這條SQL有點(diǎn)長(zhǎng),我們把它分行顯示以便于理解,但它依然是一條語(yǔ)句:
[sql] view plaincopy即使我們得到了正確的字段名和表名,但在成功攻擊之前我們還有幾件事需要了解:
在這個(gè)案例里,我們遇到了問(wèn)題#4或#5,我們無(wú)法確定到底是哪個(gè)—— 因?yàn)橛脴?gòu)造好的用戶名登陸進(jìn)去的時(shí)候,返回了服務(wù)器錯(cuò)誤的提示。盡管這就暗示了我們那些沒(méi)有構(gòu)造的字段是必須的,但我們沒(méi)有辦法正確處理。
一個(gè)可行的辦法是猜測(cè)其他字段,但這是一個(gè)勞力費(fèi)神的過(guò)程:盡管我們可以猜測(cè)其他“顯而易見(jiàn)”的字段,但要想得到整個(gè)應(yīng)用的組織結(jié)構(gòu)圖太難了。
我們最后嘗試了其他方式。
把密碼郵給我
我們意識(shí)到雖然我們無(wú)法添加新紀(jì)錄到members數(shù)據(jù)庫(kù)里,但我們可以修改已經(jīng)存在的,這被證明是可行的。
從上一步得知 bob@example.com 賬戶在這個(gè)系統(tǒng)里,我們用SQL注入把數(shù)據(jù)庫(kù)中的這條記錄改成我們自己的email地址:
[sql] view plaincopy聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com