跳转到帖子

逆向木马远控样本:从持久化、C2 配置到日志留痕的完整拆解

精选回复

发布于

背景

最近在一次授权内网排查中,某 Windows 终端出现异常外联:固定间隔访问境外 VPS 的 443 端口,但流量并非正常 TLS。主机侧用户反馈为“偶发卡顿”,EDR 告警只提示可疑 PowerShell 启动链。后续取证发现落地文件具备典型远控木马特征:开机自启动、配置加密、周期心跳、远程命令执行和文件传输能力。

本文以这类远控木马的逆向分析流程为主线,重点放在样本拆解、配置提取、行为确认、日志留痕和修复建议。场景限定在授权渗透测试和蓝队排查,不讨论投放和免杀。

问题定位

初始线索来自代理网关日志,异常主机为 10.10.23.47,外联目标为 185.x.x.x:443,访问周期约 60 秒。终端侧进一步查看进程树,发现异常链路如下:

explorer.exe
  └── powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Users\Public\update.ps1
        └── rundll32.exe C:\ProgramData\Microsoft\Windows\cache\winupdate.dat,Start

几个明显异常点:

  • rundll32.exe 加载的文件扩展名为 .dat,但 PE 头有效。
  • 路径伪装成 Windows 更新缓存目录,但目录创建时间与用户登录时间接近。
  • 父进程为隐藏 PowerShell,符合脚本落地加载 DLL 的远控启动方式。
  • 外联间隔稳定,流量包长度规律,疑似心跳包。

样本基础信息

对落地文件做静态信息确认:

certutil -hashfile C:\ProgramData\Microsoft\Windows\cache\winupdate.dat SHA256
sigcheck64.exe -m C:\ProgramData\Microsoft\Windows\cache\winupdate.dat
pefile.exe C:\ProgramData\Microsoft\Windows\cache\winupdate.dat

关键信息如下:

项目结果
文件类型PE32+ DLL
导出函数Start、ControlService
编译时间异常偏早,疑似伪造
签名无有效数字签名
导入函数WinHttpOpen、WinHttpConnect、CreateProcessW、RegSetValueExW、CryptUnprotectData

导入表已经能看出几个方向:网络通信、进程创建、注册表持久化、可能使用 DPAPI 或 CryptoAPI 处理配置。

技术分析

1. 持久化方式

样本运行后会创建 Run 键,值名伪装成系统更新组件:

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v WindowsUpdateCache

现场查到的值如下:

WindowsUpdateCache    REG_SZ    rundll32.exe "C:\ProgramData\Microsoft\Windows\cache\winupdate.dat",Start

同时,样本还会写入计划任务作为备用持久化:

schtasks /query /fo LIST /v | findstr /i "WindowsUpdateCache winupdate.dat rundll32"

对应任务 XML 中可见:

<Command>rundll32.exe</Command>
<Arguments>"C:\ProgramData\Microsoft\Windows\cache\winupdate.dat",Start</Arguments>

这种“双持久化”在远控木马里比较常见:Run 键用于用户登录触发,计划任务用于定时拉起,避免单点清理后失效。

2. C2 配置提取

静态查看字符串时没有直接出现域名或 IP,只能看到少量类似配置标记:

cfg_begin
kdf_salt
http_post
user_agent
cfg_end

用 Ghidra/IDA 跟踪 Start 导出函数,发现配置读取逻辑大致如下:

  • 从资源段读取一段二进制数据。
  • 使用固定 XOR key 做第一层解码。
  • 再对结果做 RC4 解密。
  • 解密后是 JSON 格式配置。

下面是用于还原配置的简化 Python 脚本,适合在隔离环境中对样本资源数据做离线解析:

import json
from pathlib import Path

# 从资源段中手工导出的加密配置,不直接运行样本
blob = Path("resource_cfg.bin").read_bytes()

xor_key = b"WUCACHE"
rc4_key = b"2024_update_client"

def xor_decode(data, key):
    return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))

def rc4(data, key):
    S = list(range(256))
    j = 0
    out = []
    key = list(key)
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) & 0xff
        S[i], S[j] = S[j], S[i]
    i = j = 0
    for c in data:
        i = (i + 1) & 0xff
        j = (j + S[i]) & 0xff
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) & 0xff]
        out.append(c ^ k)
    return bytes(out)

stage1 = xor_decode(blob, xor_key)
plain = rc4(stage1, rc4_key)
print(plain.decode("utf-8", errors="replace"))

cfg = json.loads(plain)
print("C2:", cfg.get("host"), cfg.get("port"))
print("URI:", cfg.get("uri"))
print("Interval:", cfg.get("sleep"))

解出的配置示例:

{
  "host": "185.x.x.x",
  "port": 443,
  "uri": "/api/v1/checkin",
  "sleep": 60,
  "jitter": 15,
  "ua": "Mozilla/5.0 Windows NT 10.0; Win64; x64 UpdateClient/7.6",
  "id": "{machine_guid}-{user_sid}"
}

这里需要注意:端口 443 不代表一定是 TLS。本例中样本通过 WinHTTP 发起明文 HTTP POST,只是目标端口使用 443,目的是绕过一些只按端口粗略放行的出口策略。

