Ruby: Denial-of-Service-Attacke durch XML-Fehler

Eine Sicherheitslücke in Ruby hat zur Folge, dass ein entfernter Angreifer Denial-of-Service-Attacken durchführen kann. Hierzu muss er ein XML-Dokument konstruieren, welches den REXML-Parser dazu bringt sehr viel Speicher zu verbrauchen.
Das Problem tritt beim Verarbeiten von bestimmten Text-Nodes in XML-Dokumenten auf. Hier kann es passieren, dass sehr grosse String-Objekte alloziert werden, die den gesamten Speicher des Systems dann verbrauchen. Diese Schwachstelle ähnelt der Billion Laughs Attacke und dem CVE-2013-1664 Sicherheitsleck von Python.  Eine Billion Laughs Attacke wird beispielsweise mit folgendem XML-Code
ausgeführt:

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

Wer sein Ruby-System nicht updaten möchte, kann den folgenden Workaround
verwenden, um die Attacke zu verhindern:

class REXML::Document
  @@entity_expansion_text_limit = 10_240
  def self.entity_expansion_text_limit=( val )
    @@entity_expansion_text_limit = val
  end
  def self.entity_expansion_text_limit
    @@entity_expansion_text_limit
  end
end
class REXML::Text
  def self.unnormalize(string, doctype=nil, filter=nil, illegal=nil)
    sum = 0
    string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
      s = self.expand($&, doctype, filter)
      if sum + s.bytesize > REXML::Document.entity_expansion_text_limit
        raise "entity expansion has grown too large"
      else
        sum += s.bytesize
      end
      s
    }
  end
  def self.expand(ref, doctype, filter)
    if ref[1] == ?#
      if ref[2] == ?x
        [ref[3...-1].to_i(16)].pack('U*')
      else
        [ref[2...-1].to_i].pack('U*')
      end
    elsif ref == '&amp;'
      '&'
    elsif filter and filter.include?( ref[1...-1] )
      ref
    elsif doctype
      doctype.entity( ref[1...-1] ) or ref
    else
      entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
      entity_value ? entity_value.value : ref
    end
  end
end

Betroffen sind die Versionen 1.9.3 Patchlevel 392 und 2.0.0 Patchlevel 0.

E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben