Struts2の脆弱性、いまだに見つかる本当の理由
ソフトウエアの脆弱性が悪用された実例として、Webアプリケーションフレームワーク「Struts2」の脆弱性について見ていこう。2017年3月9日に公開された「S2-045」というStruts2の脆弱性が原因で、2017年3月以降、多くの情報漏洩事件が起こっている。クレジットカード番号の流出で金銭被害が出た事例もある。Strut2ではこれまでも多くの脆弱性が報告されている▼。S2-045を含め、多くはリモートコード実行の脆弱性だ。
Struts2にリモートコード実行の脆弱性が多いのは、内部で「OGNL▼」というライブラリを利用しているためだ。OGNLは、Javaに似たコードをコンパイルなしで実行する。Struts2ではデータの処理にOGNLを多用している。このため、Struts2に脆弱性があると、例えば攻撃者がHTTPリクエストに埋め込んだ悪意のあるコードがOGNLによって実行されてしまう。
Struts2が備えるOGNL機能がコードを実行
Struts2ではJavaに似たコードをコンパイルなしで実行する「OGNL」というライブラリが使われている。ところがStruts2に脆弱性があると、攻撃者がHTTPリクエストに埋め込んだ悪意のあるコードがOGNLによって実行されてしまう。
[画像タップで拡大表示]
OGNLで実行されるコードを埋め込む「OGNLインジェクション」の例を示したのが下の図だ。2013年に報告された「S2-013」という脆弱性を悪用する攻撃コードである。攻撃者はHTTPリクエストのパラメーターの値にOGNLコードを埋め込む。すると、OGNLがパラメーターを処理する際にコードが実行されてしまう。
埋め込んだOGNLコードが実行されてしまうOGNLインジェクションの例
2013年に報告された「S2-013」という脆弱性があると、HTTPリクエストのパラメーターの値として渡したOGNLコードが実行されてしまう。ここでは「hacked」という文字列を出力している。
[画像タップで拡大表示]
実際のOGNLコードの内容を見てみよう。URLエンコード▼をデコードし、見やすいように整形したコードを示した。最初の3行で、コードを実行できるようにするため権限を変更している。OGNLインジェクションでよく見られる特徴的なコードだ。続いて、攻撃者が実行したい処理▼を記述する。
▼多くの脆弱性が報告されている
情報処理推進機構(IPA)は「Apache Struts2 の脆弱性対策情報一覧」(https://www.ipa.go.jp/security/announce/struts2_list.html)というWebページにStruts2の脆弱性をまとめている。
▼OGNL
Object Graph Navigation Languageの略。
▼URLエンコード
URLでは使えない文字を使う際に行われるエンコード。正確にはパーセントエンコーディングと呼び、RFC3986のSection 2.1で定義されている。
▼攻撃者が実行したい処理
ここではサンプルとして「hacked」という文字列を出力している。
根本的な対策が無効に
Struts2の脆弱性の歴史は、いわばOGNLインジェクションの歴史である。2013年から2016年にかけてHTTPのパラメーターまわりでOGNLインジェクションが可能になる脆弱性が多数報告された。しかし、Struts2の開発チームはその都度、場当たり的な対策を施すだけだった。
根本的な対策後にも新たな脆弱性が判明
2013年から2016年にかけてHTTPのパラメーターまわりでOGNLインジェクションが可能になる脆弱性が複数報告されたが、Struts2の開発チームはその都度、場当たり的な対策を施すだけだった。根本的な対策は、2016年に報告されたS2-037に対して行われた。これにより、パラメーターまわりでOGNLインジェクションを行うことは事実上不可能になった。ところが、パラメーター以外の部分でOGNLインジェクションが可能になる脆弱性が2017年に判明した。
[画像タップで拡大表示]
根本的な対策は、2016年に報告された「S2-037」に対して行われた。Struts2の開発プロジェクトは、Struts2で利用しているOGNLのメンテナンスも実施している。そこでOGNL側にセキュリティ対策機能を追加し、パラメーターからの入力の場合は、Struts2のメソッドの呼び出ししかできないようOGNLの機能を制限した。これにより、パラメーターまわりでOGNLインジェクションを行うことは事実上不可能になった。
ところが2017年、パラメーター以外の部分でOGNLインジェクションが可能になる脆弱性であるS2-045が判明した▼。悪用されたのはパラメーターではなく「エラーログ」だ。
エラーログへの出力を悪用してコードを実行
Struts2ではパラメーターの処理以外にログ機能でもOGNLが利用されており、これがS2-045の脆弱性で悪用された。攻撃者はエラーを引き起こすデータに攻撃用のOGNLコードを埋め込みStrut2に送る。Struts2ではこのデータを正しく処理できないためエラーログを出力する。ログ機能にOGNLが使われているため、HTTPで送られてきた文字をエラーログに出力する際にコードが実行されてしまう。
[画像タップで拡大表示]
Struts2ではエラーメッセージをログに記録している。国際化対応として、そうしたメッセージを英語や日本語といった複数の言語に変換している。その処理にOGNLを利用していた。
Struts2のエラーログには、エラーが起こった場所を示すためにHTTPで送られてきた文字が記録される。つまり、エラーを発生するようなデータに悪意のあるコードを埋め込んで送ると、エラーログの出力の際にOGNLが処理を行うことで、悪意のあるコードが実行されてしまう。
実際に問題があったのは、ファイルをアップロードするときによく使われるマルチパートというHTTPの形式を処理するパーサーに関する部分である。パーサーから送られてきたエラーメッセージをStruts2がログに出力しようとしたときにOGNLインジェクションが起こっていた。
Struts2の内部ではパラメーターやエラーログ以外の部分でもOGNLが使われている。このため、今後も新たなOGNLインジェクションの手法が見つかる可能性がある。
▼S2-045が判明した
S2-045への対策として当初、修正されたStruts2へのアップデート以外に、パーサーを変えることでも対応できるとされていた。ところが実際には、別のパーサーを使っても、コードを埋め込む箇所を少し変えることで同様にOGNLインジェクションが可能であることが判明した。これが「S2-046」の脆弱性である。