3. 通信特征

抓包后能看到典型心跳请求,路径固定,User-Agent 有伪装但不完全像正常浏览器:

POST /api/v1/checkin HTTP/1.1
Host: 185.x.x.x:443
User-Agent: Mozilla/5.0 Windows NT 10.0; Win64; x64 UpdateClient/7.6
Content-Type: application/octet-stream
Content-Length: 96

请求体前 4 字节为长度,后续为 RC4 加密数据。解密后结构类似:

{"type":"beacon","host":"PC-047","user":"jzhang","priv":"user","pid":4280}

从功能分支看,样本支持的远控指令包括:

  • cmd:通过 cmd.exe /c 执行命令并回传输出。
  • ps:启动 PowerShell 执行脚本片段。
  • upload/download:文件上传下载。
  • shellcode:内存加载一段二进制数据。
  • sleep:调整心跳间隔。
排查时不要只盯着样本文件本身。远控真正造成影响的部分通常体现在命令执行痕迹、横向连接、凭据访问和异常文件操作上。

操作步骤

1. 主机侧快速确认

优先确认进程、网络、持久化三类信息:

:: 查看 rundll32 异常加载
wmic process where "name='rundll32.exe'" get ProcessId,ParentProcessId,CommandLine

:: 查看当前外联
netstat -ano | findstr ":443"

:: 关联 PID
 tasklist /fi "PID eq 4280"

:: 检查 Run 键
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run"

:: 检查计划任务
schtasks /query /fo LIST /v | findstr /i "rundll32 winupdate cache update"

2. 日志留痕排查

如果环境中开启了 Sysmon,可以重点查以下事件:

  • Event ID 1:进程创建,关注 powershell.exe、rundll32.exe、cmd.exe。
  • Event ID 3:网络连接,关注异常目标 IP、非标准 TLS 的 443 流量。
  • Event ID 7:镜像加载,确认 rundll32.exe 加载的非系统路径 DLL。
  • Event ID 11:文件创建,定位落地文件和临时文件。
  • Event ID 13:注册表值修改,定位 Run 键持久化。

Windows 原生日志中也可以补充看:

  • Security 4688:进程创建,前提是开启进程命令行审计。
  • PowerShell 4104:脚本块日志,确认隐藏启动脚本内容。
  • TaskScheduler 106/140:计划任务创建和更新。

一个常用的 PowerShell 排查命令:

Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Sysmon/Operational'; Id=1,3,11,13} |
  Where-Object { $_.Message -match 'winupdate.dat|WindowsUpdateCache|185\.|rundll32.exe|update.ps1' } |
  Select-Object TimeCreated, Id, ProviderName, Message

3. 网络侧检测

代理、NDR 或防火墙上建议按以下维度检索:

  • 同一主机固定周期访问同一外部 IP。
  • 443 端口但无 TLS ClientHello。
  • User-Agent 中出现非标准更新客户端标识。
  • POST 请求体长度稳定且内容高熵。

Suricata 规则可以先做临时命中,不建议长期只依赖 IP:

alert http $HOME_NET any -> $EXTERNAL_NET 443 (
  msg:"Possible RAT beacon over fake HTTPS port";
  flow:to_server,established;
  http.method; content:"POST";
  http.uri; content:"/api/v1/checkin"; nocase;
  http.user_agent; content:"UpdateClient/7.6"; nocase;
  classtype:trojan-activity;
  sid:900047; rev:1;
)

4. YARA 辅助识别

在样本族没有大规模变种的情况下,可以用导出函数、伪装路径字符串、配置标记和导入函数组合做命中:

rule Win_RAT_WinUpdateCache_ConfigMarker
{
    meta:
        description = "Detect RAT DLL with fake Windows Update cache config markers"
        author = "community"
        scope = "authorized incident response"
    strings:
        $s1 = "cfg_begin" ascii
        $s2 = "kdf_salt" ascii
        $s3 = "UpdateClient/" ascii
        $s4 = "WindowsUpdateCache" wide ascii
        $e1 = "Start" ascii
        $api1 = "WinHttpOpen" ascii
        $api2 = "CreateProcessW" ascii
        $api3 = "RegSetValueExW" ascii
    condition:
        uint16(0) == 0x5A4D and
        5 of ($s*) and
        2 of ($api*) and
        $e1
}

YARA 只是辅助,实战中建议结合 EDR 进程链和网络日志确认,避免因为字符串碰撞误报。

风险与修复建议

1. 隔离与处置顺序

  • 先隔离网络,不要直接关机,避免丢失内存和进程现场。
  • 保留样本、脚本、计划任务 XML、注册表导出、相关日志。
  • 确认是否存在远程命令执行后的二次落地文件。
  • 检查同网段是否有相同 C2、相同 User-Agent、相同持久化键值。

2. 清理项

:: 删除 Run 键
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v WindowsUpdateCache /f

:: 删除计划任务
schtasks /delete /tn "WindowsUpdateCache" /f

