文章总结: 文章介绍了嵌套解析器情况下的XSS漏洞,解释了当数据经过多个解析器串行处理时,后一个解析器可能不知道前一个解析器已生成HTML标签,导致XSS攻击。通过PHP示例展示了URL解析器和邮箱解析器串行处理时,由于正则表达式贪婪匹配,导致HTML结构被破坏,最终触发XSS漏洞的过程。文章强调了在开发中需要注意多个解析器串行处理数据时的安全性问题。
综合评分: 87
文章分类: WEB安全,漏洞分析,渗透测试
嵌套解析器情况下的XSS
原创
Pwn1
漏洞集萃
2025年12月8日 14:55
山东
免责声明
本公众号所发布的文章内容仅供学习与交流使用,禁止用于任何非法用途。
什么是嵌套解析器情况下的XSS
嵌套解析器:这里的“嵌套”并不是指代码写成了嵌套结构,而是指数据的处理流程是串行的,导致一段被转换过的 HTML 代码,又被扔进了下一个解析器里处理。
开发眼中预期的工作逻辑:
用户输入一段话 → 经过 URL 解析器 → 经过邮箱解析器 → 输出 HTML。
漏洞原因:
但是如果第二个解析器(如邮箱解析器)并不知道第一个解析器(URL 解析器)已经生成了 HTML 标签,就会导致payload被构造暴露出来;
举个例子
这里有一个PHP的例子,假设有一个函数先转换 URL 为链接,再转换 Email 为链接。
输入:
http://google.com/[email protected]?subject='onmouseover='alert(1)'
预期:应该生成一个包含 URL 的 <a> 标签。
实际:
- 1. URL 解析器先工作,生成了一个 href 属性,如
<a href="http://example.com/[email protected]">链接</a> - 2. Email 解析器随后工作,在 URL 解析器生成的 href 属性值内部,又插入了一个
<a href="mailto:...">标签。 - 3. 结果:HTML 结构被破坏,原本属于 Email 的属性值引号提前闭合了 URL 的 href 属性,导致
onmouseover变成了一个独立的事件处理属性,触发 XSS。
我们来看一段示意代码:
<?php
function returnCLickable($input)
{
$input = preg_replace('/(http|https|files):\/\/[^\s]*/', '<a href="${0}">${0}</a>', $input);
$input = preg_replace('/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)(\?\w*=[^\s]*|)/', '<a href="mailto:${0}">${0}</a>', $input);
$input = preg_replace('/\n/', '<br>', $input);
return $input . "\n\n";
}
$message = returnCLickable(htmlspecialchars($_REQUEST['msg']));
?>
不想搭建web的话可以直接使用这段代码进行执行在线上的php在线运行工具运行这一部分代码
<?php
$input = "http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'";
function returnCLickable($input)
{
$input = preg_replace('/(http|https|files):\/\/[^\s]*/', '<a href="${0}">${0}</a>', $input);
$input = preg_replace('/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)(\?\w*=[^\s]*|)/', '<a href="mailto:${0}">${0}</a>', $input);
$input = preg_replace('/\n/', '<br>', $input);
return $input . "\n\n";
}
$message = returnCLickable(htmlspecialchars($input));
echo $message;
?>
这段代码的运行结果就是:
原始输入
http://foo.com/[email protected]?hack='onmouseover='alert(1)
第一阶段输出(URL解析器处理后)
<a href="http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'">
http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'
</a>
第二阶段输出(Email解析器再次处理后)
<a href="http://google.com/<a href="mailto:[email protected]?subject='qwe'onmouseover='alert(1)'">
http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'
</a>">
[email protected]?subject='qwe'onmouseover='alert(1)'">
http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'
</a></a>
其中,正则
/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)(\?\w*=[^\s]*|)/
试图匹配邮箱及其参数。
问题所在:正则中的 [^\s]*(匹配非空白字符)非常贪婪。
首先,它在 href 属性内部找到了 [email protected]。
紧接着,它通过 ?subject= 匹配了参数部分。
那么由于整个 HTML 字符串中间没有空格(直到结尾),[^\s]* 会吞掉闭合的引号 "、闭合的标签 > 甚至后面的 </a>。
匹配到的内容(MATCH):
[email protected]?subject='qwe'onmouseover='alert(1)'">http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'</a>
它将这部分内容替换为 <a href="mailto:MATCH">MATCH</a>,导致出现了嵌套且混乱的 HTML 结构。
浏览器是从左到右解析的,我们来分析下最终形成的DOM结构:
<body>
<a href="https://google.com/<a href=" mailto:[email protected]?subject="qwe" onmouseover="alert(1)" "="">
http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'
</a>">[email protected]?subject='qwe'onmouseover='alert(1)'">
http://google.com/[email protected]?subject='qwe'onmouseover='alert(1)'
</body>
其中
- •
<a href=":开始一个标签,开始 href 属性。 - •
https://google.com/<a href=浏览器读到这里,遇到了第二个双引号"。 - • 浏览器认为第一个属性的值结束了!
- • 随后
mailto:[email protected]?subject被作为属性名,而onmouseover也因此被逃逸了出来。 - • 那么剩下的其他值则是作为文本数据存在。
觉得本文内容对您有启发或帮助?
点个关注➕,获取更多深度分析与前沿资讯!
👉 往期精选
信息收集最强OSINT姿势:Google一搜,全球程序员的密码、API Key、邮箱全裸奔
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:漏洞集萃 Pwn1《嵌套解析器情况下的XSS》