Kozupon.com    
 
 SELinuxのセキュリティ!


kernel-2.6がリリースされてから結構耳にするようになったSELinux。名前を聞いた瞬間、新しいLinuxのディストリビューションかと勘違いさせるようなそのものズバリのLinuxの名前。ここでは、SELinuxってなんぞやから使用する場合の注意点などについて書いてみる。SELinuxは、一言でいうと従来のユーザ権限を細分化してrootの権限を必要最小限に抑えてセキュリティを保つ機能なので設定がいまいち面倒である。だから、敷居を高くしがちだが、すでにセキュリティもここまでやらなくては危険なったということだ。正直、「Linuxは簡単に自前サーバが構築できるから、俺もやろう。」なんて素人が簡単に構築して運用できるという神話は、もろくも崩れたのではなかろうか?というか、簡単にサーバを作ることは出来るが、運用にはそれなりのスキルが必要なのは今も昔も変わらないかも知れない。


1.SELinuxとはなんぞや
SELinuxとは、冒頭で言ったようにLinuxのディストリビューションではない。一言でいうとカーネルのセキュリティを強化する単独モジュールである。OS自体のPermisson check機能を強化してプロセスを管理するユーザを最小限の権限で動作させる。これにより、
不正に侵入してくるクラックな方々には、ダメージを与えようとしても大きな権限が与えられないため、ダメージを最小限に食い止めることが出来る仕組みである。しかし、逆にあくまでダメージを最小限に食い止める機能にすぎないことを良く頭に入れて使った方が良いかと思う。なんにでも言えることだが、過信しすぎないことだと思う。


2.Linuxの本来の欠点
Linuxは本来プログラムで書かれているため必ずどこかにバグがあり、そのバグが命取りになることがある。「脆弱性」ともいわれているが、脆弱性が発見されるのは、kernel本体もそうだが、その周辺モジュールやアプリケーションにも及ぶ(しかし、Windowsよりは少ない方である)。脆弱性がどこかに発見されると、だいたい以下のようなパターン多い。

1) セキュリティホール(脆弱性が発見された部分)を突いてデーモンが乗っ取られる。ユーザの権限を奪い取り、システムへのアクセス権をゲットする。

2) アクセス権をゲットしたら、システムに重要なデータを盗んだり、改ざんしたり、破壊したりする。しまいには、バックドアを設置していつでも侵入できるようにしておく。まあ、良くやられる手口だと思う。Linuxはこういった悪人の手口に対して完璧で有るとは言い難い。それはなぜか?というとrootという最高権限ユーザが存在しているため、ひとたびその権限を奪われてしまうと、何でも好き放題に出来てしまうからである。例えば、リモートシェルのSSHやtelnetなどはroot権限で実行されている。したがって、SSHやtelnetにセキュリティホールが有ると、クラックな方々はroot権限をゲットすることが出来る。こうなれば、やりたい放題になるわけである。


3.setuid(0)の恐怖
みなさんは、setuid(0)関数の恐ろしさを知っているだろうか?C言語で作られたプログラム中にsetuid(0)関数の記述を入れると、そのプログラムはroot権限で実行出来るのである。setuidというのは、対象ファイルの実行権限をチェンジすることでsetuid(0)とは、root権限のことを意味している。例えば、passwdのコマンドを使うと、ユーザのログインシェルやパスワードなどの個人情報を変更できる。これらの情報は /etc/passwd に保存されるわけである。ここでよく考えてみよう。つまり passwd は /etc/passwd のファイルを更新するということだ。もちろんこれらのファイルは、一般ユーザが書き換えできないようにパーミッションが設定されている。

# ls -al /etc/passwd
-rw-r--r-- 1 root root 1098 Oct 11 11:35 /etc/passwd

なぜコマンドを実行しているのは一般ユーザなのに、root しか書き換えられないはずのファイルを書き換えることができるのだろうか?その秘密が setuid (suid・sbit) である。ls で passwd の実行ファイルのパーミッションを見てみよう。

# ls -al /usr/bin/passwd
-rwsr-xr-x 1 root root 26616 May 18 2005 /usr/bin/passwd

パーミッションの最初の部分が「rws」となっていることに注意してほしい。「s」という文字は「そのコマンドが所有者の権限で実行される」という意味である。 /usr/bin/passwd というファイルの所有者は root なので、一般ユーザが /usr/bin/passwd を実行すると、root の権限を得ることになる。そのコマンドが終了すると root 権限は失われる。
UNIX において、setuid という仕組みは、かなり広い範囲で使われている。

