在Ubuntu服务器上做安全审计,最怕的就是信息滞后。系统被攻破后,攻击者往往会替换掉系统自带的ps、netstat、lsof等基础命令,让你看到的进程和网络连接都是假的。osquery解决的就是这个痛点。它由Facebook开源,能将操作系统状态抽象成SQL表,你不需要登录服务器去执行一堆shell命令,直接用SQL语句就能交互式查询进程、用户、内核模块、文件哈希等底层信息。更重要的是,它读取的是内核级数据源,绕过了可能被篡改的用户态工具。
安装前的环境确认osquery官方为Ubuntu提供了APT仓库,支持20.04 LTS、22.04 LTS以及最新的24.04 LTS。先确认你的系统版本,在终端执行:
lsb_release -a
输出中关注Release字段,确保是上述三个版本之一。如果你用的是18.04这种较老的LTS,官方仓库已停止支持,需要从源码编译,但这不在本文讨论范围。另外,osquery对内核版本没有硬性要求,但建议内核版本不低于5.4,因为部分审计功能依赖eBPF,老内核会降级为基于auditd的传统方式采集数据。
添加官方APT仓库并安装第一步,导入osquery官方GPG密钥。这个密钥用于验证软件包签名,防止中间人篡改:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B
如果apt-key命令在你的系统上已被弃用,可以直接用gpg来导入:
curl -fsSL https://pkg.osquery.io/pubkey | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/osquery.gpg
第二步,添加osquery的APT仓库源。这里要注意,官方提供了stable和nightly两个通道,生产环境务必使用stable:
echo "deb [arch=amd64] https://pkg.osquery.io/deb deb main" | sudo tee /etc/apt/sources.list.d/osquery.list
第三步,更新APT索引并安装:
sudo apt update sudo apt install osquery
安装完成后,osquery会作为一个系统服务自动启动,默认配置路径在/etc/osquery/osquery.conf。你可以用systemctl查看状态:
sudo systemctl status osqueryd
如果显示active (running),说明守护进程已经跑起来了。但此时它只是一个空壳,还没有加载任何查询计划,我们需要先学会交互式使用。
交互式Shell:osqueryiosqueryi是osquery的交互式控制台,相当于一个直连操作系统的SQL客户端。直接在终端输入:
osqueryi
你会进入一个类似MySQL客户端的界面,提示符为osquery>。现在就可以执行SQL了。比如查看当前所有正在运行的进程:
SELECT pid, name, path, cmdline FROM processes WHERE name NOT LIKE '%osquery%';
这条语句返回的进程列表,直接读取自/proc文件系统,但osquery在内部做了结构化处理,你拿到的数据不会被用户态rootkit污染。再比如,查看所有监听的网络端口:
SELECT pid, port, protocol, address FROM listening_ports;
你会发现,原本需要用ss -tlnp或者netstat -anp才能拿到的信息,现在一条SQL就搞定了,而且输出格式是规整的表格,可以直接导出为JSON或CSV用于后续分析。osqueryi支持.mode切换输出格式:
.mode json SELECT * FROM users WHERE uid > 0;
这条查询列出所有非root用户,输出为JSON数组,非常适合对接SIEM或日志分析平台。
核心表解读:哪些表值得重点关注osquery内置了超过200张表,但日常安全巡检中,真正高频使用的就那么十几张。我按类别梳理一下:
进程与启动项类:processes表是基础,但更关键的是process_open_sockets和process_memory_map。前者把进程和网络连接做了关联,后者能发现被注入内存的可疑映射区域。还有startup_items表,它列出了系统启动时自动运行的程序,很多持久化后门会藏在这里。
用户与认证类:users表列出本地用户,last表则记录了登录历史。重点看last表中是否有来自异常IP的ssh登录记录,以及users表中uid为0的非root账号。
文件完整性类:file表可以查询指定路径的文件属性,但更强大的是hash表,它能实时计算文件的SHA256:
SELECT path, sha256 FROM hash WHERE path LIKE '/etc/passwd';
如果这个哈希值与你基线库中的不一致,说明文件被篡改过。
内核与驱动类:kernel_modules表列出所有已加载的内核模块,rootkit经常以内核模块形式注入。如果你看到可疑模块,可以用kernel_info表进一步查看内核版本和启动参数,判断是否存在已知漏洞。
网络连接类:除了listening_ports,process_open_sockets表把进程和socket一一对应,这在追踪反弹shell时特别有用。还有arp_cache表,可以查看ARP缓存,发现中间人攻击的痕迹。
生产环境配置:从交互查询到持续监控osqueryi适合临时排查,但安全监控需要7x24小时运行。这就需要配置osqueryd守护进程。核心配置文件是/etc/osquery/osquery.conf,它用JSON格式定义了三大部分:options、schedule、packs。
options部分设置守护进程的行为,常用参数有:
{
"options": {
"config_plugin": "filesystem",
"logger_plugin": "filesystem",
"logger_path": "/var/log/osquery",
"disable_logging": "false",
"schedule_splay_percent": "10",
"host_identifier": "hostname",
"enable_syslog": "true"
}
}
schedule_splay_percent设为10,意思是所有定时查询的执行时间会随机错开10%的区间,避免大量端点同时查询造成性能峰值。host_identifier建议用hostname,这样日志里能区分是哪台机器上报的数据。
schedule部分是核心,定义定时执行的SQL查询。下面是一个生产级的配置示例,每300秒检查一次异常进程,每3600秒做一次文件完整性校验:
"schedule": {
"anomalous_processes": {
"query": "SELECT pid, name, path, cmdline FROM processes WHERE path LIKE '/tmp/%' OR path LIKE '/dev/shm/%';",
"interval": 300
},
"file_integrity_check": {
"query": "SELECT path, mtime, sha256 FROM hash WHERE path IN ('/etc/passwd', '/etc/shadow', '/etc/ssh/sshd_config');",
"interval": 3600
}
}
这条规则专门抓那些从/tmp或/dev/shm目录启动的进程,这两个目录是攻击者落地恶意文件的常见位置。文件完整性检查则覆盖了几个关键系统配置文件。
packs是osquery的模块化配置单元,可以理解为预置的查询包。官方维护了一套packs仓库,直接引用即可启用。比如要监控硬件变更和系统信息:
"packs": {
"hardware-monitoring": "/usr/share/osquery/packs/hardware-monitoring.conf",
"osquery-monitoring": "/usr/share/osquery/packs/osquery-monitoring.conf",
"incident-response": "/usr/share/osquery/packs/incident-response.conf"
}
这些packs已经定义好了查询逻辑,开箱即用。incident-response这个pack尤其重要,它包含了取证分析时常用的查询集合,比如列出所有suid文件、所有crontab任务、所有加载的内核模块等。
日志输出与对接分析平台osqueryd默认把日志以JSON格式写入/var/log/osquery/目录。osqueryd.results.log存放查询结果,osqueryd.snapshots.log存放快照数据。如果你用的是ELK或Splunk这类平台,可以直接采集这些JSON日志做索引和告警。
更进阶的用法是启用TLS logger插件,把查询结果实时推送到远程服务器。这需要部署一个osquery TLS服务器端,比如Fleet或Kolide。配置方式是在options中指定:
"options": {
"logger_plugin": "tls",
"logger_tls_endpoint": "/api/v1/osquery/log",
"enroll_tls_endpoint": "/api/v1/osquery/enroll"
}
这样每个端点首次启动时会向服务器注册,之后定时上报查询结果。对于管理几十台甚至上千台Ubuntu服务器的团队来说,这是必须走的一步,否则单机日志根本看不过来。
实战:用osquery做一次快速入侵排查假设你怀疑某台Ubuntu服务器被入侵,手头没有商业EDR工具,osquery就是你的瑞士军刀。按以下步骤逐层排查:
第一层,看异常进程。执行:
SELECT pid, name, path, cmdline, uid FROM processes WHERE path NOT LIKE '/usr/%' AND path NOT LIKE '/snap/%' AND path NOT LIKE '/opt/%';
这条语句过滤掉正常路径下的进程,剩下的就是可疑对象。重点关注uid为0的进程,以及cmdline中包含base64、eval、wget、curl等关键字的进程。
第二层,看网络连接。执行:
SELECT p.name, p.pid, po.remote_address, po.remote_port, po.state FROM process_open_sockets po JOIN processes p ON po.pid = p.pid WHERE po.remote_port NOT IN (80, 443, 53) AND po.state = 'ESTABLISHED';
这条关联查询找出所有非标准端口的已建立连接,反弹shell通常会用4444、8888、1337这类端口。
第三层,看持久化机制。执行:
SELECT * FROM crontab; SELECT * FROM startup_items; SELECT * FROM kernel_modules WHERE name NOT LIKE 'nvidia%' AND name NOT LIKE 'vmw%';
攻击者经常通过crontab、systemd service、内核模块实现持久化。这三条查询覆盖了主要的持久化路径。
第四层,看文件时间线。执行:
SELECT path, mtime, ctime, atime FROM file WHERE directory = '/tmp' AND mtime > (SELECT local_time FROM time) - 86400;
这条语句列出/tmp目录下最近24小时内修改过的文件,结合进程信息可以快速定位恶意文件。
整个排查过程不超过五分钟,而且每一步都有据可查,导出的JSON日志就是现成的取证报告。这就是osquery相比传统命令行排查的核心优势:可重复、可审计、可自动化。
性能影响与调优建议有人担心osqueryd常驻内存会拖慢服务器性能。实测在2核4G的云服务器上,osqueryd内存占用通常在80MB到150MB之间,CPU占用低于1%。真正影响性能的是定时查询的复杂度和频率。几条优化原则:
避免全表扫描。processes表有几百行数据,不加WHERE条件直接SELECT * 没问题,但file表如果对根目录做递归查询,会触发大量磁盘IO。务必用WHERE限制路径范围。
合理设置interval。文件完整性检查这种高开销查询,间隔至少3600秒。进程枚举可以设300秒。不要把所有查询都设成每分钟一次。
善用差分查询。osquery支持decorators,可以在查询结果中附加主机信息,减少重复查询。比如把hostname、uptime、os_version做成decorator,其他查询就不用再关联这些表了。
最后,如果你管理的是Ubuntu桌面版而非服务器版,osquery同样适用。桌面环境下的浏览器插件、用户登录事件、USB设备插拔记录,都有对应的表可以查询,这在DLP和终端合规场景中非常实用。
