如何構造基于瀏覽器的端口掃描器

在本文中我將介紹如何使用JavaScript構造端口掃描器,如果大家感興趣,可以直接從此處下載這款工具。

0x01 基于Chrome瀏覽器的實現

關于從Internet(互聯網)區域到Intranet(內部網)區域進行端口掃描方面的內容,網上已經有一些研究文章。Jeremiah Grossman在之前介紹過如何在不依賴JavaScript的前提下,使用link元素和時序方法進行端口掃描,而Berend Jan Wever(Skylined)寫了一個lan掃描器,也使用了時序攻擊(timing attacks)以及WebRTC和XHR原理。 這兩種技術都用到了時序攻擊,因此不是100%可靠。 這里我已經提出了一種更為可靠的技術,但主要面向的是網絡服務器掃描場景。

在測試在受限環境中使用瀏覽器來呈現用戶提供的內容的Web應用程序時,我一直在尋找能夠提取特定IP上運行的服務信息的方法。之所以選擇Chrome,是因為這個Web應用程序使用的正是這個瀏覽器。當某個端口沒有被用戶主機占用時,Chrome會拒絕連接,此時我注意到了一些有趣的行為。 Chrome會向用戶顯示一條消息,但這正是最為有趣的一點,Chrome會將實際的URL更改為chrome-error://chromewebdata/

當我們使用iframe向服務器上不存在的某個端口發送請求時,即使該端口沒有監聽任何內容,我們也會得到成功的onload事件。如果的確有服務器在該端口監聽,瀏覽器也會有一個成功的onload事件,Chrome可能的確會這樣做,以防止用戶探測哪些端口處于打開狀態。 我們可以利用這種行為,我想出了一種方法,可以使用iframe?onload事件來確定端口是否打開。

如果我們首次加載url,捕獲到onload事件,然后增加計數器值,再次發出相同的請求,但這次請求源中加了#(因為網址已更改為chrome-error:,而不是原始url),此時我們將獲得第二次onload事件,因為網址已更改。 如果某個Web服務器正在目標地址上監聽,我們只會得到一個onload事件,這是因為第二個url中包含一個哈希值,而當一個哈希發送到已加載的某個頁面時,瀏覽器不會重新加載頁面。

為了構造端口掃描程序,我首先創建了一個iframe元素和anchor元素。anchor元素用來執行對#url的點擊行為。然后,我們需要將iframe的名稱及anchor目標設置為相同的值,以便在點擊操作會在iframe上而非頂層文檔上執行:

然后我們需要設置iframe的url值以及anchorhref屬性值設置為同一個目標:

iframe需要關聯onload事件,有效端口只會觸發一次onload事件,因此我們需要使用計時器,碰到無效端口時繼續下次測試:

以上就是主要思路,我們可以使用這種方法來掃描任意主機(包括本地IP)上的Web服務器。

請注意 :在最新版的Chrome上使用X-Frame-Options: DENY選項時會修改url,所以該工具會將這種情況判斷為端口關閉。

0x02 基于Firefox瀏覽器的實現

我研究了如何在Firefox上使用這種技術,事實證明此時這種技術運用起來更加容易。如果是有效的Web服務器,那么Firefox會觸發onload事件,并且不會因為拒絕連接而觸發該事件,因此我們無需自動點擊鏈接就可以輕松找到目標。我們只需查看onload事件是否被觸發,或者檢測是否超時即可(此時沒有觸發該事件)。Firefox還可以讓我們創建大量iframe,并且不會造成性能上的損失。

這次我并沒有使用單個iframe(如Chrome瀏覽器的應用場景),而是使用了iframe池。Firefox允許我們使用大量的iframe,這里我選擇的數量為1000。

然后只需要使用onload事件就可以簡單判斷目標是否為有效的Web服務器:

Firefox場景比其他場景要更加快速,也更為強大,因為此時我們甚至可以掃描無效的響應場景。這樣我們就能檢測其他服務,比如Redis服務器等。

0x03 基于Edge瀏覽器的實現

Edge瀏覽器版的掃描器與Chrome版本相反,如果目標端口有效,那么url就會跳轉到錯誤頁面,觸發onload事件;但如果目標端口無效,那么只有哈希值會發生改變,不會觸發onload事件。

我已經將以上技術整合到一個工具中,這款工具使用我最喜歡的異步JavaScript語言進行開發,大家可以訪問此處下載該工具。

文章翻譯轉自:https://xz.aliyun.com/t/3241

原文:https://portswigger.net/blog/exposing-intranets-with-reliable-browser-based-port-scanning