跳转到帖子

逆向木马远控样本:从启动项、C2 通信到日志留痕的实战拆解

精选回复

发布于

背景

最近在一次授权内网排查中,发现一台 Windows 业务跳板机存在异常外联。EDR 告警不明显,但出口防火墙记录显示该主机周期性访问一个非常规端口的境外 VPS。样本最终定位为一个轻量级远控木马,具备开机自启动、主机信息采集、命令执行、文件上传下载等能力。

本文只围绕逆向木马远控分析展开,重点记录样本定位、静态拆解、动态行为验证、日志留痕和修复建议。场景为授权测试与应急排查,不涉及投放、免杀或攻击扩展。

问题定位

初始线索来自防火墙外联日志:

src_ip=10.10.23.18 dst_ip=185.xxx.xxx.21 dst_port=8443 proto=tcp action=allow bytes_out=1840 bytes_in=5120 interval≈60s

登录主机后,先做三类确认:

  • 确认是否存在异常进程及网络连接。
  • 确认是否存在异常启动项、计划任务、服务。
  • 确认样本落地位置、创建时间和父进程链。
netstat -ano | findstr ESTABLISHED
tasklist /svc | findstr 8443
wmic process get ProcessId,ParentProcessId,ExecutablePath,CommandLine
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run"
schtasks /query /fo LIST /v | findstr /i "TaskName Task To Run Author"
wevtutil qe Security /q:"*[System[(EventID=4688)]]" /f:text /c:20

最终发现进程路径为:

C:\Users\Public\Libraries\WindowsUpdate\wupdate.exe

对应启动项:

HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Windows Update = C:\Users\Public\Libraries\WindowsUpdate\wupdate.exe

这个路径和命名都属于常见伪装方式。真正的 Windows Update 不会以这种路径和用户态 Run 键方式启动。

静态技术分析

将样本转移到隔离分析机后,先计算哈希和基础信息:

certutil -hashfile wupdate.exe SHA256
sigcheck -m -a wupdate.exe
pefile wupdate.exe
strings -n 6 wupdate.exe > strings.txt

基础信息如下:

项目结果
文件类型PE32+ console executable
签名无有效数字签名
编译时间异常,疑似被篡改
主要导入Wininet、Advapi32、Kernel32、Shell32
可疑 APIInternetOpenA、InternetConnectA、HttpSendRequestA、CreateProcessA、RegSetValueExA

字符串中可以看到经过简单异或处理的配置片段。样本内存在固定 key,对 C2 地址、端口、上线间隔做了解密。还原逻辑大致如下:

def xor_decode(data: bytes, key: int = 0x37):
    return bytes([b ^ key for b in data])

enc = bytes.fromhex("5a4244594f5d1d5f4f5b1d4542")
print(xor_decode(enc))

逆向时重点看以下函数调用链:

  • 入口函数先调用 GetModuleFileNameA 获取自身路径。
  • 随后调用 RegCreateKeyExA、RegSetValueExA 写入 HKCU Run 启动项。
  • 通过 GetComputerNameA、GetUserNameA、GetVersionExA 采集主机信息。
  • 通过 WinINet 发起 HTTP/HTTPS 请求,上线包中包含主机名、用户名、进程 ID、系统版本。
  • 收到任务后进入分发逻辑,支持 cmd 执行、文件下载、文件上传和休眠时间修改。

远控通信行为分析

在隔离环境中配置 INetSim 和本地抓包,观察样本通信。样本默认每 60 秒请求一次固定路径:

POST /api/checkin HTTP/1.1
Host: updatecdn.example
User-Agent: Mozilla/5.0 Windows Update Client
Content-Type: application/octet-stream
Content-Length: 96

上线数据不是复杂加密,只是 XOR 后再 Base64。解码后可见结构:

{"host":"PC-23-18","user":"ops","pid":3620,"ver":"10.0","arch":"x64"}

任务响应中存在简单操作码:

操作码行为风险
0x01执行 cmd 命令远程命令执行
0x02下载文件到指定路径二阶段载荷投递
0x03上传本地文件数据外传
0x04修改 sleep 时间规避高频流量检测
0x05退出进程清理痕迹或临时停用

这里比较典型的一点是,样本没有使用服务安装方式,而是使用 HKCU Run。原因通常是权限要求低,只要当前用户登录即可触发,适合钓鱼落地后的持久化。

动态排查步骤

在受影响主机上不建议直接删除文件,先保留证据并确认影响面。可以按以下顺序处理:

:: 1. 确认异常连接对应 PID
netstat -ano | findstr "185.xxx.xxx.21"

:: 2. 查看 PID 对应进程
wmic process where processid=3620 get ProcessId,ParentProcessId,ExecutablePath,CommandLine,CreationDate

