EJSのリモートコード実行の脆弱性を修正する
Tim Kadlec
2016年11月30日
0 分で読めます今週、EJSパッケージに存在する深刻度の高いリモートコード実行の脆弱性を、脆弱性データベースに追加しました。
EJS(Embedded JavaScript Templates)は、高速でシンプルな、非常に人気のあるJavaScriptテンプレートエンジンです。EJSでは、テンプレートをレンダリングするための方法がいくつか用意されています。そのうちのrenderとrenderFileはよく似ていますが、renderがテンプレートとして文字列を受け取るのに対し、renderFileはテンプレートファイルのパスを受け取る点が異なります。どちらのメソッドも、データと任意の設定オプションを引数として受け取ります。また、renderFileメソッドはコールバック関数も受け取ります。
どちらのメソッドでも、データとオプションを1つのオブジェクトにまとめて渡すこともできます。
脆弱性について
ショートカットメソッドを使うほうが簡単に思えるかもしれませんが、データとオプションを混在させると、時間が経つにつれてエラーが起きやすくなります。それだけでは使うのを避ける理由として不十分だとしても、もっと重大な理由があります。ショートカットメソッドを使うと、アプリケーションがリモートコード実行の脆弱性にさらされる可能性があります。
コンパイルするEJSテンプレートでは、includeディレクティブを使ってほかのファイルを読み込めます。
デフォルトでは、includeのパスはテンプレートからの相対パスになります。テンプレートがtemplatesフォルダにある場合、EJSはtemplates/path/to/includeを検索して、読み込むファイルを見つけます。
使用できる設定オプションの1つにrootオプションがあります。このオプションを使うと、includeの読み込み元となるデフォルトの場所を変更できます。
オプションを別の引数として渡す場合は問題ありませんが、データとオプションを1つのオブジェクトにまとめると問題が生じます。ユーザーが指定したデータのリストをメソッドに渡す場合、攻撃者がその中にroot オプションを挿入する可能性もあります。
上の行でrootディレクティブを渡すと、includeの読み込み元が本来のパスではなく/bad/rootになり、リモートコード実行につながります。
EJSエンジンを使う開発者にとって、rootを設定できることは便利な場合があります。しかし、ユーザーデータと同じオブジェクト内で設定できるようにすると、重大なセキュリティリスクが生じます。開発者が入力をサニタイズすることはできますが、エンジン自体がデフォルトで安全ではなくなってしまいます。
当社のセキュリティチームがこの問題を発見し、11月27日に開示しました。プロジェクトのオーナーであるMatthew Eernisseは、rootオプションをブラックリストに登録し、ユーザーデータと一緒に含められないようにするシンプルな修正を用意しました。
脆弱性は、最初に開示されてから長期間修正されないことがよくあります。実際、MarkedのXSS脆弱性を覚えている方もいるかもしれませんが、修正までに1年以上かかりました。幸い、今回はそうなりませんでした。Matthewによる驚くほど迅速なリリースのおかげで、脆弱性は開示からわずか1日で修正されました。11月28日にリリースされたEJSのバージョン2.5.3には、この脆弱性の修正が含まれています。
修正方法
Snykにプロジェクトの監視を設定していて、そのプロジェクトでEJSを使用している場合は、この問題についてすでに通知を受け取っているはずです。GitHubインテグレーションを使ってダッシュボードからプルリクエストを作成するか、コマンドラインインターフェースからsnyk wizardを実行すれば、脆弱性を修正できます。どちらの場合も、Snykが問題を特定し、EJSパッケージを最新バージョンに更新するよう案内します。
Snykを使っていない方もご安心ください。もちろん、今でも大歓迎です。この問題は、EJSを最新バージョンに手動で更新することで対処できます。依存関係もすべて確認してください。依存関係のいずれかがEJSパッケージを取り込んでいる場合、package.jsonファイルには表示されず、更新にはかなり手間がかかることがあります。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップで、CTFチャレンジの解き方を学びましょう。