このappさ。動かないんだぜ。
問題文
Webアプリケーションをデプロイするために動作環境を用意したのだが、/opt/service/
以下にある app
アプリケーションを実行しても、正しく起動しないらしい。 また、担当者だったトラブル太郎さんは会社を去ってしまった。
原因を解明し、トラブルを修正してくれ。また、同じトラブルが再起動後にも発生しないようにしてくれ。
初期状態
/opt/service
にapp
,flag
,flag.txt
がある/opt/service
以下で./app
を正しく実行できない
終了状態
VMを再起動しても以下が成り立つ
./app
でアプリケーションが起動できるcurl localhost:3000
すると以下のように表示される(一行目は現在時刻/GMT)
2020-02-29 04:40:55
test
Great!!!!
補足
- セキュリティレベルが下がるようなことをしてはいけません
- セキュリティを保つため、appや関連するファイルへ不必要な権限を与えてはいけません(プロセスをroot権限で動作させたり、ケイパビリティ与えるなど)
- なぜ正しく動かなかった原因を報告してください。またその原因をどうやって特定したか具体的に報告してください。
- 解決するにあたって、何をしたか(どのようなコマンドを打ったか、どこのファイルをどう編集したか等)具体的に報告してください
- /opt/service 以下のファイルの内容を変更してはいけません
解説・解法
1. 導入・ロール昇格
SELinuxによって適切に権限が振られてない問題です。
まず、sshして/opt/service/appを実行してみます。
2020/02/29 07:17:42 ReadFile() error=open flag.txt: permission denied
以上のように表示されるため、flag.txtのパーミッションを確認しますが、オーナーは自分で、かつ権限は644です。ここで、おそらくSELinuxによってアクセス権限がないことがわかります。
/var/log/audit/audit.log
を開こうとすると権限がなく、またauditdを起動しようとしても、systemctlが発行できないことに気づきます。 またgetenforceするとenforcingです。
ここまでくればSELinux/MACが原因と確定できます。
id
コマンドを打つと、自分のSELinuxコンテキストが staff_u:staff_r:staff_t:s0-s0:c0.c1023
とわかります。CentOSの場合、 staff_uはデフォルトでstaff_r sysadm_r system_r unconfined_r
の4つのロールに属しているので、まずはadmin用であるsysadm_rへロール昇格をします。
ロール昇格は、通常sudo
かnewrole
で行えるので、まずはsudoで試してみます。
$ sudo id -Z
staff_u:staff_r:staff_t:s0-s0:c0.c1023
ロールもドメインも変化していません。次はnewroleを試します。
$ newrole -r sysadm_r
$ id -Z
staff_u:sysadm_r:sysadm_t:s0-s0:c0.c1023
昇格できました。これで作業が始められます。
2. myapp_t
へ myapp_flag_t
の読み込み権限を与える
無事staff_rからsysadm_rへ昇格できたので、auditdを再開させます。
$ sudo service auditd start
Permission denied
$ sudo systemctl start auditd
Permission denied
$ sudo tail -f /var/log/audit/audit.log
No such file or directory
auditが起動できず、またログも出ていないため、どのドメインの権限が不足しているかわかりません。audit2allowも使用できません。なので、selinuxからポリシーを吐き出させて静的に解析します。
$ ls -lZ /opt/service
-rwxr-xr-x. ictsc ictsc system_u:object_r:myapp_exec_t:s0 app
-rwxr-xr-x. ictsc ictsc system_u:object_r:usr_t:s0 flag
-rw-r--r--. ictsc ictsc system_u:object_r:myapp_flag_t:s0 flag.txt
ls -lZ
で、flag.txtファイルのコンテキストmyapp_flag_t
がわかるので、myapp_flag_t
に対する権限を持っているドメインを探す必要があります。
semodule -E myapp
でポリシーを抽出、dismodで中のポリシーを確認します。
アプリケーションはmyapp_t
ドメインで動作するとわかるので、flag.txt(myapp_flag_t
)への読み込み許可(read open)を与えるポリシーを生成します。
$ cat hoge.te
policy_module(hoge, 1.0)
require {
type myapp_t;
type myapp_flag_t;
}
allow myapp_t myapp_flag_t:file { read open };
$ cp /usr/share/selinux/devel/Makefile .
$ make
$ sudo semodule -i hoge.pp
これで、app
自体は動くようになります。
$ exit
$ ./app
3. myapp_t
へflag
の実行権限を与える
curlを投げて見ると、出力が足りません。
$ curl localhost:3000
2020-02-29 07:58:35
test
appがどのような動作をしているかわからないのでstraceをインストールし見てみます。
$ newrole -r sysadm_r
$ sudo yum install strace.x86_64
$ strace ./app
appがflagを実行しようとしています。 ただ、この状況を解決するために、myapp_tドメインにusr_t全てに対する権限を与えてしまいそうになりますが、その場合myapp_tがすべてのusr_tラベルを持つファイルを実行できてしまうため、セキュリティレベルが下がります。
なので、flagバイナリのコンテキストを押さえ込みます。新しくドメインを作ってもいいですが、既にあるmyapp_exec_tを使いましょう。
$ sudo semanage fcontext -a -t myapp_exec_t /opt/service/flag
$ sudo restorecon -FR /opt/service
restoreconができなかったので、自分に権限を与えます。 以下をteファイルへ追記して再インストールします。ちなみにこのポリシーは、audit2allowが使えないので自力でrefpolicyから推測します。
allow sysadm_sudo_t myapp_flag_t:file getattr;
allow sysadm_sudo_t usr_t:file relabelfrom;
allow sysadm_sudo_t myapp_exec_t:file relabelto;
また、requireに追記することも忘れないようにしまししょう。
以下に現在のteファイルを示します。
$ cat hoge.te
policy_module(hoge, 1.0)
require {
type myapp_t;
type myapp_flag_t;
type myapp_exec_t;
type usr_t;
type sysadm_sudo_t;
}
allow myapp_t myapp_flag_t:file { read open };
allow sysadm_sudo_t myapp_flag_t:file getattr;
allow sysadm_sudo_t usr_t:file relabelfrom;
allow sysadm_sudo_t myapp_exec_t:file relabelto;
先ほどと同じ手順で、コンテキストをインストールできたら、appを起動します。
$ make
$ sudo semodule -i hoge.pp
$ exit
$ ./app
curlします。
$ curl localhost:3000
2020-02-29 08:16:38
test
Great!!!!
正しく起動できました。
まとめです。 appが正しく動かない原因は2つ。
- app (
myapp_t
) がflag.txt
を読めない - app (
myapp_t
) がflag
を実行できない
前者はポリシーの作成、後者はfcontextを行いラベル変更で解決できました。
所感
この問題で一番大事になる部分は、SELinuxの管理を行える権限がないstaff_rロールから、newroleコマンドでsysadm_rへロール昇格ができるかどうか、という点でした。 (結構、setenforceコマンドが実行できないのは問題の不備ではないのかという質問を頂きました)
また、惜しかったのは、問題の中で「不必要な権限を与えてはいけない」と書いてあるのに、usr_tドメインへのexecuteアトリビュート権限をmyapp_tドメインへ与えていたチームです。/opt/service/appは正しく動きますが、問題の指示とあっていないため満点にはしませんでした。
SELinuxは、結構マイナーで触る機会がない技術であるため、ここまで解かれるとは思っていませんでした。作問者として、大変嬉しく思います。