slide (PowerPoint)

静的解析に基づく侵入
検知システムの最適化
大山 恵弘 (科学技術振興事業団)
王維
(筑波大学)
加藤 和彦 (筑波大学・科学技術振興事業団)
背景
 C言語
= 大大大迷惑で危険な言語
世界に大きな脅威と経済的損失
 ex1. バッファオーバフローで乗っ取り
 ex2. スタックやヒープが壊れて誤動作

 しかし、今すぐC言語を駆逐するのは無理
 支援システムでC言語の欠陥を補いましょう
バッファオーバフロー
 サイズを越えてデータをバッファに注入
 スタック、ヒープの破壊
 制御フローのねじ曲げ
突然libcのexecに突入
 注入したバイナリコード先頭にジャンプ

Cプログラムを安全に
実行するための方策
 型安全性の導入
[Oiwa et al. 02]
 Stack-smashing攻撃防止システムの導入
[Cowan et al. 96], [Etoh]
 侵入検知システムの導入
本研究
 他多数…
侵入検知システム
 基本的な動き
プログラムの実行を監視
 侵入を検知 → 対策を取る

 検知方式

シグネチャ検知: 「異常」の規則を保持
 ex.

原始的なAntivirus
異常検知: 「正常」の規則を保持 本研究
異常検知システム
 方法
プログラムのモデル(正しい動作を表す規則)を
作成
 モデルに従わない動作 = 異常と判定

 長所

未知の攻撃を検出可能
本研究の目的
 実用的な異常検知システムの構築
 小さいオーバヘッド
 高い検知精度
 使用が容易
以降の流れ
 異常検知システムの設計軸
 既存の方法
 既存の方法の問題
 本研究の方法
 実験
 議論・関連研究
異常検知システム作ろう!
異常検知システム作ろう!
といっても色々考えることがある
 何を監視するか?
 モデル(正しい動作を表す規則)を
どうやって作るか?
何を監視するか?
 キータイプ
 パケット
 システムコール
 制御スタック
 ヒープ
本研究
モデルをどうやって作るか?

人間が頭をひねって書く



過去の正常な実行を一般化・学習



[Ko et al. 94], [Sekar et al. 99]
問題: 計算機の専門知識が必要
[Forrest et al. 96], [Sekar et al. 01]
問題: 学習のためにプログラムを実行するのが面倒
プログラムの静的解析による自動生成

[Wagner et al. 01], [Giffin et al. 02]
本研究
本研究のアプローチ
main()
{
f();
if (…) {
g();
}
…
}

制御フローを監視しながら実行

モデルに無い制御フローを辿った → 異常


モデル = 制御フローの規則
システムコール呼び出し時に制御の状態を検査
Wagnerらの方法 [Wagner et al. 01] の改良
Wagnerらのシステム
main()
{
f();
if (…) {
g();
}
…
}
コンパイラ
プロセス
実行可能コード
システムコール
モデル
侵入検知システム
OS
モデル
main()
{
stat();
if (…) {
open();
} else {
connect();
}
close();
}
main → stat; X; close
X
→ open | connect
文脈自由文法
終端記号 = システムコール
実行の監視
プロセス
open, stat, …
侵入検知システム
= CFGパーザ
main → stat; X; close
X → open | connect
OS
パーズ可能
→ 正常
パーズ不可能 → 異常
問題点
 プログラムの内部状態を正確に把握
しない

制御の場所を非決定的に把握
open, stat, mmap, read, close, …
sendmail
問題点1: オーバヘッドの増加
プロセス
open, stat, …
CFGパーザ
main → f | g | h | i | …
f → open | … | …
g → open | … | …
h → open | … | …
i→f|g|…
OS
open呼ぶ候補の数100!
→全部考慮してパーズ
次にstat呼ぶ候補の数1000!
→全部考慮してパーズ
実用的とは言い難い性能
42分
1時間以上
1トランザクションあたりの
監視オーバヘッド (秒)
100
80
60
40
20
0
finger
qpopper
procmail
sendmail
問題点2: 攻撃の見逃しの増加
プロセス
open, stat, (buffer overflow), exec, …
CFGパーザ
main → f | g | h | i | …
f → open | … | …
g → open | … | …
h → open | … | …
i→f|g|…
OS
open, stat, execを
生成可能な規則あり
→ プロセス内部がどうなって
いようが正常と判断
我々の考え
 静的解析でモデルを作る着眼は良い
 しかし、システムコール列のみを検査対象に