# ls -l /{,usr/,usr/local/}{,s}bin/ | grep 'r[-w]s'

こんなコマンドを発行すると解るが、その他にはpingなども setuid されている。

# find / -perm +6000 -type f -exec ls -ld {} \; > setuid.txt

さらには、こんなコマンドでカレントディレクトリにsetuid.txtと言うテキストファイルにsetuidされてる実行ファイルを吐かせても良いだろう。ちなみに、俺のサーバで上記のコマンドを実行して結果のsetuid.txtの内容は以下である。

# more setuid.txt
-rwxr-sr-x 1 root tty 9784 Sep 18 16:04 /usr/bin/wall
-rwsr-xr-x 1 root root 22872 May 18 2005 /usr/bin/newgrp
-rwxr-sr-x 1 root shadow 34488 May 18 2005 /usr/bin/chage
-rwsr-xr-x 1 root root 28056 May 18 2005 /usr/bin/chfn
-rwsr-xr-x 1 root root 28088 May 18 2005 /usr/bin/chsh
-rwxr-sr-x 1 root shadow 16696 May 18 2005 /usr/bin/expiry
-rwsr-xr-x 1 root root 34904 May 18 2005 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 26616 May 18 2005 /usr/bin/passwd
-rwsr-xr-x 1 root root 34488 Jan 18 2002 /usr/bin/at
-rwxr-sr-x 1 root crontab 26872 Jul 29 2004 /usr/bin/crontab
-rwxr-sr-x 1 root mail 9860 Jun 5 2004 /usr/bin/dotlockfile
-rwsr-xr-x 1 root root 18136 Dec 1 2004 /usr/bin/traceroute.lbl
-rwxr-sr-x 1 root tty 7992 Nov 2 2004 /usr/bin/bsd-write
-rwsr-xr-x 1 root root 809836 May 10 2005 /usr/bin/gpg
-rwxr-sr-x 1 root mail 7764 May 23 2005 /usr/bin/mutt_dotlock
-rwsr-xr-x 1 root root 44024 Dec 13 2004 /usr/bin/mtr
-rwsr-sr-x 1 root mail 71640 Mar 2 2005 /usr/bin/procmail
-rwxr-sr-x 1 root mail 12712 Mar 2 2005 /usr/bin/lockfile
-rwxr-sr-x 1 root ssh 57304 Nov 29 2004 /usr/bin/ssh-agent
-rwsr-sr-x 1 root utmp 61464 Apr 19 2005 /usr/bin/jfbterm
-rwsr-xr-x 1 root root 669752 May 27 2005 /usr/sbin/exim4
-rwsr-xr-- 1 root dip 265880 May 6 2005 /usr/sbin/pppd
-rwsr-xr-- 1 root dip 29420 Sep 30 2004 /usr/sbin/pppoe
-rwsr-xr-x 1 root root 5668 May 11 2005 /usr/lib/pt_chown
-rwsr-xr-x 1 root root 131512 Nov 29 2004 /usr/lib/ssh-keysign
-rwxr-sr-x 1 root mail 18680 Mar 18 2005 /usr/lib/emacs/21.4/i386-linux/movemail
-r-sr-xr-x 1 root root 15000 Jun 29 2004 /sbin/unix_chkpwd
-rwsr-xr-x 1 root root 35512 May 18 2005 /bin/login
-rwsr-xr-x 1 root root 23416 May 18 2005 /bin/su
-rwsr-xr-x 1 root root 68440 Sep 18 16:04 /bin/mount
-rwsr-xr-x 1 root root 40920 Sep 18 16:04 /bin/umount
-rwsr-xr-x 1 root root 15832 Oct 25 2004 /bin/ping

pingとかpasswd以外にこれだけある。ちなみに、setuidしなくても良いコマンドが有ったら、是非「sビットを無効にする。」習慣をつけた方が良いと思う。
参考までに、sビットを無効にするやり方を以下に示す。pppd、pppoeは現在自分の鯖では使われていない機能である為、sビットを無効にしてみる。

-rwsr-xr-- 1 root dip 265880 May 6 2005 /usr/sbin/pppd
-rwsr-xr-- 1 root dip 29420 Sep 30 2004 /usr/sbin/pppoe

# chmod a-s /usr/sbin/{pppd,pppoe}
# ls -al /usr/sbin/pppd

-rwxr-xr-- 1 root dip 265880 May 6 2005 /usr/sbin/pppd

