前置知识
Content Security Policy(内容安全策略),用于定义脚本和其他资源从何处加载或者执行,总结的来说就时白名单。会一定程度的缓解xss脚本问题,也可以自己设定规则,管理网站允许加载的内容。
CSP 以白名单的机制对网站加载或执行的资源起作用,在网页中策略通过 HTTP 头信息或者 meta 元素定义。CSP 虽然提供了强大的安全保护,但是它也令 eval() 及相关函数被禁用、内嵌的 JavaScript 代码将不会执行、只能通过白名单来加载远程脚本。如果要使用 CSP 技术保护自己的网站,开发者就不得不花费大量时间分离内嵌的 JavaScript 代码和做一些调整。
Content Security Policy (CSP) Bypass(Security Level: low)
代码分析
<?php
$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com hastebin.com www.toptal.com example.com code.jquery.com https://ssl.google-analytics.com https://digi.ninja ;"; // allows js from self, pastebin.com, hastebin.com, jquery, digi.ninja, and google analytics.
header($headerCSP);
# These might work if you can't create your own for some reason
# https://pastebin.com/raw/R570EE00
# https://www.toptal.com/developers/hastebin/raw/cezaruzeka
?>
<?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>
<p>
As Pastebin and Hastebin have stopped working, here are some scripts that may, or may not help.
</p>
<ul>
<li>https://digi.ninja/dvwa/alert.js</li>
<li>https://digi.ninja/dvwa/alert.txt</li>
<li>https://digi.ninja/dvwa/cookie.js</li>
<li>https://digi.ninja/dvwa/forced_download.js</li>
<li>https://digi.ninja/dvwa/wrong_content_type.js</li>
</ul>
<p>
Pretend these are on a server like Pastebin and try to work out why some work and some do not work. Check the help for an explanation if you get stuck.
</p>
源码对http头进行csp定义,接受指定的外部javascript资源的白名单(抓包时可以看到的)
漏洞利用
前面说过了,只允许特定的网站我们先抓个包看一下
注意Content-Security-Policy
上面有几个网站Pastebin.com - #1 paste tool since 2002!
注意检查游览器是不是允许xss
将这个网站下载该文件的文件地址
Content Security Policy (CSP) Bypass(Security Level: 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> 标签和事件监听函数,nonce 值会在每次 HTTP 回应给出一个授权 token。
漏洞利用
我们需要通过内连注入
<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert("1")</script>
Content Security Policy (CSP) Bypass(Security Level: high)
代码分析
vulnerabilities/csp/source/high.php
<?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>
';
vulnerabilities/csp/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.在high.php中设置了csp头,规定只允许从同源的脚本加载
2.提交表单的时候,如果存在POST形式的include参数
3.游览器执行clickbutton,动态创建<script>元素,将src属性设置为‘source/jsonp.php?callback=solveSum’(json.php是一个远程脚本的url)
4.加载远程脚本,返回数据给solveSum,展示到页面
漏洞利用
include控制的参数可以更改
那么我们构造一下
Content Security Policy (CSP) Bypass(Security Level: impossible)
代码分析
vulnerabilities/csp/source/impossible.php
<?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>
';
vulnerabilities/csp/source/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();
});
}
-
在代码开始处,通过设置
Content-Security-Policy
头部字段,指定了一个 CSP 设置,即script-src 'self';
。这个设置规定只允许从同域名加载 JavaScript 脚本,并且不允许使用内联脚本。 -
接下来的条件语句检查是否存在名为
include
的 POST 参数。如果存在该参数,将其内容添加到$page['body']
变量中。 -
然后创建一个包含说明文本和一个空
<span>
元素的表单,表单的提交方法是 POST。 -
表单中有一个按钮元素,点击该按钮会触发一个事件,调用名为
clickButton()
的 JavaScript 函数。 -
页面加载了一个名为
source/impossible.js
的 JavaScript 文件,通过<script>
标签引入。 -
source/impossible.js
中定义了一个名为clickButton()
的函数。该函数会创建一个新的<script>
元素,并将其src
属性设置为source/jsonp_impossible.php
,然后将该元素添加到页面的<body>
元素中。 -
source/impossible.js
中还定义了一个名为solveSum(obj)
的函数,用于处理异步加载的远程脚本返回的数据。如果返回的数据包含answer
属性,该函数会将该属性值设置为页面中的<span id="answer">
元素的内容。 -
最后,通过获取按钮元素并添加点击事件监听器,实现了按钮点击后调用
clickButton()
函数的功能。
总的来说,这段代码使用 Content Security Policy(CSP)限制了 JavaScript 代码的来源和类型,同时对用户输入进行了处理。可以有效地提高了安全性。