變種XSS:持久控制

wyzsk發表於2020-08-19
作者: tig3r · 2015/11/30 10:42

0x00 引言


首先宣告,這不是一個新洞,看過 Homakov 文章(最後附)以及譯文的人想必對這種漏洞有所瞭解。

但原文寫的太過簡單(沒有說明利用條件、情景和特性),且譯文和我的理解略有偏差,於是就有了這篇文章。

這種漏洞已經存在一段時間了,有沒有被利用過尚不得知,雖然利用條件較苛刻,但是當符合條件的站點被攻擊後, 影響面和影響程度巨大,並且普通使用者不知如何清除, 可導致長期持續攻擊。

2014年底的時候,這種漏洞的利用條件沒有現在苛刻(比如沒有Service-Worker-Allowed頭),一年過來 W3C 對規範最佳化了不少(包括安全方面), 相信不久的將來,很快會被標準更新所扼殺了。

彌留之際,讓這個漏洞放點異彩吧。

0x01 一切都從 serviceWorker 說起


Service Worker是基於Web Worker的事件驅動的,他們執行的機制都是新開一個執行緒去處理一些額外的,以前不能直接處理的任務。對於Web Worker,我們可以使用它來進行復雜的計算,因為它並不阻塞瀏覽器主執行緒的渲染。而Service Worker,我們可以用它來進行本地快取,相當於一個本地的proxy。說起快取,我們會想起我們常用的一些快取技術來快取我們的靜態資源,但是老的方式是不支援除錯的,靈活性不高。使用Service Worker來進行快取,我們可以用javascript程式碼來攔截瀏覽器的http請求,並設定快取的檔案,直接返回,不經過web伺服器,然後,做更多你想做的事情。

  • 我們可以用 javascript 程式碼來攔截瀏覽器的 http 請求,並設定快取的檔案,直接返回

相信很多人看到這句已經明白了,透過 js 來代理瀏覽器 http 請求,也就是說透過執行 js 程式碼來控制瀏覽器的請求, 很容易想到,利用 xss 來修改瀏覽器請求的返回內容。

可怕的是,即便 xss 漏洞被修復了,攻擊仍然持續,並且滲透到攻擊範圍內的每一個 url。

並且,當使用者察覺到攻擊,並且理解這種攻擊,進入chrome後臺(chrome://appcache-internals), 進行手動清除攻擊快取,攻擊仍未失效!當然了,還是有辦法清除的,且無須使用者手工操作(下文會演示)。

0x02 漏洞原理和演示


serviceWorker 的官方標準文件:http://www.w3.org/TR/service-workers/

其操作可以參考:https://github.com/w3c-webmob/ServiceWorkersDemos

首先 serviceWorker 只有在 https 頁面中才可以呼叫 regist。

而 serviceWorker 需要 Promise 支撐,目前支援的瀏覽器如下:

支援 serviceWorker 的瀏覽器:

firefox 預設關閉 serviceWorker,可以透過 about:config 開啟開關:

支援 fetch 方法(抓包)的瀏覽器:


開始嘗試攻擊:

首先在 https 站點中找到一個 Xss,利用 Xss 註冊一個 serviceWorker.registration 例項:

#!js
navigator.serviceWorker.register(url).then(function(registration) {
  console.log(registration);
});

注意到有個未知引數 url,這個 url 就是拿來放我們的攻擊程式碼(假設我們能上傳一個js到根目錄):

#!js
var url = '//victim.com/evil.js'

有人說這太難了,往根目錄上傳 js 檔案不可能,那麼可以嘗試在子目錄/任何一個可能的目錄上傳js檔案, 或者和 Homakov 一樣,利用 jsonp 介面來代替這個惡意 js 檔案。

serviceWorker.register 只支援請求檔案返回頭的MIME型別為:text/javascript, application/x-javascript, application/javascript

我們知道,jsonp 的 callback 經常是可控的,那麼找到一個這樣可以寫程式碼的 jsonp 難不難?

Google it !

點選第一個連結:

可以看到,以 taobao.com 為例,第一個 jsonp 介面就存在這樣的弱點:callback 可以寫入任意程式碼。

退一步說,只要能輸入 []!() 等幾個符號,就能構造任意程式碼了。

以往安全工程師修復 jsonp 介面的 xss 漏洞,都是將頁面的 mime 修改為 application/javascript, 或者將 callback 的引數中的html符號實體轉義,就覺得杜絕 xss 了,看來以後得換個修法了

若 callback 僅僅代表一個函式名,何不只允許數字、字母和下劃線呢?

往 “js/jsonp介面” 裡寫入惡意程式碼:

#!js
onfetch = function(e) {
  e.respondWith(new Response('任意內容',{
      headers
      ...
    });
  );
}

透過 onfetch 方法攔截 http 請求,並構造返回內容,比如返回:<script>alert(/xss/)</script>

所有在 evil 路徑下的請求的內容都被篡改。


讓我們本地測試還原一遍場景(注意:本地測試不需要 https):

首先開啟網站:

開啟正常頁面:

這時候點選被攻擊頁面,此頁面事先被注入了 XSS 指令碼:

可以看到,這時候 serviceWorker 已經成功註冊了

重新整理頁面,此時返回內容以及被修改了:

這時候再看正常頁面,也被攻擊了:

首頁也是相同的情況:

關閉瀏覽器,再開啟,依舊如此:

0x03 優勢、侷限性

  • 優勢
    • 生存週期久(即便瀏覽器重啟還在)
    • 一旦中招不易清除,包括使用者和網站業務方
  • 侷限性
    • 需要同域中同時存在 XSS 和弱點 JSONP(或可控js檔案)
    • 感染路徑受弱點 js 路徑的限制
    • 被攻擊站點必須是 https

實際利用中,若弱點JSONP路徑中不存在網站業務,這個漏洞依然能發揮一定價值。

比如:殺死該JSONP路徑以及其子目錄的全部介面,從而導致網站無法正常使用。

0x04 中止及防範攻擊


1. 如何中止攻擊

從上文可以知道,即便 xss 被修復了或者消失了,攻擊依然生效,那麼如何中止攻擊呢?

作為一個普通使用者,首先嚐試開啟 chrome://inspect/#service-workers 檢視存活:

的確可以看到被用作攻擊的 Worker,點選 terminate 嘗試中止:

可以看到以及被清理了,但是開啟頁面,攻擊仍然存在!

瀏覽器中開啟F12,在console中輸入:navigator.serviceWorker., 可以看到有 getRegistration 和 getRegistrations 這兩種屬性。

查詢文件:https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistration

嘗試獲取註冊器,並且呼叫登出(由於用到 Promise,需要使用 then 調取結果):

#!js
navigator.serviceWorker.getRegistration()
  .then(function(registration) {
  registration.unregister();
});

這一次終於清除了。

而對於網站方,如何清除所有攻擊呢?

只要將“清除程式碼”部署在一個未受感染的同域的頁面裡,當使用者訪問過後,自然就清除了。

2. 防範方法:

  1. Jsonp 介面的 callback 可以做白名單,或者只允許特定字元(比如數字、字母和下劃線)。
  2. Jsonp所在域不應該存在 XSS(一切型別),至少不應該存在業務頁面。
  3. 如果做不到2,Jsonp 所在 url 路徑下不應該存在網站業務。
  4. 域名內不應存在使用者可控的 js 檔案。

reference:

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章