# ls -al /usr/sbin/pppoe
-rwxr-xr-- 1 root dip 29420 Sep 30 2004 /usr/sbin/pppoe

と言う感じである。
ところで、pingコマンドは raw socket という低レベルのネットワーク機能を使っている、raw socket は root 権限がないと使うことができないのだ。一般ユーザにも ping コマンドを使うことができないと非常に不便だ。したがって、このように root に setuid されているわけだ。

# ls -al /bin/ping
-rwsr-xr-x 1 root root 30764 Dec 23 2003 /bin/ping

つまり極端な話、一般ユーザ権限をゲットできれば、root権限もいただくのは簡単だということである。いずれにしてもroot権限を奪われてしまったら、大きな被害が出るのは必定である。


4.SELinuxのセキュリティの考え方
SELinuxは、OSレベルでセキュリティ対策を施す。OSレベルのセキュリティ対策とは、大きくいえばOSレベルでシビアーなアクセス制御をすることである。以下の3つがSELinuxのセキュリティの機能である。

■ 強制アクセス制御(MAC)
■ 最小特権制度
■ 監査用ログ出力

1)強制アクセス制御
従来のアクセス制御は、ファイルやディレクトリの所有者がパーミッションの設定を行う。したがって、セキュリティは所有者任せである。さらに、rootユーザはパーミッションなんてお構いなしの最高権限ユーザである。
つまり、このような現状ではシステムに対してのセキュリティを徹底することは非常に困難である。そこで、この強制アクセス制御(Mandatory Access Control)はプロセスがどのリソースへアクセスできるかという設定は「ポリシーファイル」という設定ファイルで一元管理される。さらに、このポリシーファイルの編集は「セキュリティ管理者権限」のみ行うことが出来る。したがって、その設定は全プロセスの各ユーザ毎に関わらず適用される。つまり、セキュリティ管理者権限のユーザが定めたセキュリティ設定を徹底できるというすんぽうである。言うなれば、各ユーザが勝手にファイルの設定変更が出来ないようにしておけば、セキュリティホールを作らな
くてよい。

2)最小特権
来のLinuxでは、root権限を取られてしまったら、やり放題にやられておしまいである。SELinuxでは、まずroot権限のような絶対的な権限を無くし、ユーザがプロセスへアクセスするための必要最低限の機能を与えることを最小特権という。
この最小特権は、

● TE(Type Enforcement)
● RBAC(Role-Based Access Control)

と言うもので構成されている。

■ TEとは?
プロセスとリソースのラベル付けて、さらにプロセス、リソース両方のラベルの間にアクセス権限を設定する。
さらには、アクセス権限を設定したらアクセス制御を行う。こう言った一連の機能がTEである(プロセスに関する最小特権)。

■ RBACとは?
一言でいうと、ユーザレベルの細かいアクセス制御の設定が出来る機能。
従来は、rootユーザが全ての権限を独り占めしていた。それというのも、rootユーザはパーミッションチェックを避ける設定が出来てしまうため、事実上最高権限者であるということ。RBACの利点は、これを設定すればrootユーザになっても全ての最高権限を持つことは出来なくなるため、管理者のミス行為や悪意のある操作による被害を最小限にくい止めることが出来る。
RBACのプロセスは、

@ 管理権限を作る。
A ユーザシェルのドメインを設定する。
B 選択可能なロールを設定する。

こんな感じのプロセスで行う。

3)監査用ログ機能

■ アクセス違反ログ出力機能
TEのアクセス制限に違反した際には、ログに書き出す機能が有る。

■ 監査ログ機能
あとは、許可されたアクセスに対してもログを書き出すことが出来る。これは、例えばTEで許可されたwebmasterがWebへ更新した際の書き込みログが出力できる。


5.SELinuxのセットアップと設定概要

 1)必要なパッケージ
パッケージ的には、Kernel-2.6系には組み込める状態にある。状態にあると言うことは初っぱなインストール時に、

boot: linux selinux

と入力すれば、後のインストールの過程でファイヤーウォールの設定画面でSELinuxがオプション設定出来るようになっている。

@ Kernel → SELinux
A libselinux → SELinux API
B policy → デフォルトセキュリティポリシ
C policy-coreutil → セキュリティポリシを扱うためのコマンド達
D policy-source → デフォルトセキュリティポリシのソースファイル達
E checkpolicy → セキュリティポリシのソースファイルをバイナリレベルへ変換するユーティリティ

 2)SELinuxのモード
SELinuxには、以下の二つのモードがある。