:: 3. 导出启动项证据
reg export "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" C:\Temp\hkcu_run.reg

:: 4. 计算样本哈希
certutil -hashfile "C:\Users\Public\Libraries\WindowsUpdate\wupdate.exe" SHA256

:: 5. 查看文件时间线
dir /t:c "C:\Users\Public\Libraries\WindowsUpdate\"
dir /t:w "C:\Users\Public\Libraries\WindowsUpdate\"

:: 6. 查询近期进程创建日志,需要已开启 4688
wevtutil qe Security /q:"*[System[(EventID=4688)]] and *[EventData[Data[@Name='NewProcessName']='C:\Users\Public\Libraries\WindowsUpdate\wupdate.exe']]" /f:text

如果环境部署了 Sysmon,建议重点查以下事件:

  • Event ID 1:进程创建,确认父进程和命令行。
  • Event ID 3:网络连接,确认 C2 地址、端口和时间规律。
  • Event ID 11:文件创建,确认样本落地时间。
  • Event ID 13:注册表值修改,确认 Run 键写入。
  • Event ID 22:DNS 查询,确认域名解析行为。

常用 Sysmon 查询示例:

wevtutil qe Microsoft-Windows-Sysmon/Operational /q:"*[System[(EventID=3)]] and *[EventData[Data[@Name='DestinationPort']='8443']]" /f:text /c:50

wevtutil qe Microsoft-Windows-Sysmon/Operational /q:"*[System[(EventID=13)]] and *[EventData[contains(Data,'CurrentVersion\\Run')]]" /f:text /c:50

逆向关注点

分析这类远控木马时,不建议一开始就陷入全部函数细节。优先还原以下信息,对处置最有价值:

  • C2 地址、端口、URI、User-Agent。
  • 持久化方式,包括 Run 键、计划任务、服务、WMI 事件订阅。
  • 配置解密方式,确认是否还有备用 C2。
  • 支持的远控指令,判断是否存在文件窃取和横向移动能力。
  • 样本落地目录和文件名规则,用于全网搜索。
  • 日志留痕点,用于还原入侵时间线。

本样本配置段在 .rdata 附近,使用固定 XOR key。可以用 YARA 做初步猎杀,但不要只依赖文件名:

rule Win_RemoteControl_WUpdate_RunKey_Xor
{
    meta:
        description = "Detects suspicious remote control sample abusing WindowsUpdate name and WinINet APIs"
        scope = "authorized incident response"
    strings:
        $s1 = "Windows Update Client" ascii
        $s2 = "Software\\Microsoft\\Windows\\CurrentVersion\\Run" ascii
        $s3 = "InternetOpenA" ascii
        $s4 = "HttpSendRequestA" ascii
        $p1 = "\\Users\\Public\\Libraries\\WindowsUpdate" ascii
    condition:
        uint16(0) == 0x5A4D and 3 of ($s*) or (uint16(0) == 0x5A4D and $p1)
}

风险与修复建议

处置时建议分为隔离、取证、清理、加固四步。

  • 隔离主机:先从网络层阻断 C2,不要立即关机,避免内存证据丢失。
  • 保留证据:保存样本、哈希、启动项、网络连接、事件日志、EDR 时间线。
  • 清理持久化:删除 Run 键、计划任务或异常服务,再删除样本文件。
  • 排查横向:根据相同哈希、相同路径、相同 C2、相同 User-Agent 在全网检索。
  • 重置凭据:如果中招用户具备运维权限,应重置其域账号、VPN、堡垒机和相关系统凭据。
  • 补齐日志:开启 4688 进程创建日志、PowerShell Script Block Logging,终端建议部署 Sysmon 或等效采集能力。

清理命令示例:

:: 删除启动项
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "Windows Update" /f

:: 结束进程
taskkill /pid 3620 /f

:: 删除样本目录,执行前确认已完成取证
rmdir /s /q "C:\Users\Public\Libraries\WindowsUpdate"

:: 添加临时阻断,正式环境建议在边界防火墙或 EDR 策略侧处理
netsh advfirewall firewall add rule name="Block suspicious C2 8443" dir=out action=block remoteip=185.xxx.xxx.21 protocol=TCP remoteport=8443

检测规则建议

如果有集中日志平台,可以从以下几个条件做关联检测:

  • 用户目录、Public 目录下出现伪系统更新命名的可执行文件。
  • 非浏览器进程访问非常规端口,并呈固定周期心跳。
  • 普通用户上下文写入 HKCU Run 且目标路径位于 Public、Temp、AppData。
  • 进程 User-Agent 伪装为 Windows Update,但进程路径不是系统组件。
  • 短时间内出现文件创建、Run 键写入、外联三类行为。
