ページの先頭です
インターネット上で発生するインシデントは、その種類や規模が時々刻々と変化しています。このため、IIJでは、流行したインシデントについて独自の調査や解析を続けることで対策につなげています。ここでは、これまでに実施した調査のうち、Struts2の脆弱性CVE-2017-5638について、monitor. appを用いたmacOSランサムウェア(Patcher)の動的解析の2つのテーマについて紹介します。
このStruts2の脆弱性CVE-2017-5638は、2017年3月6日に公開されました。この時点においては正式版ではなく、開発者向けのセキュリティアドバイザリでしたが、誰でも閲覧可能になりました。通常のセキュリティアドバイザリと同様に、必要な情報は一通りそろっており、その脆弱性の影響はリモートからの任意コード実行可能でした。修正済みのリリースバージョンはまだ存在しないにもかかわらず、その翌日には第三者によるPoC(Proof Of Concept)コードが公開され、それを元にしたと思われる攻撃により、多くの被害が発生しました。
Struts(※66)とはJavaで動作するWebアプリケーションフレームワークです。Tomcat(※67)などのアプリケーションサーバ上で動作します。Strutsには、Struts1とStruts2の系列がありますが、上位互換性はなく別物です。
Struts1は2001年に初期バージョンがリリースされ、多くの場所で採用されました。しかしながら、2013年にサポートが終了しており、脆弱性が出ても修正されない状態になりました。また、サポート終了後の2014年にリモートからコード実行が可能な脆弱性が公開されています。
Struts2は2007年に初期バージョンがリリースされ、現在に至るまでサポートが継続しています。Struts1が作られた時代とは異なり、他のフレームワーク選択肢も増えたためStruts1程の人気はありませんでしたが、それでもまだ多く使われています。
脆弱性の観点からのStruts1とStruts2の最も大きな違いとして、Struts2にはOGNL(Object Graph Navigation Language) が使われていることが挙げられます。この言語はJavaに似た文法を持ち、JSPファイルなどからOGNL式として呼び出すことにより、変数展開や条件文などが直接記述できます。
これはインタープリタ言語においてよく見られる、変数に格納されたデータをコードとして解釈するevalに相当する機能と考えると分かりやすいと思われます。evalは自由度が高い反面、危険性も高いため、その必然性がない限り使用は推奨されません。外部入力がそのまま渡されてしまった場合、任意コード実行可能な脆弱性となってしまうためです。入力値チェックやエスケープなどをしている場合も、考慮漏れが発生する可能性もあるので注意して使ったとしても、潜在的なリスクは排除できません。
Javaはコンパイル型言語であるため、もともと単体ではeval のようなことはできませんが、OGNLによりこれに近い機能を実現しています。他の言語などであれば、evalなどの危険な機能は使わないというポリシーの元開発することも可能ですが、OGNLはStruts2の機能の根底をなしているため、Struts2を使う以上、無効化はできません。この機能は開発者が記載するJSPファイル内の式以外にも、至る所で使われているため、たとえ開発者が一切OGNL式を記述しなかったとしても、影響を避けることはできません。
先に説明したとおりStruts2は、OGNLの採用によりJavaにない柔軟性の対価として、潜在的なリスクを内包しました。これがリスクに留まらなかったことは、数多く見つかっている脆弱性により証明されています。今までに見つかった、リモートコード実行可能な脆弱性の一覧を表-1に示します。なお、サンプルアプリケーションなどの、実環境に影響しないと考えられる脆弱性については除外してあります。現在に至るまで、19 件のリモートから任意コード実行が可能な脆弱性が見つかっています。そのうちS2-020とS2-021の2件のみ、クラスローダに起因する脆弱性でStruts1も同様に影響を受けました。それ以外の17件はすべてOGNLに起因する脆弱性となっています。
CVEの採番からも読み取れるとおり、毎年数件の任意コード実行が可能な脆弱性が見つかっています。OGNLに起因するコード実行は、外部から入力されたOGNL式がチェックをすり抜けそのまま評価されてしまうことにより発生します。そのため、一般的なメモリ破壊に起因する脆弱性とは異なり、相手の環境に依存しにくい安定した攻撃が可能になります。
Struts2はサポートされているバージョンであるため、新しい脆弱性が発見されると修正されますが、特定のキーワード(method:など)が含まれている場合にエラーとする、といったブラックリスト型のアプローチが殆どです。ホワイトリスト型であれば、使用可能なキーワードの集合を事前に定義する為、問題のあるキーワードが見つかる度に拒否リストに追加する必要はなくなります。しかし、現在に至るまでブラックリスト型のアプローチがとり続けられていることから、OGNLの構造上無理なのではないかと推測されます。
過去にも多数コード実行の脆弱性が公開されているにもかかわらず、今回の脆弱性はそれに比べても大きな騒ぎになりました。その原因として脆弱性の公開方法に問題があったと考えられます。今回の脆弱性に関連するタイムラインを表-2に示します。この表は、弊社の観測に基づいた時刻を記載しているため、実際はこの時刻より前に発生している可能性があります。適切に管理された脆弱性対応の場合は、脆弱性発見及び報告、開発者により修正、対策版リリース、情報公開といったフローが一般的です。しかし、今回の脆弱性について意図せずとも、開発者向けのアドバイザリが開発者以外に対しても公開がされ、更に正式な対策版がない状態で、PoCまで公開されてしまうという最悪な状態でした。まず、この点で情報管理に問題があると言えます。情報を管理していても漏れることはありますので、漏れてしまった場合のリカバリが重要になります。このような事態になった場合は、予定を繰り上げてリリースする場合が多いですが、今回のケースではリモートから任意コード実行可能という最も致命的なPoCが公開されているにもかかわらず、その約2日後まで正式な情報公開はありませんでした。実は翌日には対策版のソースコードが配布サーバ上に置かれていましたが、セキュリティアドバイザリのリリースもなく、ダウンロードページも古い脆弱性のあるバージョンが最新との記述のままであり、気づかない人も多かったと推測されます。
このような状態であり、公式のセキュリティアドバイザリやリリースをトリガーとして、対応を開始する通常の脆弱性対応の体制を敷いていた場合は、公式のリリースより前に攻撃が発生したため、手遅れでした。
リスクの高いStruts2を使用しないというのは確実な対策ではありますが、移行可能な互換性のある実装がない以上、既に導入してしまい、前提としたシステムが組まれている場合には適用できません。脆弱性が存在する可能性があるのはどの製品でも変わらないため、脆弱性対応を前提とした運用体制を組むのは必要ですが、Struts2の場合は高リスクなソフトウェアであるという前提の元に対応する必要があります。
過去のStruts2の脆弱性を対象とする攻撃ツールでは、検索エンジンを用いて対象を抽出し、攻撃を仕掛ける機能を有するものもありました。抽出する原理としては、Struts2は初期設定でURLに.actionといった拡張子を付けるため、このキーワードが含まれるサイトを検索し攻撃対象とするといったものです。検索エンジンを用いない場合においても、このURLは特徴的であるため、ブラウザでアクセスしたとしてもStruts2を使っているということは一目瞭然です。本質的な対策にはなりませんが、攻撃者に対して不必要な情報を与えないという前提の元、別の拡張子への変更をお勧めします。攻撃対象となるリスクを低減することにより、時間稼ぎできる可能性が高まります。
先に挙げたとおり、今回の脆弱性は修正版のリリース後に対応開始したとしても手遅れでした。つまり、修正版に依存しない防御策が必要です。Struts2などの動作する、多くのアプリケーションサーバは、他のWebサーバと比較してアクセス制御機能や拡張性が低い場合が殆どです。そのため、アプリケーションサーバの前段にWAF(Web Application Firewall) などを配置し、対象のアプリケーションを修正せずに防御可能な構成が推奨されます。オープンソースのWAFとしては、ModSecurity(※68)などが挙げられます。また、類似の制御機能を持つものとしてIPS(Intrusion Prevention System)などがあります。こちらでも、ある程度の防御が可能な物もありますが、Webアプリケーションに特化したWAFよりは、制御可能な範囲が狭くなるため、防げない場合もあります。
ModSecurityはオープンソースのWAF実装であり、Apache httpd(※69)などのWebサーバのモジュールとして動作します。アプリケーションサーバの前段に、このモジュールを組み込んだサーバをリバースプロキシとして配置して使用します。CRS (Core Rule Set)といった基本的な制御用ルールセットも存在しますが、今回は制御したいパターンが限定されているため不要です。守る対象のアプリケーションを限定しないルールセットは、汎用的になりすぎて誤検知が多いため、安易に適用するのは危険です。
Struts2の脆弱性の殆どは、外部から入力されたOGNL式が意図せず評価されてしまうことにより発生します。そのためOGNL 式とされる入力をフィルタすることが効率的であると考えられます。通常は"%{OGNL式}"のフォーマットですが、"${OGNL 式}"のフォーマットも同様に使用可能です。これはOGNL実装のcom.opensymphony.xwork2.util.TextParseUtilクラスにて定義されています。実際のパース処理はcom.opensymphony. xwork2.util.OgnlTextParserクラスにあります。正規の使い方をする場合はどちらを使っても構いませんが、脆弱性の対策とする場合は、両方のパターンをフィルタする必要があります。また、HTTPプロトコルにおいて改行コードはCRLF(¥r¥n) ですが、HTTPヘッダ中にCR(¥r)のみの値が出現した場合に無視する実装もありますので、"%¥r{"のような入力も想定する必要があります。これらを踏まえたルールセットを表-3に示します。
S2-045とS2-046については、今回の脆弱性にのみ適用されるルールセットです。OGNL全般のルールセットは、汎用的にOGNL式の開始タグが含まれる場合にマッチします。注意点として、OGNL全般(パラメータ値)のルールは、パラメータ値を対象とするため誤検知が発生する可能性が高いと思われます。過去の脆弱性においても、殆どは他の3種のルールで対応できるため、これを除外した3種類のみ適用するのがバランスが良いと考えられます。
昨今、脆弱性が見つかることは珍しくなくなっていますが、対応を間違ったり、遅れたりした場合には大きな損害が発生する可能性があります。攻撃者の観点からしても、リモートから安定して任意コード実行可能な脆弱性が、ほぼ毎年複数件発見されるソフトウェアを使用しているシステムは、事前にリストアップやプロファイリングをしておく価値があると考えられます。そこで扱っている情報がクレジットカードや個人情報などの金銭的利益に直結する物であれば尚更です。
リスクの高いソフトウェアを使い続ける場合は、未修正の脆弱性が出たとしても修正版がリリースされるまで時間稼ぎが可能な対策を施しておくことが重要です。リリース後に迅速にパッチを適用するだけでは不十分です。当然のことながら、全く未知の手法が見つかる可能性もありますので、すべての攻撃に対して有効な訳ではありません。しかしながら、Struts2に関しては過去の脆弱性の殆どがOGNLに起因しているため、その攻撃手法に注視した対策を事前に施しておくことは有効であると言えます。
Patcherはユーザのファイルを暗号化し、復号と引き換えにBitcoinの支払いを要求するランサムウェアで、macOS環境で動作します。このランサムウェアはAdobe Premiere Pro やMicrosoft Officeなどの商用アプリケーションを不正に利用するための"パッチ"としてBitTorrentを介して配布され、ユーザ自身の手でダウンロード、実行させることによって感染を果たします。
本稿ではこのランサムウェアの概要について、2017年3月に米FireEye社が無償公開したmonitor.app(※70)というツールを利用した動的解析の過程と共に紹介します。なお、本稿で紹介する調査過程を再現する際は、作業後に元の環境に復元可能な仮想マシンなどで、ファイル共有やネットワークを遮断した状態で実施することを強く推奨します。
monitor.appを起動し、モニタリングを開始した状態で、Patcher アプリケーションのアイコンをダブルクリックして起動します。本稿で扱う検体は、アプリケーション名が「Adobe Premiere Pro CC 2017 Patcher」と偽装されています(図-16)。起動すると、背景が透過に設定されたアプリケーションウィンドウが展開し「START」ボタンをクリックするよう促すメッセージが表示されるので、クリックして先に進みます。
このあと、10分以内に終了する旨と進捗を示すメッセージが表示され、0/3から2/3まで進みます(図-17)。
進捗が2/3の表示になり、デスクトップに「README!.txt」などのファイルが作成されると、それ以上進まなくなります。monitor.appの表示をみても、「Adobe Premiere Pro CC2017 Patcher」に関連した動作が記録されなくなっていることが分かるので、Patcherのウィンドウに戻り、command+Qキーバインドまたはメニューの「QUIT」を選択してPatcherを終了します。
ここで、monitor.appのモニタリングを停止し、ログの調査を始めます。なお、ファイルメニューの「Save As...」を選択することで、ログをファイルとして出力することも可能です。また、実行前にデスクトップに置かれていたファイルはパスフレーズ付きZIPアーカイブとして保存されていることが確認できます(図-18)。
monitor.appのモニタリングログを表示し、「Adobe Premiere Pro CC2017 Patcher」の起動を示すログを探します。ここでは、該当アプリケーションが実行され、続けて関連するdylib(※71) ファイルがロードされているログが確認できます(図-19)。
同様にモニタリングログを精査してゆくことで、本検体が次のような挙動を示したことが確認できます。
このように、monitor.appで記録した動作を精査することによって、Patcherランサムウェアの動作概要を把握することができました。一方で、表示される進捗が2/3から進まなくなった原因や、暗号化パスフレーズの共有方法(※72)などは不明です。このような疑問を解き明かすためには、静的解析を実施する必要があります。
Patcherの実行ファイルの前述5の直後を確認すると、以下のような外部コマンドを実行することで、ディスクの空きスペースをゼロで埋め、削除したファイルの復元を困難にしようとすることが分かります(図-24)
/usr/bin/diskutil secureErase freespace 0 /
しかしながら、macOS環境における、diskutilコマンドのパスは/usr/sbinであるため、この外部コマンドは実行できません。この軽率なバグによって進捗が2/3から進まなくなっていることが分かります(※73)。なお、このコマンドが完了すると進捗表示が更新され「DONE!¥nRead the README.txt file on your Desktop!」という文字列に差し替えられるようになっています。
暗号化ZIPに用いるパスフレーズは、起動されるたびにarc4random_uniform ()によって異なる値が生成されています(※74) (図-25)。また、生成したパスフレーズを外部に送信し たり、ファイルに埋め込んだりして共有する機能の存在は確認されませんでした。これは、Patcherによって暗号化されたファイルは、本稿の動的解析のようにモニタリングログを記録している場合や、プロセス終了前にメモリからパスフレーズを読みだした場合などを除いて、復号する手段がないことを意味します。
本稿で紹介してきたように、Patcherは非常に低品質・低機能なランサムウェアで解析も容易です。それでも意図せず実行してしまうと、ファイルを暗号化され、復号不能になってしまうため、感染への対策としてオフラインバックアップの用意を検討しておくことが求められます。また、これまでmacOS 環境を対象としたマルウェアは質の低いものが多いと報告されてきましたが(※75)、近年は量的に大幅な増加傾向にあるため(※76)、淘汰が進んでWindows環境で見られるような高度な機能を備えたマルウェアが増えてくる可能性も考慮しておく必要があるでしょう。
本稿で紹介した内容は以下sha-256のハッシュ値のMach-O 検体で確認したものです。
c9e1fe6a32356a823f3dc36851bc8dfd5c601481c109229bd21883bffee10f5e
ページの終わりです