@ permissiveモード
セキュリティポリシの設定を変更したときやデフォルトの設定がないアプリケーションの設定を作成したとき、もしくはアプリケーションが動かないとかの障害がおこったときに使われるモードである。基本的には、permissiveモードで出力されたログを元にセキュリティポリシの変更を行う。

A enforcingモード
セキュリティポリシ設定に違反するアクセスに対して、ログを出力して、そのアクセスを許可しない。つまり、通常のSELinuxの運用ではこのenforcingモードで行う。このモードでなければSELinuxは機能しない。

3)ファイルタイプ付け
インストール前にSELinuxを有効にする方法は、1)で説明した。そんじゃ、インストール後にSELinuxを組み込む場合は、

# vi /etc/sysconfig/selinux

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.

SELINUX=permissive
# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
#SELINUXTYPE=strict

SELINUXTYPE=targeted

SELinux=enforcing はポリシー違反があればアクセスを許否するEnforcingモードがある。もしくは、SELinux=permissive はポリシー違反があってもそのままアクセスをさせて違反内容をログに出力する。
SELinux=disabled はselinux無効状態。

SELINUXTYPE=targeted これは、SELinuxの簡易タイプらしい。言い方を変えると一部制限があるから設定にも柔軟性に欠けると言うことかも知れない。しかし、俺がテストしたCentOS 4.2(Final)では、targetedがデフォルトになっていた。したがって、targetedでテストした。
SELINUXTYPE=strict これは、SELinuxのフルスペック。

# getenforce
Permissive

で現在のモード確認。

# cd /etc/selinux/targeted/src/policy/
# make clean
# make reload relabel

ファイルのタイプ付け及び初期化を行う。

4)ファイルのタイプ確認とタイプの意味

# ls -aZ /
drwxr-xr-x root root system_u:object_r:root_t .
drwxr-xr-x root root system_u:object_r:root_t ..
-rw-r--r-- root root user_u:object_r:etc_runtime_t .autofsck
drwxr-xr-x root root system_u:object_r:bin_t bin
drwxr-xr-x root root system_u:object_r:boot_t boot
drwxr-xr-x root root system_u:object_r:device_t dev
drwxr-xr-x root root system_u:object_r:etc_t etc
drwxr-xr-x root root system_u:object_r:home_root_t home
drwxr-xr-x root root system_u:object_r:root_t initrd
drwxr-xr-x root root system_u:object_r:lib_t lib
drwx------ root root system_u:object_r:lost_found_t lost+found
drwxr-xr-x root root system_u:object_r:mnt_t media
drwxr-xr-x root root system_u:object_r:default_t misc
drwxr-xr-x root root system_u:object_r:mnt_t mnt
drwxr-xr-x root root system_u:object_r:usr_t opt
dr-xr-xr-x root root proc
drwxr-x--- root root root:object_r:user_home_dir_t root
drwxr-xr-x root root system_u:object_r:sbin_t sbin
drwxr-xr-x root root selinux
drwxr-xr-x root root system_u:object_r:default_t srv
drwxr-xr-x root root sys
drwxrwxrwt root root system_u:object_r:tmp_t tmp
drwxr-xr-x root root system_u:object_r:usr_t usr
drwxr-xr-x root root system_u:object_r:var_t var

プロセスに関しては、

