falco のルールは、そこそこ柔軟に書けるのだが、故にバイパスできてしまうよという話。
1. /proc/self/root
を使う
falco のデフォルトルールに /etc/shadow
などが開かれたことを検知するルールがある。
抜粋するとこういうルール。
- list: sensitive_file_names
items: [/etc/shadow, /etc/sudoers, /etc/pam.conf, /etc/security/pwquality.conf]
- macro: sensitive_files
condition: >
fd.name startswith /etc and
(fd.name in (sensitive_file_names)
or fd.directory in (/etc/sudoers.d, /etc/pam.d))
- rule: Read sensitive file untrusted
desc: >
an attempt to read any sensitive file (e.g. files containing user/password/authentication
information). Exceptions are made for known trusted programs.
condition: >
sensitive_files and open_read and proc_name_exists
これは fd.name
が /etc/shadow
の場合に検知するので、 /proc/self/root/etc/shadow
のようなパスを指定されると、このルールをバイパスされる。
2. $()
を使う
例えば、PHP から system()
を使って git
が使われるのを検知するシナリオを考える。
一つ方法として思いつくのは proc.cmdline
が sh -c git
から始まるかをチェックすることだろう。
これもデフォルトルールにマクロとしてある。
もうちょっと分かりやすく書くとこう。
- macro: spawned_process
condition: evt.type = execve
- rule: Spawn git process from php
desc: Spawn git process from php
condition: proc.pname=php and spawned_process and proc.cmdline startswith "sh -c git"
output: Spawn git process (command=%proc.cmdline pid=%proc.pid user=%user.name %container.info image=%container.image)
priority: WARNING
しかし、この場合、 $()
を使うことでバイパスできる。
# 検知される
$ php -r 'system("git --version")';
# 検知されない
$ php -r 'system("$(echo \"git --version\")");'
3. #
コメントを使ったバイパス
OS コマンドインジェクションを検知するために、PHP から生成されるプロセスを検知したいシナリオを考える。
ただし、バッチスクリプト( run-job.sh
)を system()
経由で実行しているという背景があり、これに関しては除外したいとする。
この場合、思いつくルールは次のような感じ。
- macro: batch_job
condition: (proc.cmdline contains "run-job.sh")
- rule: Spawn processes from php
desc: Spawn processes from php
condition: proc.pname=php and spawned_process and not batch_job
output: Spawn process (command=%proc.cmdline proc.name=%proc.name pid=%proc.pid user=%user.name %container.info image=%container.image)
priority: WARNING
ここで、実際に PHP に OS コマンドインジェクションがあった場合、次のようにコメントを含めることで proc.cmdline
が whoami;# run-job.sh
となり、 proc.cmdline contains "run-job.sh"
でマッチするのでバイパス可能。
# 検知される
<?php
$user_input = "whoami";
system($user_input);
?>
# 検知されない
<?php
$user_input = "whoami;# run-job.sh";
system($user_input);
?>
まとめ
/proc/self/root
などのシンボリックリンクを使うことで fd.name
に関してはバイパス可能である。
そのため、そのシンボリックリンクも検知対象に含めなければ完全な検知は不可能。
また、 proc.cmdline
(だけに限らないが)に関しても前述したようなバイパス手段があるため、そのような場合も考慮したルールを書いたりしなければならない。