Apparmor のバイパステクニック

この記事はGMOペパボ Advent Calendar 2018の22日目の記事です(大遅刻)。 本当は今半期やってきた総括として、コンテナランタイムのセキュリティについて一からまとめたかったのですが、Linux Namespace の実装を読み始めたら迷子になってしまったので間に合いませんでした。 なので、今回は過去に見つかった AppArmor のバイパス方法を簡単にまとめようと思います。 2018/12/24 現在、最新版で修正されているものもあるし、されていないものもあります。 ここでは、以下の3つのバイパス方法を記します。 親ディレクトリを rename するバイパス shebang を利用したバイパス pivot_root を利用したバイパス ちなみに、それぞれのバグ報告の Issue リンクは記していますが、どのバージョンやコミットで修正されているかまでは記していません。面倒だったので。 1. 親ディレクトリを rename する Bug #1794820 “filesystem blacklisting can be bypassed by moving …” : Bugs : AppArmor ~/bin/bash に対して .ssh/ 配下のファイルにアクセスを禁止する次のような profile を適用する。 #include <tunables/global> /home/vagrant/bin/bash { #include <abstractions/base> file, deny /home/vagrant/.ssh/** mrwklx, } vagrant@ubuntu-bionic:~$ ./bin/bash vagrant@ubuntu-bionic:~$ cat .ssh/id_rsa cat: .ssh/id_rsa: Permission denied このように AppArmor によってアクセス制御がされる。

aa_change_onexec がどのように動作するか

libapparmor に AppArmor のプロファイルの適用などに関するライブラリが用意されている。その中に execve のタイミングでプロファイルを変更する aa_change_onexec というものがある。 https://gitlab.com/apparmor/apparmor/blob/master/libraries/libapparmor/src/kernel.c#L481 これがどのように適用されるのか調べたのでメモ。 setprocattr を見ればわかるとおり、内部的には /proc/self/attr/exec に exec <profilename> を書き込んでいる。 ... ctl = procattr_path(tid, attr); if (!ctl) goto out; fd = open(ctl, O_WRONLY); if (fd == -1) { goto out; } ret = write(fd, buf, len); ... open("/proc/14963/attr/exec", O_WRONLY) = 4 write(4, "exec haconiwa-test", 18) = 18 close(4) 以下のようなプログラムを用いて確認してみる。 #include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <sys/syscall.h> int main(void) { int fd, res, len; char *path = NULL; char *buf = NULL; char *const cmd[] = {"/bin/bash", NULL}; pid_t tid = syscall(SYS_gettid); asprintf(&path, "/proc/%d/attr/%s", tid, "exec"); fd = open(path, O_WRONLY); if (fd == -1) { printf("failed open\n"); return 1; } len = asprintf(&buf, "exec %s", "top-deny-profile"); res = write(fd, buf, len); if (res == -1) { printf("Error: write(%d) \n", errno); exit(errno); } close(fd); execv("/bin/bash", cmd); return 0; } top-deny-profile には deny /usr/bin/top mrwklx というルールを適用しており、top コマンドを使用できないようにしている。