2022年8月、ホームページを全面リニューアルしました! 情報を分かりやすくお伝えできるサイト作りを目指してまいります。

Exec-Shieldでバッファオーバーフローをブロックする!

Exec-Shieldは、バッファ・オーパーフロー攻撃の特徴的な「プログラムのバグを突いて、そのプロセスを乗っ取る攻撃」をブロックするものである。
プログラムのバグを取り除くには、公開されているパッチを適用するか、バグが改善された新しいバージョンにアップグレードするしかない。ただし、このようなことができるのは、既に見つかったバグに対してのみ。まだ見つかっていないバグにバッチを適用したり、アップグレードしたりするのは不可能だ。こうした潜在的なバグに対処するための手段が、Exec-Shieldである。


1.バッファ・オーパーフローとは?
詳しくは、 ここ を参照して欲しい。バッファ・オーパーフロー攻撃とは、一言でいうと悪人がプロセスがメモリ領域に確保したバッファをあふれさせ、そのプロセスに任意のコードを実行させて悪事を働くことと言える。
バッファとは、CPUの処理効率を高めるために、処理途中のプログラムのデータを一時的に保存しておくメモリである。多くのプログラムは、いくつものバッファを確保しながらデータを処理する。
例えば、プログラムの外部(キーボードやマウスなど)から入力されたデータは、一時的にバッファに蓄積されてから処理される。


2.Exec-Shieldでバッファオーバーフローをブロック
Exec-Shieldは、以下の2つの機能をカーネルレベルで動作させる事でバッファ・オーパーフロー攻撃をブロックする。

( 1 )スタックセグメントを含むいくつかのセグメントから実行権限を外す
( 2 )セグメント配置をランダムにする

プログラムが実行されると、新しいプロセスが生成され、そのプロセス専用に仮想メモリー空間が割り当てられる。
このメモリー空間には、ロードした命令や、そのプログラムが利用するデータが格納される。
割り当てられたメモリー空間は、その用途毎にいくつかのブロックに分けられる。

----------------------- 0xFFFFFFFF番地

-----------------------


スタックセグメント


-----------------------


-----------------------

ヒープセグメント

-----------------------


-----------------------

データセグメント

-----------------------

テキストセグメント

-----------------------


----------------------- 0x00000000番地

図1

このセグメントには、図1のように4種類が存在する。さらに、使われないメモリ領域も存在する。
こういった使われないメモリ領域にプログラムがアクセスしようとすると、セグメンテーション違反(Segmentation Fault)が発生する。
それぞれのセグメントには、ファイルのパーミッションと同じくr(読み出し)、w(書き込み)、x(実行)の3種類の権限が設定され、その権限に違反するようなアクセスがされた場合にも、読んで字の如くセグメンテーション違反が起きる。つまり、Exec-Shieldは、つまりこの機能を利用して、バッファオーバーフロー攻撃で任意のコードが実行されるのを阻止するわけである。

1)スタックセグメントを含むいくつかのセグメントから実行権限を外す
詳細に見てみる。Linuxでは、各プロセスがどのようなメモリマップ(セグメント配置)を行っているかを /proc ディレクトリ以下のファイルを参照すれば確認が出来る。下の図2は、catコマンドを実行したときのメモリマップである。

[root@selinux proc]# cat self/maps
00421000-00434000 r-xp 00000000 03:03 552742 /lib/ld-2.3.4.so
00434000-00436000 rwxp 00013000 03:03 552742 /lib/ld-2.3.4.so
00438000-00545000 r-xp 00000000 03:03 552774 /lib/tls/i486/libc-2.3.4.so
00545000-00546000 r-xp 0010d000 03:03 552774 /lib/tls/i486/libc-2.3.4.so
00546000-00549000 rwxp 0010e000 03:03 552774 /lib/tls/i486/libc-2.3.4.so
00549000-0054b000 rwxp 00549000 00:00 0
08048000-0804c000 r-xp 00000000 03:03 666519 /bin/cat
0804c000-0804d000 rwxp 00003000 03:03 666519 /bin/cat
0804d000-0806e000 rwxp 0804d000 00:00 0
b7ff6000-b7ff7000 rwxp b7ff6000 00:00 0
bfffe000-c0000000 rwxp bfffe000 00:00 0       ← スタックセグメント
ffffe000-fffff000 –xp 00000000 00:00 0

図2

