dllハイジャッキング脆弱性について考える2

前回の最後に「このところいろいろなアプリでインストーラーに脆弱性があったとのことで、対策版のインストーラーのリリースされています」とお伝えしました。今回は、これらのインストーラーで発生した脆弱性のメカニズムについて考えてみたいと思います。

最近話題なっているアプリのインストーラーにおけるdllハイジャッキング脆弱性は、前回お話ししたLoadLibrary APIの使い方の問題によって発生する脆弱性の発生メカニズムとは異なります。

前回は、「アプリケーションが明示的にdllを読み込むとき」のdllハイジャッキング脆弱性の話でした。

最近、アプリのインストーラーで多発している(脆弱性が発見されている)のは「アプリケーションの起動時に自動的に読み込みされるように設定されているdllが読み込まれるとき」のdllハイジャッキング脆弱性です。

これらの違いは、dllファイルがどのようにアプリケーションにリンクされているかの違いです。すなわちdllファイルのリンク方法には2種類あります。

  • 明示的リンク (Explicit Linking)
    OSがアプリケーションを起動しアプリケーションのエントリポイント(メイン関数)が呼び出されます。その後、アプリケーションがLoadLibraryなどのAPIを使い明示的にdllを読み込みます。
  • 暗黙的リンク (Implicit Linking)
    OSがアプリケーションを起動する時にそのアプリケーションが依存するdll(使用することに設定されているdll)を自動的に読み込みます。指定のdllファイルの読み込みが完了した後にアプリケーションのエントリポイント(メイン関数)が呼び出されます。

前者の「明示的リンク」の場合、アプリケーションを実装するときに

  • dllファイルを絶対パス(フルパス)で指定する
  • 指定先は一般ユーザー権限で書き込めない場所を指定する

を守ればdllハイジャッキング脆弱性の問題は発生しません。

後者の「暗黙的リンク」の場合、アプリケーションが依存するdllファイルは相対パスで指定した場合と同じ状況で読み込まれます。これはOSの挙動なので変えられません。

ではどうすればよいのか?

基本に立ち返り、dllハイジャッキング脆弱性が起きる条件を考えます。dllハイジャッキング脆弱性が発生するためには悪意のあるdllファイルが読み込まれることが必要です。そのためには悪意のあるdllファイルがdllファイルの検索順序のどこかに存在する必要があります。そうです。ユーザー権限で書き込みできる場所です。

ここで相対パスで指定した時のdllファイルの検索順の表をもう一度掲載します(一般ユーザーを一つにして少し簡略化しました)。

検索順 場所(フォルダー) 管理者でアプリを起動 一般ユーアプリをザーで起動
1 a. 管理者権限で配置(インストール)したアプリのexeファイルのあるフォルダー
(C:\Program Files\配下にある)
読み/書き 読み/-
 b. 一般ユーザー権限で配置したアプリのexeファイルのあるフォルダー 読み/書き 読み/書き
2 システムフォルダー 読み/書き 読み/-
3 16bitシステムフォルダー 読み/書き 読み/-
4 Windowsフォルダー 読み/書き 読み/-
5 カレントフォルダー 読み/書き 読み/書き
6 PATH環境変数に列挙されている複数のフォルダー 読み/書き 読み/書き

管理者権限で配置したアプリを管理者権限でアプリを起動したとき

この場合はすべての場所で書き込みができてしまいますが、そもそも管理者権限が奪われていたときは攻撃者はdllハイジャッキングする必要もないので、このパターンは今回は考えないことにします。

管理者権限で配置したアプリを一般ユーザー権限でアプリを起動したとき

この場合は1a, 2, 3, 4…と検索されます。1a, 2, 3, 4までの場所は読み出し権限でしかアクセスできません。相対パスで指定したdllファイルが1a, 2, 3, 4までの場所に必ず存在するファイルであれば、悪意のあるdllファイルが読み込まれることはありません。dllハイジャッキング脆弱性が発生しません。「管理者権限でインストールしたアプリを一般ユーザーが起動する」という通常のアプリがこのパターンに該当します。

一般ユーザー権限で配置したアプリを一般ユーザー権限でアプリを起動したとき

この場合は1b, 2, 3, 4…と検索されます。ところが最初の1bの場所で一般ユーザーでの書き込み権限があります。そのためシステムフォルダーに必ず存在するdllファイルを「暗黙的リンク」した場合であっても、1bの場所に悪意のあるdllファイルが存在するとそれを読み込んでしまうことになります。dllハイジャッキング脆弱性が発生します。ありがちな「ユーザーがダウンロードしたexe形式のインストーラーを起動する」というアプリをインストールするときの状況がこのパターンに該当します。

WEBサイトからダウンロードするexe形式のインストーラー

WEBサイトからダウンロードするファイルはWEBブラウザーの仕様にもよりますが、ほとんどの場合、「ダウンロード」フォルダーなど決まったフォルダーに保存されます。そしてほとんどのユーザーは保存されたインストーラーをその場所から起動します。

