Posted by usa on 22 Feb 2013
REXML において、厳格でないエンティティ展開により、サービス不能攻撃が可能となる脆弱性が報告されました。 この脆弱性は CVE-2013-1821 として CVE に登録されています。 ユーザーの皆さんには ruby を更新することを強くお勧めします。
詳細
XML ドキュメントからテキストのノードを読み込む際、REXML のパーサに極めて巨大な String オブジェクトを生成させ、マシン上のメモリを使い果たさせてサービス不能攻撃を成立させることができます。
影響を受けるのは以下のようなコードです:
document = REXML::Document.new some_xml_doc
document.root.text
`text` メソッドが呼ばれる際、XML のエンティティが展開されます。 攻撃者の送信する XML ドキュメントが比較的小さなものであったとしても、そのエンティティが解決される際には対象システム上で非常に大量のメモリを消費させることができます。
この攻撃は「Billion Laughs」攻撃として知られているものに似ていますが、それとは別のものです。 また、この脆弱性は Python について報告されている CVE-2013-1664 とも関連しています。
影響を受けるバージョンの ruby を使用している全てのユーザーは、速やかに、ruby を更新するか、以下の回避策を適用して下さい。
回避策
もし ruby を更新できない場合、回避策として以下のモンキーパッチを適用して下さい:
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
このモンキーパッチは、エンティティ置換のサイズを 1 ノードあたり 10Kb に制限します。 REXML は元々デフォルトでは 1 ドキュメントにつき 10000 エンティティの置換しか許可していないので、この制限を追加することにより、エンティティ置換で生成されるテキストの最大サイズは 98 メガバイト前後までになります。
影響を受けるバージョン
- ruby 1.9.3 patchlevel 392 より前の全ての ruby 1.9 系列
- ruby 2.0.0 patchlevel 0 より前の全ての ruby 2.0 系列
- revision 39384 より前の開発版 (trunk)
クレジット
この脆弱性は Ben Murphy によって報告されました。
更新履歴
- 2013-03-11 16:45:00 (JST) CVE 番号について追記
- 2013-02-22 21:00:00 (JST) 初版