跳转到帖子

逆向木马远控实战:从 Windows 样本配置提取到 C2 链路与持久化排查

精选回复

发布于

背景与分析边界

本文记录一次授权内网排查中的 Windows 远控木马分析过程。终端告警显示,一个伪装成同步组件的 PE 文件在用户登录后启动,并周期性访问外网。分析目标不是运行或复现远控功能,而是确认样本行为、提取配置、还原 C2 通信特征,并给出处置和日志补强方案。

以下域名、地址和哈希均为脱敏示例。样本应放在隔离虚拟机中分析,关闭共享剪贴板、共享目录和宿主机网络直通,动态分析流量只接入 FakeNet-NG 或 INetSim。

一、现场现象与问题定位

受影响主机为 Windows 10,EDR 首先记录到以下异常链路:

  • 用户登录后出现进程:C:\Users\Public\Libraries\syncsvc.exe
  • 父进程为 taskeng.exe,说明其可能由计划任务启动
  • syncsvc.exe 创建挂起状态的系统进程,随后出现跨进程内存写入
  • 被操作进程周期性访问 update-cdn.example.test:443
  • 主机上出现名为 Microsoft\Windows\Maintenance\SyncTelemetry 的计划任务

现场处置时不要直接双击样本,也不建议第一时间关机。对于存在进程注入的主机,应先隔离网络并保留内存、进程列表、计划任务、注册表和网络连接等证据。

mkdir C:\IR
copy C:\Users\Public\Libraries\syncsvc.exe C:\IR\syncsvc.bin
certutil -hashfile C:\IR\syncsvc.bin SHA256
sigcheck64.exe -accepteula -h -i -m C:\IR\syncsvc.bin
schtasks /query /fo LIST /v > C:\IR\schtasks.txt
reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run /s > C:\IR\run-hkcu.txt
reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run /s > C:\IR\run-hklm.txt
netstat -ano > C:\IR\netstat.txt
tasklist /v > C:\IR\tasklist.txt
wevtutil epl Microsoft-Windows-TaskScheduler/Operational C:\IR\TaskScheduler.evtx

本例样本 SHA-256 记为 7c0f...9e21。签名检查显示文件无有效 Authenticode 签名,但版本资源伪造为 Microsoft Sync Service。版本信息不能作为可信依据,应结合签名链、文件来源和行为判断。

二、静态逆向:识别加载器和配置区

先使用 Detect It Easy、PE-bear、FLOSS 和 capa 做低成本筛查。该样本是 64 位 PE,导入表较小,但能看到 VirtualAlloc、VirtualProtect、CreateProcessW、WriteProcessMemory、GetThreadContext、SetThreadContext、ResumeThread 和 WinHttpOpen 等 API。这个组合通常意味着样本同时具备内存解密、进程操作和 HTTP 通信能力。

diec syncsvc.bin
floss.exe syncsvc.bin > floss.txt
capa.exe -vv syncsvc.bin > capa.txt
objdump -x syncsvc.bin > pe-headers.txt

PE 节区检查发现:

  • .text 节熵约 6.3,仍能正常反汇编,不像整体加壳
  • .rdata 中存在固定标记 CFG1,后跟长度、单字节密钥和配置密文
  • TLS Directory 不为空,存在早于入口点执行的 TLS Callback
  • 编译时间戳与数字签名时间不一致,且时间戳明显早于所使用的 SDK 版本

在 Ghidra 中从 CFG1 的交叉引用向上追踪,可以看到初始化函数先读取两字节小端长度,再读取一字节 XOR 密钥,解密后的内容为 UTF-8 JSON。这里的单字节 XOR 只用于隐藏静态字符串,不提供真正的密码学保护。

可用以下离线脚本提取配置。脚本只读取文件,不加载 PE,也不会执行样本代码:

import json
import pathlib
import struct
import sys

raw = pathlib.Path(sys.argv[1]).read_bytes()
marker = b"CFG1"
pos = raw.find(marker)
if pos < 0:
    raise SystemExit("CFG1 marker not found")

base = pos + len(marker)
length = struct.unpack_from("<H", raw, base)[0]
key = raw[base + 2]
enc = raw[base + 3:base + 3 + length]

