LEXSS: 绕过词法解析过程中的安全机制 - mss****

admin 2021年12月31日15:59:40评论95 views字数 6681阅读22分16秒阅读模式

通过使用基于HTML解析逻辑的特殊HTML标签,可以实现跨站脚本(XSS)攻击,即使在使用词法解析器过滤危险内容的情况下也是如此。利用这些类型的XSS漏洞的主要目标,就是让净化型词法解析器将数据视为文本数据,而不是计算机指令(例如,JavaScript指令)。当HTML解析器和净化型词法解析器没有以相同的方式解析数据时,就有可能导致这种类型的攻击。

关键概念介绍

注意:对本文来说,我们假定读者已经接触过XSS(更准确的说是JavaScript注入)方面的知识,并且对HTML有基本的了解。要想了解更多的入门知识,请参阅我们的XSS概述文章

针对XSS漏洞的保护措施

实际上,针对XSS漏洞的保护措施有多种形式。比如,早期的防御措施,就是利用正则表达式(regex)来检查用户输入的“危险”字符串。一个简化的例子是,如果用户提供的输入包含<script>,那么,就通过正则表达式找到该字符串并将其删除。然而,这种基于正则表达式的XSS保护措施经常出现失误,因为可以通过各种方法构造出能够顺利绕过正则表达式的JavaScript代码串。对于上面的例子来说,只需将<script>中的一个字母变为大写(如<scRipt>),就可以绕过这种过滤器,从而导致XSS攻击。因此,我们不建议使用正则表达式过滤器来防御XSS。
所以,让我们来谈谈更好的解决方案。上下文输出编码是另一种XSS保护形式,它会将特殊字符(如“<”和“>”)转化为无害的HTML编码输出(例如,“&lt;”和“&gt;”)。这种形式的保护将用户的输入放在源文件中,以确保所有可能导致JavaScript执行或HTML渲染的JavaScript或HTML可用字符都转换为不危险的HTML实体编码形式。这是处理在应用程序中呈现的用户输入的好方法;事实上,许多现代前端框架都会默认进行输出编码(例如,ReactJS和Angular)。然而,这种形式的保护会对应用程序施加某些限制,也就是禁止用户使用某些支持富文本的HTML特性。
如果用户需要支持某些HTML特性,如图片、链接和富文本等,那该怎么办呢?这就是词法解析发挥作用的地方。

通过词法解析防御XSS攻击

词法解析是一种非常复杂的XSS防御手段,因为它在执行额外的逻辑(如对数据进行分块或编码)之前,会评估数据是指令还是明文。抽象的说,词法解析可以被描述为将用户数据(即不危险的文本内容)与计算机指令(即JavaScript和某些危险的HTML标签)分离开来的过程。在想让用户使用HTML子集的情况下,这种类型的解析可以用来确定哪些是允许的内容,哪些将被阻止或过滤掉。
上面所说的想让用户使用的HTML子集的例子,包括富文本编辑器、电子邮件客户端、What-You-See-Is-What-You-Get(WYSIWYG)HTML编辑器,如TinyMCE或Froala,以及DOMPurify等净化库。在这些例子中,这种形式的词法解析保护是非常常见的。
然而,当HTML解析器和净化型词法解析器不是以完全相同的方式处理数据时,就可以将词法解析作为一种XSS保护形式。这篇文章主要讨论在某些情况下,尽管有复杂的保护措施,但仍有可能通过利用HTML解析逻辑来欺骗词法解析器,注入JavaScript代码。为了了解如何利用这些XSS问题,我们必须首先考察HTML是如何解析的;数据处理过程中的注意事项和特殊情况;以及净化型解析器是如何工作的。

数据是如何流经HTML解析器的

要了解我们如何在一个对HTML输入应用词法解析的应用程序中实现XSS攻击,我们首先必须看看HTML是如何被解析的,以及如何确定内容是数据还是指令。下图展示的是HTML解析器的操作顺序:
现在,我们对这些步骤简单加以说明:

  • 网络阶段:这个阶段指的是将输入作为字节传输给解析器。
  • 分词器阶段:分词是进行词法解析的地方。解析器将把文本数据与计算机指令分开。要做到这一点,分词器将根据它遇到的元素在数据状态之间切换上下文,并将值作为单词返回。这将在“上下文状态”部分详细介绍。
  • 树形结构阶段:从分词器阶段返回的单词被放置在一个树形结构中;每个树形分支都被称为一个节点。为了更清楚地了解它们在实践中到底是什么样子的,让我们来看看下面的HTML片段:
    <!DOCTYPE html>
    <body>
    <div>
    Hello World 
    <a href=https://bishopfox.com>Example</a></div>
    </body>
    

    下图显示了这在文档对象模型(DOM)树状结构中的样子。

