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


    内容安全策略绕过 CSP Bypass

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

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

    1 Low Level

    源码:

    
    
    # 指定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' ] .= "
        
    ";
    }
    $page[ 'body' ] .= '
    

    You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:

    '
    ;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    源码对HTTP头部定义了CSP标签,定义了可以接受外部JavaScript资源的白名单,可以通过抓包确认是哪些网站;

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

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

    在这里插入图片描述

    2 Medium Level

    源码:

    
    
    # script src有了新的变化,unsafe-inline允许执行页面内嵌的
    
    ?>
    <?php
    if (isset ($_POST['include'])) {
    $page[ 'body' ] .= "
        " . $_POST['include'] . "
    ";
    }
    $page[ 'body' ] .= '
    

    Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.

    '
    ;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    源码中nonce参数无任何过滤,对其进行注入即可。将绕过案例内容复制到输入框内,进行绕过弹窗测试。
    在这里插入图片描述

    3 High Level

    源码:

    
    
    $headerCSP = "Content-Security-Policy: script-src 'self';";
    
    header($headerCSP);
    
    ?>
    <?php
    if (isset ($_POST['include'])) {
    $page[ 'body' ] .= "
        " . $_POST['include'] . "
    ";
    }
    $page[ 'body' ] .= '
    

    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.

    1+2+3+4+5=

    # script src指向了source/high.js代码文件 '
    ;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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 > 元素的直接访问,对于定义了框架集的文档将引用最外层的,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();
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    jsonp.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).")";
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注入代码:include=

    4 Impossible Level

    源码:

    
    
    $headerCSP = "Content-Security-Policy: script-src 'self';";
    
    header($headerCSP);
    
    ?>
    <?php
    if (isset ($_POST['include'])) {
    $page[ 'body' ] .= "
        " . $_POST['include'] . "
    ";
    }
    $page[ 'body' ] .= '
    

    Unlike the high level, this does a JSONP call but does not use a callback, instead it hardcodes the function to call.

    The CSP settings only allow external JavaScript on the local server and no inline code.

    1+2+3+4+5=

    '
    ;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    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();
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    jsonp_impossible.php代码:

    
    header("Content-Type: application/json; charset=UTF-8");
    
    $outp = array ("answer" => "15");
    # outp值被锁死
    echo "solveSum (".json_encode($outp).")";
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

  • 相关阅读:
    【数据结构与算法】链表
    Imagery in Action | Week6 影像服务
    安装Ruby和安装Rails详细步骤详解
    c++之顺序容器
    ArcGIS Pro SDK 003 如何调用Toolbox
    ROS Action通信
    高通导航器软件开发包使用指南(16)
    就业这么难,十个软件测试项目帮你简历优化!
    什么是AB实验?能解决什么问题?终于有人讲明白了
    建材批发小程序微信上线开发
  • 原文地址:https://blog.csdn.net/qq_42197548/article/details/126410365