if len(enc) != length:
    raise SystemExit("truncated configuration")

dec = bytes(value ^ key for value in enc)
config = json.loads(dec.decode("utf-8"))
print(json.dumps(config, ensure_ascii=False, indent=2))

执行方式:

python extract_cfg.py syncsvc.bin

提取结果包含以下字段:

  • hosts:update-cdn.example.test、198.51.100.27
  • port:443
  • path:/api/v2/sync
  • sleep:180
  • jitter:30
  • campaign:FIN-2025-04
  • mutex:Global\SyncTelemetry_7F31

需要注意,配置中的 IP、域名和路径只是线索。部分木马会保留已废弃节点,封禁前应结合 DNS、代理日志和实际网络行为确认。

三、入口点、持久化与进程注入分析

样本真正的初始化逻辑位于 TLS Callback。回调函数先检查互斥体,随后进行简单环境判断,包括处理器数量、物理内存大小和近期用户输入时间。入口点本身只负责创建工作线程,用来干扰只跟踪 AddressOfEntryPoint 的分析流程。

持久化函数调用 Task Scheduler COM 接口创建登录触发任务。任务执行路径不是裸文件名,而是:

"C:\Users\Public\Libraries\syncsvc.exe" --background

对应的现场核查命令:

schtasks /query /tn "\Microsoft\Windows\Maintenance\SyncTelemetry" /xml
Get-ScheduledTask -TaskPath "\Microsoft\Windows\Maintenance\" |
  Where-Object {$_.TaskName -eq "SyncTelemetry"} |
  Format-List *

注入部分可从 API 调用链确认:

  • CreateProcessW 以 CREATE_SUSPENDED 创建目标进程
  • VirtualAllocEx 在远程进程申请可写内存
  • WriteProcessMemory 写入解密后的载荷
  • GetThreadContext 和 SetThreadContext 修改线程上下文
  • ResumeThread 恢复目标线程

这类行为与进程空洞或线程上下文劫持相近。不能只依据单个 API 判定恶意,因为调试器和安全软件也可能调用这些接口;关键是父子进程关系、签名、目标路径、内存权限变化和后续网络连接是否形成完整证据链。

四、动态验证:不直连真实 C2

动态分析使用快照虚拟机,网络设置为仅主机模式,由 FakeNet-NG 模拟 DNS、HTTP 和 TLS 服务。不要通过修改 hosts 后直接映射到公网分析机,以免样本利用其他协议绕过。

fakenet.exe -c configs\default.ini
procmon.exe /BackingFile C:\Analysis\syncsvc.pml
x64dbg.exe C:\Analysis\syncsvc.bin

Procmon 建议设置以下过滤条件:

  • Process Name is syncsvc.exe
  • Operation is RegSetValue、CreateFile、WriteFile 或 Process Create
  • Path contains TaskCache、System32\Tasks 或 Users\Public

x64dbg 中可在 CreateProcessW、WriteProcessMemory、SetThreadContext、WinHttpConnect 和 WinHttpSendRequest 上设置断点。命中 WinHttpSendRequest 时,应记录请求句柄对应的主机、路径、请求头和缓冲区长度,不要仅搜索明文域名,因为配置可能在运行时才解密。

本例木马使用 WinHTTP 发出 HTTPS 请求,请求路径固定为 /api/v2/sync,并带有以下特征:

  • User-Agent 伪装为系统更新组件,但版本号与主机操作系统不匹配
  • 自定义头 X-Client-ID,值为主机 GUID 截断后的十六进制字符串
  • 心跳间隔约 180 秒,存在正负 30% 抖动
  • POST 请求体前四字节固定为 53 59 4e 43,即 ASCII 的 SYNC

TLS 加密场景下,网络侧未必能看到 URI 和自定义头。此时应关联代理解密日志、终端 WinHTTP 事件、DNS 查询和进程网络事件。仅封禁 URI 对未解密流量没有效果。

五、内存与日志交叉验证

如果 EDR 显示系统进程存在异常外联,应采集内存后再结束进程。使用 Volatility 3 可以检查进程树、网络连接、可疑 VAD 和注入区域:

