### 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 最終更新:Sep.30,2017>

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


概要

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

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

  • LHMelt Ver 1.65.3.6 及びそれ以前
  • 上記をコマンド的に使用している一部のアプリケーション

詳細情報

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

想定される影響

 LHMelt を実行することにより, その時点で使用しているユーザーの権限で任意のコードを実行されたり, サービス運用妨害 (DoS) 攻撃を受ける可能性があります。

対策方法

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

 なお, 新版の自己解凍書庫については使用実績が少ないことから, ダウンロード・アップロード時に各種対策ソフトの検疫により削除される可能性があります。 UNLHA32.DLL Ver 3.00 の配布ファイルである ULH3300.EXE について Symantec へ検体提出してありますが, SHA256 によるホワイトリスト登録から「同種の自己解凍書庫」としての判別方法へ転換されるまでには時間を要すると推測されます。

回避方法

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

技術情報

 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. プログラム (今回であれば LHMelt) の置かれているディレクトリー
  2. ウインドウズ・システムディレクトリー
  3. 16 ビット用システムディレクトリー
  4. ウインドウズディレクトリー
  5. カレントディレクトリー
  6. 環境変数 PATH で指定された各ディレクトリー

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

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

補足情報

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

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

修正版 LHMelt の限界

 今回の脆弱性の素となっている 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() する」のと本質的に変わりありません。

 そこで, プログラム側 (LHMelt 側) でこれらの機能を使って脆弱性の回避を行うことになるわけですが, それには以下のような制限が付きまといます:

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

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

  • Windows 10 や Windows 8/8.1 については現状回避できているものの, OS のアップグレードや修正パッチの適用, 対策ソフトの変更といった環境の変化により DLL の依存関係が変化することで, 対応できなくなる可能性がある。
  • Windows 7 については, 少なくとも SSPICLI.DLL について独自ルールの検索と読み込みが行われていることから, 追加の対策が必要となる (対応済みではあるものの, 危険性が高いといえる。)
  • Windows Vista については, KERNEL32.DLL が NTDLL.DLL により読み込まれる時点で APPHELP.DLL に対する DLL ハイジャックが成立してしまうことから, 完全な対応は不可能。 現状, LHMelt では発生していないが「成立する」と考えておいたほうが得策。
  • Windows XP 以前については, 多数の DLL が Vista での APPHELP.DLL と同じ状況に陥っていることから, 対応自体が不可能。
  • そもそも, 「アーカイバー DLL と同じ名前の DLL を LHMelt がインストールされているディレクトリーへ配置する」ことで, アーカイバー DLL を対象としたハイジャックが成立してしまう。
    これについては, 全てのアーカイバー DLL をシステムディレクトリーへインストールした上で, 隠しメニューの「システムディレクトリのみ許可」を有効にすることで回避が可能です。 ただし, LMLzh32.DLL やバージョン情報表示ダイアログ用 DLL 等は読み込まれなくなりますので, 注意が必要となります。 (LHMelt と同じディレクトリー上へインストールされているため。)  その辺りもあって, 隠しメニューとした上で既定が無効となっています。 DLL ロードの挙動を把握できる方のみ設定を お使いください。
  • Windows 7/Vista については, KB2533623 の更新プログラムを適用していることが前提。 これが適用されていないと SetDefaultDllDirectories() API などが使えないことから, 根本的に対応が破綻する。

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

更新履歴

  • 脆弱性情報の公開 [May.15,2017]
  • 参考情報に JVN の情報 (JVNTA#91240916) を追加 [May.25,2017]
  • 対策版公開に伴う情報の変更 [Jun.11,2017]
  • 参考情報に「Windows アプリケーションにおける DLL 読み込みに関する脆弱性について」(MHVI#20170718) の情報を追加 [Aug.23,2017]
  • 参考情報に IPA の情報「【注意喚起】Windowsアプリケーションの利用における注意」を追加 [Sep.30,2017]

参考情報

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