WEBサイトからダウンロードしたファイルは同じ場所に保存されることにより、悪意のあるdllファイルも同じ場所にダウンロードされます。

ユーザーはダウンロードしたファイルがEXEファイルの場合、それを起動するときはマルウェアでないか注意深く確認してから起動すると思います。しかし、ダウンロードしたファイルが直接起動できないdllファイルであった場合、間違ってダウンロードしてしまっただけと思い、悪意のあるdllファイルがそのまま「ダウンロード」フォルダーに残り続ける可能性が高いです。

その後、ユーザーが別の機会にダウンロードしたEXE形式のインストーラーを起動したときに、dllハイジャッキング脆弱性が発生します。

そのexeファイルが存在するフォルダーはシステムフォルダーより検索順位が高いため、システムフォルダーにあるよく利用されるdllファイル名と同じものを用意すればかなりの確率でdllハイジャッキングが成功します。

それもexe形式のインストーラーの場合、起動時に管理者に昇格(エレベーション)するものが多いです。この管理者への昇格は依存するdllファイルを読み出す前に行われます。そのためdllハイジャッキングが発生したときは、管理者権限が奪われることになります。

最近、Windowsのデスクトップアプリの脆弱性対応版のインストーラーがリリースされているものは、ほとんどがこのメカニズムの脆弱性に対する対応版です。

インストーラーのdllハイジャッキング脆弱性の対応方法

対策にはいくつかあります。

  • インストーラーをexe形式ではなくmsi形式でダウンロード配布する
  • インストーラーをCD-ROM/DVD-ROMなど読み出し専用のメディアで配布する
  • dllハイジャッキングの脆弱性がないパッケージ作成アプリで自己展開形式exeファイルとして作成し、配布する
  • インストーラーをzip形式ファイル(自己展開のexeファイルではない)で圧縮し、配布する

では、それぞれについて詳しく見ていきます。

インストーラーをexe形式ではなくmsi形式でダウンロード配布する

そもそもdllハイジャッキングはインストーラーがexe形式だと発生します。だったらexe形式以外のインストーラーにすればよいのです。その一例がmsi形式ファイルです。派生としてmsp形式ファイルもあります。これらは、exeファイルと同じようにダブルクリックでインストーラーを起動できます。そのためユーザーエクスペリエンスはexe形式ファイルで配布した場合とあまり変わりません。

msi形式はマイクロソフトが2000年くらいからサポートし始めた歴史のあるインストーラーの方式です。msi形式ファイルはフルインストーラーです。それに対しmsp形式ファイルは差分インストーラーです。フルインストーラーはアプリがインストールされていない環境にもインストールできますが、差分インストーラーはアプリがインストールされている環境に一部のファイルを更新するときに使える形式です。

msi/msp形式のファイルはtxt形式やdoc形式のファイルと同様にダブルクリックなどでファイルを開く操作をした場合、それらの形式に関連付けられているexeファイルを起動されます。doc形式の場合、Microsoft Wordやワードパッドが起動されるように、msi/msp形式の場合はWindows Installerの実行エンジン(msiexec.exe)が起動されます。

このWindows Installerの実行エンジン(msiexec.exe)は、Windowsを構成するファイルの一つであり、Windowsのシステムフォルダー(C:\Windows\System32\)に存在します。このフォルダーは一般ユーザー権限では書き込みできないので、管理者権限が奪われない限り、dllハイジャッキングでの攻撃はできません。

msi形式インストーラーの作成方法には、

  • 単一ファイルのmsiインストーラー形式
    インストーラーを一つのファイルとして作成するインストーラー形式
  • 複数ファイルで構成されるmsiインストーラー形式
    インストーラーをmsiファイルとその他の複数のファイルで構成するインストーラー形式

があります。msi形式インストーラーをmsi形式のまま(単一ファイルのexeファイル化せずに)インターネットで配布する場合は、前者の方法で作成する必要があります。ただ、これらの違いは、純粋なmsiインストーラーであれば、msiインストーラーをビルドするときにその方式を設定すればよいだけなので、どちらの形式も容易に作成できます。

インターネットで配布されているアプリのインストーラーの中には、単一ファイルのmsi形式で作成されているインストーラーであるにもかかわらず、それをさらに自己展開形式exeファイルにパッケージし直しているインストーラーもいくつか見受けられます。

もちろん、そのパッケージを作成するアプリ(パッケージ作成アプリ)にdllハイジャッキングの脆弱性がなければ問題ありません。しかし、dllハイジャッキングの脆弱性をもつパッケージ作成アプリで自己展開形式exeファイルを作成しているもが多く見受けられます。単一ファイル化したmsi形式ファイルをそのまま配布できるにもかかわらず、わざわざexe化することで、dllハイジャッキングの脆弱性を埋め込んでいるのです。そのようなアプリのインストーラーを公開している会社や開発者は改めてほしいものです。

