理论
CSP(Content Security Policy):即内容安全策略。点击这里有详细的介绍。
不过简单了解下就是指:开发者在开发过程中设置了一个类似于白名单的策略,要信任某个页面,哪些外部资源可以执行,哪些不可以,我们只需要配置规则,如何拦截由浏览器自己来实现。这可以从根本上防御XSS,如果CSP配置的好,可以从根本上杜绝XSS,相较于XSS漏洞,XSS更侧重于不能做哪些事,而CSP是只有哪些事可以做。
通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,另一种 是设置 meta 标签的方式 ,当启用CSP后,不符合CSP的外部资源会被阻止加载。
低级
查看源码
<?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 ;"; // 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://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>
';
从http头部也可以得到允许什么访问。
来自图中这几个网站就属于白名单,也就是说只有这几个网站的资源可以被加载。
script-src 'self’代表着只能加载符合同源策略的文件,直接插入至 html 页面中的静态 script 标签将无法执行。
其实在源码里DVWA有给我们提供一个用于测试的文件
就是这个,我们可以访问一下
现在假设这个文件就是我们自己写的,因为他的原地址是白名单里面包含的,所以按道理说我们引入这个文件页面应该会有弹窗输出pastebin,只要能弹出,我们就可像XSS一样拿到cookie,我们尝试一下复制这个网址,加载一下
发现并没有弹窗,而且网站会有报错,说我们上传的文件类型不符
这个其实靶场后期做的一个设置,text文件类型并不匹配,那我们就按照自己的方法做,重要的是一定要设置文件类型
打开https://pastebin.com/
文件类型一定要设置成JS文件,这样才不会出现上面的报错
download一下,下载好的文件其实就可以引用
出现弹窗,搞定
中级
查看源码
<?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>
';
在允许unsafe-inline的情况下,内嵌script都可以执行,当然可以直接执行本页面的JS,如输入即可
首先,代码通过设置$headerCSP变量定义了一个内容安全策略的头部。通过"script-src ‘self’ ‘unsafe-inline’ ‘nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=’"指令设置 nonce ,其目的是为了提供额外的安全性,确保只有具有相应 nonce 的脚本能够被执行。这样可以防止未经授权的脚本注入攻击。
然后使用header($headerCSP);将该内容安全策略头部应用于响应头。
接下来,通过header(“X-XSS-Protection: 0”);这行代码,禁用了浏览器的跨站脚本攻击(XSS)防护机制,以便内联的弹窗警告框能够正常工作。
接下来的代码段是一个表单,允许用户输入内容,并将该内容直接输出到页面中。用户可以在文本框中输入任意内容,这些内容将被添加到页面的主体部分。
unsafe-inline:允许使用内联资源,如内联
nonce-source:仅允许特定的内联脚本块
nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=”
总而言之就是我们加载的东西不仅要是固定网址里的还要携带特定标签。
这个时候我们可以直接引入特定的源码:
<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>
既是内联资源,又带有标签
高级
这里的源码包括两部分
<?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>
';
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();
});
}
高级源码限制了只能加载自己的文件
首先,在文件 high.php 中设置了一个 CSP 头部,规定只允许从同一源的脚本加载,即 script-src ‘self’。这样可以防止恶意代码的注入。然后,通过 PHP 的 header 函数将 CSP 头部发送给浏览器。
接下来,在表单提交时,如果存在名为 include 的 POST 参数,将其作为代码包含在页面主体中。
点击按钮时,会执行 JavaScript 函数 clickButton,该函数动态创建一个 script 元素,并设置其 src 属性为 source/jsonp.php?callback=solveSum。这里使用了 JSONP(JSON with Padding)技术,通过指定回调函数名称的方式来获取跨域的数据。当脚本加载完成后,会调用函数 solveSum,将返回的数据展示在页面上。
在文件 high.js 中定义了 clickButton 函数用于创建 script 元素并加载跨域脚本,以及 solveSum 函数用于处理返回的数据。最后,通过事件监听,当按钮被点击时,调用 clickButton 函数。
1.首先,浏览器会执行 JavaScript 函数 clickButton。
2.在 clickButton 函数中,会动态创建一个
由于 include 为可控参数且回调函数的名称solveSum可更改
故构造POC如下:
include=<script src="source/jsonp.php?callback=alert('hacked');"></script>
F12打开hackbar