Ruby on Rails 脆弱性解説 - CVE-2016-2098

はじめに

先日、HASHコンサルティング株式会社の徳丸浩氏のブログにて CVE-2016-2098 の解説記事が公開されました。

Ruby on Railsの潜在的なリモートスクリプトインジェクション脆弱性CVE-2016-2098

記事の元になったのは GitHub で公開された CVE-2016-2098 の PoC です。

GitHub - hderms/dh-CVE_2016_2098: Proof of concept showing how CVE-2016-2098 leads to remote code execution

この PoC(dh-CVE_2016_2098) には不可解な点が見受けられました。(現在質問中、未回答)

dh-CVE_2016_2098 と CVE-2016-2098 に関して調査を行い、以下の結論に至りました。

  • dh-CVE_2016_2098 は CVE-2016-2098 を概念実証できていない
  • CVE-2016-2098 の 概念実証は可能(view の render)

本稿は CVE-2016-2098 を簡単に解説し、調査内容を公開します。

CVE-2016-2098 脆弱性とは

リモートサーバ上で任意のコードが実行可能な、いわゆるRCEの脆弱性です。
2016/2/29に情報が公開されました。

https://groups.google.com/forum/#!msg/rubyonrails-security/ly-IH-fxr_Q/WLoOhcMZIAAJ

公式の発表では Rails の Action Pack の脆弱性であり、controller または view の render メソッドにユーザー入力値など外部から指定された値を渡すアプリケーションが影響を受ける可能性がある、とされています。
影響を受けるコードとして、下記のプログラムが例示されています。

class TestController < ApplicationController
  def show
    render params[:id]
  end
end

controller の render に 外部から指定された id という名前のパラメータ値をそのまま渡す処理になっています。
上記の例に対する具体的な攻撃コードは、公式には公開されていません。(間違っていたらぜひ教えてください!)

CVE-2016-2098 が修正された Rails のバージョンは以下です。

  • 4.2.5.2
  • 4.1.14.2
  • 3.2.22.2

最初にこの脆弱性が報告されたのは、バグバウンティプラットフォームの hackerone だったようです。
タイトルから render :inline を使用した手法であることはわかりますが、詳細は公開されていませんでした。

Ruby on Rails disclosed on HackerOne: Remote code execution using...

"PoCの不可解な点" に関する話をする前に、CVE-2016-2098 と 同時に報告された CVE-2016-2097 と、これらの脆弱性と関連が深い CVE-2016-0752 についておさらいさせてください。

CVE-2016-2097 脆弱性とは

ディレクトリトラバーサルの脆弱性です。
2016/2/29に情報が公開されました。

https://groups.google.com/forum/#!msg/rubyonrails-security/ddY6HgqB2z4/we0RasMZIAAJ

CVE-2016-0752の修正に漏れがあったため、新たなCVE IDが発番され、再修正された脆弱性です。

This was meant to be fixed on CVE-2016-0752. However the 3.2 patch was not covering all the scenarios.

公式の発表では Rails の Action View の脆弱性であり、controller の render メソッドにユーザー入力値など外部から指定された値を渡すアプリケーションが影響を受ける可能性がある、とされています。
影響を受けるコードとして、下記のプログラムが例示されています。

def index
  render params[:id]
end

controller の render に 外部から指定された id という名前のパラメータ値をそのまま渡す処理になっています。
id=/etc/hosts のように単純な例で発動します。

脆弱性の影響はディレクトリトラバーサルに留まらず、任意のコード実行の可能性が示唆されています。

Carefully crafted requests can cause the above code to render files from unexpected places like outside the application's view directory, and can possibly escalate this to a remote code execution attack.

CVE-2016-2097 が修正された Rails のバージョンは以下です。4.2系は影響を受けません。

  • 4.1.14.2
  • 3.2.22.2

CVE-2016-0752 脆弱性とは

ディレクトリトラバーサルの脆弱性です。
2016/1/26に情報が公開されました。

https://groups.google.com/forum/#!msg/rubyonrails-security/335P1DcLG00/OfB9_LhbFQAJ

公式の発表では Rails の Action View の脆弱性であり、controller の render メソッドにユーザー入力値など外部から指定された値を渡すアプリケーションが影響を受ける可能性がある、とされています。
影響を受けるコードとして、下記のプログラムが例示されています。

def index
  render params[:id]
end

controller の render に 外部から指定された id という名前のパラメータ値をそのまま渡す処理になっています。

脆弱性の影響はディレクトリトラバーサルに留まらず、任意のコード実行の可能性が示唆されています。

Carefully crafted requests can cause the above code to render files from unexpected places like outside the application's view directory, and can possibly escalate this to a remote code execution attack.

公式な情報の公開と同日、CVE-2016-0752 によるディレクトリトラバーサルと任意のコード実行の手法が公開されています。

Rails Dynamic Render to RCE (CVE-2016-0752)

ERB(Embedded Ruby)を含むURLでアクセスしたログをログファイルに書き込ませ、ログファイルをレンダリングさせることで任意のコードを実行しています。

CVE-2016-0752 が修正された Rails のバージョンは以下です。

  • 5.0.0.beta1.1
  • 4.2.5.1
  • 4.1.14.1
  • 3.2.22.1

3つの脆弱性のまとめ

公式の情報を一度まとめます。

CVE-2016-0752 CVE-2016-2097 CVE-2016-2098
公開日 2016/1/26 2016/2/29 2016/2/29
脆弱性タイプ パストラバーサル パストラバーサル リモードコード実行
該当バージョン(5系) Rails 5.0.0.beta1.1 未満の 5.x - -
該当バージョン(4.2系) Rails 4.2.5.1 未満の 4.2.x - Rails 4.2.5.2 未満の 4.2.x
該当バージョン(4.1系) Rails 4.1.14.1 未満の 4.1.x Rails 4.1.14.2 未満の 4.x Rails 4.1.14.2 未満の 4.x
該当バージョン(3.2系) Rails 3.2.22.1 未満 Rails 3.2.22.2 未満 Rails 3.2.22.2 未満

上記以外では、影響を受けるコードの例が全て同じであることが特徴的です。
CVE-2016-2097 は CVE-2016-0752 の修正ミスであるため、コード例が一致するのは自然です。
CVE-2016-2098 までコード例が一致しているのは、CVE-2016-0752の修正をバイパスする手段が見つかったということでしょうか。

GitHub で公開された PoC の不可解な点

私はこの手法は、CVE-2016-2098 ではなく CVE-2016-0752 に対する PoC と捉えるのが適切だと考えています。

まず、Gemfileに書かれたRailsのバージョンが 4.2.4 になっています。
これは、CVE-2016-0752 の影響を受けるバージョンです。
CVE-2016-2098 の影響は受けるが CVE-2016-0752 の影響は受けないバージョンである 4.2.5.1 を使用すると、この手法では脆弱性が顕在化しません。
この PoC が 4.2.5.1 でブロックされる理由は、別途解説記事を書きたいと思います。

そして、dh-CVE_2016_2098 の Issue には『CVE-2016-0752 で任意のコード実行を行う手法と同じである』として上述した記事のURLを書いてしまいましたが、記憶違いでこの記事には :inline を使用した手法は書いてありませんでした。。
貼り付けるURLは間違えてしまいましたが、CVE-2016-0752 に :inline オプションを使用してRCE可能であることは過去に言及されています。
この手法は古くから、アプリケーションの脆弱性を突く攻撃(フレームワークである Ruby on Rails への攻撃手法ではない)として知られていたようです。

GitHub の PoC(dh-CVE_2016_2098)では、リクエストのフォーマットにJSONが使用されていますが、この点が新しいとか特に意味があるということは無いと思われます。
入力値にハッシュ(map)さえ指定できれば、フォーマットの差異はフレームワークで吸収されます。
以下2つのコマンドは dh-CVE_2016_2098 で同じように動作します。

$ curl -H "Content-type: application/json" -X GET -d ' {"id" : { "inline" : "<%= FileUtils.touch \"rooted\"%>"&#x7D;&#x7D;'  http://localhost:3000/exploits
$ curl 'http://localhost:3000/exploits?id\[inline\]=<%25%3DFileUtils.touch+"rooted"%25>'

CVE-2016-2098 の PoC は存在するか?

このパターン(controller の render)にこだわらなければ、Rails 4.2.5.1(CVE-2016-0752 の影響を受けず、CVE-2016-2098 の影響を受ける)で任意のコード実行が可能です。

class TestController < ApplicationController
  def show
    render params[:id]
  end
end

公式の報告には以下のようにあったことを思い出してください。

Applications that pass unverified user input to the render method in a controller or a view may be vulnerable to a code injection. (controller または view の render メソッドにユーザー入力値など外部から指定された値を渡すアプリケーションが影響を受ける可能性がある)

view の render を使って確認します。

$ rails -v
Rails 4.2.5.1

$ cat app/views/poc/render1.html.erb
<h1>Poc#render</h1>
<% render params[:template] %>

$ rake routes
     Prefix Verb URI Pattern            Controller#Action
poc_render1 GET  /poc/render1(.:format) poc#render1

上記の検証用アプリケーションは GitHub で公開しています。
https://github.com/CyberDefenseInstitute/PoC_CVE-2016-2098_Rails42

以下のコマンドで任意のコマンドが実行されることを確認できます。

$ curl 'localhost:3000/poc/render1?template\[inline\]=<%25%3d`sleep+5`%25>'

CVE-2016-2097 と同じく CVE-2016-0752 の修正漏れではないか、と思われてしまいそうな内容ですね。。
元々Ruby on Railsの脆弱性ではなくアプリケーションの脆弱性なので、修正にかけるモチベーションがあまり高くないのかもしれません。

controller の render で実行する条件は、現在のところ把握できていません。
4.2.5.1 の修正内容を確認しましたが、controller内の render params[:id] という条件下での実行は難しいと思います。

おわりに

dh-CVE_2016_2098 と CVE-2016-2098 に関して調査を行い、以下の結論に至りました。

  • dh-CVE_2016_2098 は CVE-2016-2098 を概念実証できていない
  • CVE-2016-2098 の 概念実証は可能(view の render)

今後、追加で判明した事実があればブログの更新で報告したいと思います。

記事中に、dh-CVE_2016_2098 が 4.2.5.1 でブロックされる理由を別記事で書くと告知した通り、次回は CVE-2016-0752 を解析した時の話をしたいと思います。

© 2016 - 2022 DARK MATTER / Built with Hugo / Theme Stack designed by Jimmy