Kerentanan DoS Ekspansi Entity pada REXML (Bom XML, CVE-2013-1821)

Ekspansi entity yang tak dibatasi dapat menyebabkan kerentanan DoS pada REXML. Kelemahan ini telah di-assign ke CVE dengan identifier CVE-2013-1821. Kami sangat menyarankan untuk meng-upgrade Ruby.

Rincian

Ketika membaca teks node dari dokumen XML, parser REXML dapat dipaksa untuk mengalokasikan objek string yang sangat besar yang dapat mengkonsumsi semua memori pada mesin, menyebabkan serangan denial of service.

Kode yang dapat menyebabkan masalah di atas terlihat seperti di bawah ini.

document = REXML::Document.new some_xml_doc
document.root.text

Ketika method `text` dipanggil, entitas akan diperluas. Penyerang dapat mengirimkan dokumen XML yang relatif kecil. Ketika entitas diresolusikan, sistem target akan mengkonsumsi sejumlah memori sangat besar.

Perhatikan bahwa serangan ini mirip dengan, tetapi berbeda dari serangan Billion Laughs. Hal ini juga terkait dengan CVE-2013-1664 dari Python.

Semua pengguna menjalankan rilis yang terkena dampak ini harus segera meng-upgrade atau menggunakan solusi lain.

Solusi-Solusi Lain

Jika Anda tidak dapat meng-upgrade Ruby, gunakan patch di bawah ini sebagai solusi lain.

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 == '&'
      '&'
    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

Monkey patch ini akan membatasi ukuran penggantian entity hingga 10 ribu per node. REXML already defaults to only allow 10000 entity substitutions per document, so the maximum amount of text that can be generated by entity substitution will be around 98 megabytes.

Versi yang Terkena Dampak

  • Semua ruby versi 1.9 sebelum ruby 1.9.3 patchlevel 392
  • Semua ruby versi 2.0 sebelum ruby 2.0.0 patchlevel 0
  • Sebelum trunk revisi 39384

Ucapan Terima Kasih

Terima kasih kepada Ben Murphy untuk melaporkan masalah ini.

History

  • Menambah nomor CVE pada 2013-03-11 07:45:00 (UTC)
  • Awalnya diterbitkan pada 2013-02-22 12:00:00 (UTC)