Firefox内容安全策略中的“Strict-Dynamic”限制

概述

在本文中,我们将重点分析如何绕过Firefox内容安全策略中的“Strict-Dynamic”限制。该漏洞详情请参考: https://www.mozilla.org/en-US/security/advisories/mfsa2018-11/#CVE-2018-5175 。该漏洞将绕过内容安全策略(CSP)的保护机制,而在该机制中包含一个“严格动态限制”的Script-src策略。如果目标网站中存在HTTP注入漏洞,攻击者可以将一个引用注入到require.js库的一个副本中,这个库位于Firefox开发人员工具之中,攻击者随后便可以使用已知技术,利用该库绕过CSP限制,从而执行注入脚本。

关于“Strict-Dynamic”

各位读者可能已经阅读过内容安全策略的规范( https://www.w3.org/TR/CSP3/#strict-dynamic-usage ),但在这里,我还是有必要先对“Strict-Dynamic”(严格动态限制)进行解释。如果读者已经完全掌握相关知识,可以跳过本节的阅读。 众所周知的内容安全策略(CSP)限制,其原理是通过将域名列入白名单来限制资源的加载。举例来说,下面的CSP设置仅允许从其自身的来源和trusted.example.com域名加载JavaScript:

Content-Security-Policy: script-src 'self' trusted.example.com

由于这个内容安全策略的存在,即使在页面中存在XSS漏洞,该页面也无法通过内联脚本或evil.example.org的JavaScript文件来执行JavaScript脚本。这一策略看起来确实足够安全,但是,如果在trusted.example.org中存在任何绕过内容安全策略的脚本,那么就仍然可以执行JavaScript。更具体地说,如果在trusted.example.com中存在一个JSONP端点,那么就有可能被绕过,如下所示:

<script src="//trusted.example.com/jsonp?callback=alert(1)//"></script>

如果此端点直接将用户输入的参数传递给callback函数,那么就可以执行任意脚本,示例中的脚本如下:

alert(1)//({});

另外,目前已知AngularJS也可以用于绕过内容安全策略。这种绕过方式的利用可能会更为实际,特别适用于允许托管许多JavaScript文件(如CDN)的域名。 这样一来,即使在白名单中,有时也很难通过内容安全策略来保障安全性。为了解决这一问题,就设计了“Strict-Dynamic”的限制。其用法示例如下:

Content-Security-Policy: script-src 'nonce-secret' 'strict-dynamic'

这就意味着白名单将被禁用,并且只有在nonce属性中具有“secret”字符串的脚本才会被加载。

<!-- This will load -->
<script src="//example.com/assets/A.js" nonce="secret"></script>

<!-- This will not load -->
<script src="//example.com/assets/B.js"></script>

在这里,A.js可能想要加载并使用另一个JavaScript。为了实现这一点,内容安全策略规范中允许具有正确nonce属性的JavaScript,在特定条件下加载没有正确nonce属性的JavaScript。使用规范中的关键词,就可以允许非解析型脚本(Parser-Inserted Script)元素执行JavaScript。 示例如下:

/* A.js */

//This will load
var script=document.createElement('script');
script.src='//example.org/dependency.js';
document.body.appendChild(script);

//This will not load
document.write("<scr"+"ipt src='//example.org/dependency.js'></scr"+"ipt>");

当使用createElement()加载时,它是一个非解析型脚本元素,该加载动作被允许。另一个反例是,使用document.write()加载时,它是一个解析型脚本元素(Parser-Inserted Script Element),所以不会被加载。 到目前为止,我已经大致地解释了“Strict-Dynamic”。顺便要提一句,“Strict-Dynamic”在某些情况下是可以被绕过的。下面我就介绍一种已知的“Strict-Dynamic”的绕过方式。

已知的Strict-Dynamic绕过方法

如果在目标页面中使用特定的库,那么Strict-Dynamic就可以被绕过。 该绕过方式已经由Google的Sebastian Lekies、Eduardo Vela Nava、Krzysztof Kotowicz进行测试,受影响的库请参见: https://github.com/google/security-research-pocs/blob/master/script-gadgets/bypasses.md 。 接下来,我们来看看这个列表中借助require.js实现Strict-Dynamic绕过的方法。 假设目标页面使用了Strict-Dynamic的内容安全策略,并且加载require.js,同时具有简单的XSS漏洞。在这种情况下,如果输入以下脚本元素,攻击者就可以在没有正确的nonce的情况下执行任意JavaScript。

<meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-secret' 'strict-dynamic'">
<!-- XSS START -->
<script data-main="data:,alert(1)"></script>
<!-- XSS END -->
<script nonce="secret" src="require.js"></script>

当require.js找到一个具有data-main属性的脚本元素时,它会加载data-main属性中指定的脚本,其等效代码如下:

var node = document.createElement('script');
node.url = 'data:,alert(1)';
document.head.appendChild(node);

如前所述,Strict-Dynamic允许从createElement()加载没有正确nonce的JavaScript脚本。这样一来,就可以借助某些已经加载的JavaScript代码行为,在某种情况下绕过内容安全策略的Strict-Dynamic。而在Firefox中的漏洞,正是由于require.js的这种情况引起的。

通用Strict-Dynamic绕过漏洞(CVE-2018-5175)

Firefox使用一些传统的扩展实现了部分浏览器功能。在Firefox 57版本中,移除了基于XUL/XPCOM的扩展,但没有移除WebExtensions。即使是在最新的60版本中,浏览器内部仍然使用这种机制。 要利用这一漏洞,我们首先要借助浏览器内部使用的传统扩展资源。在WebExtensions中,通过在manifest中设置web_accessible_resources项( https://developer.mozilla.org/en/Add-ons/WebExtensions/manifest.json/web_accessible_resources ),就可以从任何网页中访问所列出的资源。传统扩展中有一个名为contentaccessible标志的类似选项( https://developer.mozilla.org/ja/docs/Mozilla/Chrome_Registration#contentaccessible )。我们这一漏洞,正是通过将contentaccessible标志设置为yes,从而让浏览器内部资源的require.js可以被任意Web页面访问,最终实现内容安全策略的绕过。 接下来,我们具体分析一下manifest。如果是Windows环境下的64位Firefox,我们可以通过以下URL查看到manifest: jar:file:///C:/Program%20Files%20(x86)/Mozilla%20Firefox/browser/omni.ja!/chrome/chrome.manifest

content branding browser/content/branding/ contentaccessible=yes
content browser browser/content/browser/ contentaccessible=yes
skin browser classic/1.0 browser/skin/classic/browser/
skin communicator classic/1.0 browser/skin/classic/communicator/
content webide webide/content/
skin webide classic/1.0 webide/skin/
content devtools-shim devtools-shim/content/
content devtools devtools/content/
skin devtools classic/1.0 devtools/skin/
locale branding ja ja/locale/branding/
locale browser ja ja/locale/browser/
locale browser-region ja ja/locale/browser-region/
locale devtools ja ja/locale/ja/devtools/client/
locale devtools-shared ja ja/locale/ja/devtools/shared/
locale devtools-shim ja ja/locale/ja/devtools/shim/
locale pdf.js ja ja/locale/pdfviewer/
overlay chrome://browser/content/browser.xul chrome://browser/content/report-phishing-overlay.xul
overlay chrome://browser/content/places/places.xul chrome://browser/content/places/downloadsViewOverlay.xul
overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
override chrome://global/content/license.html chrome://browser/content/license.html
override chrome://global/content/netError.xhtml chrome://browser/content/aboutNetError.xhtml
override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
resource search-plugins chrome://browser/locale/searchplugins/
resource usercontext-content browser/content/ contentaccessible=yes
resource pdf.js pdfjs/content/
resource devtools devtools/modules/devtools/
resource devtools-client-jsonview resource://devtools/client/jsonview/ contentaccessible=yes
resource devtools-client-shared resource://devtools/client/shared/ contentaccessible=yes

上面的倒数第2、3行,就是使文件可以从任意Web站点访问的部分。这两行用于创建一个resource: URI( https://developer.mozilla.org/en-US/docs/Mozilla/Chrome_Registration#resource )。倒数第三行中,resource devtools 会将devtools/modules/devtools/目录映射到resource://devtools/,该目录存在于jar:file:///C:/Program%20Files%20(x86)/Mozilla%20Firefox/browser/omni.ja!/chrome/devtools/modules/devtools/ 。 现在,我们可以使用Firefox,通过resource://devtools/来访问目录下的文件。同理,倒数第二行是映射到resource://devtools-client-jsonview/ 。该URL可以通过contentaccessible=yes标志来实现Web访问,我们现在可以从任意Web页面加载放在该目录下的文件。 在该目录中,有一个用于绕过内容安全策略的require.js。只需要将该require.js加载到使用内容安全策略Strict-Dynamic的页面中,即可实现Strict-Dynamic的绕过。 实际绕过操作如下: https://vulnerabledoma.in/fx_csp_bypass_strict-dynamic.html

<meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-secret' 'strict-dynamic'">
<!-- XSS START -->
<script data-main="data:,alert(1)"></script>
<script  src="resource://devtools-client-jsonview/lib/require.js"></script>
<!-- XSS END -->

在这段代码中,我们看到,data:URL将作为JavaScript资源加载,并且会弹出一个警告对话框。 各位读者可能会想,为什么会加载require.js?由于脚本元素没有正确的nonce,理论上它应该会被内容安全策略所阻止。 实际上,无论对内容安全策略设置多么严格的规则,扩展程序的Web可访问资源都会在忽略内容安全策略的情况下被加载。这种行为在内容安全策略的规范中也有所提及: https://www.w3.org/TR/CSP3/#extensions “Policy enforced on a resource SHOULD NOT interfere with the operation of user-agent features like addons, extensions, or bookmarklets. These kinds of features generally advance the user’s priority over page authors, as espoused in [HTML-DESIGN].” “对资源执行的策略不应该干扰用户代理功能(如插件、扩展或书签)进行的操作。这些类型的功能通常会提高用户的优先级,正如[HTML-DESIGN]中所提到的。” Firefox的resource: URI也存在这一规则。受此影响,用户甚至可以在设置了内容安全策略的页面上使用扩展的功能,但另一方面,这一特权有时会被用于绕过内容安全策略,本文所提及的漏洞就是如此。 当然,这个问题不仅仅出现在浏览器内部资源。即使在通用浏览器扩展中,如果有可以用于绕过内容安全策略的Web可访问资源,也会发生同样的情况。 根据推测,Firefox的开发人员是通过将页面的内容安全策略应用到resource: URI中,从而实现对这一漏洞的修复。

总结

在本文中,我们对于Firefox的内容安全策略Strict-Dynamic漏洞进行了分析。该漏洞是我在Cure53 CNY XSS Challenge 2018竞赛( https://github.com/cure53/XSSChallengeWiki/wiki/CNY-Challenge-2018 )的第三级题目解题过程中发现的。在该竞赛中,我使用了另一个技巧来绕过Strict-Dynamic,如果各位读者有兴趣,可以详细查看。此外,我还创建了这个XSS挑战赛的另一个版本( https://twitter.com/kinugawamasato/status/984014228469280768 ),也期待有兴趣的同学能够参与。 最后,感谢Google团队进行的研究,从而让我关注到这一漏洞。谢谢!

本文翻译自 https://mksben.l0.cm/, 原文链接 。如若转载请注明出处。

原文地址:https://cloud.tencent.com/developer/article/2095033

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340