chrome 浏览器扩展安全

去年8月份的时候fc老板带我搞了一波浏览器扩展的问题,屯了一些思路想批量扫描一下 chrome 扩展商店里的热门扩展,一直拖着没动,今天发现被大佬做了。

浏览器扩展的配置文件为manifest.json,里面规定了扩展的权限和一些其他的属性。其中比较常见且重要的属性有content_security_policy, permissions, content_scriptscontent_security_policy指明了扩展所遵循的CSP规则,permissions代表扩展所拥有的访问权限,content_scripts则是会插入到页面中的脚本。

浏览器扩展的CSP

在chrome浏览器的文档里,默认的CSP是script-src 'self'; object-src 'self'
而在某第三方浏览器中,扩展默认的CSP是script-src 'self' blob: filesystem: chrome-extension-resource:; object-src 'self' blob: filesystem:;

其中,blob协议filesystem协议只能用过JavaScript代码来创建。

这意味着,在扩展里默认不能使用内联脚本,不能引用外部的js文件,不能动态类似eval那样执行js。同时我们也不能引入外部的swf文件通过flash来xss。
因此,即使在扩展里发现了dom类型的xss,也难以利用来完成攻击。即innerHTML或者document.write之类方法根本不需要去看,即使能利用成功插入任意内容也不能执行JavaScript代码。

当然,在引用了一些有漏洞的库之后,还是存在被攻击的可能的。( 如 http://5alt.me/2017/09/jQuery%E9%87%8C%E7%9A%84html()/

浏览器的 content_scripts

content_scripts会在网页的上下文中运行,不过是在一个称为隔离环境的特殊环境中执行。它们可以访问所在页面的 DOM,但是不能访问当前页面创建的任何 JavaScript 变量或函数。在当前页面运行的 JavaScript 不能调用或访问任何内容脚本定义的函数或变量。content_scripts执行的域是当前页面所在的域,但是仍有部分特权。

当然有的浏览器里并未对此做隔离,导致了扩展里调用的函数被页面中js劫持的情况。不过在不存在问题的情况下,很难对content_scripts做手脚,因此与之相关的manifest.json的配置项提到的文件以及chrome.tabs.executeScript函数都可以不必关心。

有人可能存在疑问,像tampermonkey,它往页面注入js脚本,脚本中的变量可以被页面访问到,这不是违反了安全规则么。tampermonkey的做法是,先往页面中动态插一个script节点,执行完毕之后删除。这样在页面的DOM里不会发现注入的脚本,同时脚本也和当前页面在同一个执行环境里。

1
2
3
4
5
6
// page.js
inject: function(a) {
var u = "text/xml" == document.contentType ? document.createElementNS("http://www.w3.org/1999/xhtml", "script") : document.createElement("script");
u.textContent = a;
(document.head || document.body || document.documentElement || document).appendChild(u);
u.parentNode.removeChild(u)

此外,根据nearg1e大佬的文章,

  1. background 并不是每次访问页面执行一次,内部定义的变量不会因为页面刷新而重新定义。

  2. background 即使域改变也不会重新定义和赋值,所有的域都用一个 runtime。

第一点使得这个漏洞更加容易利用,第二点使得我们所写的 payload 并不只影响在 payload 中利用的网站,而是在浏览器和扩展为重启之前,每次访问新的页面都可以在不同域下触发 payload。

浏览器扩展的通信方式

在浏览器中,页面与扩展通信、扩展之间通信、扩展内通信采用的是消息机制。扩展可以通过chrome.runtime.onMessage, chrome.runtime.onMessageExternal, chrome.runtime.onConnect, chrome.runtime.onConnectExternal监听消息事件并处理。其中chrome.runtime.onMessagechrome.runtime.onConnect监听的是扩展内部消息传送,而chrome.runtime.onMessageExternalchrome.runtime.onConnectExternal则是接收页面和其他扩展的消息。所以我们需要关注的是后面两个External的接口。

接口的权限在manifest.jsonexternally_connectable中进行权限设置,但有的浏览器会在此之外自行添加可以发起通信的作用域。这里更多的会出现一些逻辑问题。(尤其是在CSP的影响下)

除此之外,扩展还可以通过window.addEventListener的方式在原页面添加事件,如message事件,从页面获取事件消息。

浏览器的特权API

很多人谈浏览器安全总是绕不过一个词叫做特权域。其实并不是因为这个域被列入了特权的白名单,而是有些特权的API只允许某些页面来调用。chrome源码里有几个_api_features.json文件规定了一些API的调用来源范围。如果在某个有危险功能API所允许的域上发现了XSS,那么就会出现严重的安全问题。虽然有些API只允许某个域上的某些页面调用特权API,但是如果在这个域上的其他页面发现XSS也是可以进行攻击的,毕竟同域上没有页面之间隔离的说法。同理,如果特权API允许了http页面来调用,还会存在被中间人的风险。
所以寻找浏览器扩展方面的安全问题最好能知道浏览器存在哪些API,然后筛选出具有敏感操作的API,找出这些API允许调用的页面,然后寻找页面所在域的问题。
不过浏览器会存在一些默认的安全机制,阻止跨协议的跳转。即使有些页面存在 DOM 型的 XSS,但由于无法从http协议页面跳转过去,其被利用的可能性就会大大降低。

附一个解析_api_features.json小脚本

浏览器扩展的攻击面

从上面我们可以看到,在默认的情况下,即使一个扩展做的非常烂,由于浏览器默认的安全机制,也能保证该扩展自身大概率不受攻击。

如果攻击者能控制允许发消息的页面能发起通信,那么需要找扩展的chrome.runtime.onMessageExternalchrome.runtime.onConnectExternal事件,分析是否存在问题。
如果攻击者能在特权域找到一个XSS,就可以通过允许该页面允许的特权API做一些事情。
如果攻击者能中间人,可以尝试中间人特权域页面,或者寻找扩展中http的请求。
如果扩展将用户的数据innerHTML到扩展自身的页面显示,在CSP设置有问题的前提下,可以以扩展的权限执行代码。
如果扩展会在第三方页面上利用innerHTML方式插入一些代码并直接拼接了用户数据,则可能造成该页面的xss。
如果扩展将用户可控的内容以html的形式输出在页面上的话,需要注意是否会造成当前域以及其他域的xss。

在实际的攻击利用场景中,寻找特权域xss的方式是比较常见的,但中间人造成的影响不容忽视。

最后附一个静态分析 js 里关键字来辅助找扩展漏洞的脚本

参考资料

https://content-security-policy.com/
https://developer.chrome.com/extensions/contentSecurityPolicy
https://developer.chrome.com/extensions/content_scripts
https://developer.chrome.com/extensions/messaging
https://crxdoc-zh.appspot.com/extensions/
https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/api/_features.md
http://blog.gclxry.com/chrome-extension-features/
https://www.anquanke.com/post/id/98917

分享到 评论