auditdでLinuxのファイル改竄検知を行う

# はじめに

Linuxでファイル改竄検知をやろうと思ってauditdを試したメモです。

ファイルの改竄検知としては [Tripwire](https://sourceforge.net/projects/tripwire/) が有名ですが、Linuxであればauditdを使うことも可能です。AmazonLinuxだとデフォルトで入ってたので、設定ファイルを書くだけで使えます。

Tripwireは予めファイルのチェックサムのデータベースを作っておいて、これをファイルを比較することで、ファイルの改竄を検知します。同じようにファイルのチェックサムベースで比較するものとして[AIDE](http://aide.sourceforge.net/)というツールもあるようです。
一方auditdは仕組みとしてはLinuxカーネルでシステムコールを記録して、特定の条件にマッチする操作をログに出力します。なので、若干守備範囲の違うツールですが、システムコールを監視することでもファイルの変更は監視できます。
LinuxのAuditのアーキテクチャや説明などは、RedHatのマニュアルにイメージ図があって参考になるので貼っておく。
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/7/html/Security_Guide/chap-system_auditing.html

# 環境
稼働確認した環境は以下の通りです。
* AmazonLinux: 2016.09
* audit: 2.4.1-5.27.amzn1

カーネルバージョンは以下。

```
[root@myhost audit]# uname -a
Linux myhost 4.4.19-29.55.amzn1.x86_64 #1 SMP Mon Aug 29 23:29:40 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
```

# インストール

インストールはyumやapt-getで行えますが、RedHat系とDebian系で若干パッケージ名が異なるので注意。

ReadHat系

```
$ sudo yum install audit
```

Debian系

```
$ sudo apt-get install auditd
```

ちなみにAmazon Linuxにはデフォルトでインストールされています。

```
[root@myhost ~]# cat /etc/system-release
Amazon Linux AMI release 2016.09

[root@myhost ~]# yum list installed | grep audit
audit.x86_64                         2.4.1-5.27.amzn1              installed
audit-libs.x86_64                    2.4.1-5.27.amzn1              installed

[root@myhost ~]# chkconfig --list | grep audit
auditd          0:off   1:off   2:on    3:on    4:on    5:on    6:off

```

# 設定
設定ファイルは `/etc/audit/auditd.conf` でルール定義は `/etc/audit/audit.rules` に書きます。ログはデフォルトで `/var/log/audit/audit.log` に出ます。後述しますが、syslogなどにも出せます。

ルールの定義は `auditctl` で動的に設定変更もできますが、永続化するならルールファイルに書きましょう。

現在設定されているルールは `auditctl -l` で確認できます。

AmazonLinux 2016.09だとデフォルトで以下のようにシステムコールの監査が無効化されていました。

```
[root@myhost audit]# auditctl -l
-a never,task
```

AmazonLinuxのFAQによると2015.09以降はパフォーマンス的な観点から、システムコールの監査がデフォルトで無効化されているようです。
https://aws.amazon.com/jp/amazon-linux-ami/faqs/
Q: 2015.09 インスタンスより前のシステムコール監査をどのように無効にできますか?

Auditのルールには「制御ルール」、「ファイルシステムルール」、「システムコールルール」の３つのタイプがあります。制御ルールの説明は `man auditctl` をファイルシステムとシステムコールのルールの説明は `man audit.rules` にいろいろ説明があるので、どんな設定項目があるのかはmanを読むとよいんじゃないかと思います。

ちなみにAmazonLinux2016.09のデフォルトでは以下のような設定になってました。
設定値の意味はコメントのとおりで、最初にルールを削除して、バッファの調整と、システムコール監査の無効化をしています。

```/etc/audit/audit.rules
# This file contains the auditctl rules that are loaded
# whenever the audit daemon is started via the initscripts.
# The rules are simply the parameters that would be passed
# to auditctl.

# First rule - delete all
-D

# Increase the buffers to survive stress events.
# Make this bigger for busy systems
-b 320

# Disable system call auditing.
# Remove the following line if you need the auditing.
-a never,task

# Feel free to add below this line. See auditctl man page
```

手元で検証してみたところ、システムコールの監査が無効になっていると、ファイルの変更検知がうまくできませんでした。パフォーマンス懸念はあるのですが、取りこぼしていると監査の意味がないので、システムコール監査の無効化はコメントアウトして有効な状態としました。（何かの勘違いであれば誰か教えてください）

```/etc/audit/audit.rules
# This file contains the auditctl rules that are loaded
# whenever the audit daemon is started via the initscripts.
# The rules are simply the parameters that would be passed
# to auditctl.

# First rule - delete all
-D

# Increase the buffers to survive stress events.
# Make this bigger for busy systems
-b 320

# Disable system call auditing.
# Remove the following line if you need the auditing.
# -a never,task

# Feel free to add below this line. See auditctl man page
```

# ファイルの変更を検知する

## 特定のファイルへの書き込みアクセスと属性変更を検知する

まずは例として、/etc/passwdを変更した場合に検知するルールを設定してみる。

`/etc/passwd` への書き込みアクセスと属性変更を `passwd_changes` というキーをログに記録してみます。`/etc/audit/audit.rules` の末尾に以下の行を追記します。(設定ファイルに直接記載せずにauditctlの引数に付けて動的に変更することも可能です）

設定の書き方は以下で、

```/etc/audit/audit.rules
-w path_to_file -p permissions -k key_name
```

具体的には以下のように設定します

```/etc/audit/audit.rules
-w /etc/passwd -p wa -k passwd_changes
```

auditdを再起動します

```
[root@myhost audit]# service auditd restart
auditd を停止中:                                           [  OK  ]
auditd を起動中:                                           [  OK  ]
```

設定したら/etc/passwdの末尾にhogeユーザを追記してみます。

```
[root@myhost audit]# vi /etc/passwd
(略)
hoge:x:900:900:hoge user:/home/hoge:/bin/bash
```

/var/log/audit/audit.logを見ると以下のようなログが出力されています。

```
type=CONFIG_CHANGE msg=audit(1479097266.018:224): auid=500 ses=2 op="updated_rules" path="/etc/passwd" key="passwd_changes" list=4 res=1
type=CONFIG_CHANGE msg=audit(1479097266.018:225): auid=500 ses=2 op="updated_rules" path="/etc/passwd" key="passwd_changes" list=4 res=1
```

（余談）なんで２行出るんだろうと思って、システムコールを見てみたらviで保存する時に一瞬元のファイルを消して新しく作ってるので `/etc/passwd` のinode番号が変わってました。まじか。知らないとちょっと怖い挙動。

```
[root@myhost audit]# ls -i /etc/passwd
401210 /etc/passwd
[root@myhost audit]# vi /etc/passwd
[root@myhost audit]# ls -i /etc/passwd
401208 /etc/passwd
```

## 特定ディレクトリ配下の書き込みアクセスと属性変更を検知する

/etc配下すべての変更を検知するには以下のように設定します。

```/etc/audit/audit.rules
-w /etc/ -p wa -k etc_changes
```

## 特定ディレクトリを除外して、それ以外の書き込みアクセスと属性変更を検知する
除外ルールはファイルシステムルールだけでは表現できないので、システムコールルールを使うことで除外条件を制御できます。

例えば、以下のように除外するディレクトリを先に定義し、最後にその他全てのディレクトリを監視対象にします。

```/etc/audit/audit.rules
-a exit,never -F dir=/dev -k exclude
-a exit,never -F dir=/proc -k exclude
-a exit,never -F dir=/sys -k exclude
-a exit,never -F dir=/tmp -k exclude
-a exit,never -F dir=/var -k exclude
-a exit,always -F dir=/ -F perm=wa -k file_changes
```

個人的にはブラックリストよりもホワイトリストで除外していく方が好みです。この書き方がパフォーマンス的にどうなのかはよく分かっていないのですが、厳しめに設定して除外したりディレクトリを追加していく方が安心感はあります。本番に投入してみて、パフォーマンスがまずそうだったら考えます。

またauditdはシステムコールを拾えるので、ファイルの変更以外にも時刻変更の検知、sshログインの検知や、ファイル実行などいろいろ監視できます。

各種セキュリティ認証に準拠した設定例が `/usr/share/doc/audit-#{version}` にあるので参考にしてみるとよいかもしれません。

(2016/11/28追記)
上記のようなデフォルト検知の設定を入れる場合、OS起動/停止時に大量のファイル変更を検知してしまうので、auditdのサービス起動タイミングを最後に起動して、最初に落とすように調整した方が無難そうです。

```
# sed -i 's/# chkconfig: 2345 11 88/# chkconfig: 2345 99 01/' /etc/rc.d/init.d/auditd
# chkconfig --del auditd
# chkconfig --add auditd
# service auditd restart
```

また、特定のシステムコールを無視する方法も別エントリで書きましたので、こちらも適宜参考にしていただければと。
[auditdで特定のsyscallとexit (errno) の組み合わせを無視する](http://qiita.com/minamijoyo/items/e98dab422a370b8e7277)

# syslogに出力
ログはシスログに出力可能です。syslogに出すメリットは、バックアップや監視などを既存のsyslogの運用に載せることができるところです。デメリットは結構ログの量が出るのでファイルが混ざって見づらいことぐらい。

`/etc/audisp/plugins.d/syslog.conf` に設定ファイルがあります。

```/etc/audisp/plugins.d/syslog.conf
# This file controls the configuration of the syslog plugin.
# It simply takes events and writes them to syslog. The
# arguments provided can be the default priority that you
# want the events written with. And optionally, you can give
# a second argument indicating the facility that you want events
# logged to. Valid options are LOG_LOCAL0 through 7.

active = no
direction = out
path = builtin_syslog
type = builtin
args = LOG_INFO
format = string
```

これを `active = yes` に変更します。

```/etc/audisp/plugins.d/syslog.conf
# This file controls the configuration of the syslog plugin.
# It simply takes events and writes them to syslog. The
# arguments provided can be the default priority that you
# want the events written with. And optionally, you can give
# a second argument indicating the facility that you want events
# logged to. Valid options are LOG_LOCAL0 through 7.

active = yes
direction = out
path = builtin_syslog
type = builtin
args = LOG_INFO
format = string
```

設定変更したらauditdを再起動しておきます。

```
[root@myhost audit]# service auditd restart
auditd を停止中:                                           [  OK  ]
auditd を起動中:                                           [  OK  ]
```

ちょっとファイルを更新してみます。

```
[root@myhost audit]# echo "hoge:x:900:900:hoge user:/home/hoge:/bin/bash" >> /etc/passwd
```

こんなかんじで `audispd` という名前でシスログにも出るようになります。

```/var/log/messages
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=SYSCALL msg=audit(1479110023.548:1036): arch=c000003e syscall=2 success=yes exit=3 a0=ba47b0 a1=441 a2=1b6 a3=fffffff0 items=2 ppid=26972 pid=26973 auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="bash" exe="/bin/bash" key="file_changes"
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=CWD msg=audit(1479110023.548:1036):  cwd="/etc/audit"
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=PATH msg=audit(1479110023.548:1036): item=0 name="/etc/" inode=393218 dev=ca:01 mode=040755 ouid=0 ogid=0 rdev=00:00 nametype=PARENT
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=PATH msg=audit(1479110023.548:1036): item=1 name="/etc/passwd" inode=399590 dev=ca:01 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=PROCTITLE msg=audit(1479110023.548:1036): proctitle="-bash"
Nov 14 07:53:43 ip-10-194-1-173 audispd: node=myhost type=EOE msg=audit(1479110023.548:1036):
```

syslogに出しつつ、 `/var/log/audit/auditd.log` にも出てますが、両方出るようになるだけでこっちが止まるわけではないみたいです。

# まとめ
Linuxでファイル改竄検知を行う方法としてauditdを使った方法を紹介しました。
通知部分はfluentd + Slackで投げようと思ってますが、これはまた別に検証したら書こうかと思います。

(2016/11/15追記)
fluentd + Slack通知も実装できたので、以下にまとめました↓
[fluentdでログ監視して特定の文字列をgrepで検知したらSlackに通知する（バースト抑止付き）](http://qiita.com/minamijoyo/items/1bb277383d8d2d2c7c11)