インストーラーをCD-ROM/DVD-ROMなど読み出し専用のメディアで配布する

dllハイジャッキングは、インストーラーが実行される前までに、悪意のあるdllファイルがdllの検索順序の上位の場所に存在する必要があります。もし、exe形式のインストーラーが読み出し専用メディア上にあり、そこから直接実行された場合は、インストーラーと同じ場所に悪意のあるdllファイルが保存される(書き込まれる)ことはありません。そのため、インストーラーがdllハイジャッキングの脆弱性を持っていたとしても、dllハイジャッキングの攻撃はできません。

もちろん、初めからメディアに悪意のあるdllファイルがあった場合は攻撃が成功しますが、そのようなメディアを出荷してしまうことは出荷前確認をちゃんとしている会社ならありえないと思います。

また、ユーザーがメディアからハードディスクなどにコピーしてインストーラーを実行した場合は、dllハイジャッキングの脆弱性をもっているインストーラーの場合は、dllハイジャッキングの攻撃は可能です。

ただこの方法は、物理的なメディアを用意する必要があり、配布に費用がかかるので、インターネットが当たり前になった現在ではあまり行われていません。今はWEBサイトからのダウンロードの場合がほとんどです。

dllハイジャッキングの脆弱性がないパッケージ作成アプリで自己展開形式exeファイルとして作成し、配布する

単一ファイルの自己展開形式exeファイルにパッケージングしたすべてのインストーラーが、dllハイジャッキングの脆弱性を持つわけではありません。パッケージングに作成したツールがdllハイジャッキングの脆弱性を持たなければ、作成した自己展開形式exeファイルも脆弱性を持ちません。

ただ、このパッケージングするパッケージ作成アプリの多くが、脆弱性を持っていたことにより、いろいろなアプリの自己展開形式インストーラーでも脆弱性を持つことになりました。結果として、いろいろなアプリのインストーラーの脆弱性対策版がリリースされました。

最近、多くのパッケージ作成アプリでdllハイジャッキングの脆弱性に対して対応が進んできました。しかし、よく使われているツールでも対応できていないものがまだ多く残っています。

そこで私はdllハイジャッキングの脆弱性の問題を持たないパッケージ作成アプリを作成して公開しようと考えた次第です。開発したパッケージ作成アプリは

IconFile Package App (ファイルパッケージアプリ)

として、2018年4月22日に初版を公開しました。

インストーラーをzip形式ファイル(自己展開のexeファイルではない)で圧縮し、配布する

Windowsの機能を使って、インストーラーをzip形式として圧縮し、一つのファイル(zip形式ファイル)として配布する方法です。zip形式ファイルは、Windowsの標準機能で展開することができます。

zip形式ファイルのインストーラーをダウンロードしたユーザーは、Windowsの機能を使って新しいフォルダにzip形式ファイルを展開します。その後、展開した中のインストーラーの起動プログラム(多くの場合setup.exe)を起動してインストールします。

Windowsの標準機能(Windowsのシステムフォルダーにあるexeファイルを使って)で圧縮ファイル(zipファイル)を展開するため、dllハイジャッキングの脆弱性の攻撃は発生しません。また、新しいフォルダーに展開することにより、悪意のあるdllファイルが事前に配置される心配もありません。

ここでユーザーエクスペリエンス的に問題なのは、「ダブルクリックだけではインストールが開始できないこと」です。ダブルクリックすると、エクスプローラーがzipファイルの中のファイルを表示します。しかしこの状態は表示のために一時的に展開しているにすぎず、そのままさらにインストーラーをダブルクリックで起動することは推奨されません。起動できたように見えても、インストールが失敗する可能性があります。

ユーザーの手順としては、zipファイルのコンテキストメニュー(マウスの右ボタンクリックで表示される)の中から「すべて展開」という項目を選び、明示的に展開します。その後、展開されたフォルダの中からユーザーがインストーラー(setup.exeなど)を起動することになります。

手順を知らないユーザーの多くは、zipファイルをダブルクリックで開き、その中に表示されるインストーラーを起動しようとして、インストールが正常に完了しないことに遭遇します。

このため、zip形式ファイルでの配布は、ユーザーエクスペリエンス的に問題があります。


最近多く発生しているインストーラーにおけるdllハイジャッキングの脆弱性について考えてみました。

インストーラーを公開するときは、自己展開形式EXEファイルを作成するアプリ(パッケージ作成アプリ)として、dllハイジャッキングの脆弱性がないものを使用することの重要性がわかったと思います。

Windowsのデスクトップアプリを公開する方々(私も含め)は、自己展開形式EXEファイルを作成するアプリを選ぶときは、dllハイジャッキングの脆弱性がないことを確認しましょう。

“dllハイジャッキング脆弱性について考える2” への1件の返信

コメントを残す