作为攻击者,他们的目标是在HTML解析的这个阶段控制节点。正如我的导师Joe DeMesy曾经向我描述的那样,如果你能控制一个节点的上下文和内容,就能发动XSS攻击。

  • 脚本执行阶段:这个阶段是指通过JavaScript代码修改DOM的时候。关于这个阶段的其他细节不在本文的讨论范围之内。
  • DOM阶段:构建文档对象模型的处理的最终状态。
    现在,我们已经对数据如何在HTML解析过程中流动以及信息如何组织有了一个高层次的理解,这将在漏洞利用过程中发挥重要作用。
    ## HTML解析器的上下文状态
    在分词阶段,HTML解析器将把HTML元素分为不同类别的数据状态,称为“上下文状态”。HTML规范中列出了上下文状态的切换元素,具体如下:
    可以将HTML解析器的分词阶段的状态设置为:

    title
    textarea
    

    将分词器切换为RCDATA状态。

    style
    xmp
    iframe
    noembed
    noframes
    

    将分词器切换为RAWTEXT状态。

    script
    

    将分词器切换为脚本数据状态。

    noscript
    

    如果启用了scripting标签,则将分词器切换到RAWTEXT状态。否则,让分词器留在数据状态。

    plaintext
    

    将分词器切换为PLAINTEXT状态。

    其他元素
    

    让分词器处于数据状态。

下面介绍这些上下文状态在实践中的样子。
RCDATA示例:
输入:

<textarea><img src=x></textarea>

输出:

<textarea>&alt;img src=x&gt;</textarea>

输出内容的快照:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
DOM树:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
RAWTEXT示例
输入:

<xmp><img src=x></xmp>

输出:

<xmp><img src=x></xmp>

输出的屏幕截图:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
DOM树:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
数据示例:
输入:

<img src=x>

输出:

<img src=x>

输出内容的快照:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
DOM树:

请注意,数据状态是唯一试图加载图像的状态。这是因为数据是一种计算机指令,而不是简单的文本数据。
重点提示:提供的不同元素可以通过切换数据的上下文状态来改变这些元素中数据的解析和呈现方式。

命名空间:外来内容以及利用意外的行为

浏览器的HTML解析器不仅可以理解HTML;它还可以在三种不同的命名空间之间切换:HTML、MathML和SVG。
在HTML解析过程中,如果遇到<svg>或<math>命名空间元素(标签),解析器会将上下文切换到相应的命名空间。这种上下文切换对我们来说意味着解析器不再作为HTML进行解析,而是作为MathML或SVG进行解析。
当HTML被嵌入到MathML/SVG中时,这种命名空间的上下文切换会导致意想不到的行为,因为每个命名空间都有自己独特的元素,解析方式也略有不同。作为渗透测试人员,我们可以在某些情况下利用这种逻辑把解析器搞蒙圈,从而浑水摸鱼发动XSS攻击。
这里有一篇关于如何绕过DOMPurify的文章,其中对命名空间的混淆进行了更深入的研究,包括前沿的研究和一个很棒例子。
重点提示:当HTML解析器遇到MathML或SVG元素时,会将上下文切换到独立的命名空间,这可以用来让解析器产生混淆。

净化型词法解析器的工作流程

为了利用净化型词法解析器,我们需要了解其工作的流程;概括来说,主要流程如下所示:

  • 用户提供的数据被浏览器的HTML解析器解析为HTML。
  • 词法解析器对数据进行分析和过滤。
  • 浏览器的HTML解析器再次对数据进行解析。
    这个流程如下图所示:
    LEXSS: 绕过词法解析过程中的安全机制 -  mss****
    攻击的目的就是提供相应的HTML来欺骗净化解析器,使其相信所提供的输入是无害的文本数据(RCDATA、PLAINTEXT或RAWTEXT),而它实际上是计算机指令(数据状态)。这通常是可能做到的,原因有多个:HTML的设计之初,并没有考虑到需要解析两次;在最初的HTML解析器和解析解析器之间可能会出现细微的解析差异;净化解析器通常会实现自己的处理逻辑。

测试案例1: TinyMCE XSS

TinyMCE是一个“所见即所得”(WYSIWYG)的HTML文本编辑器和JavaScript库。它通常包含在第三方网站中,提供文本编辑功能,包括HTML文本。
CVE-2020-12648(TinyMCE中的XSS漏洞)是由George Steketee和我发现的;在这里,它将作为一个测试案例,演示在使用净化型解析器的情况下,如何利用HTML解析警告来发动XSS攻击。按照TinyMCE的介绍,XSS是通过以下payload实现的:

<iframe><textarea></iframe><img src="" onerror="alert(document.domain)">

这个payload之所以能够成功,因为在分词和DOM树构造阶段有一个安全问题。准确来说,当HTML被词法解析器重新解析时,它在分配上下文状态之前没有正确考虑到元素的顺序。
<iframe>元素导致上下文状态切换为RAWTEXT,这意味着iframe后面的数据被认为是没有危害的,不需要进行过滤处理。这种上下文切换在</iframe>的关闭标签处结束。然而,<textarea>元素也会令解析器切换到RCDATA上下文,即另一种形式的非危险文本数据。当HTML解析器处理iframe元素时,切换到RCDATA的上下文的指示就包含在这些元素中。这种包含是TinyMCE解析器没有意识到的。
当进行上述解析时,TinyMCE解析器实际上并没有考虑正确的操作顺序和上下文切换问题。因此,HTML解析器最终生成的DOM树如下所示:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
以上是TinyMCE的解析器“看走眼的”结果,实际的数据是这样的:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
请注意,具有活动内容onerror事件的img元素位于DOM树的文本上下文中;当进行词法解析时,这将被视为没有危害的,不会被剥离或进行编码处理。由于textarea元素包含在iframe中,而img元素实际上并不在textarea元素中。因此,活动内容(JavaScript)将被执行,从而实现XSS。

 测试案例2:Froala XSS

