Thoughts on a DOM XSS and jQuery

遇到一个疑似DOM XSS的漏洞。发现问题URL中的问题参数在页面并没有输出点。于是对关联的js脚本进行分析,可见在某js代码中,对当前URL的参数进行了提取,将所有的url参数提取到了params变量中。

如下图:
kingx's blog
跟踪params变量,发现在有输出的地方都进行了html编码:

kingx's blog
看样子好像都跨不了了。
继续往下看,好像看到了一些有趣的东西:
kingx's blog

这里params是可控的,并且没有过滤,也就是说这里可以控制$()选择器中定位符的部分内容。
我们知道使用jquery构造临时html元素也是可能造成跨站的。如: $(‘<img src=xx onerror=alert(1)>’)。那这里可不可以构造这样的语句进行跨站呢,比较纠结的是,在params.type参数之前 已经有一些”input[name=type]”这些定位字符串了。经过多次尝试,结果表示都不行,浏览器会抛出表达式解析错误的异常。
这里,我们对jquery()方法进行一些说明,$()是jquery()的另一种写法。jquery官方api中是这么说的:
jQuery基于传入的参数在DOM树中进行查找,或者基于传入的html字符串创建一个元素,并返回这些元素。
而jquery()有三种重载的方法:

jQuery( selector [, context ] )
接收一个包含css选择器的字符串来匹配相应的dom元素。
jQuery( html [, ownerDocument ] )
接收一个原始的html字符串来创建一个dom元素。
jQuery( callback )
绑定一个dom对象加载完成后的回调函数。

这里,jQuery就需要判定传入的字符串到底是CSS选择器还是HTML代码,从而进行不同的操作。那能否在包含选择器代码的情况下,构造原始的HTML跨站代码进行跨站呢?也就是我们之前遇到的那种情景。
于是,我们翻阅了jQuery源代码,跟踪到jQuery中的init方法,可以看到
kingx blog

jQuery代码中使用了一个正则去匹配,判断所传入的参数是那种类型的字符串。
对这个正则进行分析,意思比较明确。其中(?:)表示只进行匹配而不保存匹配到的结果,通常和逻辑符号或(|)一起使用。
而这个正则的意思就是匹配第一个非空字符为<或者#的字符串

  • 如果是<则被认为是HTML代码,从而当做HTML代码进行解析。
  • 如果是#,则会调用document.getElementById( match[2] ),查找对应的元素。
  • 如果均未匹配到,则把它当做css选择器,调用( context || rootjQuery ).find( selector )查找相应的元素。

这样看来,一开始那个DOMXSS的可疑点,由于$(”)方法参数的字符串中前面存在”input”等选择器字符串,所以无法当做是html代码来进行解析。无法进行DOMXSS。

这里,顺便说一下jQuery(<=1.6.2)版本中的DOMXSS, 漏洞版本中的相应的匹配正则表达式为:

/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

这样当<前面存在其他字符时,也可以进行匹配。
所以像$(location.hash)这样的代码,就可以执行任意跨站语句了。可以在上面图片中代码的官方注释中看到相应的说明。

Leave a comment

Your email address will not be published. Required fields are marked *