Web服務攻擊第一部分 簡單對象訪問協議(SOAP)
譯文【51CTO.com 獨家譯稿】一般說來,Web服務在人們心目中一直是那種難以精確定義、解釋及運用的小眾工具。這實際上是種誤解,詳情點擊此處查看。我也很想通過一些技術及代碼實例來消除此種誤解。在本文當中,我們將專門討論SOAP。當然類似JSON及REST也都是比較流行的重要標準,但在這里我們姑且將重點集中在SOAP身上。
簡單對象訪問協議或簡稱SOAP,是利用XML架構進行信息(且主要通過HTTP協議實現)交互的一套機制。Web服務協議則是一套相對輕量級的通信機制,在API連接驅動方面功效卓著,常見于移動設備應用程序當中。
要在閱讀本指導文章的同時嘗試當中涉及的各項操作,大家需要預先安裝Jruby、Buby、Savon、Nokogiri gems以及通過下載或購買獲得PortSwigger出品的Burp套件。整個討論過程的基本思路是通過深入挖掘并在一定程度上拓展Burp的某些功能,使得攻擊SOAP的流程更易于掌握。
如上所述,SOAP信息通信建立在XML架構的基礎之上。這種XML架構可以被定義為WSDL或是"Web服務描述語言"類文件。這種信息描述方式為針對數據的攻擊制定及請求形成提供了可資利用的寶貴空間。
SOAP的執行及其參數是頗具價值的信息單位,并且能夠從WSDL中提取得出。類似獲取電子郵件地址之類的操作可以經由類似"profileid=1000"這種參數及賦值實現。創建這一請求、更改profileid的賦值并將其發送至目標處即能夠使我們得到其它用戶的電子郵箱地址。
現在我們可以通過在XML標簽內部查驗響應及獲取數據中大值的方式對WSDL進行手動列舉,但怎樣才能在不創建可重復代碼的前提下快速且無縫地達成上述目標呢?
安裝 JRuby
$ sudo apt-get install jruby
安裝 Savon 及 Buby gems
$ sudo jruby -S gem install buby
$ sudo jruby -S gem install savon
現在我們需要編寫一些代碼。Savon gem是一款Ruby / JRuby函數庫,允許我們創建一套SOAP客戶端并使其與Web服務進行交互。首先建立一個名為attack_soap.rb的文件(單擊此處獲取代碼),接著輸入以下代碼:
一行一行逐步講解
第1至2行:
這一條是我們的腳本指令,基本上表達的意思是"使用這些函數庫"。
第 5行:
接下來我們需要輸入代碼以獲得連入Burp套件及運行工具及代碼的權限。在這里,我們定義一套標準的CustomMenuItem。第33行演示了如何將其導入并發揮作用。
第 8至9行:
這里我們創建了一種名為enum_wsdl的函數。該函數在第27行被調用并導入一個URL(rhost對象)。在第9行中大家會看到我們引入了Savon客戶端實例并將其賦值與rhost相關聯。
第 11至 12行:
這兩行的內容都是可選值。第10行為一套用戶名及密碼都為"guest"的賬號提供了授權。第11行則將此信息發送到我們的Burp代理實例中。
第 13至 18行:
第13行確保了之前建立的client.wsdl以及client.wsdl.soap_actions被正確調用。第14行為我們提供了非常美觀的紫色*標識以及內容為"可用操作列表:"的狀態欄。第15至17行用來重申soap_actions中的數組,并將每項操作"放入"控制臺;而在第17行中,我們為整個循環語句畫上句號。
第 19至21行:
我們還得為執行出現錯誤的情況做出補救措施,一旦出問題,第19行的指令能幫我們妥善解決。在第20行的描述中,我們會在遇到錯誤時向屏幕輸出一個紅色的 - 標記以示警告。第21行則用于結束整套enum_wsdl函數。
第 23 至24行:
我們在第23行中定義了名為menu_item_clicked的函數。這一點至關重要,因為Burp會調用此函數并遵循特殊的命名規范。而在第33行中,我們設定了在單擊菜單選項(指那些可用項)時,該函數正式執行調用操作。
這里談到的一切,總結起來意味著CustomMenuItem這個類必須具備一組名為menu_item_clicked的函數。請注意這里我們向其傳遞的是*參數(復數),這意味著該函數能夠同時接收到多個對象。
在第24行中我們將一對對象拆分為兩個相互獨立的個體,分別名為menu_item_caption以及message_info。
第 26 至 31行:
這一對象實際上是一個信息組。每條信息都具有與之關聯的特定值。當我們循環訪問該組時,通過第26行的指令,我們能夠同時訪問到這些數值。在第27行中我們借助獲取itm對象(此對象確實是一條信息)并訪問與之關聯的url值的方式達到上述目的。我們調用enum_wsdl函數并向其傳遞剛剛獲得的url值。最后,第28、29及30行用于關閉循環、函數及message_info類。
第33行:
最后還有同樣重要的一點--我們需要創建菜單選項。我們采取調用Burp(即&burp指令)中的注冊菜單選項函數的辦法。我們將在"enumerate wsdl"中可見的菜單選項名稱調出,如此一來該類就可以查找menu_item_clicked函數了。
整個工作流程總結如下:
" 在Burp中點擊enumerate wsdl / 菜單選項。
" CustomMenuItem.menu_item_clicked 被調用并傳遞至兩個對象處。
" 在 menu_item_clicked當中, enum_wsdl 函數被調用。
" 我們解析WSDL以獲取可行操作列表并將其輸出至控制臺。#p#
腳本運行實例:
$ jruby -S buby -i -B ~/Desktop/burp/burp.jar -r ~/Desktop/attack_soap.rb
下一步是對WSDL提出請求,并利用Burp攔截該請求。舉例來說:
攔截發往http://192.168.1.149/WebGoat/services/WSDLScanning?WSDL的請求
點擊 "enumerate wsdl"選項進入如下界面:
現在我們已經得到了一份標明所有可用操作的詳細列表!
但這還不是終點。我們需要把它當成跳板、繼續高歌猛進。將一些編寫好的代碼提交進去,以提取出可用的參數及賦值。這樣我們就可以利用這些值來創建請求。
現在一定要注意,下列代碼無法解析全部WSDL內容、也不能"自動"創建正確的請求。事實上它應該被作為一種小規模示例,向大家演示正確代碼的效果并提供SOAP請求的可視化直觀表現。
現在,我們需要重新審視自己剛剛編寫出來的代碼,并適當加以補充。下列截圖是代碼庫的前半部分。
第 3行:
我們將利用到Nokogiri函數庫。因此,我們得先進行安裝。大家務必確保在運行腳本之前執行了下列指令:
$ sudo jruby -S gem install nokogiri
第 24至27行:
在第24行,我們創建了parse_wsdl函數。該函數中包括wsdl XML。第25行中的實例及空白hash被命名為wsdl_element_hash。第26行創建了一個doc對象,由wsdl負責解析并且易于尋獲。最后,第27行以<wsdl:message>及</wsdl:message>為標簽搜索符合的XML內容。
第 28至29行:
我們對test_m1及test_m2進行了實例化,這樣它們就能在循環之外仍被調用(接下來的幾行代碼非常重要)。這種處理方式的最終目的是通過一項SOAP操作返回作為密鑰的hash及參數的實際賦值。
正如大家看到的,在下圖中,某項操作請求中有一條參數名為"id"。我們要執行能夠獲取實名、登錄賬號等等信息的操作,就先要利用這類操作所調用的參數發出SOAP請求。
從理論層面來說,我們創建的hash應該如下所示:
{
'getFirstName => 'id',
'getLoginCount => 'id',
'getCreditCard' => 'id',
'getLastName' => 'id'
}
第 30至34行:
XML/WSDL文檔中那些包含<wsdl:message>標簽的部分之前已經被解析(由第27行指令實現)為數組類結構。該對象隨即被賦予msg的標簽。在第30行中,我們開始循環訪問msg數組。第31及32行則是將SOAP操作"請求"(自我們創建該請求時起)與參數/類型進行匹配組合。第33及34行負責剔出相匹配的數據(也就是那些與31及32行中的內容相符的數據),當然沒有相符內容的情況除外。在這種情況下,test_m1及test_m2將被設置為"nil"(即'空')。
第 36至38行:
提供完整性檢查,如果test_m1與test_m2回饋的內容非"空",就意味著我們已經成功地將XML內容與想要獲取的信息表達式相匹配,此時將SOAP操作及其參數導入wsdl_element_hash即可。
第 39至 41行:
如下圖所示,我們結束循環語句,返回wsdl_hasl_element的hash對象并關閉parse_wsdl函數。
第 43至46行:
由form_request所調用的函數將實例化,而rhost的賦值(也就是一條完整的URL)將作為輸入信息被接收。第44至46行意在根據客戶端的具體設置情況正確調整我們自己創建的SOAP客戶端。
第 47至48行:
第47行創建一個名為wsdl的對象,這是一條以純XML形式構成的WSDL。第48行將該XML對象傳遞至parse_wsdl函數。
第 49至53行:
在第49行中,我們對每一條由WSDL中獲取的可用soap操作進行循環訪問。第50行則是創建一套條件性設置。如果我們的hash,由parse_wsdl函數所創建,中具備soap_action(itm)操作,則需要生成一條請求。在第51至56行中,我們生成該請求。第52及53行用于提供必要的輸入信息。因此getCreditCard指令變為:get_gredit_card這種新形式,id也變為:id。這一點非常重要,因為這是Savon gem 請求所強制要求的形式。
第 54至56行:
我們在此創建了一條動態請求。每樣操作都隨著各項參數被傳遞至客戶端請求當中。
第 57至61行:
關閉上述循環以及form_request參數。
第 67至70行:
我們建立了一條根據菜單選項點擊情況觸發的條件語句。如果"enumerate wsdl"被選中,我們就會轉向enum_wsdl函數。而如果是"form SOAP request"被選中,觸發的則是form_request函數。
第 78行:
在此我們添加另一條自定義菜單選項,名為"form SOAP request",而一旦該選項被選中,不僅會觸發WSDL解析,還將自動創建一條SOAP語法并將其發送至我們的攔截代理端以備進一步攻擊時使用。#p#
那么當我們一切就緒后,效果究竟如何呢?
這里我們點擊form SOAP request選項
此處共計創建了四條SOAP請求(因為我們共有四種可用操作)。
根據對"getCreditCardRequest" wsdl:message的深入分析,可以看到我們已經成功獲取到一些可憐蟲的信用卡號碼。
那么以此為基礎,我們能夠對創建的SOAP請求進行積極掃描,并通過進一步處理及中繼器的幫助加以調整。以往那看似無懈可擊的壁壘如今瞬間崩潰殆盡,有了SOAP請求自動解析工具,破解信用卡號碼已如探囊取物。大成功!
原文鏈接:http://resources.infosecinstitute.com/soap-attack-1/
【51CTO.com獨家譯稿,非經授權謝絕轉載!合作媒體轉載請注明原文出處及出處!】