### Micco's Home Page ### Welcome to Micco's page!!
Sorry, but this web page is written in Japanese.
<English>
■ 更新情報
■ このWebページについて
■ お知らせ
■ ダウンロード
■ DLL のインストール方法
■ SFX の設定例
■ いろいろ
対応ブラウザー
[Internet Explorer] [Firefox] [Opera] [Sleipnir] [Safari] [Google Chrome]
連絡先:Micco
[e-mail]
[→『脆弱性情報一覧』] [→Home]

<公開:May.15,2017 最終更新:Aug.23,2017>

MHSVI#20170515-02:
UNLHA32.DLL における任意の DLL 読み込みに関する脆弱性


概要

 UNLHA32.DLL は, LZH, LZS 形式に対応した圧縮・展開等の書庫操作を行うライブラリーです。 UNLHA32.DLL には DLL を読み込む際の検索パスに問題があり, 同一ディレクトリーに存在する特定の DLL を読み込んでしまう脆弱性 (CWE-427) が存在します。

影響を受けるモジュール及びシステム

  • UNLHA32.DLL Ver 2.67.1.2 及びそれ以前
  • 上記を利用しているアプリケーション

詳細情報

 UNLHA32.DLL は, 『統合アーカイバ』の API 仕様に準拠した, LZH, LZS 形式書庫に対して圧縮・展開といった操作を行うためのライブラリーです。 UNLHA32.DLL は主に圧縮・展開を行うアーカイバーソフトウェアから呼び出される形で使用されますが, 同一ディレクトリーに存在する特定の DLL を読み込んでしまう脆弱性が含まれており, 任意のコードを実行されたり, クラッシュを引き起こされる可能性があります。

想定される影響

 UNLHA32.DLL を利用しているアプリケーションの動作状況により異なりますが, 当該アプリケーションを実行しているユーザーの権限で任意のコードを実行されたり, サービス運用妨害 (DoS) 攻撃を受ける可能性があります。

対策方法

 最新版 (Ver 3.00 以降) へバージョンアップを行ってください。 [ダウンロード]

回避方法

  • UNLHA32.DLL を利用するアプリケーションについて "C:\Program Files" 配下などの保護されたディレクトリーにインストールした上で, UNLHA32.DLL をアプリケーションと同じディレクトリーかシステムディレクトリーにインストールする (配布ファイルによりインストールを行った場合は, システムディレクトリーにインストールされます。) ことで, 回避を行うことが可能です。 アプリケーション側, UNLHA32.DLL 側双方の条件が満たされないと回避は行えません。
    なお, この対策で行えるのは正確には「問題の軽減」ですが, これは市販ソフトなども同様で, その状況を問題視するのであれば, 市販ソフトや Windows のアクセサリーを含む大多数のプログラムが該当することになります。
  • アプリケーション側で UNLHA32.DLL の使用有無等を行える場合は, UNLHA32.DLL を使用しない, 別の DLL や代替方法を選択する, といった設定を行うことで回避を行うことが可能です。

技術情報

 Windows においては, ほぼ全てのプログラムが "KERNEL32.DLL" や "USER32.DLL" といったシステムライブラリーに実装されている Win32 API を使用しています。 DLL の利用については, 「存在するか判らない DLL」「必ずしも必要としない DLL」であれば, LoadLibrary() API を使用して DLL のロードを行った上で使用したい API の呼び出し先を GetProcAddress() で得る…といった手順を踏むことになります。

一方, 「Win32 API を使用するために KERNEL32.DLL や USER32.DLL をロード」といった, 「必ず使用する DLL」「システムファイルとして Windows に必ず含まれている DLL」を利用する際には, 例えば USER32.DLL であれば USER32.LIB といった, それぞれの DLL に対応したインポートライブラリーを使用することにより, DLL のロードや呼び出し先の取得といった手順を Windows に任せる…という手法が一般的に採用されます。 インポートライブラリーを使用した場合, プログラムの実行ファイル内に「当該プログラムが使用する DLL と (例えば Win32 API などの) 呼び出す機能」が一覧されたインポートテーブル…つまり, 外部参照の一覧表が作成されます。

 インポートテーブルが含まれるプログラムを起動すると, 実際に当該プログラムへ制御が渡る前の段階で, Windows のシステムライブラリーである NTDLL.DLL に存在するイメージローダーが, インポートテーブル上にある外部参照の情報を読み込んで, 必要な DLL のロードと機能の呼び出し先の取得を行います。 読み込んだ DLL がインポートテーブルをもっていれば同様の手順を再帰的に行います。 これらの作業は, 全ての外部参照が解決されるまで繰り返されます。

