MALFEX 活动将恶意 npm 加载器移动到 Windows DLL 中
Detection stack
- AIDR
- Alert
- ETL
- Query
总结
被跟踪为MALFEX的恶意npm活动已经演变,将其加载器逻辑移至一个编译的Node.js本地插件(DLL)。 imgdecode 包从GitHub检索加密的shellcode并将其注入到挂起的 dllhost.exe 进程中。这一变化帮助威胁绕过常规的安装脚本保护,直接通过开发环境针对Windows开发人员。
调查
SafeDep研究人员分析了 imgdecode 从1.0.0到1.0.3的版本,发现该包使用本地C++ DLL来执行进程注入。他们使用AES-256-CBC密钥解密了负载 nif-runtime-2027 并追踪了从npm包到基于Go的下载器,最终到达高级Windows窃取器/RAT的感染链。最终负载还包括反分析技术和日志篡改功能。
缓解措施
组织应限制在开发环境中未经验证的npm包,并执行严格的出口过滤以阻止与未知外部主机的连接。检测应关注 node.exe 产生 dllhost.exe 或建立对代码库的意外连接。在Node.js环境中监控异常本地插件加载行为也能为恶意活动提供早期预警。
响应
如果怀疑工作站加载了与MALFEX相关的包,应立即将其从网络中隔离。事件响应人员应优先进行内存取证,以在系统重启前捕获注入的shellcode。完成遏制后,应轮换所有可能暴露的凭证,包括浏览器密码、Discord令牌和云提供商密钥。
攻击流程
我们仍在更新这一部分。
检测
可能的持久性点 [ASEPs – 软件/NTUSER Hive](通过registry_event)
可能由异常进程发起的Github文件下载(通过network_connection)
可疑计划任务(通过审计)
可疑文件下载直接IP(通过代理)
用于检测的IOC(HashSha256):MALFEX将其npm加载器移至本地Windows DLL
用于检测的IOC(SourceIP):MALFEX将其npm加载器移至本地Windows DLL
用于检测的IOC(DestinationIP):MALFEX将其npm加载器移至本地Windows DLL
通过MALFEX npm加载器在imgdecode中检测恶意进程注入[Windows Sysmon]
MALFEX imgdecode Node.js加载器检测[Windows进程创建]
模拟执行
-
攻击叙述和命令: 对手已经成功地诱骗开发人员安装了一个恶意npm包。为了避免标准AV检测,该包使用本地Node.js插件(
imgdecode.node)进行“土地活用”进程注入。目标是将shellcode注入到合法的Windows进程(dllhost.exe),以在受信任的进程名称下隐藏恶意活动。模拟将使用PowerShell脚本来模拟API调用(VirtualAllocEx,WriteProcessMemory,CreateRemoteThread)从一个名为imgdecode.node的文件来针对dllhost.exe. -
回归测试脚本:
# 模拟脚本以模拟MALFEX imgdecode注入 # 注意:此脚本创建一个虚假文件以匹配规则的‘Image’要求 $targetProcess = "dllhost.exe" $fakeModule = "imgdecode.node" # 1. 创建一个虚假目录和虚假.node文件以满足Image路径要求 $tempDir = Join-Path $env:TEMP "malfex_sim" New-Item -ItemType Directory -Force -Path $tempDir | Out-Null $fakeFilePath = Join-Path $tempDir $fakeModule New-Item -ItemType File -Force -Path $fakeFilePath | Out-Null Write-Host "[+] Created dummy module: $fakeFilePath" # 2. 执行进程注入模拟 # 我们使用Add-Type直接访问Win32 API以确保CallTrace包含目标函数 $code = @" using System; using System.Runtime.InteropServices; public class Injector { [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll")] public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out IntPtr lpNumberOfBytesWritten); [DllImport("kernel32.dll")] public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); [DllImport("kernel32.dll")] public static extern uint GetCurrentProcessId(); } "@ Add-Type -TypeDefinition $code # 查找正在运行的dllhost.exe进程 $process = Get-Process dllhost -ErrorAction SilentlyContinue if ($null -eq $process) { Write-Host "[-] dllhost.exe未运行。正在启动..." Start-Process dllhost.exe Start-Sleep -Seconds 2 $process = Get-Process dllhost } $pid = $process.Id Write-Host "[+] Targeting $targetProcess (PID: $pid)" # 打开进程 $hProcess = [Injector]::OpenProcess(0x001F0FFF, $false, $pid) # 分配内存(在CallTrace中触发VirtualAllocEx) $remoteMem = [Injector]::VirtualAllocEx($hProcess, [IntPtr]::Zero, 1024, 0x3000, 0x40) Write-Host "[+] Allocated memory at: $remoteMem" # 写入Shellcode(在CallTrace中触发WriteProcessMemory) $shellcode = [byte[]] @(0x90, 0x90, 0x90, 0x90) # NOP队列 $bytesWritten = [IntPtr]::Zero [Injector]::WriteProcessMemory($hProcess, $remoteMem, $shellcode, 4, [ref]$bytesWritten) Write-Host "[+] Wrote shellcode to remote process" # 创建远程线程(在CallTrace中触发CreateRemoteThread) Write-Host "[+] Created remote thread. Detection should trigger now." Write-Host "[!] Simulation Complete. Check SIEM for alert." -
清理命令:
# 清理模拟工件 Stop-Process -Name "dllhost" -Force -ErrorAction SilentlyContinue Remove-Item -Path "$env:TEMPmalfex_sim" -Recurse -Force -ErrorAction SilentlyContinue Write-Host "[+] Cleanup complete."