作者:
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. 防範方法:
- Jsonp 介面的 callback 可以做白名單,或者只允許特定字元(比如數字、字母和下劃線)。
- Jsonp所在域不應該存在 XSS(一切型別),至少不應該存在業務頁面。
- 如果做不到2,Jsonp 所在 url 路徑下不應該存在網站業務。
- 域名內不應存在使用者可控的 js 檔案。
reference:
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!