经验上,单点 IOC 很容易失效,行为链更稳定。比如“Public 目录落地 + HKCU Run 持久化 + WinINet 周期外联”比单独匹配 IP 更有价值。

总结

这类轻量远控木马并不复杂,但在内网里很常见,主要依赖伪装路径、低权限持久化和周期心跳维持控制。逆向分析时不需要追求完整复原所有代码,优先还原 C2、持久化、指令集和日志留痕点,才能支撑后续全网排查和闭环修复。

实际处置中,建议把样本逆向结果转成可执行的检测项:哈希、路径、注册表、网络特征、Sysmon 事件和 YARA 规则。这样才能从单机清理推进到内网范围的确认和修复。

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

这类样本建议不要把“启动项、C2、日志”拆成三个孤立模块看,最好先建立一条时间线:样本落地 → 持久化注册 → 首次外联 → 配置/命令交互 → 清理痕迹。逆向时静态结论和主机侧观测要互相印证,否则很容易把安装器行为误判成木马主体行为。

1. 先做隔离和基线

  • 使用快照虚拟机,禁用共享剪贴板、共享目录和宿主机凭据。
  • C2 不要直接放通公网,优先在隔离网段用 INetSim、FakeNet-NG 或自建 DNS/HTTP 模拟服务观察请求。
  • 执行前记录进程、服务、计划任务、启动项和网络状态,执行后再做差异比对。
wmic process list full > before_process.txt
schtasks /query /fo LIST /v > before_tasks.txt
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" > before_run_user.txt
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" > before_run_machine.txt
netstat -ano > before_netstat.txt

2. 启动项不要只盯 Run 键。常见样本会把真实载荷放到用户目录或临时目录,再通过计划任务、服务、WMI 永久事件订阅或快捷方式启动。重点记录“启动位置、执行命令、父进程、文件签名和创建时间”,尤其注意命令行中的 powershell -enc、mshta、rundll32、regsvr32 和脚本解释器。

# 计划任务
schtasks /query /fo CSV /v

# 服务路径
Get-CimInstance Win32_Service |
  Select-Object Name,StartMode,State,PathName |
  Format-List

# WMI 永久事件订阅
Get-CimInstance -Namespace root\subscription -Class __EventFilter
Get-CimInstance -Namespace root\subscription -Class CommandLineEventConsumer
Get-CimInstance -Namespace root\subscription -Class __FilterToConsumerBinding

如果样本通过注册表启动,建议同时检查 32 位和 64 位视图,以及 RunOnce、用户策略项和 Explorer Shell 扩展。对 PE 文件可以记录 SHA-256、签名状态、编译时间,但不要把编译时间当作可靠时间戳,最终还是以 Prefetch、Amcache、Shimcache、USN Journal 和事件日志互相校验。

3. C2 分析最好从“协议字段”入手,而不是只描述“连接了某个 IP”。建议分别记录:

  • DNS:查询域名、TTL、失败重试间隔、是否使用随机子域。
  • TCP/TLS:目标、端口、握手时间、SNI、证书指纹、心跳周期。
  • HTTP:方法、URI、Host、User-Agent、Cookie、请求体编码、响应长度和状态码。
  • 加密前后长度:固定头、长度字段、序列号、命令字和校验字段通常比正文更容易定位。

动态分析时建议在 WinHTTP、WinINet、WS2_32 相关调用处下断点,例如 connect、send、recv、WinHttpSendRequest、InternetReadFile。如果样本自行实现加密,重点跟踪“明文生成点”和“加密函数入口”,不要只在网络层抓密文。可以给每次外联做哈希和时间记录,便于和进程树关联。

# Sysmon 配置中至少关注网络连接、进程和 DNS
<RuleGroup name="network" groupRelation="or">
  <NetworkConnect onmatch="include">
    <DestinationPort condition="is any">80</DestinationPort>
    <DestinationPort condition="is any">443</DestinationPort>
  </NetworkConnect>
  <DnsQuery onmatch="include">
    <QueryName condition="contains">.</QueryName>
  </DnsQuery>
</RuleGroup>

实际部署时不建议只靠端口过滤,至少把 Image、DestinationIp、QueryName 和父子进程关系一并保留。Sysmon 事件中,进程创建(1)、网络连接(3)、DNS 查询(22)、文件创建(11)和注册表修改(12/13/14)组合起来,通常足够还原一轮感染链。

4. 日志留痕要区分“样本产生的日志”和“系统留下的痕迹”。木马自身的 log 往往会伪装成更新、诊断或缓存文件,先看写入路径、文件句柄和写入格式,再判断用途。系统侧重点检查:

  • Security:4688(进程创建,需启用命令行审计)。
  • PowerShell:4103/4104,关注脚本块和编码命令。
  • TaskScheduler/Operational:计划任务创建和运行。
  • Microsoft-Windows-WMI-Activity/Operational:WMI 执行记录。
  • Sysmon:进程、网络、DNS、文件和注册表事件。
