La expansión de entidades sin restricciones puede resultar en una vulnerabilidad
de DoS en REXML.

A esta vulnerabilidad se le ha asignado el identificador CVE-2013-1821.

Les recomendamos actualizar Ruby cuanto antes.

## Detalles

Cuando se leen nodos de texto de un documento XML, el parser de REXML puede ser
forzado a poner en memoria objetos de cadena muy grandes que pueden terminar
consumiendo toda la memoria de una computadora, causando DoS (negación del servicio).

Código afectado puede verse de esta manera:

<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>

Cuando se llama a el método \`text\`, las entidades se exapnden. Un atacante
puede enviar un documento XML relativamente pequeño que cuando se intenten resolver
sus entidades se consumirán cantidades excesivamente grandes de memoria en el
sistema atacado.

Este ataque es similar pero diferente al ataque del billón de risas. Tambien
está relacionado a la vulnerabilidad CVE-2013-1664 de Python.

Todos los usuarios con una versión afectada por esta entrega deberian actualizar
o usar una versión de las soluciones inmediatamente.

## Soluciones

Si no puedes actualizar Ruby, puedes utilizar este parche como solución temporal:

<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>

Este parche limitará el tamaño de las entidades a 10k por nodo. REXML ya tiene como
limite predispuesto permitir solo 10000 substituciones de entidades por documento,
asi que el tamaño máximo de texto que puede ser generado mientras se substituye una entidad
será de aproximadamente 98 megabytes.

## Versiones afectadas

* Todas las versiones de ruby 1.9 anteriores a 1.9.3-p392
* Todas las versiones de ruby 2.0 anteriores a 2.0.0-p0
* Todo lo anterior a la revisión 39384

## Historia

* Agregar el numero CVE 2013-03-11 07:45:00 (UTC)
* Publicado originalmente 2013-02-22 12:00:00 (UTC)