# ps -eZ
LABEL PID TTY TIME CMD
user_u:system_r:unconfined_t 1 ? 00:00:01 init
user_u:system_r:unconfined_t 2 ? 00:00:00 ksoftirqd/0
user_u:system_r:unconfined_t 3 ? 00:00:00 events/0
user_u:system_r:unconfined_t 4 ? 00:00:00 khelper
user_u:system_r:unconfined_t 5 ? 00:00:00 kblockd/0
user_u:system_r:unconfined_t 6 ? 00:00:00 khubd
user_u:system_r:unconfined_t 23 ? 00:00:00 pdflush
user_u:system_r:unconfined_t 24 ? 00:00:01 pdflush
user_u:system_r:unconfined_t 26 ? 00:00:00 aio/0
user_u:system_r:unconfined_t 21 ? 00:00:00 kapmd
user_u:system_r:unconfined_t 25 ? 00:00:04 kswapd0
user_u:system_r:unconfined_t 99 ? 00:00:00 kseriod
user_u:system_r:unconfined_t 171 ? 00:00:01 kjournald
user_u:system_r:unconfined_t 971 ? 00:00:00 udevd
user_u:system_r:unconfined_t 1026 ? 00:00:00 kauditd
user_u:system_r:unconfined_t 1060 ? 00:00:00 kmirrord
user_u:system_r:unconfined_t 1061 ? 00:00:00 kmir_mon
user_u:system_r:unconfined_t 1080 ? 00:00:00 kjournald
user_u:system_r:syslogd_t 1511 ? 00:00:00 syslogd
user_u:system_r:initrc_t 1515 ? 00:00:00 klogd
user_u:system_r:initrc_t 1560 ? 00:00:04 sshd
user_u:system_r:initrc_t 1597 ? 00:00:00 crond
user_u:system_r:initrc_t 1614 ? 00:00:00 atd
user_u:system_r:unconfined_t 1643 tty1 00:00:00 mingetty
user_u:system_r:unconfined_t 1648 tty2 00:00:00 mingetty
user_u:system_r:unconfined_t 1649 tty3 00:00:00 mingetty
root:system_r:initrc_t 1900 ? 00:00:00 vsftpd
user_u:system_r:initrc_t 3149 ? 00:00:01 sshd
root:system_r:unconfined_t 3151 pts/1 00:00:01 bash
root:system_r:unconfined_t 3229 ? 00:00:00 sendmail
root:system_r:unconfined_t 3237 ? 00:00:00 sendmail
user_u:system_r:initrc_t 3503 ? 00:00:01 sshd
root:system_r:unconfined_t 3505 pts/2 00:00:00 bash
root:system_r:unconfined_t 3564 pts/2 00:00:00 ps

こんな感じにタイプ付けしてある。タイプの見方について、例えば/varディレクトリのタイプ付けは、

system_u:object_r:var_t var

これは右から var_tドメインでobject_rロールでsystem_uユーザであると言うこと意味している。

5)アクセス制御の実際

本来なら、以下のようにpolicyディレクトリをカレントディレクトリにしてaudit2allowコマンドを使いながらdimains/program/*.teファイルを編集し以下のようにコンパイルしながら許可タイプ( allow文 )で制御する。しかし、正直敷居が高い(・・;)。GUI上のグラフィカルな設定で行えば比較的簡単かも知れない。

# cd /etc/selinux/targeted/src/policy/
# make clean
# make reload

簡単に使えるとしたら、boolentrue or false )を使った設定が簡単で便利かも知れない。これを使えば、make reloadを実行しなくても良いようだ。

# getsebool -a
allow_ypbind --> inactive
dhcpd_disable_trans --> inactive
httpd_builtin_scripting --> active
httpd_disable_trans --> inactive
httpd_enable_cgi --> active
httpd_enable_homedirs --> active
httpd_ssi_exec --> active
httpd_tty_comm --> inactive
httpd_unified --> active
mysqld_disable_trans --> inactive
named_disable_trans --> inactive
named_write_master_zones --> inactive
nscd_disable_trans --> inactive
ntpd_disable_trans --> inactive
pegasus_disable_trans --> inactive
portmap_disable_trans --> inactive
postgresql_disable_trans --> inactive
snmpd_disable_trans --> inactive
squid_disable_trans --> inactive
syslogd_disable_trans --> inactive
use_nfs_home_dirs --> inactive
use_samba_home_dirs --> inactive
use_syslogng --> inactive
winbind_disable_trans --> inactive
ypbind_disable_trans --> inactive

これで、inactiveが無効でactiveが有効である。

# setsebool httpd_enable_cgi true

でactive。

# setsebool httpd_enable_cgi false

でinactive。

設定したら、SELinuxの設定状態を全て確認する。

# sestatus -v

以上で設定は、


6.SELinuxの限界
今まで話してきて勘のいい人は解ると思うが、SELinuxはアクセス制御なのでアクセス制御に関係ない悪事を働かれたらおしまいである。以下に、出来ないことを列記する。

1)バッファオーバーフロー攻撃
バッファオーバーフロー攻撃自体は防げない。しかし、バッファオーバーフロー攻撃で侵入されてもアクセス制御で被害を最小限に防ぐことは出来る。

2)DoS攻撃
これは、侵入と言うよりサーバを停止させることが目的なので防ぐことは出来ない。

3)アプリの脆弱性
スクリプトのクロスサイトスクリプティングやセッション管理のバグ等も防ぐことは出来ない。

4)管理者が悪人だった場合
これも、言わずと知れて防ぐことは出来ない。管理者の管理者たる教育や信頼性の問題かと思うが。

SELinuxは、「侵入されても被害を最小限に防ぐセキュリティ機能である。」

以上


 
 
 



Copyright 2005 Kozupon.com.