セキュリティ技術カテゴリ担当の村上です。今回は、少し前に話題になったKHOBE(Kernel HOoking Bypassing Engine)と呼ばれるセキュリティ機能回避の問題について説明します。
今月5日、matousec.comによってKHOBEと呼ばれる技術を利用することで多くのセキュリティソフトが備えるセキュリティ機能が回避可能であることが報告されました。こうしたセキュリティソフトの多くは、APIフックを行うことでOSが提供している正規の処理をインターセプトし、独自のセキュリティ機能を実装した代替処理を実行します。例えば、統合セキュリティソフトやデスクトップIPSの場合、マルウェアによって自身のプロセスが強制終了させられないようにプロセスを停止させるAPI、サービスを停止させるAPI、ドライバをアンロードするAPI等をフックしているケースがあります。他にもファイル、レジストリ、プロセス等へのアクセス制御を実現するためにこうしたリソースにアクセスするAPIをフックし、定義されたポリシーとの比較検証ロジックを実装しているケースも存在します。KHOBEは、セキュリティ機能をバイパスする技術です。
この問題は、APIフックの代替関数における引数の取扱いに起因します。例えば、OSが提供しているファイルを開くAPIをフックするケースを考えてみましょう。ここでは当該APIを便宜上、OpenFileと呼びます。APIフックを行うプログラムは、このOpenFile APIを、独自のセキュリティ機能を実装したCustomOpenFile関数でフックします。以下にAPIフックを行うプログラムの疑似コードを示します。
---
some_func(...)
{
// OpenFile APIをCustomOpenFile関数でフックし、
// OpenFile APIのアドレスをOrigOpenFileに保存する
OrigOpenFile = ApiHook(OpenFile, CustomOpenFile);
...
}
CustomOpenFile(char *filename, ...)
{
// ファイルオープンの妥当性を引数に含まれる
// filenameに基づいて比較検証する
if (filename && check_policy(filename)) {
return ACCESS_DENIED;
}
// ※1
// 保存しておいたアドレスを利用して、元のOpenFile APIを呼び出す
return OrigOpenFile(filename, ...);
}
---
一見するとなんの問題もないように見えますが、CustomOpenFile関数にはレースコンディションの脆弱性が存在します。これは、より具体的には、TOCTOU(time-of-check, time-of-use)問題と呼ばれており、攻撃者は、※1のfilenameチェック後のタイミングでfilenameを変更することで、チェックを回避してOrigOpenFile APIを呼び出すことができます。
攻撃を行うプログラムは、例えばマルチスレッドで動作し、スレッドAがOpenFileを繰り返し呼び出し、スレッドBがスレッドA中で呼び出されたOpenFile APIの引数であるfilenameを絶えず変更します。スレッドBのfilenameの変更がちょうど※1のタイミングで行われれば、チェックを回避することが可能です。
ご想像の通り一回でこの攻撃を成功させることは確率的に考えて非常に難しく、数千回、数万回試行してやっと一回成功する、という性質の問題です。攻撃の成功確率はプロセッサ環境(シングル・マルチプロセッサ)、値のチェックと利用の間に行われる処理の有無・量、タスクスケジューラーの実装等によって変動します。とは言っても、一回でも成功すればそれで十分というケースもあるため軽視することはできません。対策としては、チェック時の値が実際に利用されることを保証する必要があります。そのため、下記のような修正が有効です。
---
CustomOpenFile(char *filename, ...)
{
char *copy_filename = NULL;
int ret;
if (!filename)
return OrigOpenFile(NULL, ...);
// filenameのコピーを作成する
// ※このstrdupは必ず成功する
copy_filename = strdup(filename);
// 作成したコピーを利用してチェックを行う
if (check_policy(copy_filename)) {
// 関数を抜ける前にコピーを解放する
free(copy_filename);
return ACCESS_DENIED;
}
// 作成したコピーを利用する
ret = OrigOpenFile(copy_filename, ...);
// 関数を抜ける前にコピーを解放する
free(filename);
reutrn ret;
}
---
matousec.comの報告では、実際に多くのセキュリティ製品がこうした問題を含んでおりセキュリティ機能を回避することが可能とのことです。興味のある方は、一次情報もチェックするお勧めします。余談ですが、一次情報では、SSDTフックを例に問題の説明がされていますが、この問題自体はSSDTフックに限らずフック全般に関連した実装の脆弱性だと言えます。
KHOBE – 8.0 earthquake for Windows desktop security software