osquery多级通配符使用问题:监控/etc下.conf文件误触发
环境确认
先贴出你验证环境版本的命令和输出:
$ osqueryi --line "SELECT version, build, platform FROM os_version;" version = 16.04.3 LTS (Xenial Xerus) build = platform = ubuntu $ osqueryi --line "SELECT version from osquery_info;" version = 4.1.1
问题回顾
你尝试用/etc/%%/%.conf作为通配符规则,递归监控/etc目录下所有.conf后缀的文件,但创建/etc/foo这类非目标文件时,却触发了CREATED、ATTRIBUTES_MODIFIED、UPDATED等file_events事件。以下是你的复现配置和触发的事件日志:
复现配置
{ "schedule": { "file_events": { "query": "SELECT * FROM file_events", "interval": "5", "removed": "false" } }, "file_paths": { "sys": ["/etc/%%/%.conf"] } }
触发的事件日志
{"name":"file_events","hostIdentifier":"<hostname>","calendarTime":"Mon Dec 30 13:56:03 2019 UTC","unixTime":1577714163,"epoch":0,"counter":0,"numerics":false,"columns":{"action":"CREATED","atime":"1577714161","category":"sys","ctime":"1577714161","gid":"0","inode":"389945","mode":"0644","mtime":"1577714161","size":"0","target_path":"/etc/foo","time":"1577714161","uid":"0"},"action":"added"} {"name":"file_events","hostIdentifier":"<hostname>","calendarTime":"Mon Dec 30 13:56:03 2019 UTC","unixTime":1577714163,"epoch":0,"counter":0,"numerics":false,"columns":{"action":"ATTRIBUTES_MODIFIED","atime":"1577714161","category":"sys","ctime":"1577714161","gid":"0","inode":"389945","mode":"0644","mtime":"1577714161","size":"0","target_path":"/etc/foo","time":"1577714161","uid":"0"},"action":"added"} {"name":"file_events","hostIdentifier":"<hostname>","calendarTime":"Mon Dec 30 13:56:03 2019 UTC","unixTime":1577714163,"epoch":0,"counter":0,"numerics":false,"columns":{"action":"UPDATED","atime":"1577714161","category":"sys","ctime":"1577714161","gid":"0","inode":"389945","mode":"0644","mtime":"1577714161","size":"0","target_path":"/etc/foo","time":"1577714161","uid":"0"},"action":"added"}
针对你的疑问逐一解答
1. /etc/%%/%.conf是否为有效可用的通配符?
这个规则不完全有效:
- 从osquery的通配符语法来说,
%%确实用于匹配任意深度的子目录,%用于匹配单个路径段(比如文件名),但/etc/%%/%.conf的写法要求目标文件必须位于/etc下的至少一级子目录中,完全漏掉了/etc根目录下直接存在的.conf文件(比如/etc/resolv.conf)。 - 更关键的是,在你使用的osquery v4.1.1版本中,这个规则还会导致监控范围被扩大到整个
/etc目录,后续的过滤逻辑失效,这是版本特定的问题。
2. 如何实现递归监控/etc目录下所有.conf文件的需求?
要覆盖/etc根目录和所有子目录下的.conf文件,需要在file_paths中添加两条规则,组合起来实现完整覆盖:
{ "schedule": { "file_events": { "query": "SELECT * FROM file_events", "interval": "5", "removed": "false" } }, "file_paths": { "sys": [ "/etc/%.conf", // 匹配/etc根目录下的.conf文件 "/etc/%%/%.conf" // 匹配/etc所有子目录下的.conf文件 ] } }
考虑到你使用的是v4.1.1版本,这种分规则的写法是最稳妥的;如果是更新的osquery版本(比如v4.5+),也可以尝试更简洁的/etc/%%%.conf,但旧版本对这个写法的支持可能不稳定。
3. 为何未按通配符过滤事件?
在osquery v4.1.1中,当路径规则包含%%时,监控逻辑会先把整个父目录(这里就是/etc)加入监控列表,然后在事件上报阶段再根据通配符规则过滤符合条件的事件。但这个版本的过滤逻辑存在缺陷,导致非匹配路径的事件(比如/etc/foo)也被错误地上报了。
关于osquery通配符转换逻辑的补充
你提到的filesystem.cpp#replaceGlobWildcards()函数,核心作用是把osquery特有的通配符转换为fnmatch兼容的匹配表达式:
- 单个
%会被替换为[^/]*,也就是匹配不包含路径分隔符/的单个路径段(等价于shell中的*但限制在当前目录) %%会被替换为.*,也就是匹配任意字符(包括/),实现跨目录的递归匹配(等价于shell中的**)
osquery的SQL模式和fnmatch的转换逻辑是对齐的:SQL中的LIKE操作符用%作为通配符,而file_paths中的通配符规则在此基础上扩展了%%用于递归目录匹配,本质上都是通过上述函数转换为底层可执行的匹配规则。
内容的提问来源于stack exchange,提问作者prateeknischal