# 查询最近 24 小时内的 PowerShell 脚本块日志
Get-WinEvent -FilterHashtable @{
  LogName = 'Microsoft-Windows-PowerShell/Operational'
  Id = 4104
  StartTime = (Get-Date).AddHours(-24)
} | Select-Object TimeCreated, Message

# 按 PID 关联网络连接和进程路径
Get-NetTCPConnection -State Established |
  Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess |
  ForEach-Object {
    $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
    [pscustomobject]@{
      PID=$_.OwningProcess
      Process=$p.Path
      Remote="$($_.RemoteAddress):$($_.RemotePort)"
    }
  }

最后建议把静态 IOC、行为 IOC 和关联条件分开输出。例如单独的 IP 或文件名误报率较高,而“某哈希创建计划任务 + 非常规父进程启动 + 固定周期 DNS/HTTP 心跳”更适合作为检测规则。清理时也不要直接删除启动项和样本,先导出注册表、保存内存和相关事件日志,否则后续很难复盘 C2 配置和持久化链路。

补充一个容易被忽略的点:这类远控样本看“启动项”和“C2”时,最好把父子进程链和注册表写入者一起记下来,不然只看到 Run 项里的路径,后面很难判断是 dropper 写的、主体写的,还是二阶段模块写的。 可以加几组更细的采集点:
rem 启动项相关,含 Wow6432Node
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

rem 常见服务持久化
sc query state= all
reg query "HKLM\SYSTEM\CurrentControlSet\Services" /s /f ".exe"

rem WMI 持久化,这个很多样本会漏看
wmic /namespace:\\root\subscription PATH __EventFilter get Name,Query
wmic /namespace:\\root\subscription PATH CommandLineEventConsumer get Name,CommandLineTemplate
wmic /namespace:\\root\subscription PATH __FilterToConsumerBinding get Filter,Consumer

rem 最近执行痕迹
dir /a /t:w "%APPDATA%"
dir /a /t:w "%LOCALAPPDATA%"
dir /a /t:w "%TEMP%"
网络侧建议不要只看域名和 URL,顺手把第一次外联前后的进程句柄、DNS 缓存、TCP 连接快照抓一下。远控经常先连硬编码 IP,失败后再走 DGA 或备用域名,单看 FakeNet 的 HTTP 记录容易漏掉前面的探测逻辑。
ipconfig /displaydns > dns_cache.txt
netstat -ano > netstat.txt
tasklist /svc > task_svc.txt
如果样本用了 WinHTTP/WinINet,可以在动态调试里重点盯这些 API: - `InternetOpenUrlW / HttpSendRequestW` - `WinHttpConnect / WinHttpOpenRequest / WinHttpSendRequest` - `WSAStartup / connect / send / recv` - `DnsQuery_W` x64dbg 里可以直接对这些 API 下断,命中后看参数里的域名、路径、User-Agent、POST body 长度。有些样本配置是运行时解密的,静态搜字符串搜不到,断在 `connect/send` 之前反而更省时间。 日志留痕这块也可以和时间线对齐看。比如样本注册服务、计划任务、登录自启之后,通常能在这些事件里看到辅助证据:
wevtutil qe Security /q:"*[System[(EventID=4688)]]" /f:text /c:20
wevtutil qe Microsoft-Windows-TaskScheduler/Operational /f:text /c:30
wevtutil qe System /q:"*[System[(EventID=7045)]]" /f:text /c:20
wevtutil qe Microsoft-Windows-WMI-Activity/Operational /f:text /c:30
另外建议把 Procmon 过滤规则提前配好,不要执行后再临时翻海量事件。至少过滤: - `Process Name is 样本名.exe` - `Operation is RegSetValue` - `Operation is CreateFile` - `Operation is WriteFile` - `Operation is Process Create` - `Path contains CurrentVersion\Run` - `Path contains \Startup` - `Path contains \Tasks` 最后落报告时,别只写“写入启动项”“访问 C2”。可以按这种格式记录,后续复现和比对家族会更清楚:
[T+00:03] sample.exe 创建 %APPDATA%\xxx\svchost.exe
[T+00:04] sample.exe 写入 HKCU\...\Run\Windows Update = "%APPDATA%\xxx\svchost.exe"
[T+00:06] svchost.exe 发起 DNS 查询 example.com
[T+00:07] svchost.exe POST /gate.php,UA=...
[T+00:10] 收到配置,解密后包含 sleep、cmd、download 三类命令
这样能把安装器、主体、通信模块和清理动作分开,不容易把一次性落地行为误判成长期驻留逻辑。

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

最近浏览 0

  • 没有会员查看此页面。