當前位置:
首頁 > 最新 > 從一道CTF題目看Gopher攻擊MySql

從一道CTF題目看Gopher攻擊MySql

前言

雖然比賽過程中沒做出來,結束後仔細研究了一下。感覺很有意思,分享給大家。再次體會到重要的不是結果,而是研究的過程。


題目簡介

34c3CTF web中的extract0r。

題中的目是一個安全解壓服務,用戶輸入zip的url地址,程序對url進行合法性校驗後會下載該zip,然後為用戶創建一個目錄,把文件解壓進去


經過測試,發現輸入的域名中不能含有數字,並且壓縮文件中不能含有目錄,解壓後的目錄不解析php。通過上傳一個含有符號鏈接文件的壓縮包,可以達到任意文件讀取的效果。

上傳後訪問得到源代碼

簡要分析代碼流程

經rebirth提醒,可以使用以.開頭的文件來繞過中對鏈接目錄的檢測。把打包上傳即可。這裡是因為*遍歷不到以.開頭的文件。故繞過了對文件類型的檢測,成功了鏈接到了根目錄。

翻一翻目錄會發現:

這裡創建了一個空密碼的mysql用戶,並且flag就在資料庫中。之前已經有利用gopher協議攻擊redis、fastcgi等的案例。我們可以試著利用gopher攻擊一下mysql。這裡有兩個要點

繞過ip檢查,實現ssrf

研究mysql協議,構造payload


通過代碼邏輯我們可知

url->php parse_url(過濾ip)->過濾url各部分(空白字元和數字)->curl發送請求

這裡可利用和對url解析的差異來繞過。經過測試,得出以下結論(我本地環境)

那麼我們可以構造出一個域名,讓php解析出來的host是a.com,dns解析後ip不在黑名單,這樣就繞過了黑名單檢查。而libcurl實際請求時候是另外一個域名,這樣我們就可以實現任意ip請求了。

但此題目中php解析url後在中過濾了空白字元和數字,所以以上url均不可用。

題目作者給出的url是:剛開始不太理解,後來@rebirth告訴我在rfc3986是這樣定義url的:

A host identified by an Internet Protocol literal address, version 6 or later, is distinguished by enclosing the IP literal within square brackets (「[" and "]「). This is the only place where square bracket characters are allowed in the URI syntax.

IP-literal = 「[" ( IPv6address / IPvFuture ) "]」

也就是說[ip]是一種host的形式,libcurl在解析時候認為[]包裹的是host

另外ricter大佬的在題目環境中是可用的,我本地不可用(題目的libcurl版本比我本地高)


研究的目的是為了構造出gopher連接mysql的payload,mysql協議分為4.0之前和4.0之後兩個版本,這裡僅討論4.0之後的協議,mysql交互過程:

MySQL資料庫用戶認證採用的是挑戰/應答的方式,伺服器生成該挑戰數(scramble)並發送給客戶端,客戶端用挑戰數加密密碼後返回相應結果,然後伺服器檢查是否與預期的結果相同,從而完成用戶認證的過程。

登錄時需要用伺服器發來的scramble加密密碼,但是當資料庫用戶密碼為空時,加密後的密文也為空。client給server發的認證包就是相對固定的了。這樣就無需交互,可以通過gopher協議來發送。

mysql數據包前需要加一個四位元組的包頭。前三個位元組代表包的長度,第四個位元組代表包序,在一次完整的請求/響應交互過程中,用於保證消息順序的正確,每次客戶端發起請求時,序號值都會從0開始計算。


具體到抓包數據


當用戶密碼為空時,認證包唯一的變數挑戰認證數據為0×00(NULL),所以認證包就是固定的了,不需要根據server發來的初始化包來計算了

這裡順帶提一下密碼的演算法為


命令報文相當簡單

第一個位元組表示當前命令的類型,比如0×02(切換資料庫),0×03(SQL查詢)後面的參數就是要執行的sql語句了。

經過分析,執行一句sql語句時,發送了兩個packet(認證packet、命令packet) ,那麼我們把兩個packet一起發給server端,server就會響應給我們結果。 packet的構造參見上文協議格式,需要注意的是mysql協議是小端位元組序。

這裡我用socket做一個簡單的測試,使用的是無密碼用戶,發送的sql語句是

那麼在php下,使用libcurl請求也是一樣的

php的payload最後加了四個空位元組,這是為了讓server端解析第三個數據包時出錯,斷開與我們的連接。儘快返回數據,題目中curl的超時時間是3s

至此,我們完成了從gopher到sql執行。反觀題目,這裡需要curl得到的響應是可以被解壓的。所以我們需要想辦法把查出來的數據構造成壓縮文件格式。


zip壓縮演算法壓縮出來的文件一般包括四部分。

經過測試,7z是可以成功解壓一個格式合法的壓縮文件的,即使是文件CRC錯誤,部分欄位異常。

那麼思路就來了,利用sql語句構造查詢出zip的頭和尾部,把我們想要的數據concat到中間的Deflate部分即可。(7z解壓時候發現部分header異常,Deflate部分的數據會不經解壓直接寫入到解壓後的文件)

形如

針對zip具體的構造,不在贅述,參見zip演算法詳解

這裡我寫了一個函數幫助我們創建

需要注意的是,zip的Deflate部分是保存文件壓縮後的內容,zip格式又要求必須給出Deflate部分的大小。這裡我們只需把查出數據保存在Deflate部分,並且根據查詢結果的預期大小來指定Deflate部分的尺寸。

比如查詢時候Deflate大小20就夠了。 這裡給出一個sql大家可以自行測試

這裡的1000就是Deflate數據部分佔用大小。 至此我們也就完成了sql語句的構造,可以通過sql查出一個壓縮包格式的數據。並且解壓後的文件內容就是查詢結果。

那麼梳理一下,先是通過符號鏈接,得到了一個沒有密碼的資料庫用戶。又通過和的解析差異,繞過了對ip的合法性校驗,從而可以實現ssrf任意ip。又通過分析mysql協議,發現空密碼用戶可以直接構造出packet執行sql語句。最終我們只需要輸入就可以得到結果。


為了方便,我寫了一個簡單的mysql client,測試與mysql 的通信並生成payload。

輸入後:

有興趣的可以連接自己的mysql,dump出packet


這道題目融合了很多知識點,測試中還是學到不少東西。尤其是題目腳本中防dns rebindingb部分。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 瘋貓網路 的精彩文章:

SCADA工控黑客:小白也能「黑」施耐德TM221

TAG:瘋貓網路 |