python vol.py -f memory.raw windows.pslist
python vol.py -f memory.raw windows.pstree
python vol.py -f memory.raw windows.netscan
python vol.py -f memory.raw windows.malfind --dump
python vol.py -f memory.raw windows.vadinfo --pid 4120

重点关注以下现象:

  • 映像路径与进程名不一致,或父进程关系不合理
  • 私有内存区域同时具备可写和可执行权限
  • 内存中的 PE 头不存在于对应磁盘映像
  • 网络连接归属于被注入进程,而不是原始 syncsvc.exe
  • 线程起始地址落在 Private VAD,而不是已加载模块

Windows 日志侧建议关联以下事件:

  • 安全日志 4698、4702:计划任务创建或更新
  • TaskScheduler Operational 106、140、200:任务注册和执行
  • Sysmon 1:进程创建及完整命令行
  • Sysmon 3:进程网络连接
  • Sysmon 8:CreateRemoteThread;本例未必触发,因为样本采用线程上下文修改
  • Sysmon 10:Process Access,可发现对目标进程申请高权限句柄
  • Sysmon 13:注册表值修改
  • Sysmon 22:DNS 查询

Sysmon 不能完整记录 WriteProcessMemory 的内容,因此 Event ID 10 的 SourceImage、TargetImage、GrantedAccess 和 CallTrace 很关键。建议避免全量记录所有进程访问,否则日志噪声和磁盘压力会很高,可优先记录非系统路径程序访问浏览器、lsass.exe、explorer.exe 和常见系统宿主进程的行为。

六、样本级检测规则

可以基于配置标记、互斥体和特征路径编写 YARA 规则。规则应至少组合两个相对稳定的特征,避免只依赖单个域名或文件名。

rule Win64_SyncTelemetry_RAT_Loader
{
    meta:
        description = "Detects the analyzed SyncTelemetry RAT loader"
        scope = "file"

    strings:
        $cfg = { 43 46 47 31 }
        $mutex = "Global\\SyncTelemetry_7F31" ascii wide
        $uri = "/api/v2/sync" ascii wide
        $task = "\\Microsoft\\Windows\\Maintenance\\SyncTelemetry" ascii wide
        $arg = "--background" ascii wide

    condition:
        uint16(0) == 0x5A4D and
        filesize < 5MB and
        $cfg and 2 of ($mutex, $uri, $task, $arg)
}

部署前应使用正常软件库做误报测试。CFG1 这类短标记可能出现在无关程序中,所以不能单独作为封禁条件。若样本更新后只替换域名,互斥体、配置结构和任务路径通常比网络 IOC 更耐用。

七、处置与修复建议

  • 先通过 EDR 或交换机隔离受影响主机,保留管理通道,避免木马继续接收指令。
  • 采集内存、样本、计划任务 XML、事件日志、Prefetch、Amcache、Shimcache、SRUM、DNS 缓存和代理日志。
  • 在证据保全后删除恶意计划任务和落地文件,同时检查相同用户配置文件及公共目录是否存在副本。
  • 若确认发生进程注入或远程命令执行,优先重装或从可信镜像恢复,不建议仅删除文件后继续使用。
  • 轮换该主机上登录过的域账号、本地管理员账号、浏览器会话、API Token 和已挂载共享凭据。
  • 检索全网相同哈希、互斥体、任务名称、命令行参数、DNS 请求和固定心跳周期。
  • 限制普通用户从 Users\Public、AppData 和临时目录执行未签名程序,可结合 AppLocker 或 WDAC 分阶段实施。
  • 对服务器和办公终端建立出站访问控制,非必要程序不应直接访问互联网;代理侧保留主机、用户、进程和目的域名的关联字段。

清理计划任务时应在取证完成后执行:

schtasks /delete /tn "\Microsoft\Windows\Maintenance\SyncTelemetry" /f
Remove-Item "C:\Users\Public\Libraries\syncsvc.exe" -Force
Get-FileHash "C:\Users\Public\Libraries\syncsvc.exe" -Algorithm SHA256

