對寬字節(jié)注入的漏洞實現(xiàn)淺析和如何簡單修復
原創(chuàng)【51CTO.com原創(chuàng)稿件】寬字節(jié)注入之前我看到過,但是沒有實戰(zhàn)過,后面也沒有找到合適的測試環(huán)境,今天剛好看到一個關(guān)于寬字節(jié)注入的ctf題,因此借此來學習下寬字節(jié)注入,如果寫得不好的地方,煩請各位多多指導!
本文主要是簡單介紹下寬字節(jié)注入,以及如何通過手工和工具進行寬字節(jié)注入的一個利用,通過本文主要可學習到以下三點:
- 擴展了對SQL注入進行探測的一個思路!
- 學習了如何使用寬字節(jié)探測注入!
- 如何使用sqlmap自動化對寬字節(jié)進行注入!
1. 寬字節(jié)注入
這里的寬字節(jié)注入是利用MySQL的一個特性,MySQL在使用GBK編碼(GBK就是常說的寬字節(jié)之一,實際上只有兩字節(jié))的時候,會認為兩個字符是一個漢字(前一個ascii碼要大于128,才到漢字的范圍),而當我們輸入有單引號時會自動加入\進行轉(zhuǎn)義而變?yōu)閈’(在PHP配置文件中magic_quotes_gpc=On的情況下或者使用addslashes函數(shù),icov函數(shù),mysql_real_escape_string函數(shù)、mysql_escape_string函數(shù)等,提交的參數(shù)中如果帶有單引號’,就會被自動轉(zhuǎn)義\’,使得多數(shù)注入攻擊無效),由于寬字節(jié)帶來的安全問題主要是吃ASCII字符(一字節(jié))的現(xiàn)象,將后面的一個字節(jié)與前一個大于128的ascii碼進行組合成為一個完整的字符(MySQL判斷一個字符是不是漢字,首先兩個字符是一個漢字,另外根據(jù)gbk編碼,第一個字節(jié)ascii碼大于128,基本上就可以了),此時’前的\就被吃了,我們就可以使用’了,利用這個特性從而可實施SQL注入的利用。
最常使用的寬字節(jié)注入是利用%df,其實只要第一個ascii碼大于128就可以了,比如ascii碼為129的就可以,但是我們怎么將他轉(zhuǎn)換為URL編碼呢?其實很簡單,我們先將129(十進制)轉(zhuǎn)換為十六進制,為0x81,如圖1所示,然后在十六進制前面加%即可,即為%81,任意進制在線轉(zhuǎn)換網(wǎng)站請點擊此處!另外可以直接記住GBK首字節(jié)對應(yīng)0×81-0xFE,尾字節(jié)對應(yīng)0×40-0xFE(除0×7F),則尾字節(jié)會被吃點,如轉(zhuǎn)義符號\對應(yīng)的編碼0×5C!另外簡單提一下,GB2312是被GBK兼容的,它的高位范圍是0xA1-0xF7,低位范圍是0xA1-0xFE(0x5C不在該范圍內(nèi)),因此不能使用編碼吃掉%5c。
圖1 將十進制129轉(zhuǎn)換為十六進制
2. 實驗環(huán)境
本次實驗環(huán)境如下:
URL地址:http://103.238.227.13:10083/
相關(guān)版本信息:
- PHP 7.0.7、mysql 5.5.48-log!
- WebServer: nginx!
- Content-Type: text/html; charset=gbk!
以上多數(shù)信息可使用F12進行簡單的信息收集(近期我正在將我目前會的滲透實戰(zhàn)中常用的信息收集進行整理,其中第一個信息收集就是F12信息收集),通過F12我們收集到如圖2所示信息,另外我們也可通過添加火狐插件server-spy進行這些信息的獲取。
圖2 F12信息收集
3. SQL注入簡單思路
今天學習到了一個SQL注入探測的一個簡單思路,而不是說就簡單的and或者or以及’進行探測,或者直接使用sqlmap的-b參數(shù)來進行探測(以前的我是這樣的),因此可能錯過了好幾個億。對SQL注入進行探測可根據(jù)以下思路來進行:
第一步: 簡單使用and、or、’,判斷是否有注入,不行接著加入一些自創(chuàng)的語句進行簡單判斷(如order by看有沒有報錯等)!
第二步,如果第一步?jīng)]有看到效果,可進行寬字節(jié)注入探測,輸入%bf'(或者%81’),發(fā)現(xiàn)報錯,存在寬字節(jié)注入!
第三步,如果上述兩步都沒有效果,可以接著但不限于http頭注入探測(sqlmap的話使用—level參數(shù)進行設(shè)置),等等。
4. 注入類型探測
SQL注入根據(jù)不同的標準有不同的分類,如根據(jù)參數(shù)類型可分為數(shù)值型注入、字符型注入,根據(jù)注入的位置可分為POST注入、GET注入、cookie注入等,而sqlmap則將注入分為基于布爾的盲注、基于時間的盲注、基于報錯的注入、聯(lián)合查詢注入、堆查詢注入,這里為了方便我將SQL分為寬字節(jié)注入和非寬字節(jié)注入(個人分類,沒有依據(jù))。
寬字節(jié)注入在實際滲透測試中也是存在的,只是很少很少,這次剛好看到一個寬字節(jié)注入的ctf,也順便再認真學習寫寬字節(jié)注入的一些基本知識。如圖3,通過提示我們可知該題是一道字符型的注入。
圖3 注入測試提示
既然是字符型的注入,那么我們可以使用’和and來進行簡單的判斷,該測試點是否是SQL注入點!通過使用’,我們無法判斷是否存在注入,沒有可供我們判斷的信息,如圖4所示。
圖4 ‘無法判斷是否是注入
我們結(jié)合and來進一步判斷,但是依舊沒有任何信息可供我們進行判斷該測試點是否是注入點,如圖5所示。
圖5 and也無法判斷是否是注入點
難道是不存注入(肯定不是這樣的),那我們使用神器sqlmap盲跑試試,但是很失望,居然沒有直接告訴我們有沒有存在注入點,如圖6所示。
圖6 sqlmap提示不像是注入
如果按照我以前的思路,我可能就已經(jīng)放棄了,在實戰(zhàn)中的話可能就認為真的不是注入點了(有點草率),此時我們使用思路的第二步來進行判斷,該測試點是不是寬字節(jié)注入,我們使用ascii碼的129(也即是%81,可以使用常使用的%df)進行探測,如圖7所示,發(fā)現(xiàn)頁面報錯了,根據(jù)頁面信息可判斷該測試點存在SQL注入,并且是寬字節(jié)注入。
圖7 判斷注入是寬字節(jié)注入
5. 寬字節(jié)手工簡單注入
通過上面的說明,我們可知該注入點是寬字節(jié)注入,且是字符型的注入,此時我們可通過構(gòu)造SQL語句來進行SQL的寬字節(jié)注入,另外我們也可測試下我們輸入的’是否被轉(zhuǎn)義成為了\’,如圖8所示,我們輸入的’確實被轉(zhuǎn)義了!
圖8 ‘被轉(zhuǎn)義了
此時我們可構(gòu)造語句%81’ and 1=1-- -來進行注入,原因是’被轉(zhuǎn)義成為\’,而%81的ascii碼大于128,此時%81’就被看作一個字符(兩個字節(jié)),此時’就可以使用了,而后面我們構(gòu)造一個數(shù)值型的注入語句,最后再加注釋把最后的那個’注釋掉,如圖9所示。
圖9 寬字節(jié)注入
此時我們使用order by來看看當前數(shù)據(jù)庫有幾列,發(fā)現(xiàn)數(shù)據(jù)庫有三列,如圖10所示:
圖10 當前數(shù)據(jù)庫有3列
我們看看我們將要查詢的數(shù)據(jù)會在頁面中哪些地方顯示,如圖11所示。
圖11 查詢在頁面中顯示的位置
到此,手工注入就結(jié)束了,后續(xù)操作請查看我的文章《mysql手工注入》的最后部分!
6. 寬字節(jié)sqlmap注入
在前面我們直接使用sqlmap盲跑,是沒有發(fā)現(xiàn)該測試點是SQL注入點的,根據(jù)上面的特性,我們可以在id后面添加一個%81’,然后在使用sqlmap進行注入,注入語句為:
- sqlmap.py -u "http://103.238.227.13:10083/?id=1%81’" -b
這時,我們發(fā)現(xiàn)sqlmap可成功發(fā)現(xiàn)該注入點了,如圖12所示。
圖12 sqlmap成功檢測出該注入點
除了上面的這種方法外,我們可以使用寬字節(jié)注入腳本來使用sqlmap進行注入,注入語句為:
- sqlmap.py -u "http://103.238.227.13:10083/?id=1" -b --tamper=unmagicquotes.py
這樣我們也能成功探測出該注入點,如圖13所示,對于后續(xù)的注入此處不再累贅!
圖13 sqlmap成功檢測出注入點
7. 簡單修復建議
在初始化連接和字符集之后,使用SET character_set_client=binary來設(shè)定客戶端的字符集是二進制的,另外對于服務(wù)器端返回的錯誤信息要么進行自定義,要么進行歸一化的錯誤提示!
【51CTO原創(chuàng)稿件,合作站點轉(zhuǎn)載請注明原文作者和出處為51CTO.com】