この際, Windows は定められた優先順位に従って複数のディレクトリーを検索して DLL を読み込みます。 例えば Safe DLL search mode が有効の場合は次のようになります:

  1. UNLHA32.DLL を呼び出したプログラムの置かれているディレクトリー
  2. ウインドウズ・システムディレクトリー
  3. 16 ビット用システムディレクトリー
  4. ウインドウズディレクトリー
  5. カレントディレクトリー
  6. 環境変数 PATH で指定された各ディレクトリー

この時に, プログラムの置かれているディレクトリーが最も優先順位の高い検索対象となっているため, システム DLL と同じ名前の細工された攻撃用 DLL をプログラムと同じディレクトリーへ置くことで, 優先的に攻撃用 DLL を読み込ませることが可能となります。

DLL の読み込み時には必ず初期化が行われることから, 初期化ルーチンにおいてプログラムの実行に使用したアカウントがもつ権限の範囲で任意のコードを実行することが可能となります。 初期化ルーチンを利用できることから, 細工された攻撃用 DLL がシステム DLL の仕様を満たしている必要はありません。

補足情報

 今回の脆弱性は, MHSVI#20100824:「LHMelt における安全でないライブラリーのロードによりリモートでコードが実行される脆弱性」と同じ脆弱性ではありますが, 置かれている状況は大きく異なります。 今回「安全でないライブラリーのロード」を行っているのは Windows システムの一部である NTDLL.DLL (上のイメージローダー) であり, しかもそれは「ユーザーが起動しようとしたプログラム (=UNLHA32.DLL を呼び出すプログラム) 若しくは UNLHA32.DLL へ制御が渡る前」に行われています。 つまり, UNLHA32.DLL 側には通常の方法では対処のしようがないことになります。

この点は市販ソフトや巷に溢れている Windows プログラムも同じで, 言ってしまえば「ほぼ全てのプログラム」が該当してしまうことになります。 「市販ソフトなど一般的なアプリケーションでは, 書き込みに管理者権限を必要とする "C:\Program Files" ディレクトリー配下へインストールされるケースが多く, その分安全性が若干高まっている」に過ぎません。 反対に, インストーラーやツール, 自己解凍書庫といったプログラムは「置き場所 (実行場所) を選ばず使われることから, 脆弱性として問題になっている」といえます。

修正版 UNLHA32.DLL の限界

 今回の脆弱性の素となっている NTDLL.DLL (イメージローダー) の仕様ですが, MSVCRT.DLL や CTL3D.DLL, CTL3DV2.DLL といった DLL に始まり, MFC32.DLL などの MFC ライブラリーで大問題となってしまった「バージョンヘル」の軽減策として, 「プログラムと同じディレクトリーへ DLL を配置することで使用 DLL をオーバーライドする」という手法が定着してしまったことから, 今となっては仕様変更を行えない事態に陥ってしまっています。 また, 過去のしがらみから, 本来行われるべき「(システムライブラリーについて) システムディレクトリー以外から読み込まない, 読み込めないようにする」といった保護策についても, 一部のシステム DLL にしか講じられていません。

