42个被武器化的GitHub储存库揭示了一个隐藏的npm发布者
Detection stack
- AIDR
- Alert
- ETL
- Query
摘要
一个被跟踪为的复杂活动 testmetest 使用恶意的 npm 包和被入侵的 GitHub 仓库来窃取凭据并自动化恶意包发布。攻击者依赖于多态包装器、原生 Node.js 插件和加密负载来规避检测。该活动还涉及用于扫描和利用 cPanel 漏洞的基础设施。
调查
JFrog 安全研究人员识别出了 42 个武器化的 GitHub 仓库以及多个恶意 npm 包。他们发现攻击者使用了一种原生插件伪装技术,其中一个编译的 .node 文件在运行时解密隐藏的有效负载。调查还将该活动与通过 CVE-2026-41940 攻击 cPanel 系统的 shellpanel 扫描器联系在一起。
缓解措施
用户应移除已识别的恶意 npm 包并从可信来源重建受影响的系统。组织必须更换所有可能被入侵的凭据,包括 GitHub、npm 和云令牌。还必须对仓库进行审核,寻找未经授权的配置文件,如 .github/init.js 和在 package.json 文件或 Makefile 中意外的执行钩子。
响应措施
当检测到恶意活动时,立即撤销暴露的密钥并更换凭据。搜寻持久机制,如 net-health-checker or pkg-runtime。审查 GitHub Actions 日志,查找未经授权的工作流,并监控系统中写入临时目录的解密负载。
攻击流程
我们仍在更新此部分。
检测
在 Linux 主机上创建了隐藏文件(通过 file_event)
可疑的 NodeJS 子进程 [Windows](通过 cmdline)
可能由异常进程发起的 GitHub 文件下载(通过 network_connection)
Nohup 使用(通过 cmdline)
可疑的 NodeJS 子进程 [Linux](通过 cmdline)
指向可疑目录的可疑 Chmod 执行(通过 cmdline)
下载到可疑文件夹(通过 cmdline)
检测 IOCs(HashSha256):超越 testmetest:原生插件伪装和 42 个武装的 GitHub 仓库揭示隐藏的 npm 发布者
检测 IOCs(SourceIP):超越 testmetest:原生插件伪装和 42 个武装的 GitHub 仓库揭示隐藏的 npm 发布者
检测 IOCs(DestinationIP):超越 testmetest:原生插件伪装和 42 个武装的 GitHub 仓库揭示隐藏的 npm 发布者
通过 IsDebuggerPresent 或 CheckRemoteDebuggerPresent 的调试器存在检测 [Windows 安全事件日志]
可疑的进程创建和临时 JS 文件执行 [Windows 进程创建]
原生 Node.js 插件执行检测 [Windows 图像加载]
检测到恶意 Node 插件进程执行 [Linux 进程创建]
可疑的原生插件内存映射读取 [Google Cloud Platform]
模拟执行
-
攻击叙述 & 指令: 攻击者已成功在用户的临时目录中投放了恶意的 JavaScript 有效负载,将其命名为
.nc以可能模仿与 Netcat 相关的文件或仅仅是为了模糊其用途。为此,攻击者使用了一个加载器,该加载器调用CreateProcessAWin32 API 来启动 Windows Script Host(wscript.exe),将临时文件作为参数。这一特定序列——使用 ANSI 版本的进程创建 API 来运行脚本%TEMP%——正是检测规则旨在拦截的模式。 -
回归测试脚本:
# 模拟脚本:触发“可疑进程创建和临时 JS 文件执行” # 1. 定义路径 $tempPath = $env:TEMP $targetFile = Join-Path $tempPath ".nc" # 2. 在 %TEMP% 目录中创建一个虚假恶意的 JS 文件 # 注意:我们将其命名为 .nc 以符合检测逻辑需求 "WScript.Echo('模拟恶意活动');" | Out-File -FilePath $targetFile -Encoding ascii Write-Host "[+] 已在: $targetFile 创建恶意文件" # 3. 通过 wscript.exe 模拟执行 # 在真实场景中,包含 'CreateProcessA' 的 'CallTrace' 是由被恶意软件加载器使用的底层 Windows API 调用生成的。 # 通过 PowerShell/CMD 运行此命令将生成进程创建事件。 Write-Host "[+] 执行脚本以触发检测..." Start-Process "wscript.exe" -ArgumentList "`"$targetFile`"" Write-Host "[+] 已发送模拟命令。" -
清理命令:
# 清理脚本:移除模拟工件 $tempPath = $env:TEMP $targetFile = Join-Path $tempPath ".nc" if (Test-Path $targetFile) { Remove-Item -Path $targetFile -Force Write-Host "[+] 清理成功:已移除 $targetFile。" } else { Write-Host "[!] 清理失败:文件未找到。" }