図2では、一行分のセグメント情報が表示される。多くのプログラムはダイナミックリンクされているため、実行の時に必ずライブラリを読み込む。
そのため、上記のセグメントだけでなく、ライブラリ用のテキストセグメント及びデータセグメントなども割り当てられる。
上記の結果から、スタックセグメントにx(実行権限)が設定されていることが分かる。バッファオーバーフロー攻撃のほとんどは、任意のコードはスタックセグメントに配置され、嘘のリターンアドレスに基づいて実行される。これは、スタックセグメントにx(実行権限)が設定されるため、実行が許可されてしまう。スタックセグメントにx(実行権限)が設定されていなけれぱ、言うまでもなくバッファオーパーフローが発生してリターンアドレスが書き換えれたとしても、任意のコードを実行する時にカーネルがそれを阻止(セグメンテーション違反による異常終了)させる。このアルゴリズムは、SPARCマシンの Solaris 2.6 でマウントされた仕組みである。これを、Linuxでも使えるようにした。
このことは、5項のExec-Shieldの動作確認のところで実証している。

2)セグメント配置をランダムにする
Exec-Shieldがもつ機能の二番目は、「セグメント配置のランダム化」は、割り当てられるセグメントを、プログラムが実行されるたびにランダムに配置する方法である。
これにより、スタックセグメントの位置が随時、変更されるため、嘘のリターンアドレスで任意のコードを指し示すごとが非常に困難になる。たとえバッファオパーフロー攻撃でリターンアドレスが書き換えられたとしても、任意のコードを実行されない。


3.Exec-Shieldをインストールする
Exec-Shieldは、kernelにパッチを当てて使用する。一部RedHat系(Fedora、WhiteBox、CentOS等)は標準で実装されてるようだ。
Exec-Shieldは、 ここ で拾ってくる。それで、kernelの再構築を行う。

例えば、
root@slack10:/usr/src# cd linux-2.6.16
root@slack10:/usr/src/linux-2.6.16# wget http://people.redhat.com/mingo/exec-shield/exec-shield-nx-2.6.16.patch   ← 一行で
root@slack10:/usr/src/linux-2.6.16# patch -sp0 < exec-shield-nx-2.6.16.patch
root@slack10:/usr/src/linux-2.6.16# make -s menuconfig
root@slack10:/usr/src/linux-2.6.16# make -s
root@slack10:/usr/src/linux-2.6.16# make -s modules modules_install install

こんな感じかな。


4.Exec-Shieldの設定

Exec-Shieldを有効にする。
[root@selinux ~]# echo 3 > /proc/sys/kernel/exec-shield

設定値の意味
0:
常に無効
1:
マークされたバイナリを有効にし、以外は無効
2:
マークされたバイナリを無効にし、以外は有効
3:
常に有効

起動時に、有効にする。RedHat系(CentOS等)の場合、
[root@selinux ~]# vi /etc/rc.d/rc.local
省略
echo 3 > /proc/sys/kernel/exec-shield    ← 追加
省略


5.Exec-Shieldの動作確認

1)libsafeを入れる
バッファオーバーフローを起こさせるサンプルがlibsafeに入っている。したがって、これをインストールしたいのだが、ライブラリの配布サイトが見つからない。どうやら、ダウンロードサイトを閉鎖したようだ。多分、早い話バッファオーバーフローサンプルを悪用されるからだと思う。しようがないので、色々調べてみたところ俺が使ってるSlackware10の slackpkg ライブラリの中に有ったのでとりあえずslackへインスコ。

root@slack10: # slackpkg update
root@slack10: # slackpkg install libsafe
以下のディレクトリにt1.cと言うバッファオーバーフローのサンプルが有る。
root@slack10:~# ls -al /usr/doc/libsafe-2.0.16/doc/whitepaper-1.3/t1.c
-rw-r–r– 1 root root 515 2001-02-02 07:04 /usr/doc/libsafe-2.0.16/doc/whitepaper-1.3/t1.c

これを、CentOS4へ移植する。gccを使ってソースをコンパイルする。
[root@selinux ~]# gcc -O2 t1.c -ot1
コンパイル後、t1と言うバイナリファイルが出来る。
[root@selinux ~]# ls -al t1
-rwxr-xr-x 1 root root 5006 Apr 13 14:45 t1

2)実際にバッファオーバーフローさせる
■ Exec-Shieldを無効にして、バッファオーバーフローサンプルを実行
[root@selinux ~]# ./t1
sh-3.00#
バッシュシェルが落ちてしまった。多分、現状このまま使っても不安定なシステムだと思う。

■ Exec-Shieldを有効にして、バッファオーバーフローサンプルを実行
[root@selinux ~]# ./t1
Segmentation fault
セグメンテーション違反でバッファオーバーフローを抑制した。

ひとまず、動作確認は成功( ̄ー ̄)ニヤリッ!
以上

コメント