この辺りは MSDN でも説明されていて, それを避けるために用意されているのが, SetDllDirectory() や SetDefaultDllDirectories(), SetSearchPathMode(), LoadLibraryEx() (の追加機能) といった API 群, そしてリンカーとヘルパーライブラリーによる「DLL の遅延ロード」です。 遅延ロードは, ランタイムの一部ともいえるヘルパーライブラリーがプログラムの起動後に LoadLibrary() + GetProcAddress() を行う機能で, 先に書いた「プログラム側が LoadLibrary() + GetProcAddress() する」のと本質的に変わりありません。

 そこで, UNLHA32.DLL 側でこれらの機能を使って脆弱性の回避を行うことになるわけですが, それには以下のような制限が付きまといます:

  • KERNEL32.DLL の遅延ロードを行うことは出来ない (これが読み込まれていないと, そもそも DLL のロードを行えない…どころか, ほぼ何も出来ない。)
  • SetDefaultDllDirectories() などの設定に因らない, 独自ルールの検索と読み込みが行われる DLL の存在。 Windows 7 での SSPICLI.DLL 辺りが該当し, 一捻り加えた対応を行わないと, 素直な対策だけではハイジャックが成立してしまう。 遅延ロードなどは逆にハイジャックへ寄与することになるので注意。
  • 自身 (UNLHA32.DLL) や呼び出し側プログラムに接触してくる他プログラム (IME や (システムを含む) 監視ツール・対策ソフトの類い) の存在。 「英仏環境 (キーボード) だと大丈夫なのに日本語環境だとハイジャックが成立」などはこれ。
  • システムにより保護されている DLL と保護されていない DLL の, 呼び出し状況による依存関係の変化で生じる影響。 「対策済みとされていたソフトが BCRYPT.DLL 辺りで転ける」などはこれ。
  • UNLHA32.DLL を呼び出すプログラム側 (例えば LHMelt) の対応状況
  • 「呼び出される側」である UNLHA32.DLL 側では SetDefaultDllDirectories() を使用できない (呼び出し側プログラムに影響を与えてしまい, 最悪プログラムを起動できなくなる…どころか, Windows 8/8.1 では NTDLL.DLL が一般保護エラーを起こす。)

結果, 修正版の UNLHA32.DLL には以下のような限界が存在します。

  • Windows 10 や Windows 8/8.1 については現状回避できているものの, OS のアップグレードや修正パッチの適用, 対策ソフトの変更といった環境の変化により DLL の依存関係が変化することで, 対応できなくなる可能性がある。
  • Windows 7 については, 少なくとも SSPICLI.DLL について独自ルールの検索と読み込みが行われていることから, 追加の対策が必要となる (対応済みではあるものの, 危険性が高いといえる。)
  • Windows Vista については, KERNEL32.DLL が NTDLL.DLL により読み込まれる時点で APPHELP.DLL に対する DLL ハイジャックが成立してしまうことから, 完全な対応は不可能。
    なお, APPHELP.DLL に限って言えば, 単に同名の DLL を作成した程度では, 初期化ルーチンを含めて実際にコードが実行されることはない。 ただし, DLL のロードが試みられるため, 実行ファイル以外の形式が使われた場合, システムによる「○○は Windows 上では実行できないか、エラーを含んでいます。」の警告が表示される。 どちらの場合も, 実際にロードされるのはシステムディレクトリー上の正規版 APPHELP.DLL となる。
  • Windows XP 以前についてはシステムに保護機能が備わっていず, 多数の DLL が Vista での APPHELP.DLL と同じ状況に陥っていることから, 対応自体が不可能。
  • Windows 7/Vista については, KB2533623 の更新プログラムを適用していることが前提。 これが適用されていないと SetDefaultDllDirectories() API などが使えないことから, 根本的に対応が破綻する。
  • そもそも UNLHA32.DLL を呼び出す側のプログラム (例えば LHMelt) が この脆弱性に対応していないと, UNLHA32.DLL 側での対応が無意味となってしまう。 上述の「回避方法」の対策が講じられているのであれば, 危険性は市販ソフト等と同じ。

Windows XP 以前の OS はともかく, Windows 7 や Vista については, 可能であれば「システムディレクトリー (若しくは正規なものと判明している DLL が置かれているディレクトリー) 以外に存在する SSPICLI.DLL や APPHELP.DLL について, 実行やアクセスを拒否する設定を行う」ことで, 危険性の軽減を図ることが可能です。

更新履歴

  • 脆弱性情報の公開 [May.15,2017]
  • 参考情報に JVN の情報 (JVNTA#91240916) を追加 [May.25,2017]
  • 「修正版 UNLHA32.DLL の限界」の項目について, Windows Vista での APPHELP.DLL に関する問題の情報を更新。 [Aug.19,2017]
  • 参考情報に「Windows アプリケーションにおける DLL 読み込みに関する脆弱性について」(MHVI#20170718) の情報を追加 [Aug.23,2017]

参考情報

[→Page top] [→『脆弱性情報一覧』] [→Home]