230 likes | 381 Views
スタック保護システム : (propolice 、 StackGuard 、 XP SP2). 江藤 博明 日本アイ・ビー・エム株式会社、東京基礎研究所. 目次. スタックのバッファ オーバーフロー スタックスマッシング攻撃とは? スタック プロテクタ ランドスケープ Stack Guard propolice Windows XP SP2 (/Gs option) 比較 まとめ. スタックのバッファ オーバーフローとは?. バッファ オーバーフローは割り当てられたメモリ領域(バッファ)を超える量のビットを入力しようとすると発生する
E N D
スタック保護システム: (propolice、StackGuard、XP SP2) 江藤 博明 日本アイ・ビー・エム株式会社、東京基礎研究所
目次 • スタックのバッファ オーバーフロー • スタックスマッシング攻撃とは? • スタック プロテクタ ランドスケープ • Stack Guard • propolice • Windows XP SP2 (/Gs option) • 比較 • まとめ
スタックのバッファ オーバーフローとは? • バッファ オーバーフローは割り当てられたメモリ領域(バッファ)を超える量のビットを入力しようとすると発生する • 以上が起こった場合、次の連続したメモリの塊が上書きされてしまう • 戻りアドレス • 関数ポインタ • 前回のフレームポインタなど • また攻撃コードも挿入される • これらは深刻なセキュリティ問題に繋がる
スタックレイアウトおよび攻撃により影響を受けたメモリ---関数fooがbarによって呼び出される場合スタックレイアウトおよび攻撃により影響を受けたメモリ---関数fooがbarによって呼び出される場合 int bar (int val1) { int val2; foo (a_function_pointer); } 文字列増加 影響を受けたメモリ int foo (void (*funcp)()) { char* ptr = point_to_an_array; char buf[128]; gets (buf); strncpy(ptr, buf, 8); (*funcp)(); } 最も攻撃を受けやすいターゲット スタック増加
攻撃シナリオ#1---戻りアドレスの変更 ② これらのポインタをスタックにセットする 攻撃コード “/bin/sh” ① system() 戻りアドレスを、攻撃コードをポイントするように変更する。関数が戻った後、攻撃コードに導く。 コードセグメント内に存在する命令はsystem()やexec()などのような攻撃コードとして使用できる。
攻撃シナリオ#2---ポインタ変数の変更 攻撃コード グローバル オフセット テーブル 関数ポインタを攻撃コードをポイントするよう変える。続く関数ポインタ呼び出しは攻撃コードへ導く。 あらゆるメモリが、たとえスタック内になくても、影響を受けたポインタに値を保存する命令文によって変更されうる。E.g. strncpy(ptr, buf, 8); *ptr = 0;
攻撃シナリオ#3--- 前回のフレームポインタの変更 攻撃コード 呼び出し側フレームを近くの場所に変更する。フレームには影響を受けた戻りアドレスが含まれている。
スタック プロテクタ ランドスケープ • コンパイラベースのプロテクタ • StackGuard、stack shield、propolice、XP SP2 /Gs • ランタイムスタック信頼性チェッカー • Libsafe • アドレス空間の非実行可能な部分 • Solar Designer の 「non-exec stack patch」、Exec Shield、OpenBSD のW^X、XP SP2 NX • 単独のソリューションでは解決不可能!!!
Stack Guard • StackGuard ではスタックの戻りアドレスの直前に「カナリア」と呼ばれる値 を挿入する。 • 関数を実行後、プロテクションツールは、「カナリア」が戻りアドレスにジャンプする前に修正されていないかをチェックする。 • 「カナリア」の値が不正に修正されている場合、プログラムは終了する。 • 脆弱性報告 • “BYPASSING STACKGUARD AND STACKSHIELD( STACKGUARDおよびSTACKSHIELDの回避法)”, Phrack 56 • “Four different tricks to bypass StackShield and StackGuard protection (StackShield およびStackGuard 防御を回避する4つの方法)”
Stack Guard 2.1 • 様々な「カナリア」の値 • ターミネーター カナリア 0x000aff0d • ランダム カナリア random • XOR カナリア random ^ return address • コンパイラを構築する際に、「カナリア」メソッドを選ぶ mprotect はこのデータへの書き込みアクセスを禁止する 文字列増加 データのランダムな値 スタック増加
開発中のStack Guard • フレームポインタ問題を解決するために、「カナリア」を移動 • 戻りアドレス、 フレームポインタ、ローカル変数の広範的な完全性チェック 文字列増加 データのランダムな値 XOR スタック増加
propolice:設計目標 • “Safe Stack Usage Model”の導入 • これは、理想的なスタックレイアウトとスタックの完全性をチェックする手段を組み合わせたものである。 • プログラムをできるだけ理想的なスタックレイアウトに近づけるよう変換する • GNU gcc コンパイラのパッチはプログラムを変換するコンパイル過程を追加する
Safe Stack Usage Model • スタックの完全性チェック: • 関数のプロローグで、guardに予想不可能な値をいれる • 関数のエピローグで、guard値の完全性を確かめる、もしくはプログラムの実行を中止する • 理想的スタックレイアウト: • A配列もポインタ変数もなし • B配列のみ • C配列なし、ポインタ変数あり 文字列増加 A オーバーフローによって影響を受けない B C スタック増加
呼び出し側の関数がスタックスマッシング攻撃に対し安全である理由呼び出し側の関数がスタックスマッシング攻撃に対し安全である理由 • 関数がアクセスできる範囲であるargs から guardまではポインタ変数がない。よってメモリはポインタ攻撃の影響を受けない。 • 関数が呼び出し側の関数に戻った場合、呼び出し側の関数の連続するメモリの塊はバッファ オーバーフローによる影響をうけない。 文字列増加 A 関数がアクセスできる範囲 B C スタック増加
わかりやすい説明: PFP と配列の間に「guard」 を構築する方法 foo () { char *p; char buf[128]; gets (buf); } Int32 random_number; foo () { volatile int32 guard; char buf[128]; char *p; guard = random_number; gets (buf); if (guard != random_number) /* program halts */ } • 「guard」と呼ばれる値の挿入 • ローカル変数の位置を入れ替える • + オプティマイザはrandom_numberへの二度目のアクセスを削除する。 • - 配置されたバッファ allocaはguardの隣に位置を変更できない。
わかりやすい説明: ポインタタイプがある場合の関数引数の扱い方 foo (int a, void (*fn)()) { char buf[128]; gets (buf); (*fn)(); } Int32 random_number; foo (int a, void (*fn)()) { volatile int32 guard; char buf[128]; (void *safefn)() = fn; guard = random_number; gets (buf); (*safefn)(); if (guard != random_number) /* program halts */ } • ポインタをC領域から指定された変数にコピーする。実際、それはその変数にレジスタを指定しようとする。 • 指定された変数で関数呼び出しの名前を変更する
propolice: スタック プロテクタ オプション • -fstack-protector • スタック保護は関数がバイト配列の時のみ生成される。 • -fstack-protector-all • 常に「guard」を作成する。 • バイト配列が使用されていれば、「guard」の隣に指定される。 • そうでなければ、配列が「guard」の隣に指定される。
propolice の現状http://www.research.ibm.com/trl/projects/security/ssp/ • 実際の使用 • Laser5, trusted debian, openbsd, gentooなど • 対応アーキテクチャ • Ix86, powerpc, alpha, sparc, mips, vax, m68k, amd64 • Gccバージョン • gcc2.95.3 – gcc3.4.1 • gcc HEAD cvs 開発中
Microsoft XP SP2 --- Windows 2003 スタック保護 • 非実行スタック • コンパイラ/Gs オプション • xor カナリアとpropoliceのコンビネーションメソッド • 理想的なスタックレイアウトとはほど遠い • 脆弱性報告 • David Litchfield氏、 “Defeating the stack based buffer overflow prevention mechanism of Microsoft Windows 2003 server (Microsoft Windows 2003 サーバにおけるスタックベースのバッファ オーバーフロー防御メカニズムを破る)”
Gsオプションがどのように機能するか • カナリアは最初に配置されたバイト配列の前に挿入される。 • 配列以外のローカル変数はスタック内でアルファベット順に指定されるようである。 文字列増加 Stack point register データのランダムな値 canary XOR First byte array スタック増加
防御法の比較表 --- 防御レベル 検知: 関数の終わりに修正がみられる。 防御: 修正されない。
パフォーマンスに関して考慮すべき点 ここで示すオーバーヘッド率は、すべてのOSのデフォルトでこれを有効にすることを十分なものにする
まとめ • スタックオーバーフロー問題の説明 • 様々なスタックスマッシング攻撃の説明 • StackGuard, propolice, およびMS/Gsの特性を説明 • さまざまな観点によるそれぞれの防御法の比較