Froala是一个所见即所得(WYSIWYG)的HTML文本编辑器和JavaScript库,其功能与TinyMCE类似。对于第二个测试案例,我们将审查作为这项研究的一部分而发现的一个XSS漏洞(CVE-2021-28114)。在这个CVE的公告中,详细介绍了如何使用以下payload实现XSS:

<math><iframe><!--</iframe><img src onerror=alert("XSS")>

在功能方面,这个payload与测试案例1中讨论的TinyMCE XSS相同,但有一点需要注意:进入MathML命名空间虽然会导致解析混乱,但是,这并不足以让Froala的解析器彻底蒙圈。然而,由于Froala的解析器并不理解MathML命名空间的标签,因此,它会丢弃这些标签,并继续解析其余的内容。这样的结果是:对于HTML解析器创建的节点来说,其payload被限制为文本数据,具体如下面的树结构所示:
LEXSS: 绕过词法解析过程中的安全机制 -  mss****
然而,由于Froala的解析器遗漏了<math>元素,所以,它仍然会错误地将img元素的payload视为一个没有任何危害的注释。当JavaScript payload被最后阶段的HTML解析器处理并放入DOM时,它将会:

其结果是,XSS payload将得到执行。通过检查相应的源代码,可以进一步看清这一点:

<iframe><!--</iframe>
    <img src="" onerror="alert(&quot;XSS&quot;)" style="" class="fr-ficfr-dii"> --&gt;

Froala解析器删除了<math>元素,并添加了一个-->来结束它所认为的注释。最后阶段的HTML解析器将开头的注释视为是iframe元素中的,并将Froala解析器添加的、用于结束注释的元素设置为RCDATA状态,而不是把它看作一个有效的结束标签,其结果是主动内容得以执行(XSS)。

预防措施

当实现允许用户控制某些HTML元素的应用程序时,避免这些类型的错误的关键是,让HTML的解析结果尽可能地接近其本意。在这样做的时候,重要的是要考虑到元素的顺序和嵌入元素的上下文。如果HTML解析器对一个节点的看法与净化型解析器对一个节点的看法存在差异,那么在词法解析中就会出现这些XSS问题。当不需要MathML和SVG命名空间元素时,最好将其列入黑名单,并将包含这些元素的请求全部丢弃(即不要继续将数据写入DOM)。
对于那些不创建这些类型的解决方案,而是将它们纳入其应用程序的组织来说,一个好的补丁策略能在很大程度上缓解这种漏洞。同时,我们建议大家经常检查这些库的最新版本,并定期给它们打补丁。
除了代码/应用层面的安全防御措施外,企业还应在应用程序中实施内容安全策略(CSP)。一个定义良好的CSP可以在浏览器定义的层面上阻止JavaScript注入,从而创建一种深入防御的安全态势。此外,CSP应避免某些危险的指令,如unsafe-inline或unsafe-eval,因为这些指令可以执行用户定义的内联JavaScript代码。关于CSP的更多信息,请参考这篇内容丰富的文章

小结

即使对输入进行了词法解析,XSS仍有可能通过利用HTML解析和重新解析时的漏洞来实现,无论使用的是何种净化库。在测试这种类型的XSS时,我建议用各种命名空间和上下文切换元素对输入进行模糊测试处理,记录所有可疑的结果,并根据这些结果进行相应的处理。

参考资料

Whatwg - HTML Specification
https://html.spec.whatwg.org/multipage/parsing.html
W3 – HTML Parser Working Draft
https://www.w3.org/TR/2011/WD-html5-20110525/tree-construction.html
Securitum - DOM Purify Bypass
https://research.securitum.com/mutation-xss-via-mathml-mutation-dompurify-2-0-17-bypass/
Bishop Fox – TinyMCE v5.2.1 Advisory
https://labs.bishopfox.com/advisories/tinymce-version-5.2.1
Hixie – DOM Tree viewer
https://software.hixie.ch/utilities/js/live-dom-viewer/
Techopedia – Lexical Analysis Defined
https://www.techopedia.com/definition/8051/lexical-analysis
PortSwigger – Preventing XSS
https://portswigger.net/web-security/cross-site-scripting/preventing
OWASP – Contextual Output encoding
https://owasp.org/www-project-proactive-controls/v3/en/c4-encode-escape-data
Mozilla – Content Security Policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
CSP – CSP details
https://content-security-policy.com/

原文地址:https://labs.bishopfox.com/tech-blog/lexss-bypassing-lexical-parsing-security-controls

BY:先知论坛

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日15:59:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   LEXSS: 绕过词法解析过程中的安全机制 - mss****http://cn-sec.com/archives/713309.html

发表评论

匿名网友 填写信息