关于 hunting-threats
面向安全团队的威胁狩猎技能,用于主动查找告警可能遗漏的活动。它以可验证的假设、遥测检查和结果记录组织狩猎,也重视记录未发现威胁的结论。
主要功能
- 01编写可验证的狩猎假设
- 02确认遥测并界定范围
- 03运用频次、异常值和聚类分析
- 04依据威胁报告狩猎攻击技术
- 05记录发现并将结果转为后续行动
适用场景
- 01查找告警未发现的入侵活动
- 02验证环境中的特定攻击者行为
- 03检查生产环境中的控制或检测覆盖
- 04建立基线以便后续分析异常
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trilwu/ secskills --skill hunting-threats安装后在 Claude Code 中输入/hunting-threats确认已加载。
详细介绍
威胁狩猎
狩猎始于一种失败假设:防护措施已部署,没有触发警报,但攻击者可能仍然潜伏。产出通常不是一次失陷,而是一个检测结果、一个遥测缺口或一项有记录的阴性结果。只有发现问题才算成功的狩猎,会逐渐陷入确认偏误。
适用场景
- 主动搜索检测措施遗漏的失陷迹象
- 验证关于攻击者在你环境中行为的具体假设
- 针对你的遥测数据,将威胁情报报告付诸实践
- 验证某项防护措施或检测规则在生产环境中是否确实有效
- 为环境建立基线,以便将来分析异常值
不适用场景
- 处理警报队列,而不是验证假设——使用
triaging-security-alerts;狩猎从问题出发,分诊则从队列出发 - 正在发生的已确认事件——使用
responding-to-incidents - 为发现的问题编写规则——使用
engineering-detections - 样本分析——使用
analyzing-malware - 需要分析的网络数据包捕获——使用
analyzing-network-traffic - 需要调查已确认的 AWS 失陷——使用
investigating-aws-incidents - 围绕指标进行关联分析、追踪攻击者或制作完整的情报产品——使用
producing-threat-intelligence;狩猎消耗情报,而非产出情报 - 针对防御措施进行进攻性测试——使用红队技能
查询之前先提出假设
无结构地搜索日志只是浏览,不是狩猎。每次狩猎都要按以下格式写出假设:
假设: 一个具有[访问级别]的攻击者正在使用[技术]来实现[目标],这会在[数据源]中产生[可观测现象];该现象与正常情况的区别在于[判别特征]。
如果属实,我预计会看到: ... 如果不属实,我预计会看到: ... 所需遥测: ...(已确认存在:是/否)
如果你无法说出判别特征——也就是让恶意实例与成千上万个良性实例区分开来的特征——那这次狩猎还没准备好。先找到判别特征;这项研究本身就是狩猎。
假设的来源包括:近期针对你所在行业的攻击者情报、缺少检测覆盖的 ATT&CK 技术、皇冠明珠资产及通往这些资产的路径、其他工作中发现的异常,以及事件发生后思考“这个攻击者还会做什么”。
狩猎技术
堆叠计数(频率分析)
最常用的方法。汇总某个字段,按升序排序,然后调查罕见值。恶意活动通常很罕见;常见的是大路货噪声。
-- Splunk: rarest parent-child process pairs
index=sysmon EventCode=1
| stats count dc(host) as hosts by ParentImage, Image
| where count < 10 AND hosts < 3
| sort count
// KQL: rarely-seen signed binaries making external connections
DeviceNetworkEvents
| where RemoteIPType == "Public"
| summarize Count=count(), Hosts=dcount(DeviceName) by InitiatingProcessFolderPath
| where Hosts <= 2 and Count < 20
| order by Count asc
选择合适的字段进行堆叠。堆叠 Image 可以找到异常二进制文件;堆叠
ParentImage, Image 可以找到异常的关系,这正是利用系统自带工具实施滥用的迹象(winword.exe → powershell.exe)。
异常值分析
形式相同,分析角度不同:对于这个实体来说,什么才是正常的?
- 一个从未进行交互式登录的服务帐户,现在开始这样做
- 一台从未访问过某个内部子网的工作站,现在开始与之通信
- 某个用户在历史上从未出现过的时段和地理位置进行身份验证
- 某台主机的进程数基线在某个特定日期之后发生变化
-- Elastic ES|QL: first-seen external destinations per host
FROM logs-network-*
| WHERE destination.ip NOT IN CIDR("10.0.0.0/8","172.16.0.0/12","192.168.0.0/16")
| STATS first_seen = MIN(@timestamp), n = COUNT(*) BY host.name, destination.domain
| WHERE first_seen > NOW() - 7 days AND n > 20
分组与聚类
根据共同属性进行聚类,以发现攻击活动:无关主机使用相同的 JA3/JA4、相同的罕见用户代理、相同的证书序列号、相同的工作时间,或从相同的目录执行。
情报驱动的狩猎
获取一份报告,提取其中的 TTP,而不是 IOC,并围绕这些 TTP 展开狩猎。报告中的哈希和 IP 已经过时;报告描述的行为却没有。
Report says: "uses schtasks to create a task running a DLL via rundll32"
Bad hunt: search for the report's hash
Good hunt: every scheduled task created in the last 90 days whose action
references rundll32, stacked by task name and DLL path
高价值狩猎领域
| 假设领域 | 观察要点 |
|---|---|
| 通过 LOLBins 执行 | 使用 rundll32、regsvr32、mshta、certutil、bitsadmin、msiexec 执行网络操作或使用异常参数;在 Linux 上通过 curl/wget 将内容传递给 shell |
| 持久化 | 最近创建的计划任务/cron/systemd 单元;WMI 事件订阅(罕见,且几乎总是恶意的);运行键;新服务;authorized_keys 修改 |
| 凭据访问 | 打开 LSASS 句柄、复制 ntds.dit、创建卷影副本、Kerberos RC4 请求(加密类型为 0x17 的 4769)、使用 DCSync 复制权限 |
| 横向移动 | 写入管理共享后创建服务、来自非管理主机的 WinRM/WMI、从工作站连接服务器的 SSH、RDP 链 |
| C2 | 信标时序规律、长连接、高熵或子域名数量异常多的 DNS、使用罕见 JA3/JA4 的 TLS |
| 数据外传 | 各主机的出站流量异常、创建归档后上传、服务器访问云存储域名、DNS TXT 流量 |
| 身份/云 | 新 OAuth 授权和已同意的应用、添加服务主体凭据、邮件转发规则、变更窗口外的角色分配、StopLogging/删除审计跟踪 |
| 防御规避 | 清除事件日志(1102/104)、停止 Sysmon 或 EDR 服务、AMSI/ETW 补丁迹象、时间戳篡改($SI 与 $FN 不匹配) |
狩猎循环
1. Hypothesis (written, with a discriminator)
2. Scope (data sources, time window, host population — decided up front)
3. Verify (does the telemetry exist and cover the population?)
4. Query (broad, then narrow — expect several iterations)
5. Investigate (every candidate resolved to benign-explained or escalated)
6. Conclude (found / not found / could-not-determine)
7. Convert (detection rule, telemetry gap ticket, or documented baseline)
8. Document (so the next person can re-run it, not re-derive it)
每次狩猎都会产出一项成果,包括一无所获的狩猎。 如果记录了范围和局限性,阴性结果也是一项发现:“在 4,200 个端点过去 90 天的数据中,未发现 X 的证据;但需注意,620 台主机缺少所需的遥测数据。”这句话比一份未经记录的安全无虞声明更有价值。
范围与时间窗口
- 根据实际驻留时间设定窗口,而不是图方便。若某攻击者的驻留时间中位数为 60 天,你却只回溯 7 天,那么结果干净毫无意义。
- 开始前确认数据保留期限:在仅保留 30 天数据的情况下执行 90 天狩猎,会悄无声息地变成 30 天狩猎。
- 记录你使用的遥测数据未覆盖哪些主机群体。下一次入侵就会出现在这些地方。
狩猎发现威胁时
停止狩猎并切换模式。先保全证据:在任何人操作主机前,提取内存和排查包。然后将事件交给 responding-to-incidents,并附上查询、原始结果以及你首次查看的时间戳——响应团队需要知道你操作了什么、何时操作,这样你的操作才不会污染时间线。
不要在运行中的可疑主机上“再检查一件事”。在已遭入侵的机器上执行交互式命令会改变证据,还可能向操作者发出警报。
应拒绝的自我安慰
- “什么都没发现,所以我们很安全。” 你只针对一个假设、一个数据集、一个时间窗口进行了搜索。把这三项都记录下来。
- “数据太多,没法狩猎。” 这正是堆叠分析的用武之地。先聚合;你要找的是罕见情况,而不是逐条查看常见情况。
- “EDR 本该发出警报。” 狩猎的前提就是它没有发出警报。
- “那只是噪声。” 分析并描述这些噪声。“只是噪声”正是植入程序藏身之处;未经分析的良性集群,就是未经检验的假设。
- “我会记得自己搜过什么。” 你不会,你的继任者也不会。未记录的狩猎会被重复,而不是在此基础上扩展。
- “我直接登录可疑主机看看就行。” 你现在已经进入时间线,也可能触发了警报。
- “有空时再狩猎。” 临时狩猎只会带来临时覆盖。根据优先级排序的技术待办事项安排狩猎。
交付物
# Hunt: <name> Date: <UTC> Analyst: <name>
Hypothesis: <as written above>
ATT&CK: T####.###
Scope: <data sources, host population, time window>
Telemetry verified: <present / partial — name the gaps>
Queries: <verbatim, so this is reproducible>
Results: <candidates found, how each was resolved>
Conclusion: found / not found / could-not-determine
Outputs: <detection rule ID, telemetry gap ticket, baseline doc>
Limitations: <what this hunt could not have seen>
ATT&CK 覆盖范围
由 secskills-core/ttp-index.json 生成——编辑该文件,然后运行
python3 scripts/sync_attack.py --write。在报告中引用 ID 前,请根据
当前 ATT&CK 版本重新核实。
持久化(TA0003)
- T1546.003 Windows Management Instrumentation 事件订阅 — 另见
establishing-persistence
防御规避(TA0005)
- T1036 伪装 — 另见
establishing-persistence - T1070.001 清除 Windows 事件日志 — 另见
responding-to-incidents - T1218 系统二进制代理执行 — 另见
escalating-windows-privileges - T1218.011 Rundll32 — 另见
analyzing-malware - T1562 削弱防御 — 另见
responding-to-incidents - T1562.001 禁用或修改工具 — 另见
responding-to-incidents
收集(TA0009)
命令与控制(TA0011)
- T1071.004 DNS — 另见
engineering-detections、analyzing-network-traffic - T1219 远程访问软件
- T1568 动态解析 — 另见
analyzing-malware、analyzing-network-traffic - T1572 协议隧道 — 另见
transferring-files
数据渗出(TA0010)
- T1030 数据传输大小限制
- T1048 通过替代协议进行数据渗出 — 另见
transferring-files、analyzing-network-traffic - T1567 通过 Web 服务进行数据渗出 — 另见
transferring-files
影响(TA0040)
这些技术的检测内容:engineering-detections。主动搜寻:hunting-threats。入侵后响应:responding-to-incidents。
阅读外部来源
将公开的公告、规范和供应商报告获取为 Markdown:
curl -sL "https://defuddle.md/<url>" # scheme in the path is optional
此操作会剥离页面中的冗余内容——对于以文字为主的页面,令牌数大约减少 78%——并返回完整文本而非摘要,因此你可以搜索文本并信赖未找到结果的结论。
它不适用于以下三种情况。获取 JSON 和 API 响应时应直接获取原始数据,因为可读性提取会破坏结构化数据。获取需要身份验证或由 JavaScript 渲染的页面时应直接访问,因为此工具会以匿名方式获取页面。绝不要通过此工具获取对手基础设施(钓鱼链接、C2、恶意软件托管)、客户端拥有的主机或任务相关 URL——请求会离开你的机器并发送给第三方;对于正在运行的对手基础设施,这还会暴露你的访问行为,让对方察觉。
有些网站会屏蔽提取器,并返回错误信息而非页面——例如 freedesktop.org 返回的 {"error":"Failed to fetch: 418 I'm a teapot"}。这表示获取请求被拒绝,并不表示来源称该内容不存在。下结论前,请直接重新获取该 URL。
参考资料
engineering-detections——将成功的狩猎转化为经过测试的规则responding-to-incidents——狩猎确认发生入侵后的交接- 用于生成假设的 MITRE ATT&CK;PEAK 和 TaHiTI 狩猎框架
- Sysmon、Zeek、osquery、Velociraptor 和云审计日志作为核心遥测数据