:: 删除落地文件,清理前建议先取证备份
 del /f /a "C:\ProgramData\Microsoft\Windows\cache\winupdate.dat"
 del /f /a "C:\Users\Public\update.ps1"

如果样本曾以管理员权限运行,还要检查服务项、WMI 事件订阅和启动目录:

sc query type= service state= all | findstr /i "update cache win"
wmic /namespace:\\root\subscription PATH __EventFilter get Name,Query
wmic /namespace:\\root\subscription PATH CommandLineEventConsumer get Name,CommandLineTemplate
dir "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup"

3. 加固建议

  • 开启 PowerShell Script Block Logging 和 Module Logging,保留 4104 日志。
  • 开启 4688 进程命令行审计,至少覆盖服务器和高价值终端。
  • 限制普通用户对 C:\ProgramData 下可疑目录的写入和执行。
  • 出口策略不要只按端口放行,建议识别真实 TLS 和 HTTP 协议。
  • 对 rundll32.exe、regsvr32.exe、mshta.exe 等 LOLBin 建立基线。
  • 对无签名 DLL 从用户目录、公共目录、ProgramData 加载的行为做告警。

总结

远控木马的逆向分析不应只停留在“样本是什么”这一层,更关键的是把配置、通信、持久化、命令执行和日志证据串起来。本文这个样本的核心特征是:DLL 伪装成更新缓存、通过 rundll32 加载、Run 键和计划任务双持久化、443 端口明文 HTTP 心跳、资源段加密保存 C2 配置。

实际处置时建议按“进程链确认 → 配置提取 → 网络侧扩线 → 日志回溯 → 清理和加固”的顺序推进。这样既能控制当前主机风险,也能发现同源感染和后续横向移动痕迹。

逆向分析与样本观察示意图
逆向分析、样本行为与调试流程示意

这类样本拆解建议把“行为链”和“证据链”分开记录,否则容易只看到启动项和 C2,遗漏前置投递、权限变化以及清理痕迹。

持久化部分,除了常见的 Run/RunOnce、计划任务、服务和启动目录,建议重点核对:

  • 任务是否通过 COM Handler、WMI 永久事件订阅或注册表 IFEO 实现;
  • 服务的 ImagePath、ServiceDll 是否指向临时目录或用户可写目录;
  • 快捷方式的 Target、Arguments 是否带有隐藏参数;
  • 样本是否先落地 loader,再由 loader 解密或释放真正载荷。

Windows 主机上可以先做一轮基线采集:

autorunsc64.exe -accepteula -a * -c -h -s -m > autoruns.csv
schtasks /query /fo LIST /v > tasks.txt
reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Svchost" /s
wevtutil qe Microsoft-Windows-TaskScheduler/Operational /f:text /c:50

C2 配置不要只搜明文 URL。实际样本里常见的是“配置头 + 加密 blob + 运行时拼接”,建议同时关注字符串交叉引用、网络 API 调用参数和内存中的解密结果。静态分析时可重点跟 WinHttpConnect、WinHttpOpenRequest、InternetConnectW、WSAConnect 以及 DNS 查询调用;动态分析时记录 DNS、SNI、HTTP Host、URI、请求头、心跳间隔和失败重连策略。

如果怀疑配置是 XOR/AES 解密后使用,可以在解密函数返回点下断点,而不是只在网络发送函数处抓包。例如 x64dbg 中对 WinHttpSendRequest 设置断点,检查调用前的缓冲区;同时对疑似配置缓冲区下硬件访问断点,通常能定位到解密完成的位置。提取后建议记录以下字段:

{
  "campaign_id": "...",
  "mutex": "...",
  "c2": [
    {"host": "...", "port": 443, "path": "..."}
  ],
  "sleep": 30,
  "jitter": 20,
  "user_agent": "...",
  "transport": "http"
}

日志留痕方面,最好把时间线和 IOC 对齐,而不是只罗列日志名称。重点看进程创建、网络连接、持久化创建和文件落地之间的先后关系:

  • Security 4688:异常父子进程、脚本解释器启动、带可疑参数的系统工具;
  • Sysmon 1/3/11/12/13/14:进程、网络、文件创建、注册表修改;
  • PowerShell 4103/4104:编码命令、下载执行和反射加载;
  • TaskScheduler 106/140/141:任务创建、更新和删除;
  • DNS Client 3008 或网络设备日志:首次解析、短周期重复解析和异常域名。

例如可以用 PowerShell 快速把样本进程的网络行为串起来:

Get-WinEvent -FilterHashtable @{
  LogName='Microsoft-Windows-Sysmon/Operational'
  Id=1,3,11,12,13,14
} | Where-Object {
  $_.Message -match 'sample\.exe|powershell|rundll32|regsvr32'
} | Select-Object TimeCreated, Id, Message

最后建议在报告中明确区分“样本直接行为”和“环境诱发行为”,并保留哈希、样本路径、命令行、父进程、连接时间、解析 IP 及原始日志。这样后续写 YARA、Sigma 或 EDR 检测规则时,能避免把实验环境中的随机路径、测试域名误写成硬编码 IOC。

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

最近浏览 0

  • 没有会员查看此页面。