发布于23小时前23小时 背景在一次已授权的终端排查中,EDR 发现某台 Windows 10 测试主机周期性访问外部 HTTPS 地址。进程树显示 explorer.exe 启动了位于 C:\ProgramData\UpdateCache\UpdateHost.exe 的未知程序,随后该程序创建计划任务,并间歇拉起 powershell.exe。样本没有有效数字签名,文件时间与所在目录的创建时间也不一致。本文以这一类典型远控木马为分析对象,重点说明如何在隔离环境中确认样本入口、持久化方式、C2 配置和主机留痕。涉及的地址、任务名和互斥体均为实验环境示例,操作仅适用于已授权分析。不要直接在办公网络或可访问生产凭据的虚拟机中运行未知样本。建议使用无共享剪贴板、无共享目录、快照可回滚的隔离虚拟机,并将网络接入 INetSim、FakeNet-NG 或受控代理。一、现场定位:先保留证据,再处理文件发现可疑程序后,不建议立即删除。直接删除会损失父子进程、任务创建时间、网络目的地址和配置数据等关键信息。应先记录文件元数据、进程树、网络连接、计划任务以及相关事件日志。$sample = 'C:\ProgramData\UpdateCache\UpdateHost.exe' # 文件摘要与基本属性 Get-Item $sample | Format-List FullName,Length,CreationTimeUtc,LastWriteTimeUtc,Attributes Get-FileHash $sample -Algorithm SHA256 Get-AuthenticodeSignature $sample | Format-List Status,StatusMessage,SignerCertificate # Sysinternals 签名和版本信息 sigcheck64.exe -accepteula -nobanner -h -i -m $sample # 当前进程与命令行 Get-CimInstance Win32_Process | Where-Object {$_.ExecutablePath -eq $sample} | Select-Object ProcessId,ParentProcessId,Name,ExecutablePath,CommandLine,CreationDate # 关联网络连接 Get-NetTCPConnection | Where-Object {$_.OwningProcess -in (Get-Process UpdateHost -ErrorAction SilentlyContinue).Id} | Select-Object State,LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess # 导出日志,避免后续清理或覆盖 wevtutil epl System C:\IR\System.evtx wevtutil epl Security C:\IR\Security.evtx wevtutil epl Microsoft-Windows-Sysmon/Operational C:\IR\Sysmon.evtx wevtutil epl Microsoft-Windows-TaskScheduler/Operational C:\IR\TaskScheduler.evtx如果进程仍在运行,可在隔离后制作内存转储。对于存在运行时解密、反射加载或配置仅驻留内存的样本,内存通常比磁盘文件更有价值。mkdir C:\IR -ErrorAction SilentlyContinue procdump64.exe -accepteula -ma (Get-Process UpdateHost).Id C:\IR\UpdateHost.dmp Get-FileHash C:\IR\UpdateHost.dmp -Algorithm SHA256转储文件可能包含令牌、Cookie、主机信息或其他敏感数据,应按取证材料控制访问,不要上传到公开平台。二、静态分析:确认 PE 结构与可疑能力先用 Detect It Easy、PE-bear 或 pefile 检查 PE 类型、编译时间、节区、导入表和 TLS 目录。编译时间只能作为弱线索,木马经常伪造 TimeDateStamp。更值得关注的是节区熵、RawSize 与 VirtualSize 的差异、入口点所在节区以及是否存在 TLS Callback。入口点位于高熵自定义节区,且导入函数很少:可能经过壳或运行时解析 API。存在 VirtualAlloc、VirtualProtect、WriteProcessMemory、CreateRemoteThread:需要检查是否有解包、注入或远程线程行为。存在 WinHttpOpen、WinHttpConnect、WinHttpSendRequest:可从参数交叉引用定位 HTTP 配置。存在 RegSetValueExW、CreateServiceW、Task Scheduler COM 接口:重点追踪持久化逻辑。存在 CryptUnprotectData:配置或凭据可能通过当前用户或本机 DPAPI 解密。可先用 FLOSS 和 capa 缩小范围。FLOSS 对栈字符串、简单异或字符串和运行时构造字符串通常比普通 strings 更有效;capa 则适合快速识别网络通信、服务创建、互斥体和进程注入等能力。floss.exe UpdateHost.exe > floss.txt capa.exe -v UpdateHost.exe > capa.txt strings64.exe -n 6 UpdateHost.exe > strings.txt # 查看 PE 头和导入表 llvm-readobj --file-headers --sections --coff-imports UpdateHost.exe本例样本的导入表较小,但在入口函数附近可以看到 LoadLibraryW 和 GetProcAddress 的循环调用。继续跟踪哈希比较函数后,可确认样本动态解析 winhttp.dll 中的网络 API。这类实现会削弱基于静态导入表的检测效果,但 API 名称、DLL 名称或哈希常量仍可能出现在解包后的内存中。三、动态调试:从关键 API 反推木马行为在 x64dbg 或 WinDbg 中,不必一开始逐指令跟踪。针对远控样本,更高效的方法是先在行为边界设置断点,再根据调用栈回到样本代码。建议关注以下位置:kernel32!CreateProcessW:观察子进程命令行及隐藏窗口参数。advapi32!RegSetValueExW:定位 Run 键或其他注册表持久化。taskschd 相关 COM 调用:确认计划任务名称、触发器和执行路径。winhttp!WinHttpConnect、winhttp!WinHttpOpenRequest、winhttp!WinHttpSendRequest:提取主机名、URI、请求头和请求体。ws2_32!connect:对自定义 TCP 协议记录目标地址和端口。crypt32!CryptUnprotectData:在函数返回后读取明文缓冲区。kernel32!VirtualProtect:寻找解包结束点或修改为可执行权限的内存区域。# WinDbg 示例:命中后打印关键参数并查看调用栈 bp kernel32!CreateProcessW bp advapi32!RegSetValueExW bp winhttp!WinHttpConnect bp winhttp!WinHttpOpenRequest bp winhttp!WinHttpSendRequest bp crypt32!CryptUnprotectData bp kernel32!VirtualProtect g # 断点触发后 k r 在 x64 Windows 调用约定下,前四个整数或指针参数通常位于 RCX、RDX、R8、R9。以 WinHttpConnect 为例,第二个参数 RDX 通常指向服务器名称宽字符串,可直接跟随内存查看。WinHttpOpenRequest 的对象路径同样可以从对应参数中取得。本例中,WinHttpConnect 收到的主机名并未直接保存在磁盘明文中,而是在调用前由一个循环解码到堆缓冲区。对该缓冲区设置硬件写断点后回溯,可定位到配置解密函数。解密后的结构包含版本号、轮询间隔、主机名、端口、URI 和互斥体名称。轮询间隔为 60 秒,并加入约 0 至 15 秒随机抖动,因此流量并非严格等间隔。四、持久化分析:计划任务与权限边界样本通过当前用户权限创建计划任务,任务路径为 \Microsoft\Windows\Maintenance\UpdateCheck,登录后延迟执行 UpdateHost.exe。由于样本运行在普通用户上下文,它无法直接写入 HKLM 服务项,但仍可利用用户可写目录和登录触发器维持驻留。# 定位任务定义及执行动作 Get-ScheduledTask | Where-Object {$_.TaskName -like '*UpdateCheck*'} | ForEach-Object { $_ | Select-Object TaskPath,TaskName,State,Author $_.Actions | Format-List Execute,Arguments,WorkingDirectory $_.Triggers | Format-List * $_.Principal | Format-List UserId,LogonType,RunLevel } # 查询任务创建、更新和删除事件 Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-TaskScheduler/Operational' Id=106,140,141 } | Select-Object TimeCreated,Id,Message # 同时检查常见自启动位置 Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' -ErrorAction SilentlyContinue Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run' -ErrorAction SilentlyContinue Get-CimInstance Win32_Service | Where-Object {$_.PathName -match 'ProgramData|AppData|Temp'}权限分析不能只看样本当前是否提权。还应检查任务动作指向的目录是否允许普通用户覆盖、任务是否以高权限账户运行,以及服务路径是否存在弱 ACL。如果高权限任务执行用户可写文件,即使当前木马仅获得普通用户权限,也可能形成后续提权条件。icacls C:\ProgramData\UpdateCache icacls C:\ProgramData\UpdateCache\UpdateHost.exe sc.exe qc SuspiciousService accesschk64.exe -accepteula -uwdqs Users C:\ProgramData五、C2 行为与网络侧验证动态调试显示样本使用 WinHTTP 发送 HTTPS POST,请求路径为 /api/v2/checkin。首次请求体包含主机名、用户名、系统版本、进程位数和样本生成的终端标识。后续响应决定是否执行命令、上传文件或调整轮询时间。如果流量由 TLS 加密,不建议仅依赖抓包内容。可以结合 DNS、代理、TLS 元数据和主机 API 参数进行关联:Sysmon 事件 ID 22:DNS 查询。Sysmon 事件 ID 3:进程级网络连接。代理日志:HTTP 方法、目标域名、URI、状态码和传输字节数。防火墙日志:目标 IP、端口、连接频率和持续时间。Schannel 或 TLS 采集设备:SNI、证书指纹和 JA3/JA4 等辅助特征。域名、IP 和证书都可能快速变化,不宜将单个地址作为唯一检测依据。更稳定的组合特征是:异常目录中的无签名进程、固定 URI、特定请求头顺序、近似固定的心跳周期,以及同一进程创建计划任务的行为链。六、日志关联:还原完整攻击时间线建议以样本首次落盘时间为中心,向前后各扩展至少 30 分钟。重点关联文件创建、进程启动、DNS、网络连接、注册表修改和计划任务事件。若启用了 Sysmon,可优先检查以下事件:事件 ID 1:进程创建,确认父进程、命令行和哈希。事件 ID 3:网络连接,关联 UpdateHost.exe 的远端地址。事件 ID 11:文件创建,追踪样本落盘及更新文件。事件 ID 13:注册表值设置,确认自启动或配置写入。事件 ID 22:DNS 查询,补充 C2 域名。事件 ID 25:进程篡改,辅助发现空洞化等行为。$start = (Get-Date).AddDays(-2) Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-Sysmon/Operational' StartTime=$start Id=1,3,11,13,22,25 } | Where-Object { $_.Message -match 'UpdateHost.exe|UpdateCache|UpdateCheck' } | Select-Object TimeCreated,Id,Message | Export-Csv C:\IR\timeline.csv -NoTypeInformation -Encoding UTF8如果未部署 Sysmon,仍可从安全日志 4688、任务计划日志、PowerShell 4103/4104、Defender Operational 日志、Prefetch、Amcache 和 SRUM 中补充证据。需要注意,4688 是否包含命令行取决于审计策略;PowerShell 脚本块日志也必须在事件发生前启用。七、用于内网排查的 YARA 规则根据逆向得到的互斥体、任务路径和 URI,可以编写初步 YARA 规则扫描磁盘样本。规则应使用多个独立特征组合,避免只凭一个通用字符串产生大量误报。rule Win_RAT_UpdateHost_Triage { meta: description = "Triage rule for analyzed UpdateHost RAT sample family" scope = "authorized incident response only" strings: $task = "Microsoft\\Windows\\Maintenance\\UpdateCheck" wide ascii $uri = "/api/v2/checkin" ascii $mtx = "Global\\UpdateHost_Instance_" wide ascii $ua = "WindowsUpdateClient/10.0" ascii condition: uint16(0) == 0x5A4D and filesize < 10MB and 3 of ($task,$uri,$mtx,$ua) }该规则适合对同批次样本进行快速排查,不应单独作为恶意判定依据。部署前应在正常软件集上回归测试,并记录命中路径、签名状态、文件哈希和首次出现时间。八、处置与修复建议先隔离受影响终端,再终止进程、禁用计划任务和封禁网络指标,避免样本收到新的远控指令。保留样本、内存转储、任务 XML、事件日志和代理日志,并计算 SHA-256,确保后续分析可复核。删除持久化前导出任务定义,确认任务是否由其他高权限账户创建,以及相同任务是否存在于其他终端。若样本具备凭据访问、浏览器数据读取或键盘记录能力,应轮换在该主机上使用过的域账户、VPN、邮箱和运维凭据。检查 C:\ProgramData、用户 AppData、Temp 和公共启动目录的 ACL,避免高权限任务或服务执行普通用户可覆盖的文件。为关键终端启用进程命令行审计、PowerShell 脚本块日志和合理裁剪的 Sysmon 配置,并集中保存日志。对出站网络实施代理或主机防火墙控制,普通办公终端不应能够任意直连外部高位端口。处置完成后持续观察至少一个原轮询周期的数倍时间,确认 DNS、TLS 和任务触发行为不再出现。删除计划任务和文件的操作应在取证完成后进行:# 先导出任务定义 schtasks.exe /Query /TN "\Microsoft\Windows\Maintenance\UpdateCheck" /XML > C:\IR\UpdateCheck.xml # 完成取证并确认任务恶意后再删除 schtasks.exe /Delete /TN "\Microsoft\Windows\Maintenance\UpdateCheck" /F Stop-Process -Name UpdateHost -Force -ErrorAction SilentlyContinue Remove-Item 'C:\ProgramData\UpdateCache\UpdateHost.exe' -Force # 最后复查残留 Get-ScheduledTask | Where-Object {$_.TaskName -like '*UpdateCheck*'} Get-NetTCPConnection | Where-Object {$_.RemotePort -eq 443 -and $_.State -eq 'Established'}总结远控木马分析的关键不是单独识别某个字符串或外联地址,而是建立从样本入口、配置解密、持久化、进程链到网络心跳的完整证据链。实际排查时,应先保留文件与日志,再通过静态分析筛选能力,通过 API 断点和内存观察提取运行时配置,最后把逆向结果转化为 YARA、日志查询和权限修复措施。只有同时清理持久化、控制凭据风险并修复可被滥用的权限边界,才能避免样本被简单删除后再次落地。 逆向分析、样本行为与调试流程示意 服务器、云资产与权限边界梳理示意
22小时前22小时 这类样本做“日志闭环”时,建议不要只记录任务名和 C2。计划任务名很容易随机化,真正稳定的是任务 XML 中的 Exec.Command、Arguments、Principal/UserId、触发器,以及落地文件哈希。 现场可以同时保全任务文件、TaskCache 注册表和事件日志,避免样本自删除任务后只剩零散记录: # 导出当前计划任务定义 Get-ScheduledTask | ForEach-Object { $name = ($_.TaskPath + $_.TaskName).TrimStart('\').Replace('\', '_') Export-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath | Out-File ".\tasks\$name.xml" -Encoding utf8 } # 保全计划任务文件及注册表 robocopy C:\Windows\System32\Tasks .\TasksBackup /E /COPYALL reg save "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache" .\TaskCache.hiv # 导出关键事件日志 wevtutil epl Microsoft-Windows-TaskScheduler/Operational .\TaskScheduler.evtx wevtutil epl Security .\Security.evtx wevtutil epl Microsoft-Windows-Sysmon/Operational .\Sysmon.evtx 时间线关联上重点看 Security 4698/4699,TaskScheduler/Operational 106、140、141、200、201,再用 Sysmon 1 的 ProcessGuid 串到 3(网络连接)、11(文件创建)、13(注册表修改)和 22(DNS)。尤其注意任务动作是直接启动木马,还是通过 cmd.exe /c、powershell.exe、rundll32.exe、regsvr32.exe 做了一层代理执行。 C2 配置提取建议同时做静态和动态验证。静态侧先定位 URL、域名、User-Agent、端口和互斥体附近的交叉引用;如果只看到高熵数据,就继续追配置解密函数的调用链,关注 Base64 后的 XOR、RC4/AES,以及硬编码 key/IV。动态侧可在解密函数返回后或 WinHTTP/WinINet 调用前下断点,直接取明文缓冲区;常见位置包括 WinHttpConnect、WinHttpOpenRequest、InternetConnectW、HttpSendRequestW 和 WSAConnect。 最终 IOC 最好区分“样本配置值”和“实际观测值”:配置里存在备用域名不代表本次运行访问过,反过来 DNS 解析结果和重定向地址也未必直接出现在配置中。报告中把任务创建时间、首次进程启动、首次 DNS、首次外连和回连周期放到同一条时间线上,闭环会更扎实,也更方便后续转成 Sysmon/Sigma 检测规则。
创建帐户或登录后发表意见