发布于8小时前8小时 背景本文记录一次授权内网排查中的 Windows 远控样本分析过程。告警起点是一台办公终端周期性访问未知 443 端口,EDR 同时记录到非系统目录程序创建计划任务并操作 dllhost.exe。分析目标不是简单提取域名或删除文件,而是确认样本加载链、持久化位置、进程注入方式、权限边界及可能的横向活动。样本只能在快照可回滚、禁止直连互联网的隔离环境中运行。建议使用 FakeNet-NG 或 INetSim 接管 DNS、HTTP 和 TLS 流量,不要让样本接触真实业务网络、域凭据、共享目录或宿主机剪贴板。一、现场现象与证据固定终端上的可疑文件位于 C:\ProgramData\WinCache\UpdateHelper.exe。首次处置时不要直接双击、删除或使用杀毒软件清理,否则计划任务、内存载荷和时间线可能被破坏。先隔离主机网络,并固定文件、进程、网络连接和事件日志。$sample = 'C:\ProgramData\WinCache\UpdateHelper.exe' Get-Item $sample | Format-List FullName,Length,CreationTimeUtc,LastWriteTimeUtc Get-FileHash $sample -Algorithm SHA256 Get-AuthenticodeSignature $sample | Format-List Status,SignerCertificate Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name,ExecutablePath,CommandLine | Export-Csv C:\IR\processes.csv -NoTypeInformation Get-NetTCPConnection | Select-Object State,LocalAddress,LocalPort,RemoteAddress,RemotePort,OwningProcess | Export-Csv C:\IR\connections.csv -NoTypeInformation schtasks /Query /TN "\Microsoft\Windows\WDI\WDI-Update" /XML > C:\IR\WDI-Update.xml wevtutil epl Microsoft-Windows-TaskScheduler/Operational C:\IR\TaskScheduler.evtx wevtutil epl Microsoft-Windows-Sysmon/Operational C:\IR\Sysmon.evtx wevtutil epl Security C:\IR\Security.evtx现场观察到的关键链路如下:UpdateHelper.exe 无有效数字签名,父进程为用户下载目录中的安装程序。样本创建计划任务 \Microsoft\Windows\WDI\WDI-Update,触发方式为用户登录后延迟执行,运行账户为 SYSTEM。UpdateHelper.exe 启动挂起状态的 dllhost.exe,随后出现跨进程内存写入行为。dllhost.exe 每隔约 60 秒发起一次外连,间隔存在约 15 秒抖动,目的端口固定为 443,但流量并非浏览器产生。二、静态分析:识别加载器而不是只看字符串样本为 64 位 PE,导入表很小,只保留 LoadLibraryW、GetProcAddress、VirtualAlloc 等少量函数。节区中 .rsrc 熵值明显偏高,说明主体载荷可能被压缩或加密存放。此类加载器直接执行 strings 往往只能得到诱饵版本信息,需要同时检查节区、资源和动态解析 API 的位置。certutil -hashfile UpdateHelper.exe SHA256 sigcheck64.exe -nobanner -a -h -i UpdateHelper.exe floss.exe -n 6 UpdateHelper.exe > floss.txt capa.exe -vv UpdateHelper.exe > capa.txt python - <<PY import math import pefile from collections import Counter path = 'UpdateHelper.exe' pe = pefile.PE(path, fast_load=False) print('ImageBase:', hex(pe.OPTIONAL_HEADER.ImageBase)) print('EntryPoint:', hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)) for sec in pe.sections: data = sec.get_data() counts = Counter(data) entropy = 0.0 for count in counts.values(): p = count / len(data) if data else 0 if p: entropy -= p * math.log2(p) name = sec.Name.rstrip(b'\x00').decode(errors='replace') print(name, hex(sec.VirtualAddress), len(data), round(entropy, 3)) for entry in getattr(pe, 'DIRECTORY_ENTRY_IMPORT', []): dll = entry.dll.decode(errors='replace') names = [] for imp in entry.imports: names.append(imp.name.decode(errors='replace') if imp.name else f'ord:{imp.ordinal}') print(dll, names) PY本次样本的 .rsrc 熵值为 7.82,资源尾部存在 CFG0 标记。解包后可见一个反射加载 DLL 和一段配置数据。配置使用单字节异或混淆,并不具备真正的密码学强度;字段包括互斥体、休眠时间、启动方式和两个候选 C2。分析记录中应使用脱敏域名,例如 sync-gw.invalid,避免误传播仍然有效的基础设施。静态导入中出现 VirtualAlloc、WriteProcessMemory、GetThreadContext、SetThreadContext 和 ResumeThread 时,应重点验证进程空洞或相近的注入流程。不过仅凭 API 名称不能定性,因为这些 API 也可能被调试器、安装器使用,最终结论必须和进程关系、内存权限及线程起始地址关联。三、动态调试:还原解密和注入链在隔离虚拟机中使用 x64dbg、Procmon 和 Process Monitor Backing File 记录行为。调试时可在 VirtualAlloc、VirtualProtect、WriteProcessMemory、SetThreadContext、QueueUserAPC、NtUnmapViewOfSection 和 ResumeThread 附近设置断点。重点不是逐条单步,而是在内存解密完成后及时转储明文载荷。bp kernel32!VirtualAlloc bp kernel32!VirtualProtect bp kernel32!WriteProcessMemory bp kernel32!SetThreadContext bp kernel32!ResumeThread bp ntdll!NtUnmapViewOfSection bp ntdll!NtWriteVirtualMemory bp ntdll!NtResumeThread实际执行顺序为:创建互斥体 Global\WDI_{7A4B9C2E},避免同一主机重复运行。读取自身资源,定位 CFG0 标记,对后续数据进行异或解码并解压。以 CREATE_SUSPENDED 标志启动 C:\Windows\System32\dllhost.exe。取消映射原始映像,在目标进程中申请 RW 内存并写入解包后的 PE。修复重定位和导入表,将载荷区域改为 RX,修改线程上下文后恢复线程。退出加载器,后续心跳和命令执行均由 dllhost.exe 承担。判断进程空洞时可以检查三个相互印证的特征:dllhost.exe 的映像路径仍指向系统文件;主线程起始地址落入匿名可执行内存而不是已加载模块;内存中的 PE 头、节区布局与磁盘上的 dllhost.exe 不一致。仅看到父子进程异常不足以确认注入。四、C2 行为与网络侧验证FakeNet-NG 捕获到样本先进行 DNS 查询,随后连接 TCP 443。流量首包不是标准 TLS ClientHello,而是固定四字节标记、版本号、主机标识长度和加密负载,因此基于端口判断为 HTTPS 会漏检。心跳包长度集中在 96 至 144 字节,服务器不可达时采用 5、15、30、60 秒递增退避。Wireshark 可先使用以下过滤条件缩小范围:dns.qry.name || tcp.dstport == 443 tcp.stream eq 7 tcp.len > 0 && ip.addr == 192.0.2.25 tls.handshake.extensions_server_name如果 443 流量无法被 TLS 解析、没有 SNI、首包字节稳定且连接周期固定,应按自定义协议继续检查,不能直接归类为“加密流量不可见”。可结合 Zeek conn.log、dns.log 以及代理设备日志统计周期性、目的地址稀有度和单连接字节数。从内存载荷导出的功能字符串和命令分发表明,该远控包含主机信息收集、文件读写、屏幕截取和命令执行模块。没有发现键盘记录模块,也没有看到浏览器凭据解密代码。报告中应区分“代码具备能力”和“现场已经执行”:只有对应线程、文件、网络回包或日志证据存在时,才能认定某功能被实际调用。五、持久化与权限边界判断计划任务 XML 显示运行主体为 SYSTEM,且任务位于受保护目录。普通用户进程无法直接完成该配置,因此需要继续确认加载器是否继承了安装程序的管理员令牌,或者此前已发生提权。建议核对以下日志:Security 4688:进程创建及完整命令行。Security 4624、4672:登录类型、管理员特权分配和账户来源。TaskScheduler Operational 106、140、141:任务注册、更新和删除。Sysmon 1、3、7、8、10、11、13、22、25:进程、网络、模块加载、远程线程、进程访问、文件、注册表、DNS 和进程篡改。System 7045 与 Security 4697:是否额外创建服务。WMI-Activity 5857 至 5861:是否存在 WMI 永久事件订阅或远程执行。本次事件中,4688 显示加载器由提权后的安装程序启动,随后以高完整性令牌创建 SYSTEM 计划任务。未发现 UAC 绕过痕迹,因此权限边界突破点是用户主动批准的伪造安装程序,而不是操作系统本地提权漏洞。横向排查不能只搜索样本文件哈希。还应检索同名任务、互斥体关联字符串、异常 dllhost.exe 网络连接,以及 4624 登录类型 3、5140 管理共享访问、7045 远程服务创建等事件。文件哈希在重新打包后容易变化,行为组合通常更稳定。六、检测规则示例以下 YARA 规则针对本次加载器的稳定结构编写。任务路径和互斥体属于高置信特征,通用注入 API 只作为组合条件,避免把普通安装程序全部命中。import "pe" rule Win64_WDI_RemoteAccess_Loader { meta: description = "Detects the analyzed WDI-themed RAT loader" scope = "authorized incident response" strings: $task = "\\Microsoft\\Windows\\WDI\\WDI-Update" wide ascii $mutex = "Global\\WDI_{" wide ascii $cfg = { 43 46 47 30 } $api1 = "WriteProcessMemory" ascii $api2 = "SetThreadContext" ascii $api3 = "ResumeThread" ascii condition: uint16(0) == 0x5A4D and pe.machine == pe.MACHINE_AMD64 and $cfg and 1 of ($task, $mutex) and 2 of ($api*) }主机侧还可以围绕“非系统父进程创建挂起 dllhost.exe,随后发生进程访问并连接外网”建立关联规则。单独对 dllhost.exe 外连告警可能产生噪声,建议同时约束父进程路径、签名、线程起始地址和网络时间窗口。七、清除与修复清除顺序应为隔离、取证、阻断、移除持久化、删除载荷、凭据处置和复核。不要只结束 dllhost.exe 或删除 UpdateHelper.exe;计划任务可能再次拉起副本,远控也可能已经获得用户令牌。# 先保存任务和文件证据,再执行清理 schtasks /End /TN "\Microsoft\Windows\WDI\WDI-Update" schtasks /Delete /TN "\Microsoft\Windows\WDI\WDI-Update" /F Stop-Process -Id <suspicious_dllhost_pid> -Force Remove-Item 'C:\ProgramData\WinCache\UpdateHelper.exe' -Force Remove-Item 'C:\ProgramData\WinCache\wincache.dat' -Force # 清理后复查 schtasks /Query /FO LIST /V | findstr /I "WDI-Update WinCache" Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'dllhost.exe' -and $_.ExecutablePath -ne 'C:\Windows\System32\dllhost.exe' } Get-NetTCPConnection | Where-Object State -eq 'Established'在 DNS、防火墙和代理侧阻断已确认的 C2,但保留首次、末次访问时间和命中主机清单。重置受影响用户密码,吊销当前登录会话、VPN 会话和应用令牌。若存在 LSASS 访问或浏览器数据读取证据,应扩大凭据轮换范围。启用 4688 命令行审计、PowerShell 4103/4104、TaskScheduler Operational 和合理裁剪后的 Sysmon 规则。使用 WDAC 或 AppLocker 限制 ProgramData、用户下载目录和临时目录中的未签名可执行文件。复核本地管理员成员、计划任务、服务、启动项、WMI 订阅和 Defender 排除项,防止残留第二种持久化方式。如果无法证明载荷未执行凭据窃取或内核级操作,业务终端优先重装并从可信基线恢复,不建议仅做文件级清理。总结远控样本分析的重点不是得到一个域名或文件哈希,而是把“入口文件、解包过程、注入目标、持久化、C2、权限来源和横向痕迹”串成可验证的证据链。本次样本最终确认通过计划任务维持 SYSTEM 权限,将载荷空洞注入 dllhost.exe,并使用伪装为 443 的自定义协议周期回连。静态特征用于快速归类,动态调试确认真实执行路径,主机和网络日志则用于判断影响范围。修复时只有同时处理持久化、凭据风险和同类行为狩猎,才能避免把一次远控入侵误处理成普通恶意文件告警。 逆向分析、样本行为与调试流程示意 服务器、云资产与权限边界梳理示意
8小时前8小时 这类事件不要先删加载器,建议按“保全现场 → 确认执行链 → 还原 C2 → 清除与轮换凭据”的顺序处理。直接删除样本会丢失内存注入、父子进程和持久化证据。 1. 先隔离网络并保留内存、连接信息 mkdir C:\IR tasklist /v > C:\IR\tasklist.txt wmic process get ProcessId,ParentProcessId,ExecutablePath,CommandLine /format:csv > C:\IR\process.csv netstat -abno > C:\IR\netstat.txt ipconfig /displaydns > C:\IR\dns-cache.txt arp -a > C:\IR\arp.txt wevtutil epl System C:\IR\System.evtx wevtutil epl Security C:\IR\Security.evtx wevtutil epl Microsoft-Windows-PowerShell/Operational C:\IR\PowerShell.evtx wevtutil epl Microsoft-Windows-Windows Defender/Operational C:\IR\Defender.evtx 有条件的话再做完整内存镜像。重点检查加载器进程的父进程、外连 PID,以及同一进程中是否存在私有可执行内存、异常线程起始地址或被替换的映像段。若怀疑进程注入,仅看磁盘样本通常不够。 2. 从加载器行为关联到 C2 把连接记录中的 PID 回查到进程命令行,并核对 DNS 缓存、代理配置和证书信息: Get-NetTCPConnection | Sort-Object OwningProcess | Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,State,OwningProcess Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,ExecutablePath,CommandLine netsh winhttp show proxy Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' | Select-Object ProxyEnable,ProxyServer,AutoConfigURL 取证时不要只记录域名。建议同时保留目标 IP、端口、首次/末次出现时间、DNS 解析结果、HTTP Host、TLS SNI、证书指纹和固定 Beacon 间隔。若流量看似正常 HTTPS,但连接周期高度稳定、每次上下行字节数接近,也应纳入 C2 判断。 3. 排查常见持久化点 schtasks /query /fo LIST /v > C:\IR\schtasks.txt sc query type= service state= all > C:\IR\services.txt reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run /s reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run /s reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" /s reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Shell reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit Get-CimInstance -Namespace root\subscription -ClassName __EventFilter Get-CimInstance -Namespace root\subscription -ClassName CommandLineEventConsumer Get-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding 还应核对启动目录、服务二进制路径、计划任务 Action、WMI 永久事件订阅,以及用户目录下新出现的 DLL/EXE。服务路径无引号、指向 AppData/ProgramData/Temp,或计划任务调用 rundll32、regsvr32、mshta、powershell -enc,都需要重点确认。 4. 用时间线验证,不要只依赖文件时间戳 加载器可能回改时间。可交叉比对 Prefetch、Amcache、Shimcache、Defender、PowerShell 和计划任务日志。重点事件包括 Security 4688、PowerShell 4104、任务计划 106/140/141、服务安装 7045,以及 Defender 检测与隔离记录。若系统原先未开启进程创建审计,4688 可能不完整,应以多源证据互相印证。 5. 清除时按 IOC 对象逐项处理 确认对应关系后,再停止恶意进程、禁用持久化项、隔离文件并封禁域名/IP。样本先计算哈希并记录路径: Get-FileHash 'C:\path\sample.exe' -Algorithm SHA256 Get-AuthenticodeSignature 'C:\path\sample.exe' | Format-List # 示例:确认任务确属恶意后再执行 schtasks /change /tn "\可疑任务名" /disable schtasks /delete /tn "\可疑任务名" /f # 示例:确认服务确属恶意后再执行 sc.exe stop SuspiciousService sc.exe delete SuspiciousService 如果已经出现 LSASS 访问、浏览器凭据窃取、令牌盗用、横向移动或域管理员登录痕迹,不建议把“文件删除后不再外连”视为清除完成。更稳妥的是重装受影响主机,并在可信设备上轮换本地管理员、域账号、VPN、邮箱、浏览器保存密码及 API 密钥,同时吊销现有会话和令牌。最后用原有 C2 IOC、文件哈希、计划任务名和异常命令行在全网回溯,避免只处理首台告警主机。
创建帐户或登录后发表意见