最后一条哈希命令应在删除前执行,实际流程中应先复制留证、计算哈希并记录文件时间,再进行清理。

总结

远控木马排查不能停留在“发现可疑外联后删除文件”。比较可靠的方法是把静态逆向、动态行为、内存证据和日志关联起来:通过 PE 结构和交叉引用定位配置,通过隔离环境验证持久化与注入链路,再使用终端和网络日志评估影响范围。修复阶段既要清除样本,也要处理被窃取凭据、持久化项、出站控制和日志缺口。对于已经发生内存注入和远程指令执行的终端,可信重建通常比单点清理更稳妥。

逆向分析与样本观察示意图
逆向分析、样本行为与调试流程示意
网络流量与边界分析示意图
网络请求、日志与边界流量分析示意

这类样本建议把“静态配置、运行时链路、持久化落点”做成交叉验证,避免仅凭 strings 里的域名就下结论。尤其是配置区经常存在单字节 XOR、Base64 后再压缩,或者运行时拼接 C2 的情况。

先固定样本信息并保留原始证据,分析环境使用快照和 Host-only 网络,不要让样本直接访问公网:

Get-FileHash .\sample.exe -Algorithm SHA256
Get-AuthenticodeSignature .\sample.exe | Format-List
sigcheck64.exe -a -h -i .\sample.exe
diec.exe .\sample.exe
floss.exe -n 6 .\sample.exe > floss.txt
capa.exe .\sample.exe

配置提取时可优先从网络 API 的交叉引用反推,而不是盲搜字符串。重点看 WinHttpConnect、WinHttpOpenRequest、InternetConnect、getaddrinfo、connect 周围的数据流,以及资源段、较高熵的自定义节和全局初始化函数。若发现解密循环,最好只复现解码函数,并同时记录偏移、密钥和字段边界,便于后续批量验证。

C2 链路建议在 FakeNet-NG 或 INetSim 下复现,同时抓取 ETW/Sysmon 和 PCAP。这样能区分硬编码域名、备用 IP、DGA、DNS TXT 配置以及 HTTP Host 与实际目的地址不一致等情况。常用过滤可以先从这些入手:

# Wireshark
dns || http.request || tls.handshake.extensions_server_name

# 当前连接及对应进程
Get-NetTCPConnection |
  Sort-Object State,RemoteAddress |
  Format-Table LocalAddress,LocalPort,RemoteAddress,RemotePort,State,OwningProcess

Get-CimInstance Win32_Process |
  Select-Object ProcessId,ParentProcessId,ExecutablePath,CommandLine

如果是 HTTPS,不要只记录域名和 JA3。还应保留连接周期、DNS 响应、SNI、证书指纹、URI 结构、User-Agent、请求体长度和回连间隔。JA3 很容易因系统 TLS 栈或版本变化产生偏差,而“固定间隔并带少量抖动”的行为特征通常更稳定。

持久化排查除了 Run 键,还要覆盖 32/64 位注册表视图、计划任务 XML、服务、WMI 永久事件订阅和启动目录:

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run" /s

schtasks /query /fo LIST /v
sc.exe query type= service state= all

Get-CimInstance -Namespace root/subscription -Class __EventFilter
Get-CimInstance -Namespace root/subscription -Class CommandLineEventConsumer
Get-CimInstance -Namespace root/subscription -Class __FilterToConsumerBinding

Get-ChildItem "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup" -Force
Get-ChildItem "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp" -Force

排查时要关注的不只是条目名称,还包括引用文件是否位于 AppData、ProgramData、Temp,命令行是否使用 rundll32、regsvr32、mshta、powershell -enc,以及任务触发器是否为登录、空闲或短周期重复执行。服务项还应核对 ImagePath 是否带有未加引号路径或异常参数。

最后建议按时间线归并结果:进程创建 → 文件落地 → 持久化写入 → DNS/连接 → 二阶段载荷。Sysmon 中至少关联 Event ID 1、3、11、12/13、22;单独看到一个注册表键或域名不足以证明完整感染链。清理前先导出任务 XML、注册表项和落地文件哈希,完成隔离后再删除持久化,避免条目被存活进程重新写回。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。