none
WPFで開発したEXEのあるフォルダーにダミーの VERSION.dll を配置するとEXEが起動しなくなる。 RRS feed

  • 質問

  • Visual Studio 2015 Update 3でWPFアプリケーションの開発を行っているのですが、脆弱性の問題で困っています。

    WPFで開発したEXEファイルのあるフォルダーにダミーの VERSION.dll を配置すると、
    EXE起動時に下記エラーメッセージが表示されてEXEが起動できなくなります。

    エラーメッセージの内容:
    「VERSION.dllはWindows上では実行できないか、エラーを含んでいます。
    元のインストールメディアを使用して再インストールするか、システム管理社またはソフトウェアの製造元に問い合わせてください。」

    Visual Studio 2015でWPFアプリケーションのプロジェクトを新規作成した直後の状態でビルドしたEXEでも再現します。

    どなた様か対策方法をご存知ありませんでしょうか?

    噂では脆弱性対策を施したVisual Studio 2015のパッチ等があると聞いたのですが、それらしいものは見つけられませんでした。
    • 編集済み nino-n 2017年5月25日 11:46
    2017年5月25日 11:38

回答

  • .Netのランタイムのロードを行っているらしいmscoree.dllからアプリケーションのフォルダにあるversion.dllを呼び出している?
    mscoree.dllが参照しているversion.dll以外のdllは偽装dllを置いても呼ばれていないみたいなので、version.dllだけがおかしいと言えばおかしいかな。
    間接的に呼び出されてしまうdllを一般の開発者がどうにかすることもできないのでOSや.Net側で対処してもらわないとどうにもならなそう。

    例えばClickOnceは保護されていないフォルダに実行ファイルが置かれるので、悪意のある攻撃者が権限の低いアプリケーションを配布して、そのアプリケーションが権限の高いClickOnceアプリケーションのフォルダに偽装したversion.dllを注入するというシナリオが考えられるかなぁ。

    https://support.microsoft.com/ja-jp/help/2264107/a-new-cwdillegalindllsearch-registry-entry-is-available-to-control-the-dll-search-path-algorithm
    http://eternalwindows.jp/windevelop/dll/dll05.html
    を読むと、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs\にリストされているdllはシステムフォルダから読み込まれますが、それ以外は実行ファイルのあるフォルダから優先して読み込まれるとなるようです。
    それで、なぜversion.dllが除外されているかを調べてみると、
    Windows Confidential: The Known DLLs Balancing Act:という記事に理由が書かれていて、除外されたままであるためにこの現象が起こってしまうのでしょう。

    CWDIllegalInDllSearchはどうやればシステムフォルダ優先になるかよくわからなくて、KnownDLLsにversion.dllを追加するのは権限の問題で試験できてません

    追記05/26 12:55
    Windows7と10でKnownDLLsに定義(して再起動)したらシステムからversion.dllが読み込まれることを確認できました。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2017年5月26日 3:56
    • 回答としてマーク nino-n 2017年5月30日 4:25
    2017年5月25日 16:49

