关键词:Sysmon、事件聚合、Windows Event Forwarding、进程创建、配置驱动
难度:进阶
前置知识:事件日志结构(03)、注册表取证(02)
一、概述
自带事件日志撑不起入侵检测。缺陷有两头:
- 默认什么都不记。
4688(进程创建)要先开「审计进程创建」,而 Windows 默认不开。命令行、哈希、父子链,一样都没有。
- 记了就留不住。日志定长循环覆盖,Security 默认 20 MB,活动多的机器几小时就冲干净。
Sysmon(Sysinternals 的工具)以驱动形式常驻内核,把进程创建(带完整命令行与哈希)、网络连接、DLL 加载、注册表操作写进独立通道 Microsoft-Windows-Sysmon/Operational。
这一篇解决三件事:它记什么、怎么配(配错等于没开)、怎么集中采集(把易覆盖的日志变成远端副本)。
| 维度 |
原生事件日志 |
Sysmon |
| 进程命令行 |
4688 需开启审计,且参数可能截断 |
默认记录,完整命令行 |
| 进程哈希 |
无 |
SHA-1/SHA-256/MD5/IMPHASH |
| 父子关系 |
需交叉查询 |
每条自带 ParentImage/ParentCommandLine |
| 网络连接 |
需开启审计防火墙规则 |
默认记录(IPv4/IPv6/DNS) |
| 持久化位置 |
无对应事件 |
服务、计划任务、启动项、驱动 |
| 保留策略 |
20 MB 循环 |
可配置,且支持远程转发 |
在取证流程中的位置:本篇横跨部署期与取证期两个阶段,这一点和同板块其他文章不同。取证期它是一次性证据解析(导出 .evtx 后离线分析,与 事件日志深度分析 的方法完全一致);部署期它是一套需要提前落地的采集设施,错过事发时点就永远补不回来。所以如果检材上没有 Sysmon 通道,本篇第三章第 3 步(确认是否部署)会在 30 秒内给出阴性结论,然后你在第四章第 1 组里找替代路径——这时 Sysmon 相关的所有结论都不成立,必须换成原生日志加 MFT 加 Prefetch 的组合。上游依赖是事件日志的解析基础与注册表持久化位置(注册表取证),Sysmon 事件 12/13/14 的判读直接建立在 Run 键与服务键的知识上。
本篇处理的证据形态,是一个通道加一份 XML 配置:
| 证据 |
位置或字段 |
说明 |
| 事件通道 |
Microsoft-Windows-Sysmon/Operational |
默认不启用,要先装 Sysmon 再用 -i 写入注册表 |
| 单条事件 |
EventData 里的 RuleName、UtcTime、ProcessGuid、Image、CommandLine、Hashes、ParentImage、ParentCommandLine、User、LogonId |
ProcessGuid 是把同一进程的多条事件串起来的关键 |
| 配置文件 |
Sysmon64.xml 或 Sysmon.xml |
决定 <EventFiltering> 里哪些 <ProcessCreate onmatch="include"> 生效 |
| 转发配置 |
订阅管理器里的 WEF 订阅,落地在 .evtx 汇聚文件 |
MaxSize、MaxEventTime、是否启用 |
| 版本标识 |
事件里的 Version 字段与配置里的 schemaVersion |
报告里必须写明,不同版本事件集不同 |
配置文件是本篇最容易出事的地方:一个 <ProcessCreate> 里既能写 <Image path="...">,也能写 <CommandLine condition="contains"> 和 <ParentImage>,条件之间是与关系,<Image> 支持 is / contains / begin with / end with 及 exclude 变体。排除项写错一个进程名,就等于给它开了一扇免检门——第二章会把这套匹配语义讲透。
本篇能回答什么:某个时间窗内系统上执行过哪些程序、命令行与哈希是什么、父子链是否合理、DNS 与出站连接指向哪里、注册表持久化位置被写过什么、文件创建时间是否被篡改、某个进程是否被远程线程注入。
本篇不能回答什么:Sysmon 没有部署就是没有,此时所有阴性结论都不成立,而且原生日志无法补上缺失的部分——4688 不带哈希,SRUM 的粒度与保留期都不同。Sysmon 是存在性日志:它只记录"配置范围内发生过的事件",配置里被 <exclude> 掉的对象等于不存在,而且被排除的记录不会留痕,你事后无法判断某类事件是没发生还是被过滤了。日志被清空或被配置改成不记录后,仍会继续产生"正常"的新事件——只有时间戳断层,没有"清空"这个事件本身。另外命令行与哈希证明的是"这样一件程序跑起来了",证明不了它做了什么,后续行为要看文件、注册表、网络三类事件;GrantedAccess 判读也不能替代对目标进程内存的实际分析。
读者前提:需要先掌握 .evtx 的导出与字段解析(能读 EventData 的 XML 结构、知道 Properties 集合只给值不给字段名这件事),否则拿到 Sysmon 日志也只能干瞪眼;需要理解 LogonId 与 ProcessGuid 这两个关联字段的含义——前者把事件挂到登录会话上,后者把同一进程的多条事件串起来,这一步做不对,父子链和注入结论全部断裂;还需要知道审计策略与 Sysmon 过滤器是两套独立的开关,前者管原生日志,后者管 Sysmon,两者不通。
二、核心原理
2.1 Sysmon 的工作方式
sysmon.exe(用户态 CLI) → 发送配置 XML → SysmonDrv.sys(内核驱动)
↓ ETW
Microsoft-Windows-Sysmon/Operational.evtx
- 驱动在系统调用层捕获行为;用户态进程本身是攻击面(rootkit 可挂钩它)。
- 配置是 XML,经
sysmon.exe -c config.xml 下发。配置变更通常需要重启(是否支持热重载以实际版本为准)。
- 日志落在
C:\Windows\System32\winevt\Logs\Microsoft-Windows-Sysmon%4Operational.evtx(注意 %4 是通道分隔符的编码,勿漏)。
推论只有一条,但很实用:Sysmon 日志和 Security 是两个独立文件。wevtutil cl Security 清不掉 Sysmon 日志。只清了 Security 的攻击者若没意识到 Sysmon 存在,就等于把最高质量的那份证据留在了原地。
2.2 ★ 事件 ID 清单
Sysmon 沿用 WMI 事件编号(1–25),但不是每个编号都会产生数据,集合还随版本变。下面按取证价值分类。
报告中必须写明所用的 Sysmon 版本与 schemaVersion。
A. 进程与线程(最核心)
| ID |
事件 |
关键字段 |
取证价值 |
| 1 |
进程创建 |
Image、CommandLine、ParentImage、ParentCommandLine、User、Hashes、LogonId |
★★★ 一切执行的完整记录,含命令行与哈希 |
| 2 |
文件创建时间被修改 |
Image、NewTime、PreviousTime |
★★★ 时间戳篡改的直接证据(timestomp) |
| 3 |
网络连接 |
Image、DestinationIp/Port/Hostname、Protocol、Initiated |
★★★ 出站历史,含 Initiated=false 的入站 |
| 8 |
CreateRemoteThread |
SourceImage、TargetImage、StartModule |
★★★ 进程注入(DLL 注入、进程镂空) |
| 10 |
ProcessAccess |
SourceImage、TargetImage、GrantedAccess、CallTrace |
★★ 凭据窃取:LSASS 被 PROCESS_VM_READ 打开 |
| 15 |
进程流哈希 |
Image、Hashes、Length |
★★★ 内存加载 PE(fileless) |
| 22 |
DNS 查询 |
QueryName、QueryResults、Image |
★★ 域名级 C2 证据 |
B. 文件、镜像与内核
| ID |
事件 |
取证价值 |
| 7 |
映像加载 |
★★★ DLL 注入/侧载;Signed=false + 位于 Temp 是强信号 |
| 11 / 23 |
文件创建 / 文件删除 |
★★ 落地与清理痕迹(TargetFilename) |
| 12 / 13 / 14 |
注册表对象创建 / 值设置 / 键重命名 |
★★★ 持久化检测(Run 键、服务注册) |
| 6 |
驱动加载 |
★★★ 加载未签名驱动 = rootkit 强信号 |
| 5 |
进程终止 |
★ 存活时长(短命进程可能是一次性利用) |
| 17 / 18 / 19 / 20 / 21 |
WMI 事件 / 命名管道 / 永久事件订阅 |
★★ 域内横向与隐蔽信道 |
| 24 |
剪贴板内容更改 |
★ 密码搬运行为 |
2.3 与原生日志的互补关系
没有任何单一工件能证明入侵。Sysmon 的价值在与原生日志互补:
| 场景 |
只有原生日志 |
只有 Sysmon |
两者结合 |
| 进程执行 |
4688 未开启则无;开启也缺哈希 |
完整命令行 + 哈希 |
可哈希比对威胁库 |
| 登录 |
4624 有 TargetLogonId |
事件 1 也带 LogonId |
用 LogonId 把进程归属到具体登录会话 |
| 服务持久化 |
7045(安装时) |
事件 12/13(注册表写入时) |
两条独立时间线互证 |
| 文件落地 |
无 |
事件 11 |
与 Prefetch(05)交叉 |
| 时间戳篡改 |
MFT 可见但无上下文 |
事件 2 直接报告新旧时间 |
强证据 |
| 网络外联 |
需开审计 |
事件 3 + 22 |
与防火墙、SRUM(09)对照 |
LogonId 是整篇的关联枢纽。4624 告诉你「用户 X 在 23:12 以类型 3 登录,LogonId=0x3E7」,Sysmon 事件 1 告诉你「这个 LogonId 下启动了哪些进程」。把两者按 LogonId 串起来,得到的是一条完整的攻击会话。
2.4 集中化采集:为什么必须转发
单机 Sysmon 日志照样会被覆盖——上限有限,而攻击者只要知道通道名就能清。
所以企业环境的做法是双写:
Sysmon 驱动
├─→ 本地 .evtx(缓冲,便于单机取证)
└─→ Windows Event Forwarding(WEF)→ 远程订阅源(日志服务器 / SIEM)
WEF 是 Windows 内置的转发机制:日志通道订阅 Microsoft-Windows-Sysmon/Operational,经 WinRM 推给远程 Collector,终端上不用装 EDR agent。
取证上的意义很直接:只要日志已经推到远端,本地被清空也不影响结论。
三、操作步骤
3.1 第 1 步:先确认系统是否部署了 Sysmon
这一步必须最先做。绝大多数终端默认没有 Sysmon,查不到不是异常。
# 活系统:查通道是否存在及其上限
Get-WinEvent -ListLog 'Microsoft-Windows-Sysmon/Operational' -ErrorAction SilentlyContinue |
Select LogName, RecordCount, FileSize, MaximumSizeInBytes, LogMode
# 离线:从镜像定位日志、驱动与用户态程序
fls -o 2048 -r -p /work/DigiForensics.dd | grep -i 'Sysmon'
# → /Windows/System32/sysmon64.exe (Win8+ 无 32 位版)
# → /Windows/System32/drivers/SysmonDrv.sys
# → /Windows/System32/winevt/Logs/Microsoft-Windows-Sysmon%4Operational.evtx
| 检查结果 |
结论 |
.evtx + 驱动 + 服务注册项齐全 |
已部署,继续 3.3 |
只有 .evtx 无驱动文件 |
曾部署后卸载,日志残留仍可分析 |
| 全无 |
该机从未部署 Sysmon,改用 4688 / EDR / 其他工件 |
3.2 第 2 步:配置 Sysmon(现场部署的正确做法)
配置不当等于白开:默认配置只记事件 1 和 6,网络、注册表、DNS 全无。
<Sysmon schemaVersion="4.60">
<EventFiltering>
<ProcessCreate onmatch="include">
<CommandLine condition="is not contains">\WmiPrvSE.exe</CommandLine>
</ProcessCreate>
<NetworkConnect onmatch="exclude">
<DestinationIp condition="is any of">127.0.0.1;192.168.0.0/16;10.0.0.0/8;172.16.0.0/12;fe80::/10;::1</DestinationIp>
</NetworkConnect>
<FileCreate onmatch="exclude">
<TargetFilename condition="is any of">%SystemRoot%\Prefetch\*;%SystemRoot%\Temp\*</TargetFilename>
</FileCreate>
<RegistryEvent onmatch="exclude">
<TargetObject condition="is any of">\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\*</TargetObject>
</RegistryEvent>
</EventFiltering>
<Hashes>sha256,sha1,md5,imphash</Hashes>
<ProcessAccess onmatch="exclude">
<GrantedAccess condition="is any of">0x1000;0x1010;0x100000;0x100010;0x100020;0x100038</GrantedAccess>
</ProcessAccess>
<FileCreateStreamHash>on</FileCreateStreamHash>
<DNSQuery onmatch="exclude">
<QueryName condition="is any of">\*.microsoft.com;*.windowsupdate.com;*.msftconnecttest.com</QueryName>
</DNSQuery>
</Sysmon>
| 字段 |
作用 |
建议 |
EventFiltering |
各事件类型的包含/排除规则 |
必配。不配则全是系统噪声,硬盘几天就满 |
Hashes |
记录哪些哈希 |
sha256,sha1,md5,imphash 全开,匹配不同威胁库 |
ProcessAccess 的 GrantedAccess |
排除正常查询权限 |
排除 0x1010(VM_READ|QUERY)之类,否则真信号被淹没 |
FileCreateStreamHash |
计算内存流哈希 |
on —— fileless 只能靠这个抓 |
DNSQuery |
DNS 查询日志 |
开,但排除微软域名降噪 |
sysmon64.exe -accepteula -i Sysmon.xml # 安装并加载配置
sysmon64.exe -c Sysmon.xml # 更改配置(部分版本需重启)
sysmon64.exe -d # 卸载(先归档日志!)
sysmon64.exe -h # 版本与支持的 schema
sysmon64.exe -z # 检查配置是否被 hash 锁定
wevtutil sl Microsoft-Windows-Sysmon/Operational /ms:268435456 # 调大到 256 MB
⚠️ 不调大日志上限,繁忙终端的 Sysmon 日志同样会被循环覆盖。
3.3 第 3 步:解析 Sysmon 日志
# 3.3.1 转 CSV:EventData 字段名成列,便于统计
EvtxECmd.exe -f C:\evidence\Sysmon.evtx --csv C:\evidence\sysmon_out
# → Sysmon_Operational.csv,列为 TimeCreated / Id / Image / CommandLine /
# ParentImage / User / Hashes / TargetFilename / DestinationIp ...
# 3.3.2 活系统直查:★ 用 ToXml 按字段名取(见第 03 篇)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational'; Id=1} -MaxEvents 5000 |
ForEach-Object {
[xml]$x = $_.ToXml(); $d=@{}; $x.Event.EventData.Data | %{ $d[$_.Name]=$_.'#text' }
[pscustomobject]@{ Time=$_.TimeCreated; Image=$d['Image']; Cmd=$d['CommandLine'];
Parent=$d['ParentImage']; Hashes=$d['Hashes'] }
} | Format-Table -AutoSize -Wrap
核心查询场景(CSV 版,列号以实际表头为准):