如何使用Osquery在Linux上监控文件完整性?
本教程介绍如何安装该应用程序、如何运行基本查询以及如何在Linux系统管理工作中使用FIM(文件完整性监控)。
本教程将介绍:
- 如何安装Osquery
- 如何列出可用表
- 如何从osqueryi外壳执行查询
- 如何使用osqueryd守护程序监控文件完整性
软件需求和使用的约定
- 对SQL概念有基本知识
- 拥有执行管理任务的root权限
软件需求和Linux命令行约定
安装
我们基本上有两种方法来安装Osquery:第一种是从官方网站下载适合我们系统的软件包;第二种(通常是优选方法)是将Osquery存储库添加到发行版软件源。下面简要介绍这两种方法。
图1
通过软件包安装
可以从Osquery官方网站(https://osquery.io/downloads/official)下载签名的deb和rpm软件包,或下载更通用的打包文件。我们先选择要安装的版本,然后下载软件包。
建议选择最新的可用版本(截至发稿时4.1.2)。下载软件包后,我们可以使用发行版软件包管理器来安装。比如想在Fedora系统上安装该软件(假设软件包在当前的工作目录中),我们将运行:
$ sudo dnf install ./osquery-4.1.2-1.linux.x86_64.rpm
使用存储库
我们还可以将rpm或deb存储库添加到发行版中。如果我们使用基于rpm的发行版,可以运行以下命令来完成任务:
$ curl -L https://pkg.osquery.io/rpm/GPG | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-osquery $ sudo yum-config-manager --add-repo https://pkg.osquery.io/rpm/osquery-s3-rpm.repo $ sudo yum-config-manager --enable osquery-s3-rpm-repo $ sudo yum install osquery
借助上述Linux命令,我们可以将用来签名软件包的gpg公钥添加到系统中,然后添加存储库。最后,我们安装Osquery软件包。注意,在近期版本的Fedora和CentOS/RHEL中,yum只是dnf的符号链接,所以我们调用前者时,使用的却是后者。
如果你运行基于Debian的发行版,可以将deb存储库添加到软件源中,只要运行:
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B $ sudo add-apt-repository 'deb [arch=amd64] https://pkg.osquery.io/deb deb main' $ sudo apt-get update $ sudo apt-get install osquery
一旦软件包安装完毕,我们可以看一下软件的基本用法。
基本用法
Osquery让我们可以监控采用“表格抽象”的操作系统的不同方面,使用类似sqlite数据库上所用语法的SQL语法。针对表执行查询,表对操作系统的不同方面(比如进程和服务)进行抽象处理。
我们可以直接使用osqueryi交互式外壳来运行查询,也可以通过osqueryd守护程序来安排查询。下面这个例子显示了列出所有可用表的查询(还可以在此处https://osquery.io/schema/4.1.2#processes看到附有表描述的完整列表):
$ osqueryi osquery> .tables => acpi_tables => apt_sources => arp_cache => atom_packages => augeas => authorized_keys => block_devices => carbon_black_info => carves => chrome_extensions => cpu_time => cpuid => crontab => curl => curl_certificate => deb_packages => device_file => device_hash => device_partitions => disk_encryption => dns_resolvers => docker_container_labels => docker_container_mounts => docker_container_networks => docker_container_ports => docker_container_processes => docker_container_stats => docker_containers => docker_image_labels => docker_images => docker_info => docker_network_labels => docker_networks => docker_version => docker_volume_labels => docker_volumes => ec2_instance_metadata => ec2_instance_tags => elf_dynamic => elf_info => elf_sections => elf_segments => elf_symbols => etc_hosts => etc_protocols => etc_services => file => file_events => firefox_addons => groups => hardware_events => hash => intel_me_info => interface_addresses => interface_details => interface_ipv6 => iptables => kernel_info => kernel_integrity => kernel_modules => known_hosts => last => listening_ports => lldp_neighbors => load_average => logged_in_users => magic => md_devices => md_drives => md_personalities => memory_array_mapped_addresses => memory_arrays => memory_device_mapped_addresses => memory_devices => memory_error_info => memory_info => memory_map => mounts => msr => npm_packages => oem_strings => opera_extensions => os_version => osquery_events => osquery_extensions => osquery_flags => osquery_info => osquery_packs => osquery_registry => osquery_schedule => pci_devices => platform_info => portage_keywords => portage_packages => portage_use => process_envs => process_events => process_file_events => process_memory_map => process_namespaces => process_open_files => process_open_sockets => processes => prometheus_metrics => python_packages => routes => rpm_package_files => rpm_packages => selinux_events => shadow => shared_memory => shell_history => smart_drive_info => smbios_tables => socket_events => ssh_configs => sudoers => suid_bin => syslog_events => system_controls => system_info => time => ulimit_info => uptime => usb_devices => user_events => user_groups => user_ssh_keys => users => yara => yara_events => yum_sources
运行osqueryi命令,我们进入交互式外壳;我们可以从该外壳执行查询或指令。这是查询的另一个例子,这回列出所有运行中进程的pid和name。对process表执行查询(为便于阅读,查询的输出已截短):
osquery> SELECT pid, name FROM processes; +-------+------------------------------------+ | pid | name | +-------+------------------------------------+ | 1 | systemd | | 10 | rcu_sched | | 10333 | kworker/u16:5-events_unbound | | 10336 | kworker/2:0-events | | 11 | migration/0 | | 11002 | kworker/u16:1-kcryptd/253:0 | | 11165 | kworker/1:1-events | | 11200 | kworker/1:3-events | | 11227 | bash | | 11368 | osqueryi | | 11381 | kworker/0:0-events | | 11395 | Web Content | | 11437 | kworker/0:2-events | | 11461 | kworker/3:2-events_power_efficient | | 11508 | kworker/2:2 | | 11509 | kworker/0:1-events | | 11510 | kworker/u16:2-kcryptd/253:0 | | 11530 | bash | [...] | +-------+------------------------------------+
甚至可以使用JOIN语句对连接表执行查询,就像我们在关系数据库中操作那样。在下面例子中,我们对processes表执行查询,通过uid列与users表进行连接:
osquery> SELECT processes.pid, processes.name, users.username FROM processes JOIN users ON processes.uid = users.uid; +-------+-------------------------------+------------------+ | pid | name | username | +-------+-------------------------------+------------------+ | 1 | systemd | root | | 10 | rcu_sched | root | | 11 | migration/0 | root | | 11227 | bash | egdoc | | 11368 | osqueryi | egdoc | | 13 | cpuhp/0 | root | | 14 | cpuhp/1 | root | | 143 | kintegrityd | root | | 144 | kblockd | root | | 145 | blkcg_punt_bio | root | | 146 | tpm_dev_wq | root | | 147 | ata_sff | root | [...] | 9130 | Web Content | egdoc | | 9298 | Web Content | egdoc | | 9463 | gvfsd-metadata | egdoc | | 9497 | gvfsd-network | egdoc | | 9518 | gvfsd-dnssd | egdoc | +-------+-------------------------------+------------------+
文件完整性监控(FIM)
前面我们使用交互式外壳osqueryi来使用Osquery。想使用FIM(文件完整性监控),我们改用osqueryd守护程序。通过配置文件,我们列出了想要监控的文件。file_events 表中记录了涉及指定文件和目录的事件,比如属性变化。守护程序在指定的时间间隔后对该表运行查询,并在日志中通知何时发现新记录。不妨看看配置示例。
配置结构
Osquery的主配置文件是/etc/osquery/osquery.conf。该文件默认情况下不存在,于是我们要创建它。配置以JSON格式来提供。假设我们想要监控/etc下的所有文件和目录;下面显示了我们如何配置该应用程序:
{ "options": { "disable_events": "false" }, "schedule": { "file_events": { "query": "SELECT * FROM file_events;", "interval": 300 } }, "file_paths": { "etc": [ "/etc/%%" ], }, }
不妨分析上述配置。首先在options部分,我们将disable_events设为“false”,以便启用文件事件。
之后我们创建schedule部分:在该部分,我们可以描述和创建各种命名的调度查询。我们在本文中创建了一个查询,以便从file_events表选择所有列,这意味着每300秒(5分钟)执行一次。
安排查询后,我们创建了file_paths部分,在该部分指定要监控的文件。在该部分,每个键代表要监控一组文件的名称(Osquery术语中的类别)。这里“etc”键引用仅含有一个条目/etc/%%的列表。
%符号代表什么?指定文件路径时,我们可以使用标准通配符(*)或SQL通配符(%)。如果提供单通配符,它将选择位于指定级别的所有文件和目录。如果提供双通配符,它将递归选择所有文件和文件夹。比如说,/etc/%表达式匹配/etc下面一级的所有文件和文件夹,而/etc/%%递归匹配/etc下的所有文件和文件夹。
如果需要,我们还可以使用配置文件中的exclude_paths部分,从提供的路径中排除特定文件。在该部分,我们只能引用file_paths部分中定义的类别(本例中是“etc”)。我们提供了要排除的文件列表:
"exclude_paths": { "etc": [ "/etc/aliases" ] }
仅作为例子,我们从列表中排除了/etc/aliases文件。下面是最终配置的样子:
{ "options": { "disable_events": "false" }, "schedule": { "file_events": { "query": "SELECT * FROM file_events;", "interval": 20 } }, "file_paths": { "etc": [ "/etc/%%" ] }, "exclude_paths": { "etc": [ "/etc/aliases" ] } }
开启守护程序
配置已到位,我们可以开启osqueryd守护程序:
$ sudo systemctl start osqueryd
为了使守护程序在系统启动时自动开启,我们要运行:
$ sudo systemctl enable osqueyd
一旦守护程序运行,我们可以核实配置有效。仅举个例子,我们将修改/etc/fstab文件的许可权,将它们从644改为600:
$ sudo chmod 600 /etc/fstab
现在我们可以核实文件更改以记录下来,只需阅读/var/log/osquery/osqueryd.results.log文件。下面是该文件的最后一行:
{ "name":"file_events", "hostIdentifier":"fingolfin", "calendarTime":"Mon Dec 30 19:57:31 2019 UTC", "unixTime":1577735851, "epoch":0, "counter":0, "logNumericsAsNumbers":false, "columns": { "action":"ATTRIBUTES_MODIFIED", "atime":"1577735683", "category":"etc", "ctime":"1577735841", "gid":"0", "hashed":"0", "inode":"262147", "md5":"", "mode":"0600", "mtime":"1577371335", "sha1":"", "sha256":"", "size":"742", "target_path":"/etc/fstab", "time":"1577735841", "transaction_id":"0", "uid":"0" }, "action":"added" }
在上述日志中,我们可以清楚地看到在target_path "/etc/fstab"(第23行)上进行了ATTRIBUTES_MODIFIED操作(第10行),/etc/fstab是“etc”类别(第12行)的一部分。有必要注意这点:如果我们从osqueryi外壳查询file_events表,由于osqueryd守护程序和osqueryi无法联系,因此看不到任何行。
结论