看我如何发现Chrome浏览器阅读辅助插件SOP绕过漏洞
本文讲述的是作者发现谷歌浏览器Chrome阅读辅助插件(Read&Write Chrome extension)1.8.0.139版本同源策略(SOP)绕过漏洞的过程。该漏洞在于Read&Write插件缺少对正常交互网页请求源的安全检查,导致任意网页都可以调用Read&Write插件的后台特权页面API来执行多种存在风险的操作。由于该版本插件的在线下载使用量较大,在漏洞上报前估计有八百万用户受到影响。
漏洞介绍
比如,利用名为 “thGetVoices”方法的后台API调用方式,可以用插件执行一个任意URL链接的检索,并用postMessage方式来进行响应通信。通过这种方式的API恶意调用,攻击者可以劫持Read&Write插件去读取一些恶意且未经验证的会话数据。
作为验证,作者在文末制作了一个漏洞利用PoC视频,在安装了存在该漏洞的Read&Write插件之后,在进行应用操作时,可以利用漏洞远程读取到用户的Gmail邮箱地址信息。在漏洞上报之后,Read&Write插件开发方Texthelp公司迅速修复了漏洞,并于第二天释出了更新补丁。目前,新版本的Read&Write插件已不存在该漏洞。
漏洞分析
Chrome的Read&Write插件利用名为“inject.js”的Google浏览器内置脚本(Content Script)来向诸如Google Docs在内的各种在线文档页面插入一个自定义工具栏,以方便读者用户可以利用该插件进行文档读写。默认情况下,此脚本将会向所有HTTP和HTTPS源执行插入,插件的使用说明中已定义了这一点:
...trimmed for brevity...
"content_scripts": [
{
"matches": [ "https://*/*", "http://*/*" ],
"js": [ "inject.js" ],
"run_at": "document_idle",
"all_frames": true
}
],
...trimmed for brevity...
在 “inject.js” 脚本文件中,存在一个事件监听函数addEventListener,任何被插入 “inject.js” 脚本文件的交互网页,如果以“postMessage”方式向插件发送响应消息,都能被该函数捕获到:
window.addEventListener(“message”, this.onMessage)
这个addEventListener函数还会调用另一个名为“this.onMessage”的函数,该函数用于处理任意发往页面窗口的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() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本需要具备同源策略才能通信。window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
在上述代码中,可以看到onMessage()会把所有接收到的postMessage消息通过“chrome.extension.sendRequest”方法发送到Read&Write插件的后台页面。另外,对这些消息的响应将传递回onMessage()函数,然后再通过其传递回Web页面中去。这个过程,实际上就在正常的Web访问页面和Read&Write插件后面之间形成了一个代理机制。
从Read&Write插件的使用说明中,可以发现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"
本文讲述的是作者发现谷歌浏览器Chrome阅读辅助插件(Read&Write Chrome extension)1.8.0.139版本同源策略(SOP)绕过漏洞的过程。该漏洞在于Read&Write插件缺少对正常交互网页请求源的安全检查,导致任意网页都可以调用Read&Write插件的后台特权页面API来执行多种存在风险的操作。由于该版本插件的在线下载使用量较大,在漏洞上报前估计有八百万用户受到影响。
漏洞介绍
比如,利用名为 “thGetVoices”方法的后台API调用方式,可以用插件执行一个任意URL链接的检索,并用postMessage方式来进行响应通信。通过这种方式的API恶意调用,攻击者可以劫持Read&Write插件去读取一些恶意且未经验证的会话数据。
作为验证,作者在文末制作了一个漏洞利用PoC视频,在安装了存在该漏洞的Read&Write插件之后,在进行应用操作时,可以利用漏洞远程读取到用户的Gmail邮箱地址信息。在漏洞上报之后,Read&Write插件开发方Texthelp公司迅速修复了漏洞,并于第二天释出了更新补丁。目前,新版本的Read&Write插件已不存在该漏洞。
漏洞分析
Chrome的Read&Write插件利用名为“inject.js”的Google浏览器内置脚本(Content Script)来向诸如Google Docs在内的各种在线文档页面插入一个自定义工具栏,以方便读者用户可以利用该插件进行文档读写。默认情况下,此脚本将会向所有HTTP和HTTPS源执行插入,插件的使用说明中已定义了这一点:
...trimmed for brevity...
"content_scripts": [
{
"matches": [ "https://*/*", "http://*/*" ],
"js": [ "inject.js" ],
"run_at": "document_idle",
"all_frames": true
}
],
...trimmed for brevity...
在 “inject.js” 脚本文件中,存在一个事件监听函数addEventListener,任何被插入 “inject.js” 脚本文件的交互网页,如果以“postMessage”方式向插件发送响应消息,都能被该函数捕获到: www.wnhack.com
window.addEventListener(“message”, this.onMessage)
这个addEventListener函数还会调用另一个名为“this.onMessage”的函数,该函数用于处理任意发往页面窗口的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() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本需要具备同源策略才能通信。window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。 内容来自无奈安全网
在上述代码中,可以看到onMessage()会把所有接收到的postMessage消息通过“chrome.extension.sendRequest”方法发送到Read&Write插件的后台页面。另外,对这些消息的响应将传递回onMessage()函数,然后再通过其传递回Web页面中去。这个过程,实际上就在正常的Web访问页面和Read&Write插件后面之间形成了一个代理机制。
从Read&Write插件的使用说明中,可以发现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"