威胁狩猎实战是安全运营从被动告警走向主动检测的关键能力。告警只能覆盖已知规则命中的场景,而攻击者使用系统自带工具、异常时间窗、低频凭据尝试时往往不触发任何规则。本文给出一套可落地的威胁狩猎流程:从数据源准备、假设设计、查询编写到用 Atomic Red Team 验证,并把有效假设固化为长期检测规则,附可直接执行的 auditd、ausearch、Sigma 与 Wazuh 配置。
适用场景
- 已部署日志集中或 EDR,但每天只处理告警、缺少主动排查环节的安全团队。
- 等保、关键信息基础设施保护要求提供”主动检测能力”证据的场景。
- 出现业务系统异常但现有规则全部静默(无告警无日志异常)时,需要人工挖掘线索。
- 重大漏洞预警发布后,需要在内部确认是否存在利用痕迹,而不是等 WAF 拦截记录。
需要区分三个概念:告警是规则命中后的被动通知,应急响应是已确认事件后的处置,威胁狩猎则是假设攻击者可能已经得手、主动去数据中寻找证据的过程。狩猎的产出不只是”有没有发现”,更重要的是把验证有效的假设固化成新的检测规则。
前置条件
- 日志集中:Linux 主机已通过 rsyslog 或 journald 外发日志,关键主机部署 auditd;Windows 主机部署 Sysmon 并采集到集中平台。
- 统一时间:所有主机启用 chrony 或 systemd-timesyncd,时钟偏差控制在 1 秒内,否则时间线无法拼接。
- 资产清单:知道每台主机的角色、责任人、对外端口,否则无法判断行为是否异常。
- 最小查询能力:不要求 SIEM,单机具备
ausearch、journalctl、grep即可构成最小闭环。 - 狩猎工具:建议安装 Atomic Red Team 或 atomic-operator 用于验证假设,
atomic-operator或 PowerShell 版Invoke-AtomicTest均可。
原理说明
威胁狩猎遵循一个闭环流程,通常称为狩猎循环:
- 提出假设:基于攻击者战术(ATT&CK)推断”若攻击者用某种技术,会在数据里留下什么痕迹”。例如假设:攻击者用
curl或wget从临时目录下载载荷。 - 确定数据源:明确该假设需要哪类日志。进程执行看 execve 审计或 Sysmon Event ID 1,网络连接看
ss/netflow 或 Sysmon Event ID 3,凭据尝试看 sshd 日志。 - 编写并执行查询:把假设翻译成可执行查询,先用宽条件捞全,再按父进程、路径、时间窗收窄。
- 验证假设有效性:用 Atomic Red Team 在测试机复现该技术,确认查询确实能抓到;抓不到说明数据源或查询设计有问题。
- 沉淀为检测规则:把有效查询写成 Sigma 规则、Wazuh 规则或 Suricata 规则,纳入常规告警,并做误报回归测试。
与应急响应最大的区别在于:狩猎的数据量通常是”安静的”,需要靠特征组合(父进程关系、路径、时间分布)而非单一黑名单触达结果。因此数据源的完整性和保留周期直接决定狩猎的上限。
操作步骤
步骤一:补齐高价值审计数据源
# /etc/audit/rules.d/hunt.rules
# 记录高危工具执行
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/curl -k hunt_tool
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/wget -k hunt_tool
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/nc -k hunt_tool
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/socat -k hunt_tool
# 记录临时目录可执行行为
-a always,exit -F arch=b64 -S execve -F path=/tmp -F perm=x -k hunt_tmp_exec
-a always,exit -F arch=b64 -S execve -F path=/var/tmp -F perm=x -k hunt_tmp_exec
# 记录权限提升相关行为
-a always,exit -F arch=b64 -S setuid -S setgid -k hunt_priv
-a always,exit -F arch=b64 -S init_module -S finit_module -k hunt_rootkit
# 记录敏感文件读取
-w /etc/shadow -p r -k hunt_cred
-w /root/.ssh/authorized_keys -p wa -k hunt_persist
# 加载并确认规则生效
augenrules --load
auditctl -l | grep -c hunt_
auditd 自身也应加固:日志外发到集中平台,本地开启防篡改,避免攻击者删除痕迹。同时确认日志保留满足狩猎需要,关键主机建议保留 90 天以上。
步骤二:设计狩猎假设
| 假设 | 对应 ATT&CK | 数据源 |
| 攻击者用命令行工具下载载荷到临时目录 | T1105 / T1059 | execve 审计、Sysmon 1 |
| Web 服务进程派生了 shell 或解释器 | T1059 / T1505.003 | 进程父子关系 |
| SSH 凭据尝试呈分布式低频特征 | T1110 | sshd 日志 |
| 计划任务被新增用于持久化 | T1053.003 | cron 文件审计、auditd |
| 凭据文件被异常读取 | T1003.008 | 文件访问审计 |
选择假设的原则是”高价值 + 可验证”。一次狩猎聚焦 3 到 5 条假设,5 天内不产生结论就应及时调整,不要在同一假设上无限投入。
步骤三:编写并执行查询
以第一条假设为例,先用 auditd 检索工具执行记录:
# 检索今天的工具执行,输出可读时间与命令行
ausearch -k hunt_tool -i --start today | aureport -f -i
# 聚合统计:哪个用户、哪个进程频繁调用这些工具
ausearch -k hunt_tool -i --start today \
| grep -E '^type=EXECVE|^type=SYSCALL' \
| awk '{print $0}' | sort | uniq -c | sort -rn | head -20
再用临时目录执行记录,重点找”Web 服务用户派生可执行文件”这类组合特征:
# 查出 /tmp 下被执行过的程序
ausearch -k hunt_tmp_exec -i --start today
# 结合 syslog 中的 nginx 用户行为
journalctl -u nginx --since "24 hours ago" | grep -iE "cannot execute|permission"
在集中日志平台上,用进程父子关系收窄误报:正常运维不会让 nginx 直接派生 shell。以 KQL 为例:
process.parent.name: ("nginx" or "php-fpm" or "apache2")
and process.name: ("sh" or "bash" or "curl" or "wget" or "nc")
用 Sigma 形式表达同一检测逻辑,便于跨平台转换:
title: Web Server Spawning Download Utility
status: experimental
logsource:
category: process_creation
product: linux
detection:
parent:
ParentImage|endswith:
- '/nginx'
- '/php-fpm'
- '/apache2'
child:
Image|endswith:
- '/curl'
- '/wget'
- '/nc'
condition: parent and child
level: high
tags:
- attack.execution
- attack.t1059
步骤四:用 Atomic Red Team 验证检测有效性
假设写完必须验证,否则无法区分”没有攻击”和”查询写错”。在测试机上执行对应原子测试:
# 查看某个技术的可用测试
atomic-operator run -t T1059.004 --show-details
# 执行单条测试并保留痕迹供检索
atomic-operator run -t T1059.004
# Windows 环境使用 PowerShell 版
# Invoke-AtomicTest T1105 -TestNumbers 1
# Invoke-AtomicTest T1053.003 -TestNumbers 2
执行后立即用步骤三的查询检索,确认能命中。若命中失败,依次检查:审计规则是否覆盖该路径、日志是否已外发、时间是否对齐、查询字段名是否与平台一致。
步骤五:固化为长期检测规则
假设验证有效后,应立即落成规则,避免下次再从零开始。以 Wazuh 规则为例:
<group name="threat_hunting,">
<rule id="100210" level="10">
<if_sid>80700</if_sid>
<field name="audit.key">hunt_tmp_exec</field>
<description>Temporary directory executable launched from \/tmp</description>
<mitre>
<id>T1059</id>
</mitre>
</rule>
</group>
# 校验规则语法(不同发行版路径略有差异)
/var/ossec/bin/wazuh-logtest
systemctl restart wazuh-manager
规则上线后要做误报回归:把业务系统正常行为(如监控脚本调用 curl、发布脚本调用 wget)加入白名单,白名单条目必须写明业务方与到期复核时间,避免长期累积成盲区。
配置验证
| 检查项 | 验证命令 | 期望结果 |
| 审计规则已加载 | auditctl -l \| grep -c hunt_ |
数量与配置一致,非 0 |
| 审计日志可检索 | ausearch -k hunt_tool -i --start today |
有结构化记录,字段完整 |
| 时间已对齐 | chronyc tracking |
System time 偏差小于 0.1 秒 |
| 日志已外发 | journalctl --since "10 min ago" \| grep -c audit |
集中平台可看到同批记录 |
| 检测规则生效 | Atomic 测试后重跑查询 | 查询命中且产生告警 |
| 规则语法正确 | wazuh-logtest |
无语法错误,能正确匹配 |
建议把”狩猎结论”写成固定模板存档:假设描述、查询语句、执行时间范围、数据源、命中数量、误报分析、是否固化为规则。这样下一次狩猎可以直接复用,也让检测能力可度量。
常见问题
FAQ 1:没有 SIEM 和 EDR,只有单机日志,能做威胁狩猎吗?
可以,最小闭环只需要 auditd 加 journalctl。落地建议:
# 单机最小狩猎组合
auditctl -l | grep hunt_ # 确认数据源
ausearch -k hunt_tool -i --start today # 进程执行
ausearch -k hunt_tmp_exec -i --start today # 临时目录执行
journalctl _COMM=sshd --since "24 hours ago" \
| grep -E "Accepted|Failed" | awk '{print $1,$2,$3,$11}' | sort | uniq -c
先只覆盖 3 到 5 条高价值假设,例如”Web 进程派生 shell””临时目录执行””SSH 凭据分布式尝试””authorized_keys 被写入””新增计划任务”。这些假设用单机日志就能验证,且命中后价值很高。等覆盖率稳定后再考虑上集中平台。
FAQ 2:狩猎结果误报太多,每天几百条,如何收敛?
误报高的根因通常是查询只用了单特征(只看命令名),没有用组合特征。收敛方法按优先级排列:
- 加父进程约束:curl 被监控脚本调用是正常的,被 nginx 调用才是异常。父进程是性价比最高的收窄维度。
- 加路径与用户约束:区分
/tmp与业务发布目录,区分服务账户与运维账户。 - 建立基线白名单:对确认安全的调用方登记白名单,白名单必须带责任人与复核时间。
- 调整阈值与时间窗:低频分布式行为要靠单位时间内的尝试次数而非单条日志识别。
FAQ 3:日志要保留多久才够支撑狩猎?
保留周期取决于狩猎的起点时间。基准建议:
- 关键主机与对外服务主机:90 至 180 天,至少覆盖一个季度。
- 一般办公主机:30 至 90 天。
- 网络设备与边界日志:不少于 90 天,便于回溯外联行为。
同时必须做两件事:本地日志外发到集中平台(单机日志易被攻击者清除),并与宿主机、容器、应用日志的时间线对齐。保留周期不足会让”攻击者三个月前留下的持久化”永远查不到。
总结
威胁狩猎实战的价值不在于某次是否抓到攻击者,而在于把安全运营从”等告警”变成”主动验证假设”。落地路径为:先用 auditd 与 Sysmon 补齐进程、凭据、持久化三类高价值数据源,再按 ATT&CK 设计 3 到 5 条可验证假设,用单特征捞全、用父进程与其他组合特征收窄,接着用 Atomic Red Team 复现验证查询有效性,最后把有效逻辑固化为 Sigma、Wazuh 或 Suricata 规则并做误报回归。把假设、查询、结论按模板存档,团队检测能力才会逐次累积,而不是每次重新摸索。