Неограниченное расширение сущности может привести к DoS уязвимости в
REXML. Этой уязвимости присвоен CVE идентификатор CVE-2013-1821.
Мы строго рекомендуем обновить ruby.

## Детали

Во время чтения текстовых нод XML документа, парсер REXML может быть
вынужден к резервированию экстремально больших строковых объектов,
которые могут растратить всю память машины, вызвав недоступность
сервиса (DoS).

Опасный код может выглядеть как-то так:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">document</span> <span class="o">=</span> <span class="no">REXML</span><span class="o">::</span><span class="no">Document</span><span class="p">.</span><span class="nf">new</span> <span class="n">some_xml_doc</span>
<span class="n">document</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">text</span></code></pre></figure>

Когда вызывается метод \`text\`, сущности раскрываются. Атакующий может
послать относительно небольшой XML документ так, что когда сущности
будут раскрываться, их вложенности будут потреблять экстремально большое
количество памяти атакованной системы.

Заметьте, что данная атака похожа на Billion Laughs атаки, хотя и имеет
некоторые отличия. Это также относится к CVE-2013-1664 уязвимости Python.

Все пользователи, использующие затронутые релизы, должны либо
обновиться, либо использовать один из обходных путей.

## Обходные пути

Если вы не можете обновить Ruby, используйте этот манкипатч как обходной
путь:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">REXML::Document</span>
  <span class="vc">@@entity_expansion_text_limit</span> <span class="o">=</span> <span class="mi">10_240</span>

  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">entity_expansion_text_limit</span><span class="o">=</span><span class="p">(</span> <span class="n">val</span> <span class="p">)</span>
    <span class="vc">@@entity_expansion_text_limit</span> <span class="o">=</span> <span class="n">val</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">entity_expansion_text_limit</span>
    <span class="vc">@@entity_expansion_text_limit</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="k">class</span> <span class="nc">REXML::Text</span>
  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">unnormalize</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">doctype</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span> <span class="n">filter</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span> <span class="n">illegal</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
    <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">string</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span> <span class="sr">/\r\n?/</span><span class="p">,</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span> <span class="p">).</span><span class="nf">gsub</span><span class="p">(</span> <span class="no">REFERENCE</span> <span class="p">)</span> <span class="p">{</span>
      <span class="n">s</span> <span class="o">=</span> <span class="nb">self</span><span class="p">.</span><span class="nf">expand</span><span class="p">(</span><span class="vg">$&amp;</span><span class="p">,</span> <span class="n">doctype</span><span class="p">,</span> <span class="n">filter</span><span class="p">)</span>
      <span class="k">if</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">s</span><span class="p">.</span><span class="nf">bytesize</span> <span class="o">&gt;</span> <span class="no">REXML</span><span class="o">::</span><span class="no">Document</span><span class="p">.</span><span class="nf">entity_expansion_text_limit</span>
        <span class="k">raise</span> <span class="s2">"entity expansion has grown too large"</span>
      <span class="k">else</span>
        <span class="n">sum</span> <span class="o">+=</span> <span class="n">s</span><span class="p">.</span><span class="nf">bytesize</span>
      <span class="k">end</span>
      <span class="n">s</span>
    <span class="p">}</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">expand</span><span class="p">(</span><span class="n">ref</span><span class="p">,</span> <span class="n">doctype</span><span class="p">,</span> <span class="n">filter</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">ref</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">?#</span>
      <span class="k">if</span> <span class="n">ref</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="sc">?x</span>
        <span class="p">[</span><span class="n">ref</span><span class="p">[</span><span class="mi">3</span><span class="o">...-</span><span class="mi">1</span><span class="p">].</span><span class="nf">to_i</span><span class="p">(</span><span class="mi">16</span><span class="p">)].</span><span class="nf">pack</span><span class="p">(</span><span class="s1">'U*'</span><span class="p">)</span>
      <span class="k">else</span>
        <span class="p">[</span><span class="n">ref</span><span class="p">[</span><span class="mi">2</span><span class="o">...-</span><span class="mi">1</span><span class="p">].</span><span class="nf">to_i</span><span class="p">].</span><span class="nf">pack</span><span class="p">(</span><span class="s1">'U*'</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">elsif</span> <span class="n">ref</span> <span class="o">==</span> <span class="s1">'&amp;amp;'</span>
      <span class="s1">'&amp;'</span>
    <span class="k">elsif</span> <span class="n">filter</span> <span class="ow">and</span> <span class="n">filter</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span> <span class="n">ref</span><span class="p">[</span><span class="mi">1</span><span class="o">...-</span><span class="mi">1</span><span class="p">]</span> <span class="p">)</span>
      <span class="n">ref</span>
    <span class="k">elsif</span> <span class="n">doctype</span>
      <span class="n">doctype</span><span class="p">.</span><span class="nf">entity</span><span class="p">(</span> <span class="n">ref</span><span class="p">[</span><span class="mi">1</span><span class="o">...-</span><span class="mi">1</span><span class="p">]</span> <span class="p">)</span> <span class="ow">or</span> <span class="n">ref</span>
    <span class="k">else</span>
      <span class="n">entity_value</span> <span class="o">=</span> <span class="no">DocType</span><span class="o">::</span><span class="no">DEFAULT_ENTITIES</span><span class="p">[</span> <span class="n">ref</span><span class="p">[</span><span class="mi">1</span><span class="o">...-</span><span class="mi">1</span><span class="p">]</span> <span class="p">]</span>
      <span class="n">entity_value</span> <span class="p">?</span> <span class="n">entity_value</span><span class="p">.</span><span class="nf">value</span> <span class="p">:</span> <span class="n">ref</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

Этот манкипатч ограничивает размер вложенностей каждой сущности до 10k
на ноду. REXML уже по умолчанию настроен на 10000 вложенностей сущности
на документ, так что максимальное количество текста, который может быть
сгенерирован из вложенностей сущностей должен быть около 98 мегабайт.

## Затронутые сущности

* Все версии ruby 1.9 до ruby 1.9.3 patchlevel 392
* Все версии ruby 2.0 до ruby 2.0.0 patchlevel 0
* транк до ревизии 39384

## Благодарности

Спасибо Ben Murphy за сообщение о данной проблеме.

## История

* Добавлено о CVE номере 2013-03-11 07:45:00 (UTC)
* Оригинал опубликован 2013-02-22 12:00:00 (UTC)
