欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 前端技术 > HTML >内容正文

HTML

html中alert的用法_【渗透实战】通过HTML命名空间混淆绕过DOMPurify实现XSS

发布时间:2025/3/19 HTML 26 豆豆
生活随笔 收集整理的这篇文章主要介绍了 html中alert的用法_【渗透实战】通过HTML命名空间混淆绕过DOMPurify实现XSS 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
点击上方蓝字关注我们1概述本篇文章主要介绍了如何绕过主流的HTML杀毒程序库DOMPurify。DOMPurify是一款使用JavaScript编写的的HTML过滤库,可以处理来自用户的不受信任的HTML片段,删除可能导致跨站脚本攻击(XSS)的所有元素及属性。具体的绕过方法如下所示:<form><math><mtext>form><form><mglyph><style>math><img src onerror=alert(1)>以上代码没有任何多余的元素,为了理解具体的绕过原理,我们需要先了解HTML规范的一些特性。2DOMPurify用法

我们首先了解下DOMPurify通常是如何使用的。假设我们需要将html Markup中一个不受信任的HTML赋值给某个div,我们可以通过以下代码使用DOMPurify对该内容进行过滤,在赋值给div:

div.innerHTML = DOMPurify.sanitize(htmlMarkup)

在解析、系列化以及处理DOM树的过程中,上诉代码实际上会执行以下操作:

  • htmlMarkup被解析为DOM树

  • DOMPurify过滤DOM树(简而言之,这个过程中DOMPurify会遍历DOM树中的所有元素以及属性,并删除不在允许列表中的所有节点)

  • DOM树被序列化回HTML标记

  • 赋值给innerHTML之后,浏览器将再次解析HTML标记

  • 解析的DOM树被附加到文档的DOM树中

  • 来看个简单的示例。假设我们的初始标记为AB。在第一步中,它会被解析到以下树中:然后,DOMPurify对其进行过滤后,剩下以下DOM树:将其系列化后得到以下内容:A<img src="1">B

    这就是DOMPurify.sanitize返回的结果。然后浏览器在赋值给innerHTML时会再次解析该标记。

    DOM树与DOMPurify处理过的树相同,然后将其附加到目标文档中。

    简而言之,按顺序,以上过程可以总结成:解析->序列化->解析。直观上,大家可能会觉得系列化DOM树,并再次解析后,应该会返回初始的DOM树,但事实并非如此。

    HTML规范中,关于系列化HTML片段的警告信息表明:如果使用HTML解析器进行解析,则此算法[序列化HTML]的输出可能不会返回初始的树结构。HTML解析器本身也有可能输出不往返序列化和重新解析步骤的树结构,尽管这种情况通常不符合要求。

    值得注意的是,序列号-重新解析的往返操作并不一定能返回初始的DOM树,这也是造成mutation XSS(突变XSS) 的根本原因。通常这类情况是由于某些解析器、序列化器错误所导致的结果,但有两种特殊情况符合上诉警告信息所描述的场景。

    3嵌套FORM元素

    其中一种情况涉及FORM元素,它是HTML里非常特殊的一个元素,因为它本身不能嵌套。HTML规范中,明确指出FORM元素不可以是某个FORM元素的后继。

    可以在任何浏览器中使用以下标记进行验证:

    <form id=form1>INSIDE_FORM1<form id=form2>INSIDE_FORM2

    该片段会生成以下DOM树:

    第2个form在DOM树中会被完全忽略,就像从未存在过一样。

    接下来是比较有趣的部分。如果我们继续阅读HTML规范,会发现它实际上给出了一个示例,该示例通过带有错误嵌套标签的标记成功创建了一个嵌套式表单。如下所示:

    <form id="outer"><div>form><form id="inner"><input>

    结果会生成以下包含一个嵌套表单元素的DOM树:

    这并不是特定浏览器的bug,它直接来自HTML规范,并且在解析HTML的算法中也有描述。大意如下所示:

    • 当我们打开标签时,解析器需要记录该标签是由表单元素指针打开的。如果指针不为空,则无法创建表单元素。

    • 当我们结束标签时,表单元素指针始终设置为null。

    因此,回到以下片段:

    <form id="outer"><div>form><form id="inner"><input>

    首先,表单元素指针设置为id =“outer”,然后开始解析div,碰到闭合标签后,表单元素指针会被设置为null。由于指针为null,因此可以创建下一个id=“ inner”的表单。并且由于我们当前位于div内,因此可以成功创建一个嵌套式表单。

    现在,如果我们尝试序列化生成的DOM树,将获得以下标记:

    <form id="outer"><div><form id="inner"><input>form>div>form>

    值得注意的是,该标记将不包含任何错误嵌套的标签。当再次解析标记时,将创建以下DOM树:

    综上,我们证明了经过序列化、重解析后并不一定能返回原始的DOM树。更有趣的是,这基本上是一种符合规范的突变。

    当我发现这一点后,便意识到可以通过某种方式滥用这种特性以绕过HTML过滤器。思考了很久后,偶然间发现HTML规范中的另一个异常点。在继续讨论该问题前,我们先来了解下HTML规范中的潘多拉魔盒:外部内容(foreign content)。

    4外部内容

    外部内容就好比一把瑞士军刀,可以用来破坏解析器及过滤器。该方法曾被我用来绕过DOMPurify以及Ruby过滤库。

    HTML解析器可以使用三个命名空间元素创建DOM树: 

    • HTML命名空间(http://www.w3.org/1999/xhtml) 

    • SVG命名空间(http://www.w3.org/2000/svg) 

    • MathML命名空间(http://www.w3.org/1998/Math/MathML) 

    默认情况下,所有元素都位于HTML命名空间中。但是,如果解析器遇到或元素,则它将分别“切换”到SVG和MathML命名空间。这两个命名空间都会产生外部内容。

    在外部内容中,标记的解析过程与普通的HTML不同。尤其是在解析


    思考以下标记:

    <style><a>ABCstyle><svg><style><a>ABC

    它将被解析成以下DOM树:

    备注:从现在开始,本文DOM树中的所有元素都将包含一个命名空间。因此html style意味着它是HTML命名空间中的


    最终的DOM树证实我的观点:html style仅包含文本内容,而svg style会像普通元素一样被解析。 


    继续分析,我们可能会猜想:如果我们位于或内部,则所有元素也都会位于非HTML命名空间中。但事实并非如此,HTML规范中包含MathML文本集成点和HTML集成点,这些元素的子元素都具有HTML命名空间(但某些情况除外)。 


    思考以下示例:

    <math><style>style><mtext><style>style>

    它将被解析成以下DOM树

    请注意观察,在MathML命名空间中,style元素是如何成为math的直接子元素的,而mtext中的style元素则位于HTML命名空间中。这是因为mtext是MathML文本集成点,并使用解析器切换命名空间。


    MathML文本集成点包括:


    • math mi

    • math mo

    • math mn

    • math ms


    HTML集成点包括:


    • math annotation-xml(如果其具有encoding属性,并且属性值等于text/html或者application/xhtml+xml)

    • svg foreignObject

    • svg desc

    • svg title

    我之前一直以为MathML文本集成点或HTML集成点的所有子级,默认情况下都具有HTML命名空间,但事实并非如此。HTML规范指出,默认情况下,MathML文本集成点的子级都位于HTML命名空间中。但有两种例外情况:mglyph和malignmark。只有当它们是MathML文本集成点的直接子级时,才会发生这种情况。


    我们可以通过以下标记进行检查:

    注意,作为mtext的直接子元素的mglyph在MathML命名空间中,而作为html元素的子元素的mglyph在HTML命名空间中。


    假设我们想确定一个“当前元素”的命名空间。此时我已经制定了一些经验法则:


    • 非满足以下条件,否则当前元素将位于其父元素的命名空间中

    • 如果当前元素为或,且其父元素在HTML命名空间中,则当前元素分别位于SVG或MathML命名空间中。 

    • 如果当前元素的父元素是HTML集成点,则当前元素位于HTML命名空间中除非它是或。 

    • 如果当前元素的父元素是MathML集成点,则当前元素位于HTML命名空间中,除非它是,,或。

    • 如果当前元素是,,

      ,,
      ,,,,,,, ,,

      ,,,,,
    • ,,,,,,

      ,,,,或,并定义了color,face或size属性,那么堆栈上的所有元素将关闭,直到看到MathML文本集成点、HTML集成点或HTML命名空间中的元素为止。然后,当前元素也会位于HTML命名空间中。

    当我在HTML规范中找到mglyph时,马上就意识到这是滥用html form突变以绕过过滤器的方法。
    5
    DOMPurify绕过


    因此,让我们回到绕过DOMPurify的有效载荷上:有效载荷利用了错误嵌套的html form元素,并且包含mglyph元素,它将生成以下DOM树:该DOM树是无害的,所有元素都在DOMPurify的允许列表中。值得注意的是,mglyph位于HTML命名空间中,而看起来像XSS有效载荷的代码片段只是html style中的一个文本。由于存在一个嵌套的html form,所以我们可以确定此DOM树将在重新解析时发生突变。


    因此,这里DOMPurify不会执行任何操作,将返回序列化的HTML:



    该片段具有嵌套的Form标签。因此,当其赋值给innerHTML时,将被解析成以下DOM树:所以现在没有创建第二个html表单,mglyph为mtext的直接子元素,这意味着它位于MathML命名空间中。因此,style同样位于MathML命名空间中,且其内容不会被视为文本来解析。然后, math>会闭合元素,现在会在HTML名称空间中创建img,从而导致XSS。


    6总结


    以上绕过方式可以总结成以下几点:


    DOMPurify的典型使用方法致使HTML标记被解析两次

    HTML规范中存在特殊情况,可以创建嵌套form元素。但是,在重新解析时,第二个form会被忽略

    mglyph和malignmark是HTML规范中的特殊元素,即使默认情况下其他所有标签都位于HTML命名空间中,但如果它们是MathML文本集成点的直接子元素,那么它们也将位于MathML命名空间中。

    结合以上几点,我们可以创建一个具有两个form元素和mglyph元素的标记,这些标记最初位于HTML命名空间中,但是在重新解析时位于MathML命名空间中,从而使后续的style标签的解析方式有所不同,导致XSS。


    end




    好文!必须在看

    总结

    以上是生活随笔为你收集整理的html中alert的用法_【渗透实战】通过HTML命名空间混淆绕过DOMPurify实现XSS的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。