Content Security Policy (CSP) Bypass

前言

内容安全策略,  全称: Content Security Policy (CSP)。

为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。

以白名单的机制对网站加载或执行的资源起作用。在网页中,这样的策略通过两种方法定义:

1.  HTTP 头信息Content-Security-Policy的字段

2.  网页的meta 元素定义

CSP虽然提供了强大的安全保护,但是他也造成了如下问题:Eval及相关函数被禁用、内嵌的JavaScript代码将不会执行、只能通过白名单来加载远程脚本。这些问题阻碍CSP的普及,如果要使用CSP技术保护自己的网站,开发者就不得不花费大量时间分离内嵌的JavaScript代码和做一些调整。

更多关于CSP的请参考:   Content Security Policy 入门教程

CSP之所以可以绕过,是因为策略的制定不够合理,从而让攻击者有了可乘之机

下面分析四种不同等级的漏洞:

 

 

  • Low

服务端核心代码:

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

# https://pastebin.com/raw/R570EE00

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
	<script src='" . $_POST['include'] . "'></script>
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
	<p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
	<input size="50" type="text" name="include" value="" id="include" />
	<input type="submit" value="Include" />
</form>
';

服务端中定义了CSP策略 (允许的脚本来源) :

self,(本地)

https://pastebin.com

example.com

code.jquery.com

https://ssl.google-analytics.com

将过滤后的include参数作为script脚本执行 (加载外部资源)。

且可以看到在响应头中有Content-Security-Policy的字段,  里面包含了允许加载的外部资源:

 

漏洞利用

先说明一下策略 self,  他是允许服务端加载自身的网站资源,  如果不允许加载本网站的资源, 这样网站也没啥用了..

访问本地网站目录下的xss0A.js文件, 内容如下

alert(1);

然后看看CSP策略中允许的其他资源-----https://pastebin.com

这个被信任的网址是可编辑脚本的 !!!  (在实战中,  要攻击A,  可以转为攻击A的CSP策略中的网址B,  从而进一步拿下A )

我们编辑一个js:

然后使目标机include该网址:

https://pastebin.com/raw/88f0vL4U

这样我们就可以在被目标网站信任的网站上做好攻击脚本,   诱使受害者点击即可以完成攻击。

 

 

  • Medium

服务端核心代码:

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";

header($headerCSP);

// Disable XSS protections so that inline alert boxes will work
header ("X-XSS-Protection: 0");

# <script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
	" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
	<p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p>
	<input size="50" type="text" name="include" value="" id="include" />
	<input type="submit" value="Include" />
</form>
';
  • 引申知识点:

除了常规值,script-src还可以设置一些特殊值。注意,下面这些值都必须放在单引号里面。

  • unsafe-inline:允许执行页面内嵌的<script>标签和事件监听函数
  • unsafe-eval:允许将字符串当作代码执行,比如使用evalsetTimeoutsetIntervalFunction等函数。
  • nonce值:每次HTTP回应给出一个授权token,页面内嵌脚本必须有这个token,才会执行
  • hash值:列出允许执行的脚本代码的Hash值,页面内嵌脚本的哈希值只有吻合的情况下,才能执行。

nonce值的例子如下,服务器发送网页的时候,告诉浏览器一个随机生成的token。

Content-Security-Policy: script-src 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA='

页面内嵌脚本,必须有这个token才能执行。比如服务端中的:

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>

服务端正是引用了nonce和unsafe-inline来防止攻击

 

漏洞利用

只要我们在注入js标签中加入nonce属性即可:

<script nonce='TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA='>alert(1)</script>

 

不过这样直接攻击太明显了,   用户不会去点击模式的js标签的,  所以我们可以进一步对其进行包装等

 

 

  • High

服务端核心代码:

<?php
$headerCSP = "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
	" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
	<p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p>
	<p>1+2+3+4+5=<span id="answer"></span></p>
	<input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/high.js"></script>
';

在High级别中,  CSP策略只允许加载本地资源。

 

漏洞利用

既然CSP不允许请求外部资源,  我们只能从内部入手了, 可以看到在服务端的代码中执行本地的high.js:

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    document.body.appendChild(s);
}

function solveSum(obj) {
	if ("answer" in obj) {
		document.getElementById("answer").innerHTML = obj['answer'];
	}
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
	solve_button.addEventListener("click", function() {
		clickButton();
	});
}
  • clickButton():点击按钮后,在页面上创建<script src="source/jsonp.php?callback=solveSum"></script>
  • solveSum(obj):将answer写入页面。

获取按钮,点击触发clickButton事件,这个受到 jsonp.php 的callback参数控制,  当参数值为solveSum函数的时候,  将会调用 solveSum函数进行计算。

攻击者可以通过修改callbakc的参数值为恶意脚本,  从而完成攻击。

比如通过注入将上面high.js代码第三行的

s.src = "source/jsonp.php?callback=solveSum"; 改为: s.src = "source/jsonp.php?callback=alert(1)";

 

上面是思路,  接下来我们来具体分析网站:

点击solve the sum按钮,  抓个包:

将参数callback的值改为:

然后forward,  弹窗成功:

 

 

 

  • Impossible

服务端核心代码:

<?php

$headerCSP = "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
	" . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
	<p>Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.</p><p>The CSP settings only allow external JavaScript on the local server and no inline code.</p>
	<p>1+2+3+4+5=<span id="answer"></span></p>
	<input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/impossible.js"></script>
';

可以看到服务端在impossible级别中,  和high级别也是差不多,  区别就在于是用impossible.js

我们可以看看impossible.js:

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp_impossible.php";
    document.body.appendChild(s);
}

function solveSum(obj) {
	if ("answer" in obj) {
		document.getElementById("answer").innerHTML = obj['answer'];
	}
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
	solve_button.addEventListener("click", function() {
		clickButton();
	});
}

可以看到,  在clickButton函数中,  去掉了high级别的缺陷----应用callback参数,  转而应用jsonp_impossible.php

直接把js写固定了,  杜绝了注入漏洞。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值