出処 : http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c904.html
第10章 著名な脆弱性対策
バッファオーバーフロー: #4 あふれを検出するデバッグ
領域あふれの問題の検出については、ロジックが複雑に入り組んでいる場合、ソースコードから見いだすのは容易でない。そのような場合、デバッガ等のツールの下で対象のプログラムを動かして、問題を見つけ出すことになる。
スタックおよびヒープにおけるあふれを検出するためのコンパイラのオプションやデバッグ・ツールがいくつか存在する。
次にその主なものを紹介する。
あふれの検出等に使うことのできるデバッグ・ツール
ヒープにおける領域あふれやダブルフリー等の問題を検出できるツールをふたつ紹介する。ひとつは独立したツール、もうひとつは統合開発環境の中の機能である。
(1) Valgrind [GNU/Linux]
ヒープデバッガを中心とした GNU/Linux 専用のツールスイートである。割当領域外への書き込みや、メモリリークを検出することができる。
Valgrind が備えるツールには、下記のようなものがある。
- Memcheck
最も主要なツール、ヒープデバッガ。動的メモリに関わる諸問題を検出する(領域外のアクセス、未初期化領域の参照、不正free、メモリリーク、重複領域のmemcpy) - Cachegrind
キャッシュプロファイラ。CPUキャッシュをエミュレートし、使用状況を調べることができる - Callgrind
Cachegrind プラス呼び出しグラフ生成 - Massif
ヒーププロファイラ - Helgrind
スレッドデバッガ ほか
対象プログラムをデバッグモード(gcc -g 等)でコンパイルしてあると、Valgrindは問題とともにソースコード位置も知らせてくれる。
1: $ valgrind --tool=memcheck --leak-check=yes test_program ... ↓≪≪実行途中における、 malloc()した領域からのあふれの検出≫≫ 8: ==1929== Invalid write of size 1 9: ==1929== at 0x8048970: header_getContentType (test_program.c:110) 10: ==1929== by 0x8049A58: block_processHeader (test_program.c:586) 11: ==1929== by 0x8049EA6: block_processField (test_program.c:673) 12: ==1929== by 0x8049F80: main_processBlock (test_program.c:712) 13: ==1929== Address 0x1BA4B4B2 is 0 bytes after a block of size 434 alloc'd 14: ==1929== at 0x1B904DF0: malloc (vg_replace_malloc.c:131) 15: ==1929== by 0x8048930: header_getContentType (test_program.c:106) 16: ==1929== by 0x8049A58: block_processHeader (test_program.c:586) 17: ==1929== by 0x8049EA6: block_processField (test_program.c:673) 18: ==1929== ... ↓ ≪≪プログラム終了時、メモリリークの検出≫≫ 1048: ==1929== 60907 bytes in 134 blocks are definitely lost in loss record 12 of 12 1049: ==1929== at 0x1B904DF0: malloc (vg_replace_malloc.c:131) 1050: ==1929== by 0x8048930: header_getContentType (test_program.c:106) 1051: ==1929== by 0x8049A58: block_processHeader (test_program.c:586) 1052: ==1929== by 0x8049EA6: block_processField (test_program.c:673) 1053: ==1929== ↓ ≪≪メモリリークのサマリ≫≫ 1054: ==1929== LEAK SUMMARY: 1055: ==1929== definitely lost: 60907 bytes in 134 blocks. 1056: ==1929== possibly lost: 334 bytes in 1 blocks. 1057: ==1929== still reachable: 1512 bytes in 14 blocks. 1058: ==1929== suppressed: 0 bytes in 0 blocks.
参照URL http://valgrind.org/
(2) Application Verifier [Visual Studio 2005, Windows]
領域あふれの検出に使うことはできないが、Visual Studio に備わっているApplication Verifier(日本語名「アプリケーションの検証」)は、Visual C++ のデバッガとともに動作させると、ヒープのダブルフリー等の不具合を検出してくれるものである。
他にも、ハンドルの検証やロックの検証等の機能がある。
参照URL http://www.microsoft.com/japan/msdn/vstudio/
あふれを検出できるランタイム・ライブラリの機能
通常のランタイムライブラリの代わりに、領域あふれ等を検出する能力が組み込まれたライブラリをプログラムにリンクしてデバッグを行う方法がある。
(1) Mudflap [GCC]
バッファオーバーフロー、メモリリーク、ポインタの誤使用等を実行時に検出してくれるライブラリおよびGCCのコンパイルオプション。
Valgrind に比べて、解析速度が速く、stack, data, bss 変数のチェックが行えるが、コンパイルオプションとライブラリの追加オプションが必要である。
GCCオプション: -fmudflap -lmudflap
マルチスレッドの場合のGCCオプション: -fmudflapth -lmudflapth
プログラム example3.c
1 #include <string.h> 2 3 sub () { 4 char c8[8]; 5 strcpy(c8, "1234567890"); 6 } 7 8 main () { 9 sub(); 10 }
cc -fmudflap -lmudflap example3.c -o example3
$ ./example3 ******* mudflap violation 1 (check/write): time=1167124492.737106 ptr=0xbff80720 size=11 pc=0x5d5f9d location=`(strcpy dest)' /usr/lib/libmudflap.so.0(__mf_check+0x3d) [0x5d5f9d] /usr/lib/libmudflap.so.0(__mfwrap_strcpy+0x158) [0x5e2368] ./example3(sub+0x3c) [0x8048630] Nearby object 1: checked region begins 0B into and ends 3B after mudflap object 0x8fb2588: name=`example3.c:4 (sub) c8' bounds=[0xbff80720,0xbff80727] size=8 area=stack check=0r/3w liveness=3 alloc time=1167124492.700013 pc=0x5d59dd number of nearby objects: 1
環境変数 MUDFLAP_OPTIONS を設定すると次のようなこともできる。
・Mudflapを一時的に無効にする
- 例
- $ MUDFLAP_OPTIONS="-mode-nop" ./example3
・タイムスタンプとバックトレースを止める
- 例
- $ MUDFLAP_OPTIONS="-no-timestamps -backtrace=0" ./example3
$ MUDFLAP_OPTIONS="-no-timestamps -backtrace=0" ./example3 ******* mudflap violation 1 (check/write): time=1167124513.569876 ptr=0xbff0d680 size=11 pc=0xd31f9d location=`(strcpy dest)' Nearby object 1: checked region begins 0B into and ends 3B after mudflap object 0x9f7d5f0: name=`example3.c:4 (sub) c8' bounds=[0xbff0d680,0xbff0d687] size=8 area=stack check=0r/3w liveness=3 alloc time=0.000000 pc=0xd319dd number of nearby objects: 1
参照URL http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging
(2) MALLOC_CHECK_ [glibcを制御する環境変数]
MALLOC_CHECK_ は、glibc(GNU C Library)がもつ malloc() - free() 関連のチェック機能を活性化させる環境変数である。この環境変数に値を定義すると、malloc() で割り当てたメモリブロックの簡単な保護と異常検出の機能がはたらき、free() 関数が呼び出されたときに次の問題が生じていないかのチェックが行われるようになる。
- malloc() で割り当てたブロックの手前のメモリの4バイト分のどこかが不正な値で上書きされていないか
- malloc() で割り当てたブロックの後続のメモリ1バイト分が不正な値で上書きされていないか
- すでに free() されたポインタを再度 free() しようとしていないか
環境変数 MALLOC_CHECK_ に設定された値に応じ、glibc は次のように振る舞う。
- MALLOC_CHECK_=0 上記の問題でプログラムに異常をきたすのを防ぐが報告はしない
- MALLOC_CHECK_=1 問題を検出してメッセージを出す
- MALLOC_CHECK_=2 問題を検出してプロセスをアボートさせる
- MALLOC_CHECK_=3 1 と 2 の両方を行う
参照URL http://www.gnu.org/software/libc/manual/html_node/Heap-Consistency-Checking.html
(3) -D_FORTIFY_SOURCE=n [GCC, glibc]
C言語の標準ランタイム関数を使用するプログラムの実行がよりセキュアに行われるよう、マクロの仕組みを用いて呼び出すライブラリ関数をより堅固なバージョンに置き換えるglibc(GNU C Library)の機能である。
1) 呼び出すライブラリ関数を切り替えるオプション
GCC にコンパイルオプション -D_FORTIFY_SOURCE=1 あるいは =2 を指定すると、あふれを起こしやすい strcpy() のような関数がマクロ展開によって同様な処理を行うが領域あふれを検査するよう対策された別の関数 __strcpy_chk() に置き換わる。
プログラム実行時にあふれ等の問題が検出されたときは、プロセスの実行が abort()によって中止される。
この方法を使うと、ソースコードを変更する必要がなく、コンパイルのし直しのみであふれ検出機能をはたらかせることができる。
GCCに指定するオプション: -O1 -D_FORTIFY_SOURCE=1 または =2
この機能を使用するときは、コンパイラの最適化オプションを -O1 またはそれ以上のレベルで指定する必要がある。
プログラム example1.c
1 #include <stdio.h> 2 main () { 3 char buf[4]; 4 gets (buf); 5 puts (buf); 6 }
$ gcc -O1 -D_FORTIFY_SOURCE=2 example1.c -o example1 $ ./example1 aaaa *** buffer overflow detected ***: ./example1 terminated ======= Backtrace: ========= /lib/libc.so.6(__chk_fail+0x41)[0x464d7161] /lib/libc.so.6(__gets_chk+0x174)[0x464d70c4] ./example2[0x804840d] /lib/libc.so.6(__libc_start_main+0xdc)[0x4640bf2c] ./example2[0x8048351] ======= Memory map: ======== 00651000-00652000 r-xp 00651000 00:00 0 [vdso] 08048000-08049000 r-xp 00000000 fd:00 914420 /home/test/example2 08049000-0804a000 rwxp 00000000 fd:00 914420 /home/test/example2 0947a000-0949b000 rwxp 0947a000 00:00 0 45a27000-45a40000 r-xp 00000000 fd:00 948678 /lib/ld-2.5.so ...省略... bfa0c000-bfa22000 rw-p bfa0c000 00:00 0 [stack] アボートしました $
2) コンパイル時にも問題を検出
判断が可能な場合にはコンパイル時にもあふれの警告が出力される。
プログラム example2.c
1 #include <string.h> 2 main () { 3 char c8[8]; 4 strcpy (c8, "1234567890"); 5 }
3) 運用における使用
-D_FORTIFY_SOURCE によって導入されるチェックロジックのオーバーヘッドは比較的小さいと言われている。デバッグ時のみならず、プログラムのリリース後もこのオプションを使用することによって攻撃に備えるのもひとつの方法である。
(4) /RTCs [Visual Studio 2005, Windows]
スタック上の変数領域のあふれを実行時に検出してくれる、Visual C++ のコンパイルオプション。
文字型配列(char[ ])のみならず、スタック上のすべての変数を検査してくれるのが特徴である。変数の大きさが1バイトしかなくても、型がintやポインタであってもあふれが検査される。
あふれを検出するのに使われる方法は、変数ひとつひとつの前後に 0xCCCCCCCC の値をもつ4バイトのワードが置かれ、これが壊れていないか、関数からのリターン時に調べるというものである。この /RTCs の検査は、/GS のスタック破壊検査よりも先に行われる。
プログラム
func () { int i; char c16[16]; char *p; int j; i = 0x11111111; memset (c16, 0x22, sizeof(c16)); p = 0x33333333; j = 0x44444444; c16[16] = 0xFF; return 0; }
0x0012FE20 cccccccc cccccccc cccccccc cccccccc フフフフフフフフフフフフフフフフ 0x0012FE30 cccccccc cccccccc 44444444 cccccccc フフフフフフフフDDDDフフフフ ↑int j 0x0012FE40 cccccccc 33333333 cccccccc cccccccc フフフフ3333フフフフフフフフ ↑char *p 0x0012FE50 22222222 22222222 22222222 22222222 """""""""""""""" ↑char c16[16] 0x0012FE60 ccccccff cccccccc 11111111 cccccccc .フフフフフフフ....フフフフ ** ↑int i 0x0012FE70 9bbfcf2a 0012ff48 004114a3 00000000 *マソ・H...」.A..... 0x0012FE80 00000000 7ffdf000 cccccccc cccccccc .....・..フフフフフフフフ 0x0012FE90 cccccccc cccccccc cccccccc cccccccc フフフフフフフフフフフフフフフフ
※ c16[ ] の前後に 0xcc 以外が書き込まれていることがあふれとして検出される
'리눅스 서버에 대해서' 카테고리의 다른 글
putty 한글 텍스트 붙여넣기 에러 해결하기 (0) | 2022.07.12 |
---|---|
리눅스 강제 코어 남기기 (0) | 2014.07.21 |
[gcc] mudflap - 포인터 접근 검사 (0) | 2014.06.18 |
병렬 프로그래밍 페러다임 (0) | 2014.06.18 |
OpenMP를 이용한 병렬 프로그래밍 (0) | 2014.06.18 |