すべての返信

  • WPFで開発したEXEに限らずほぼすべてのアプリケーションでversion.dllを読み込んでいます。実際、Google Chromeも該当しますし、メモ帳も同様です。ですので、version.dllというDLLを読み込むのはWindowsの仕様と考えるべきです。なおWindowsではアプリケーションはProgram Files下に配置し、書き込み禁止にしているため基本的にはこの問題は顕在化しません。

    その上で、質問者さんはこの問題に対してどう対処したいのでしょうか?

    2017年5月25日 13:39
  • 下記の脆弱性に関する対策を実装し、検証しようとしている…のですかね?
    そうだとすると、脆弱性に対する理解の誤りがあり、検証方法を間違えています。

    https://support.microsoft.com/ja-jp/help/2389418/secure-loading-of-libraries-to-prevent-dll-preloading-attacks

    この問題は「カレントディレクトリ」に対するものなので、「アプリケーションと同じフォルダーに対して DLL を配置されること」への対策ではありません。
    「カレントディレクトリ」(作業フォルダーとも呼ぶ)と「アプリケーションのフォルダー」は別物だと言うことは理解しておいた方が良いでしょう。
    (アプリケーションと同じフォルダーに、アプリケーション利用者が想定しないような偽の DLL が置かれるような状況では、この脆弱性の比ではない、深刻な状況であり、アプリケーションでの対応というレベルを超えています)


    そうではなく、アプリケーションの利用者が悪意を持ち、自分達のアプリケーションに不正なコードを挿入してくること(例:ゲームに対するチート)を防ぎたいという主旨なら、かんたんな対策はないと思った方が良いです。
    偽 DLL 対策のほか、DLL Injection 対策も必要でしょうし…。
    2017年5月25日 13:55
  • .Netのランタイムのロードを行っているらしいmscoree.dllからアプリケーションのフォルダにあるversion.dllを呼び出している?
    mscoree.dllが参照しているversion.dll以外のdllは偽装dllを置いても呼ばれていないみたいなので、version.dllだけがおかしいと言えばおかしいかな。
    間接的に呼び出されてしまうdllを一般の開発者がどうにかすることもできないのでOSや.Net側で対処してもらわないとどうにもならなそう。

    例えばClickOnceは保護されていないフォルダに実行ファイルが置かれるので、悪意のある攻撃者が権限の低いアプリケーションを配布して、そのアプリケーションが権限の高いClickOnceアプリケーションのフォルダに偽装したversion.dllを注入するというシナリオが考えられるかなぁ。

    https://support.microsoft.com/ja-jp/help/2264107/a-new-cwdillegalindllsearch-registry-entry-is-available-to-control-the-dll-search-path-algorithm
    http://eternalwindows.jp/windevelop/dll/dll05.html
    を読むと、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs\にリストされているdllはシステムフォルダから読み込まれますが、それ以外は実行ファイルのあるフォルダから優先して読み込まれるとなるようです。
    それで、なぜversion.dllが除外されているかを調べてみると、
    Windows Confidential: The Known DLLs Balancing Act:という記事に理由が書かれていて、除外されたままであるためにこの現象が起こってしまうのでしょう。

    CWDIllegalInDllSearchはどうやればシステムフォルダ優先になるかよくわからなくて、KnownDLLsにversion.dllを追加するのは権限の問題で試験できてません

    追記05/26 12:55
    Windows7と10でKnownDLLsに定義(して再起動)したらシステムからversion.dllが読み込まれることを確認できました。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2017年5月26日 3:56
    • 回答としてマーク nino-n 2017年5月30日 4:25
    2017年5月25日 16:49
  • 質問させていただいた脆弱性の問題は、昨年末に公開された「InstallShieldFAQ」に基づきます。

    https://hds.networld.co.jp/helpdesk/support/FaqFacadeServlet?TaskType=Detail&seriesId=InstallShieldFAQ&id=00003343&categoryId=0074&faqInfo=1&JspUrl=/support/FrequentlyDetail.jsp#question

    # InstallShield の検索パスに関する処理の不備により信頼性のない検索パスの脆弱性が存在し、
    # ごく特定の条件下で InstallShield で作成したセットアップランチャー(setup.exe)の実行時に
    # 意図しない悪意のある DLL が読み込まれる可能性があります。

    インストーラのEXEファイルと同じフォルダに悪意あるversion.dllが配置された場合、
    本来は、Windowsのシステムフォルダのversion.dllを参照すべきところを、
    インストーラと同じフォルダ内にあるversion.dllが実行されてしまいます。

    その対策として、InstallShieldではhotfixが公開されました。

    また、MFCのEXEファイルは、今まで静的リンクで呼び出していたDLLを、
    フルパス指定で動的に呼び出すことにより対策できました。

    ですが、WPFのEXEファイルは、
    無条件でversion.dllが読み込まれるみたいで、
    対策方法が分からず質問させていただいた次第です。

    回答いただきました内容にもある通り、
    WPFの.Netのランタイムがロードしているらしいので、
    対策のしようがなさそうですね。

    レジストリKnownDLLsにversion.dllを定義する対策ですが、
    もし自前で作成したversion.dllという名前の別のDLLを利用しているソフトウェアが存在する場合、
    それらのソフトウェアに影響してしまうので、現実的な対策ではないような気がいたします。
    2017年5月30日 4:25
  • インストーラのEXEファイルと同じフォルダに悪意あるversion.dllが配置された場合、
    本来は、Windowsのシステムフォルダのversion.dllを参照すべきところを、
    インストーラと同じフォルダ内にあるversion.dllが実行されてしまいます。
    インストーラーだと問題のレベルが上がります。

    • Setup.exe などのインストーラーはほぼ管理者権限に昇格する
    • Setup.exe にデジタル署名がなされており、他者の信頼を元に実行される
    • Setup.exe に同梱される、悪意あるコードが実行される可能性がある
    • ローカルドライブ以外の場所から実行される可能性も十分高い
      (組織内の共有フォルダーなど、ローカルドライブよりも信頼性の低い場所から実行されうる)

    (たとえば、Microsoft の安全な exe とだまして不正なコードをユーザー環境で管理者権限で実行することで、UAC をくぐり抜ける攻撃となりうる)

    こう言うような状況もあり、Hotfix を出したのでしょう。

    さて、他の一般的な exe が問題になるかどうかですが、前の投稿でも述べましたように、「アプリケーションと同じフォルダーに、アプリケーション利用者が想定しないような偽の DLL が置かれるような状況では、この脆弱性の比ではない、深刻な状況であり、アプリケーションでの対応というレベルを超えています」という意見から変わりません。

    Program Files に置いていれば、昇格なしにそこにファイルを忍ばせることはできません。
    Program Files 以外だとしても、そこに DLL を忍ばせることができるということは、悪意あるユーザーにすでにだまされたか、ローカル環境へのアクセスを許してしまったかです。
    (それが満たされると言うことは、すでにローカル環境は信頼できない状況に陥っているので、アプリケーション個別の脆弱性対策の効果はありません。そこまでされる状況なら、exe 自体を偽物にすり替えることも容易でしょうから)

    アプリケーションに不正なコードが挿入されることのリスクはどの程度か、本当に対策が必要かで考えていくことになると思いますが、神経質に対応する必要はないと、私は考えています。
    (対策に伴うバイナリ構成の自由度の低下、工数の増加に見合う効果がないケースが多いと予想されるため)

    WPF を使う exe で同じフォルダーに不正な DLL が置かれる可能性が考えられ、それが非常にまずい(=アプリケーションを守る必要がある)のであれば、ビジネスインパクトを伝えられるようにしつつ、Microsoft のプレミアサポートなどで要望してください。

    2017年5月30日 13:22
  • 客先が公開しているダウンロードモジュール(InstallShieldのインストーラ、ラウンチャ)
    について、「JPCERT」から客先に指導があり、それに対する対策でございます。
    インストールラウンチャ、アップデータなど、対象は必ずしも
    Program Filesにインストールするアプリケーションだけではございません。

    最終的な解決策として、 WPFのEXEファイルをMFCのEXEファイルで
    パッキングし、MFCのEXEファイルの起動時に毎回新規フォルダーを作成して、
    そこにWPFのEXEファイルを展開して、起動させることにいたしました。

    また、DllImoport属性等で静的リンクしていたDLLは、すべて
    デジタル署名を確認の上、フルパス指定で動的にロードすることにいたしました。

    皆さま、親切にご回答いただきありがとうございました。

    2017年5月31日 6:36
  • 対策はVERSION.DLLだけに限られるのでしょうか?

    UNLHA32.DLL で作成された自己解凍書庫における任意の DLL 読み込みに関する脆弱性で説明されていますが、Windows Vista環境ではすべてのアプリケーションがカレントディレクトリに置かれたAPPHELP.DLLを読み込んでしまう問題が存在します。Windows 7以降ではAPPHELP.DLLを読み込む問題だけは改善されてはいますが、参照するDLLが増えれば増えるほど連鎖して読み込まれるDLLが増えていきます。

    MFCのEXEファイルを作成したとのことですが、たとえMFCをスタティックリンクしたとしてもかなりの数のWindows DLLを読み込まれますし、読み込まれたDLLが連鎖して読み込みします。どのDLLが読み込まれることになるのか確認されたのでしょうか?

    書き込まれた内容を読む限り問題の本質を理解せず場当たり的な対応でむしろ被害を広げているだけなように見受けられます。

    試しにVisual Studio 2017にてMFCダイアログアプリケーションをスタティックリンクで作成してみたところ、次のDLLがリンクされていました。

    • KnownDLLs記載あり
      • ADVAPI32.dll
      • GDI32.dll
      • KERNEL32.dll
      • ole32.dll
      • OLEAUT32.dll
      • SHELL32.dll
      • SHLWAPI.dll
      • USER32.dll
    • KnownDLLs記載なし
      • COMCTL32.dll
      • OLEACC.dll
      • WINSPOOL.DRV

    後半の3DLLについてはVERSION.DLLと同様の問題を抱えています。また上記11DLLは更に追加で読み込むDLLが存在するため、問題は3DLLに限定されません。

    2017年5月31日 7:31
  • 客先が公開しているダウンロードモジュール(InstallShieldのインストーラ、ラウンチャ)
    について、「JPCERT」から客先に指導があり、それに対する対策でございます。
    インストールラウンチャ、アップデータなど、対象は必ずしも
    Program Filesにインストールするアプリケーションだけではございません。

    最終的な解決策として、 WPFのEXEファイルをMFCのEXEファイルで
    パッキングし、MFCのEXEファイルの起動時に毎回新規フォルダーを作成して、
    そこにWPFのEXEファイルを展開して、起動させることにいたしました。

    ちょっとよくわからないんですが、WPFのEXEはインストーラがインストール時に実行するのですか?

    ※インストールした後に、改めて普通に起動する通常のアプリケーションではなく?

    JPCERTからの指導というのは、インストーラに対しての話なのですから、InstallShieldの脆弱性修正で対応されている話に見えるのですが、またそういうのとは状況が違うのでしょうか?

    実行時にフォルダを新規作成っていうのは、どこに作成でしょうか?インストーラならインストーラを実行したフォルダ配下とかでしょうか?

    ※もし通常のアプリケーションだと、Program Files配下に作るわけにはいかないと思いますし、どこか別のフォルダに作成するのでしょうか?

    で、もし仮にインストーラが、インストール時に自分のいる場所の配下にフォルダを作るとかだと、問題は回避できていないように思うのでまずいです。

    もし、通常のアプリがフォルダを作って実行するなら、余計に危険を増やしていると思うのでやっぱりまずいと思います。

    --追記

    インストール時に、インストーラ経由で実行されるWPFのEXEが問題、ということなら、新しくフォルダを作成した後、追加でカレントディレクトリを安全な場所に変えてしまう(作成した新しいフォルダでもよい)とどうなるでしょうか?

    • 編集済み なちゃ 2017年5月31日 8:09
    2017年5月31日 8:06