するのはいかがなものか
 プログラムの内部状態をもっと取得・活用して
もいいのでは?
イメージ
open, stat, mmap, read, close, …
sendmail
提案方式
main()
{
f();
if (…) {
g();
}
…
}
コンパイラ
プロセス
実行可能コード
システムコール
モデル
侵入検知システム
OS
モデル
 制御の移動を表すオートマトン
main()
{
open();
if (…) {
f();
} else {
g();
}
close();
}
main
入口
open
f
g
close
出口
検査方法
 システムコールでプログラムを停止
 スタックを検査
 前回停止時のスタックから現在のスタックへの
制御フローがモデル中にあるかどうか調べる
open
printf
f
main
遷移可能?
read
fgets
h
g
f
main
遷移可能?
connect
p
main
遷移可能性の検査
 現在はナイーブなやり方

スタックの各フレームごとに遷移の存在を検査
 popするパスの探索
 pushするパスの探索
open
printf
f
main
read
fgets
h
g
f
main
実装
 モデル生成機能つきコンパイラ部

GCCを改造して作成
工数: 0.018人年
 実行監視部
別プロセスによる監視
 カーネルモジュールによってプロセスを操作

 システムコールをフック
 レジスタ・スタック情報の取得
特徴
 Wagnerらの方法
偽警報が出ない (正常を異常と誤判定しない)
 モデルを作る手間がかからない

 加えて、本研究のシステム

Wagnerらの方法より
 オーバヘッドが小さい(?)
 見逃す攻撃が少ない
実験
 環境
Pentium 4 (2.8GHz) 上のVMware
 Red Hat Linux 7.1

 アプリケーション
wc: 22MBのファイルのカウント
 cp: 22MBのファイルのコピー
 tar: ソースツリーのtarファイルを作成

結果
wc
A: 異常検知なし
cp
335 ms
tar
805 ms
62 sec
B: 異常検知あり 1267 ms 4921 ms 581 sec
B/A
3.8
6.1
9.3
関連研究: 異常検知システム
システムコールの情報 システムコール以外の
だけから判断
情報も用いて判断
学習による
モデル生成
[Forrest et al. 96]
[Lee et al. 98]
[Liao et al. 02]
静的解析による [Wagner et al. 01]
モデル生成
[Sekar et al. 01]
[Oyama et al. 01]
本研究
関連研究: バッファオーバフロー対策

Non-executable stack, StackGuard [Cowan et al.
96], propolice [Etoh]


関数ポインタを書き換える攻撃を防げない
Program shepherding [Kiriansky et al. 02]

全ブランチ命令で安全性検査



ex. ブランチが関数先頭に飛んでいるか
ex. retがcallの次の命令に飛んでいるか
「ソースコード通りの制御フローを辿る」というポリシーは
扱っていない
まとめ
 ソースコード情報と実行時スタックの情報を
両方活用する異常検知システムを提案
今後の課題
 大規模なアプリケーションを用いて性能測定
 Wagnerらの方法との性能比較
 システムコールの引数情報の活用
質問・議論スライド
議論: サンドボックスとの関係

サンドボックスと侵入検知システムは似ている


実行を監視、邪悪な操作を拒否
サンドボックスがあれば十分? → No!
 サンドボックスの適切なポリシーを定めることは
簡単ではない
 厳しすぎるとプログラムが動かない
 緩すぎると危険
議論: mimicry attack
[Wagner et al. 02]

侵入検知システムによる検知を回避する攻撃

ex. ダミーシステムコールを発行して正常を偽装

システムコールだけを検査するシステム
→ mimicry attackがやりやすい

本研究のシステム
→ mimicry attackがやりにくい

スタック内の制御情報も偽装する必要がある
議論: なぜシステムコールの
タイミングで検査するのか?
 オーバヘッドを(比較的)小さく抑えられる
 実装が楽
 システムコール呼び出しに検査が挟まると
ハッカーは攻撃を成功させにくい
異常検知の投機的実行
 プログラムの未来の状態を予測
次に出るシステムコール
 次のスタック状態

 次にどの状態が来たら正常/異常かを事前に
計算しておく
 アプリケーションの停止時間が短縮される
コンパイル処理に加わるオーバヘッド
 wget-1.8.2のmakeにかかる時間
元のGCC: 12.3秒
 改造GCC: 12.4秒
