使用auditd监控Linux文件访问
1.简介
Linux 系统通常有多个用户。审计是这种多用户环境的重要组成部分。特别是,作为文件系统的原子部分,文件通常是被监控的单元。
**在本教程中,我们将探讨如何在 Linux 下执行文件访问监控。**首先,我们回顾一下文件访问权限。接下来,我们跳到审计的一般主题。之后,我们深入研究 Linux 下的审计。具体来说,我们讨论了使用广泛使用的审计组件来安装、配置和监视文件访问。
我们使用 GNU Bash 5.1.4 在 Debian 11 (Bullseye) 上测试了本教程中的代码。它应该在大多数符合 POSIX 的环境中工作。
2. 寻找
找出谁在任何系统中做了什么并非易事。 例如,让我们假设一个简单的情况:多用户 Linux 环境中的文件丢失。通常,管理员可以通过ls 检查谁拥有或有权访问该文件:
$ ls -l /dir/file
-rwxr--r-- 1 user1 user1 666 May 6 16:56 file
阅读该行,我们可以破译所有权和权限 。 特别是,用户user1是唯一的所有者,他还具有对常规(第一个*-)文件的读取*( r ) 和写入( w ) 访问权限。此外,用户的私有组(也称为user1)和全局权限是只读的。
在实践中,删除需要包含目录的读、写和执行权限:
$ ls -l /dir
drwxrwxrwx 1 root root 4096 May 6 16:25 .
drwxr-xr-x 1 root root 4096 May 6 06:25 ..
请注意,我们添加了*-a*标志来获取特殊的. /dir的目录 ,它告诉我们它的属性。
现在,我们知道user1可能是删除*/dir/file*的那个人。未来,我们如何确保?
3. 审计
审计的总体思路是帮助控制用户操作。它提供了一种将活动映射到某些帐户的方法,使管理员能够跟踪:
- 执行了什么操作
- 哪个用户采取了行动
- 涉及哪些对象或对象
- 事件发生的时间
结合强大的安全概念,如加密保护的身份验证和授权 ,审计可以确保几乎完全的问责制。
通过这种方式,存在一系列记录,从而可以重建事件。实际上,该机制在数据方面与用于跟踪数据库(例如mysql )的日志或多或少相同:
$ cat /var/lib/mysql/audit.log
[...]
<AUDIT_RECORD>
<TIMESTAMP>2022-10-05T16:06:56 UTC</TIMESTAMP>
<RECORD_ID>6_2022-10-05T16:03:33</RECORD_ID>
<NAME>Query</NAME>
<CONNECTION_ID>5</CONNECTION_ID>
<STATUS>0</STATUS>
<STATUS_CODE>0</STATUS_CODE>
<USER>root[root] @ localhost [127.0.0.1]</USER>
<OS_LOGIN/>
<HOST>localhost</HOST>
<IP>127.0.0.1</IP>
<COMMAND_CLASS>drop_table</COMMAND_CLASS>
<SQLTEXT>DROP TABLE IF EXISTS t</SQLTEXT>
</AUDIT_RECORD>
[...]
当然,操作系统审计并不像某些数据库那样直接允许恢复——我们需要数据 和手段 。通过这种方式,审计数据位于备份和简单历史日志之间:
$ cat /home/user1/.mysql_history
create database blogdemo
create user [[email protected]](/cdn_cgi/l/email_protection) IDENTIFIED BY 'password'
grant select,insert,update,delete,create,drop,index,alter,create temporary tables,lock tables on blogdemo.* to [[email protected]](/cdn_cgi/l/email_protection)
flush privileges
exit
然而,有了这些知识,我们仍然比求助于人工取证要好得多。让我们看看这在操作系统级别是如何工作的。
4. 使用auditd进行 Linux 审计
在 Linux 下,我们可以通过多种方式执行和自动化审计。在非常简单的情况下,我们可以使用inotifywait和inotifywatch 。但是,综合auditd 包可能是更好的选择。
4.1. 安装及主要配置
由于默认情况下它不是所有 Linux 发行版的一部分,我们可能需要自己安装auditd:
$ apt-get install auditd
[...]
接下来,我们在*/etc/audit/auditd.conf*中建立守护进程的默认配置:
$ cat /etc/audit/auditd.conf
#
# This file controls the configuration of the audit daemon
#
local_events = yes
write_logs = yes
log_file = /var/log/audit/audit.log
log_group = adm
log_format = ENRICHED
flush = INCREMENTAL_ASYNC
freq = 50
max_log_file = 8
num_logs = 5
priority_boost = 4
name_format = NONE
##name = mydomain
... long output omited
transport = TCP
krb5_principal = auditd
##krb5_key_file = /etc/audit/audit.key
distribute_network = no
q_depth = 400
overflow_action = SYSLOG
max_restarts = 10
plugin_dir = /etc/audit/plugins.d
文件中的大多数关键设置都是不言自明的,并且具有合理的默认值。其余的,我们可以使用配置参考 。
至关重要的是,我们应该记下log_file的路径:/var/log/audit/audit.log。当然,write_logs必须是yes才重要。
为了使auditd满足我们的需求,我们可能还需要设置一些规则,基于哪些审计将被执行。
4.2. 规则结构
基本上,规则是管理审计事件记录的触发器。与防火墙类似,当事件与规则匹配时,它会被记录下来。
规则存储在/etc/audit/audit.rules*文件*中:
$ cat /etc/audit/audit.rules
## This file is automatically generated from /etc/audit/rules.d
-D
-b 8192
-f 1
--backlog_wait_time 60000
但是,此文件只是*/etc/audit/rules.d/目录中所有.rules*文件的合并版本:
$ ls /etc/audit/rules.d/
audit.rules
因此,要正确更改或添加规则,我们应该首先在那里修改或创建文件。
4.3. 了解规则
让我们首先检查默认值:
$ cat /etc/audit/rules.d/audit.rules
## First rule - delete all
-D
## Increase the buffers to survive stress events.
## Make this bigger for busy systems
-b 8192
## This determine how long to wait in burst of events
--backlog_wait_time 60000
## Set failure mode to syslog
-f 1
在大多数情况下,这些选项在评论中进行了解释。值得注意的是,缓冲区大小以条目为单位,而不是字节的倍数。
以下是规则文件行的所有选项:
- # <评论>
- -w <文件路径> -p <权限> -k <密钥名>
- -a , -S -F <field=value> -k
- – <标志> <值>
请注意,该包对规则语法非常严格。例如,不允许与规则在同一行的注释。此外,重复规则是有风险的。因此,为避免出现问题,应严格遵循语法。考虑到这一点,我们可以继续。
4.4. 设置规则
现在,让我们创建一个非常简单的规则文件*/etc/audit/rules.d/blogdemo.rules*:
## Enable ruleset
-e 1
## Limit the rate to 120 audit entries per second
-r 120
## Monitor /blogdemo for rwxa events
-w /blogdemo -p rwxa -k toplevel_blogdemo
## Monitor /file for read events
-w /file -p r -k root_file
## Monitor for name change syscall
-S sethostname -a always,exit -k hostname_change
*在这里,-w /blogdemo -p rwxa -k toplevel_blogdemo监视/blogdemo*目录中涉及读取 ( r )、写入 ( w )、执行 ( x ) 或属性更改 ( a )**的任何事件。
另一方面,-a always,exit -S sethostname -k hostname_change 监视系统调用(-S with sethostname)。需要always操作来记录事件,而exit决定何时以及如何发生。
本质上,规则文件的所有行都传递给用户空间审计控制组件auditctl 。因此,我们可以通过工具手册解释任何规则。
4.5. 启动守护进程
完成初步步骤后,我们可以通过augenrules 加载配置:
$ augenrules --check
/sbin/augenrules: Rules have changed and should be updated
$ augenrules --load
No rules
enabled 1
failure 2
[...]
$ augenrules --check
/sbin/augenrules: No change
在这里,–check开关测试任何新规则添加,而*–load从**/etc/audit/rules.d/重新生成所有规则。 重要的是,augenrules –check可能会显示假阴性,在语法出现问题时声称没有变化。*我们可以通过检查规则并确保它们正确来诊断这里的任何问题。此外,我们可以确认什么是有效的:
$ auditctl -l
-w /blogdemo -p rwxa -k toplevel_blogdemo
-w /file -p r -k root_file
-a always,exit -S sethostname -F key=hostname_change
切换到auditctl的*-l会列出所有当前活动的规则。 最后,我们可以使用auditd*运行守护进程:
$ auditd
通常,我们可以使用journalctl -u auditd在启动期间查找问题。
4.6. 阅读日志
现在让我们使用我们在上面的配置中看到的路径检查日志:
$ cat /var/log/audit/audit.log
type=DAEMON_START msg=audit(1644796660.200:666): op=start ver=3.0.7
format=enriched kernel=4.9.0-8-amd64 auid=4294967295 pid=1666000 =0 ses=4294967295
subj=unconfined res=success AUID="unset" UID="root"
[...]
type=SERVICE_START msg=audit(1644796660.216:669): pid=1 uid=0 auid=4294967295
ses=4294967295 subj==unconfined msg='unit=auditd comm="systemd"
exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
UID="root" AUID="unset"
显然,服务已经启动。此外,从type=DAEMON_START行,我们可以看到它的PID 为 1666000。 此外,我们可以从msg部分(1644796660.200 )中提取时间戳,这也是其他事件的一部分。在它之后,用冒号分隔的是事件标识号(666和669)。 现在,我们可以手动浏览日志或使用提供的ausearch 进行过滤搜索:
## $ ausearch --event 666
time->Tue Feb 15 20:11:06 2022
type=DAEMON_START msg=audit(1644948666.200:666): op=start ver=3.0.7
format=enriched kernel=4.9.0-8-amd64 auid=4294967295 pid=1666000 uid=0
ses=4294967295 subj=unconfined res=success AUID="unset" UID="root"
值得注意的是,ausearch的一大优势是–interpret ( -i ) 标志,它对消息中的数据进行解码,因为它们的一部分是十六进制编码的**:
## $ ausearch --event 666 --interpret
time->Tue Feb 15 20:11:06 2022
type=DAEMON_START msg=audit(02/15/2022 20:11:06.200:666): op=start ver=3.0.7
format=enriched kernel=4.9.0-8-amd64 auid=unset pid=1666000 uid=0 ses=unset
subj=unconfined res=success
比较输出,我们看到记录中auid参数的值从一串十六进制数字转换为unset。此外,日期戳被转换为人类可读的格式。 在上面的两个示例中,我们直接使用了事件编号,但也有许多其他条件,例如:
- -m ( –message ) 按消息类型查询
- -c ( –comm ) 按命令名查询
- -ui ( -uid ) 按用户 ID 查询 此外,我们可以将输出格式化为raw、default、interpret、csv和text。这可以通过*–format*标志实现。
5. 使用auditd生成事件和检查记录
最后,我们可以通过一些简单的示例来查看auditd的运行情况。让我们先探索阅读和写作,然后再进行删除。
5.1.读写
首先,让我们写入*/file*:
$ echo Input. > /file
接下来,我们使用*–file*标志检查日志中的任何操作:
$ ausearch --file /file
<no matches>
在这里,我们看不到匹配项,因为根据我们的规则,我们只审核读取事件。考虑到这一点,让我们通过cat 执行一个简单的读取 :
$ cat /file
Input.
## $ ausearch --file /file --interpret
type=PROCTITLE msg=audit(02/15/2022 20:12:22.240:11666) : proctitle=cat /file
type=PATH msg=audit(02/15/2022 20:12:22.240:11666) : item=0 name=/file inode=22
dev=08:11 mode=file,644 ouid=root ogid=root rdev=00:00 nametype=NORMAL
cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(02/15/2022 20:12:22.240:11666) : cwd=/
type=SYSCALL msg=audit(02/15/2022 20:12:22.240:11666) : arch=x86_64
syscall=openat success=yes exit=3 a0=AT_FDCWD a1=0x7fffd21697d9 a2=O_RDONLY
a3=0x0 items=1 ppid=1732318 pid=1733641 auid=user1 uid=user1 gid=user1
euid=user1 suid=user1 fsuid=user1 egid=user1 sgid=user1 fsgid=user1
tty=pts1 ses=3873 comm=cat exe=/usr/bin/cat subj==unconfined key=root_file
所有这些行也称为记录,是同一事件11666的一部分。在该事件的type=PATH行中,我们可以看到有关文件本身的详细信息,例如inode编号、设备、模式等。 此外,以type=SYSCALL开头的行是我们的主要兴趣,也由规则的key=root_file 值标识。事实上,它包含完整的用户名 ( uid=user1 )。当不解释结果时,用户会按他们的数字记录。在这种情况下,我们可以通过id 获取用户名:
$ id -nu 1000
user1
type=SYSCALL记录还为我们提供了用于访问文件的命令( comm=cat、exe=/usr/bin/cat )。
5.2. 删除
回到前面的文件删除示例,我们可以检测谁从*/blogdemo*的子目录中删除了文件。首先,让我们创建一个其中包含单个文件的文件:
$ mkdir --parents /blogdemo/x/
$ echo Input. > /blogdemo/x/file.ext
接下来,我们检查日志:
$ ausearch --file /blogdemo --interpret
type=PROCTITLE msg=audit(02/15/2022 20:30:40.504:12666) : proctitle=mkdir --parents /blogdemo/x/
type=PATH msg=audit(02/15/2022 20:30:40.504:12666) : item=4 name=(null) inode=1966583
dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=CREATE cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(02/15/2022 20:30:40.504:12666) : item=3 name=(null) inode=1966582
dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=PARENT cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(02/15/2022 20:30:40.504:12666) : item=2 name=(null) nametype=CREATE
cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(02/15/2022 20:30:40.504:12666) : item=1 name=(null) inode=1966582
dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=PARENT cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(02/15/2022 20:30:40.504:12666) : item=0 name=/blogdemo inode=1966582
dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=PARENT cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(02/15/2022 20:30:40.504:12666) : cwd=/blogdemo
type=SYSCALL msg=audit(02/15/2022 20:30:40.504:12666) : arch=x86_64 syscall=mkdir
success=yes exit=0 a0=0x7ffcf6eb17d8 a1=0777 a2=0x0 a3=0xfffffffffffffb8d items=5
ppid=1732318 pid=1734036 auid=noot uid=root gid=root euid=root suid=root fsuid=root
egid=root sgid=root fsgid=root tty=pts1 ses=3873 comm=mkdir exe=/usr/bin/mkdir
subj==unconfined key=toplevel_blogdemo
[...]
目录*/blogdemo/x* 和文件*/blogdemo/x/file.ext*以及负责用户 ( root )的创建和填充都有事件。现在,让我们更改整个目录的权限 以允许任何用户删除文件:
$ ls -la /blogdemo
total 12
drwxr-xr-x 3 root root 4096 Feb 18 00:06 .
drwxr-xr-x 29 root root 4096 Feb 18 00:01 ..
drwxr-xr-x 2 root root 4096 Feb 15 00:06 x
$ chmod --recursive 777 /blogdemo
$ ls -la /blogdemo/.
total 12
drwxrwxrwx 3 root root 4096 Feb 15 00:06 .
drwxr-xr-x 29 root root 4096 Feb 15 00:01 ..
drwxrwxrwx 2 root root 4096 Feb 15 00:06 x
甚至这些更改也有相关的记录,我们可以通过*–comm*标志看到:
## $ ausearch --file /blogdemo --comm chmod --interpret
type=PROCTITLE msg=audit(02/15/2022 20:56:56.248:12696) : proctitle=chmod --recursive 777 /blogdemo
type=PATH msg=audit(02/15/2022 20:56:56.248:12696) : item=0 name=/blogdemo inode=1966582
dev=08:11 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=NORMAL cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(02/15/2022 20:56:56.248:12696) : cwd=/
type=SYSCALL msg=audit(02/15/2022 20:56:56.248:12696) : arch=x86_64 syscall=fchmodat
success=yes exit=0 a0=AT_FDCWD a1=0x55b15f13e500 a2=0777 a3=0xfffffffffffffd2c
items=1 ppid=1732318 pid=1734049 auid=noot uid=root gid=root euid=root suid=root
fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=3873 comm=chmod exe=/usr/bin/chmod
## subj==unconfined key=toplevel_blogdemo
type=PROCTITLE msg=audit(02/15/2022 20:56:56.248:12697) : proctitle=chmod --recursive 777 /blogdemo
type=PATH msg=audit(02/15/2022 20:56:56.248:12697) : item=0 name=/blogdemo inode=1966582
dev=08:11 mode=dir,777 ouid=root ogid=root rdev=00:00 nametype=NORMAL cap_fp=none
cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(02/15/2022 20:56:56.248:12697) : cwd=/
type=SYSCALL msg=audit(02/15/2022 20:56:56.248:12697) : arch=x86_64 syscall=openat
success=yes exit=3 a0=AT_FDCWD a1=0x55b15f13e500
a2=O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC a3=0x0 items=1 ppid=1732318
pid=1734049 auid=noot uid=root gid=root euid=root suid=root fsuid=root egid=root
sgid=root fsgid=root tty=pts1 ses=3873 comm=chmod exe=/usr/bin/chmod subj==unconfined
key=toplevel_blogdemo
最后,让我们删除file.ext作为user1:
$ whoami
user1
$ rm --force /blogdemo/x/file.ext
事件记录包含我们需要的所有数据:
## $ ausearch --file /blogdemo/x/file.ext --comm rm --interpret
type=PROCTITLE msg=audit(02/15/2022 23:59:59.159:16660) : proctitle=rm --force /blogdemo/x/file.ext
type=PATH msg=audit(02/15/2022 23:59:59.159:16660) : item=1 name=/blogdemo/x/file.ext
inode=1966584 dev=08:11 mode=file,777 ouid=user1 ogid=user1 rdev=00:00 nametype=DELETE
cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(02/15/2022 23:59:59.159:16660) : item=0 name=/blogdemo/x/
inode=1966583 dev=08:11 mode=dir,777 ouid=user1 ogid=user1 rdev=00:00
nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(02/15/2022 23:59:59.159:16660) : cwd=/
type=SYSCALL msg=audit(02/15/2022 23:59:59.159:16660) : arch=x86_64 syscall=unlinkat
success=yes exit=0 a0=AT_FDCWD a1=0x56227e23e4d0 a2=0x0 a3=0xfffffffffffffbca items=2
ppid=1732318 pid=1734073 auid=noot uid=user1 gid=user1 euid=user1 suid=user1 fsuid=user1
egid=user1 sgid=user1 fsgid=user1 tty=pts1 ses=3873 comm=rm exe=/usr/bin/rm
subj==unconfined key=toplevel_blogdemo
请注意,由于我们更改了其内容,因此审核条目也包含目录的数据。
现在,我们已经证明了导致删除给定目录中任何数据的所有事件。让我们无可争辩。
6. 安全与整合
保护任何类型的日志都很重要,但审计信息本质上是敏感的。因此,让我们确保只有root可以访问审计日志:
$ ls -la /var/log/audit/audit.log
-rw-r----- 1 root root 66600 May 16 12:15 /var/log/audit/audit.log
重要的是,当存储来自多个节点的信息时,这可能变得更加关键。由于auditd包使我们能够将服务器配置为来自其他机器的事件的整合节点,因此可以出现这种情况。