Ruby Sanitize<5.2.1的HTML sanitization绕过

发布于 2017-08-29 17:05:17

2020年6月16日,发布了有关Ruby Sanitize库的安全公告,该公告涉及其RELAXED配置可能导致完全绕过该库的问题。我在Securitum进行的渗透测试中发现了这个错误,在这篇文章中,我将解释我如何提出绕过的想法并展示它是如何工作的。

Sanitize介绍

本节包含有关HTML清理器的概念及其工作方式的基本信息。如果您熟悉此主题,则可以安全地跳到下一部分。

Sanitize是一个充当HTML清理程序的Ruby库。其目标是获取不受信任的HTML标记,删除潜在的不安全元素和属性,并生成新的“安全”HTML。实际上,Sanitize是基于白名单列表的,这意味着它将删除列表中未包含的所有元素和属性。您可以定义自己的白名单列表(例如,您可能只希望允许<b><i>标签),但是这有一些预定义的白名单。在本文中,我将专门讨论名为RELAXED的配置,其中包含以下允许的元素列表:

a abbr address article aside bdi bdo blockquote body br caption cite
code col colgroup data dd del dfn div dl dt figcaption figure footer 
h1 h2 h3 h4 h5 h6 head header hgroup hr html img ins kbd li main mark 
nav ol p pre q rp rt ruby s samp section small span strike  sub 
summary sup sup table tbody td tfoot th thead time  tr ul var wbr

通常,消毒剂的工作可以概括为三个步骤:

  • 将HTML解析为DOM树。
  • 从DOM树中删除不允许的元素和属性。
  • 将新的DOM树序列化为HTML标记。

举例来说,让我们看看Sanitize如何处理以下标记:

ABC<>alert(1)</><img src=1 onerror=alert(2)>

它被解析为以下DOM树:

标签和onerror属性不在白名单中,将被删除。这将导致以下DOM树:

并在序列化之后:

ABC<img src="1">

总而言之,由于进行了过滤,最初的不安全HTML被重写为安全形式。

STYLE的实体编码和解码

Sanitize库的白名单列表包含元素;这看起来很有希望,因为它表现出一些特定的行为。首先,HTML解析器不会解码<>内的HTML实体。看下面的HTML:

<div>I <3 XSS</div>
<>I <3 XSS</>

它被解析为以下DOM树:

注意到实体&lt;<div>中被解码为<,但是在<>中根本没有被解码。
类似地,大多数元素的文本内容的序列化会产生转义的文本(即&"<>分别用&amp;&quot;&lt;&gt;替换),但是对于某些元素(例如<>),该文本按字面意义呈现。
考虑以下DOM树:

它被实体编码为:

<div>I &lt;3 XSS</div>
<>I <3 XSS</>

请注意,<<div>中实体编码为&lt;,但在<>中未编码。
字符不能在<>中进行转义的情况具有重要作用:如果<>中的字符内容是<><img src onerror=alert(1)> ,如下面的DOM树:


然后将其序列化为:

<></><img src onerror=alert(1)>

并且当再次解析序列化格式时,将引入XSS。 HTML规范中直接提到了这种风险:

仍然存在的问题是:如何在STYLE元素内放置文本</>

外部内容

HTML规范具有一个称为外部内容的安全性问题潘多拉盒。简而言之,当在标记中打开<svg><math>标签时,就会引入外部内容;并且解析发生了巨大的变化。我在上一节中提到的<>的两个特征不再成立。如果<><svg><math>的子元素,在DOM解析时会对HTML实体进行解码,并在序列化时对字符进行HTML编码。

看一个简单的例子:

<svg><>I &lt;3 XSS

它被解析为以下DOM树:

请注意,&lt;解码为<,而<><svg>的父元素的情况则不是这种情况。DOM树被序列化回:

<svg><>I &lt;3 XSS</></svg>

同样,在<><svg>的父元素的情况,在<><不会被实体编码为&lt;

Sanitize绕过

回到重点上,让我们看看如何绕过Sanitize库。RELAXED配置允许使用<>元素,但不允许使用<svg><math>元素。Sanitize使用Google Gumbo解析器,它是HTML5兼容的解析器,因此它完全了解我上面提到的所有细节。

Sanitize还可以对CSS规则进行消毒处理,但是将任意内容放入<>的简单技巧就是利用注释符进行处理。</p> <p>因此,绕过payload如下:</p> <div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">svg</span><span class="p">&gt;&lt;</span><span class="nt"></span><span class="p">&gt;</span><span class="err">/*&amp;lt;/&gt;&amp;lt;img src onerror=alert(1)*/</span> </pre></div> <p>让我们逐步分析原因。首先,Sanitize将HTML解析为以下DOM树:</p> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20200729091644-2ad022d2-d139-1.png" alt=""></p> <p><code>&lt;svg&gt;</code>不在白名单列表中,并被删除。但是,<code>&lt;svg&gt;</code>的内容会被忽略。因此,此时的DOM树如下:</p> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20200729091739-4b759904-d139-1.png" alt=""></p> <p>没有更多要清除的内容,因此代码被序列化为:</p> <div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt"></span><span class="p">&gt;</span><span class="o">/*</span><span class="p">&lt;/</span><span class="nt"></span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">src</span> <span class="na">onerror</span><span class="o">=</span><span class="s">alert(1)</span><span class="p">&gt;</span>*/ </pre></div> <p>这将导致XSS。</p> <h2>总结</h2> <p>Ruby Sanitize库存在一个安全问题,如果网站使用<code>RELAXED</code>配置,则可以完全绕过它。在我的报告之后,删除<code>&lt;svg&gt;</code>和<code>&lt;math&gt;</code>元素的默认行为已更改,以便它们的内容也被删除。</p> <p>参考:<a href="https://research.securitum.com/html-sanitization-bypass-in-ruby-sanitize-5-2-1/">https://research.securitum.com/html-sanitization-bypass-in-ruby-sanitize-5-2-1/</a></p> </>


4 条评论