您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何分析并滲透WebSocket和Socket.io,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
WebSocket是一種允許瀏覽器和服務器建立單個TCP連接然后進行全雙工異步通信的技術。由于它允許實時更新,而瀏覽器也無需向后臺發送數百個新的HTTP polling請求,所以對于web程序來說,WebSocket非常流行。這對于測試者來說是不好的,因為對WebSocket工具的支持不像HTTP那樣普遍,有時候會更加復雜。
除了BurpSuite之外,還有一些其他工具可用于處理WebSocket。不過經過測試,它們都不怎么理想。
Zed Attack Proxy (ZAP)
Pappy Proxy
Man-in-the-Middle Proxy (mitmproxy)
WebSocket/Socket.io (WSSiP)
在這里主要會講socket.io,它是一個很流行的JavaScript WebSockets庫。在GitHub上它有多流行呢?---已經有超過41.4的star了。
在NPM上,它在WebSocket中排行第二和第三。
另外,OWASP Juice-Shop這樣非常棒的項目也使用了socket.io庫,所以本篇文章中將使用websocket.io進行演示。
https://github.com/bkimminich/juice-shop/search?utf8=%E2%9C%93&q=socket.io&type=
在本文中,我們假設你已經熟悉使用BurpSuite測試Web應用程序,所涵蓋的所有內容都可以在其社區版本中完成。不用多說,現在開始吧。
如果我們在瀏覽器中訪問Juice-Shop,則可以在后臺快速查看WebSocket流量。你也可以在BurpSuite中通過Proxy-> WebSockets歷史記錄找到。
由于協議的無狀態特性,HTTP需要始終發送請求/響應對,而WebSocket是一種有狀態協議。這意味著你可以從服務器獲得任意數量的傳出“請求”和任意數量的傳入“響應”。由于底層連接是保持打開的TCP,因此客戶端和服務器可以隨時發送消息而無需等待對方。這就是為什么WebSocket歷史記錄與你習慣查看的HTTP歷史記錄存在差異。
在此界面中,你可以看到發送和接收的單字節消息。但是,當應用程序執行一些有趣的操作時,你就可以看到具有更大負載的消息。
BurpSuite具有測試WebSockets的能力,你可以實時進行攔截和修改,但WebSocket沒有Repeater,Scanner或Intruder功能。默認情況下,如果要在BurpSuite中啟用WebSocket攔截,你只需要打開主攔截就好了。
這樣一來,你就可以通過與HTTP相同的方式獲取所截獲的WebSocket消息。同時也可以在攔截窗口中編輯它們。
在WebSockets歷史記錄選項卡中可以查看已編輯的消息。
一個非常奇怪的點是,有時在HTTP歷史記錄中也能看到類似Websocket歷史記錄中的消息,回想一下,這些比較有趣的WebSocket消息需要解決記分板相關問題,下圖顯示了來自服務器的相同響應,但這次是在HTTP歷史記錄中。由此可以看出socket.io能夠通過WebSocket或HTTP發送消息。
在所觀察的請求中,傳遞的參數值有些為“websockets”,而有些則是“polling”。那么據推測,可能為了防止WebSockets在應用程序中不受支持或被阻止,才允許使用HTTP。
socket.io文檔中解釋了“polling”和“websockets”如何作為兩個默認傳輸選項。它還介紹了如何通過將WebSockets指定為唯一傳輸方式來禁用polling。我認為反過來也是如此,我可以指定polling作為唯一的傳輸機制。
https://socket.io/docs/client-api/#with-WebSocket-transport-only
通過搜索socket.io.js源代碼,我找到了以下內容:
this.transports=n.transports||["polling","WebSocket"]
這行代碼會將一個名為transports的內部變量設置為傳入的值,如果傳入的值為false/empty,則為默認的[“polling”,“websocket”]。這很符合我們對polling和WebSocket的默認傳輸的推測。現在通過Burp中的Proxy->Options下設置匹配并替換規則來更改這些默認值,看看會發生什么。
成功了!添加規則后,刷新頁面(需要啟用Burp的內置規則“Require non-cached response”或執行強制刷新),數據不再通過WebSockets進行通信。進展不小,但是如果使用的應用程序已經提供了優先于我們的新默認值的傳輸選項呢?在這種情況下,我們可以修改匹配和替換規則。以下規則應適用于socket.io庫的不同版本,并忽略應用程序開發人員所指定的任何傳輸方式。
以下是要使用的字符串,務必將其設置為正則表達式匹配:
this\.transports=.*?\.transports\|\|\["polling","websocket"]this.transports=["polling"]
方法一只能用于于socket.io,可能會擴展到其他客戶端庫。但是,以下方法應該更加通用,因為它以WebSockets協議本身為目標。
經過分析,我發現WebSockets首先通過HTTP進行通信,以便與服務器協商并“升級”為WebSocket。其中重要的部分是:
1)客戶端通過一些WebSocket特定header發送升級請求。
2)服務器響應狀態碼為101 Switching Protocols,以及WebSocket header。
3)通信轉換到WebSocket,此特定會話不再使用HTTP。
WebSockets RFC文檔第4.1節提供了有關如何中斷此工作流的各種信息,以下是https://tools.ietf.org/html/rfc6455#section-4.1的摘錄,并附加了觀點。
1.如果從服務器收到的狀態碼不是101,則客戶端響應HTTP[RFC2616]。特別情況下,收到401狀態碼時,客戶端可能會執行身份驗證;服務器也可能會通過3xx狀態碼重定向客戶端(但客戶不需要遵循)等。否則按以下步驟進行。
2.如果響應缺少Upgrade header,或Upgrade header包含的值與“WebSocket”的ASCII不匹配,則客戶端必須關閉WebSocket連接。
3.如果響應缺少Connection header,或Connection header包含的值與“WebSocket”的ASCII不匹配,則客戶端必須關閉WebSocket連接。
4.如果響應缺少Sec-WebSocket-Accept header,或Sec-WebSocket-Accept header的值并非是由Sec-WebSocket-Key(作為字符串,未經base64解碼)與字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"串聯起來的字符串(忽略任何前導和尾隨空格)的base64編碼后的SHA-1值的話,則客戶端必須關閉WebSocket連接。
5.如果響應中包括Sec-WebSocket-Extensions header,并且header要求使用的擴展并沒有出現在客戶端的握手消息中(服務器指示的擴展并非是客戶端所請求的),則客戶端必須關閉WebSocket連接。(解析header以確定請求哪些擴展的問題,將在第9.1節中討論)
考慮到這些“連接必定被關閉”的條件,我想出了以下一套替換規則,這些規則應該包含了所有五個的失敗條件。
一旦使用這些規則,所有WebSocket升級請求都會失敗。由于socket.io默認情況下無法使用HTTP,因此已經達到所需的效果。其他庫的表現可能不同,并導致你正在測試的應用程序出錯。但我們的工作就是讓軟件做一些不應該做的事情!
原始響應看起來像這樣,并且會使客戶端和服務器轉換到WebSocket進行通信。
相反,客戶端從服務器收到此修改后的響應,會關閉WebSocket連接。
我在測試中遇到的一件事是,在將這些匹配和替換規則加入后,客戶端在重試WebSocket連接時非常持久,并在我的HTTP歷史記錄中引起了大量不必要的流量。如果你正在處理socket.io庫,則最簡單的方法是使用上面的方法1。如果你有不同的庫或其他情況,則可能需要添加更多規則來使客戶端服務器不支持WebSocket。
由于我們強制通過HTTP而非WebSockets進行通信,所以現在可以添加自定義匹配并替換將應用于已經通過WebSockets流量的規則!接下來,可以使用Repeater,Intruder和Scanner等工具,這些更改將特定于socket.io庫。不過現在還有兩個問題:
1.每個請求都有一個會話號,任何無效請求都將導致服務器終止該會話
2.每個請求的主體都有一個計算字段,表示消息的長度。如果這不正確,服務器會將其視為無效請求并終止會話。
以下是應用程序中使用的幾個示例URL。
/socket.io/?EIO=3&transport=polling&t=MJJR2dr/socket.io/?EIO=3&transport=polling&t=MJJZbUa&sid=iUTykeQQumxFJgEJAABL
URL中的“sid”參數表示到服務器的單個連接流。如果發送了無效消息(在嘗試破解時很常見),那么服務器將關閉整個會話,之后必須重新開始新會話。
給定請求的主體中含有一個字段,其中存放有效載荷的字節數。這類似于“Content-Length”HTTP header,只不過該字段的值近針對socket.io。例如,如果你要發送的有效載荷是“hello”,那么,相應的主體將是“5:hello”,Content-Length頭部的值是7。其中,5表示字符串“hello”中的字母數量,而7則表示字符串“hello”中的字母數量以及socket.io添加到主體內的字符串“5:”中的字母數量之和。與往常一樣,Burp將替我們更新Content-Length頭部,因此,這件事情我們無需擔心。但是,我還沒有找到能夠自動計算和包含有效載荷長度的好方法。更讓人頭疼的是,我發現socket.io竟然會在同一個HTTP請求中發送多條消息。由于每個消息都是一個封裝后的WebSocket有效載荷,并且每個消息都有自己的長度,因此,最終看起來就像這樣:“5:hello,4:john,3:doe”(實際的語法可能有所不同,這里只是便于演示)。計算長度時一旦出錯,服務器就會將其作為無效消息拒絕,這樣,我們就要重新開始了。
這是body的示例。這是Juice-Shop應用程序中的響應,請求的格式相同。注意,這里的“215”表示“:”之后的有效載荷的長度。
215:42[“challenge solved”,{“key”:”zeroStarsChallenge”,”name”:”Zero Stars”,”challenge”:”Zero Stars (Give a devastating zero-star feedback to the store.)”,”flag”:”e958569c4a12e3b97f38bd05cac3f0e5a1b17142″,”hidden”:false}]
使用Burp宏能解決第一個問題。基本上,每次Burp在服務器拒絕消息時匹配,宏將自動建立新會話并用有效的“sid”更新原始請求。通過轉到options->Sessions->Macros->Add來創建新宏。
建立新會話的URL只需省略“sid”參數。例如:
/socket.io/?EIO=3&transport=polling&t=MJJJ4Ku
服務器響應包含一個全新的“sid”值以供使用。
接下來,單擊“Configure item”按鈕,并將參數名稱命名為“sid”。然后,選擇“Extract from regex group”選項,并使用如下所示的正則表達式。
"sid"\:"(.*?)"
這時,配置窗口應如下所示:
現在有了一個宏,我們需要一種方法來觸發它。這就是Burp會話處理規則的用武之地。通過
Project options->Sessions->Session Handling Rules->Add
為“Check session is valid”創建新的規則動作:
配置新規則操作如下:
按如下方式配blackhillsinfosec置新規則操作:最后,在完成新規則操作后,還需修改規則的范圍。你可以在此處決定要應用此規則的位置。建議至少將它用于Repeater,這樣就可以手動重復請求。
以下是我配置范圍規則的方法。你可以更加具體地了解自己所需范圍,但下面的選項應該適用于大多數情況。
這是在沒有會話處理規則的情況下發出的請求:
這里是在會話處理規則生效后發出的相同請求:
以上就是如何分析并滲透WebSocket和Socket.io,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。