白帽故事 · 2025年7月21日 0

化腐朽为神奇:将 Self-XSS 升级为真正可利用的 XSS 漏洞

巧妙绕过 Referer 来源验证

在对一个电商网站进行安全测试时,白帽小哥发现了一处接口,它会将用户传入的参数值,未经任何处理就直接显示在返回的页面内容中。

具体来说,就在 /ajax/popup_login_bootstrap.php 这个接口中,通过 source_url 参数发现了一处反射型 XSS (跨站脚本攻击) 漏洞。

file

从上图可以清楚地看到,source_url 参数的值被原封不动地呈现在了响应页面里。

file

当尝试将请求的 Referer 头从合法的 www.target.co.uk 修改为 www.target.couk 时,服务器返回了 403 Forbidden 错误,拒绝了请求。

file

这说明服务器后台正在检查 Referer 头部,要求其中必须包含 www.target.co.uk 字符串。

在目前这种情况下,这最多算是一个 Self-XSS 漏洞,也就是说,我们只能对自己执行 XSS 攻击,无法影响到其它用户。

那么,我们该如何将其升级成一个真正有威胁的漏洞呢?

Self-XSS 的华丽变身

要完成整个攻击链,白帽小哥采取了以下几个步骤:

  1. 搭建一个 Python Flask 服务器,用它来托管一个我们精心构造的恶意页面。这个页面的 URL 设置为 evil.com/target.co.uk/exploit.html。这样做是为了让 URL 中包含 target.co.uk 字符串,从而满足服务器对 Referer 的验证规则

  2. 关键一步:在我们搭建的“恶意服务器”上,设置一个特殊的 HTTP 响应头:Referrer-Policy: unsafe-url,这个设置能确保当用户从我们的恶意页面跳转时,浏览器会在 Referer 头部发送完整的、未经删减的 URL

  3. 诱导用户访问我们的恶意页面,一旦用户点击页面上的链接,他们就会被自动重定向到目标网站存在漏洞的接口,从而成功触发 XSS 攻击

解读 Referrer-Policy 响应头

HTTP 的 Referrer-Policy 响应头,是用来控制浏览器在跨域请求时,应该在 Referer 头部中包含多少引荐来源信息的策略。

它可以被设置为多种不同的值,例如:

  • Referrer-Policy: no-referrer
  • Referrer-Policy: no-referrer-when-downgrade
  • Referrer-Policy: origin
  • Referrer-Policy: origin-when-cross-origin
  • Referrer-Policy: same-origin
  • Referrer-Policy: strict-origin
  • Referrer-Policy: strict-origin-when-cross-origin
  • Referrer-Policy: unsafe-url

file

file

file

在我们的攻击场景中,目标是让 Referer 头部完整地包含我们的恶意 URL (evil.com/target.co.uk/exploit.html),因此,我们必须选择 unsafe-url 这个策略。

PoC (概念验证) 代码

使用下面这段简单的 Flask 代码快速搭建了恶意服务器:

import requests
from bs4 import BeautifulSoup
import re
from urllib.parse import parse_qs, urlencode
from flask import Flask, make_response, jsonify, request, render_template
from flask_cors import CORS
from flask import Flask, render_template

app = Flask(__name__)

# 为两个不同的路径注册同一个处理函数
@app.route('/')
@app.route('/target.co.uk/evil.html')
def index():
    # 渲染 xss.html 模板文件
    response = make_response(render_template('xss.html', the_title='XSS POC'))
    # 设置关键的响应头
    response.headers["Referrer-Policy"] = 'unsafe-url'
    return response

这段代码的作用是,当用户访问 /target.co.uk/evil.html 这个路径时,服务器会返回 xss.html 页面的内容。

xss.html 文件中则包含了真正的攻击链接:

<a href="https://www.target.co.uk/ajax/popup_login_bootstrap.php?source_url=%27%22%3e%3c%69%6d%67%20%73%72%63%3d%78%20%6f%6e%65%72%72%6f%72%3d%61%6c%65%72%74%28%64%6f%6d%61%69%6e%29%20%2f%3e">点我触发攻击</a>

为了让这个攻击能够在互联网上被访问到,可以使用 ngrok 工具,将本地的恶意服务器暴露在公网上。

file

从上图可以看到,我们服务器的响应头中,Referrer-Policy 确实已经被设置为了 unsafe-url

file

当受害者点击我们页面上的链接时,浏览器会将完整的 Referer 头部 (evil.com/target.co.uk/evil.html) 发送到目标服务器。

由于这个 URL 满足了其正则表达式的检查规则,服务器返回了 200 OK 的正常响应。

最终,我们的 XSS 攻击载荷 (payload) 被未经任何编码地插入到返回页面中,成功执行!

file

你学到了么?

原文:https://infosecwriteups.com/transforming-self-xss-to-exploitable-xss-part-1-9f2d0f94f807