弹性安全实验室发布了 Axios 供应链泄露事件的初步分流和检测规则。这是对 RAT 和有效载荷的详细分析。
简介
Elastic Security Labs 发现了 axios npm 软件包的供应链漏洞,该软件包是 JavaScript 生态系统中最受依赖的软件包之一,每周下载量约为 100 万次。攻击者入侵了一个维护者账户,并发布了后门版本,通过恶意安装后钩子向 macOS、Windows 和 Linux 系统发送跨平台远程访问木马。
关键要点
- 一个被入侵的 npm 维护者账户(jasonsaayman)被用来发布两个被广泛使用的 Axios HTTP 客户端的恶意版本--1.14.1(标记为最新)和 0.30.4(标记为旧版)--这意味着默认的 npm install axios 会解析到一个后门软件包。
- 恶意 JavaScript 为 macOS、Windows 和 Linux 部署了特定平台的第二阶段植入程序
- 所有三个第二阶段有效载荷都是同一个 RAT的实现--相同的 C2 协议、命令集、信标步调和欺骗用户代理,分别用 PowerShell(Windows)、C++(macOS)和 Python(Linux)编写
- 滴管会执行反取证清理,删除自身并将其 package.json 换成一份干净的副本,从而抹去从
node_modules
前言
3 月30 ,2026 ,Elastic Security Labs 通过自动供应链监控检测到针对axiosnpm 软件包的供应链入侵。攻击者控制了属于该项目的主要维护者之一 jasonsaayman 的 npm 账户,并在 39 分钟内发布了两个后门版本。
axios 软件包是 JavaScript 生态系统中使用最广泛的 HTTP 客户端库之一。在发现时,最新和旧版本的发行标签都指向了被破解的版本,确保了大多数新安装的程序都会调用一个有后门的版本。
恶意版本引入了一个新的依赖项:plain-crypto-js,这是一个专用软件包,其安装后钩子会从 sfrclak[.]com:8000 静默下载并执行特定平台的第二阶段 RAT 植入。
除了爆炸半径之外,这次活动的亮点还在于第二阶段的工具。攻击者部署了同一 RAT的三个并行实施方案--Windows、macOS 和 Linux 各一个--所有实施方案都共享相同的 C2 协议、命令结构和信标行为。这并不是三个不同的工具,而是一个跨平台的植入框架,具有平台本地实现功能。
Elastic Security Labs 于3 月 31 日向axios 存储库提交了一份 GitHub 安全建议, 2026 ,网址为01:50 协调披露工作,确保维护者和 npm 注册表能够对受损版本采取行动。
随着社会各界在社交媒体上对这一泄露事件的关注,Elastic Security Labs 公开分享了早期发现,以帮助防御者实时做出反应。
这篇文章涵盖了整个攻击链:从 npm 级供应链入侵到混淆滴管,再到跨平台 RAT 的架构及其三个变种之间的显著差异。
活动概述
从 npm 注册表元数据中可以明显看出这种妥协。在恶意版本中,维护者电子邮件从jasonsaayman@gmail[.]com (存在于之前的所有合法版本中)变为ifstap@proton[.]me 。出版方式也发生了变化:
| 版本 | 发表人 | Method | 出处 |
|---|---|---|---|
axios@1.14.0 (合法) | jasonsaayman@gmail[.]com | GitHub 行动 OIDC | SLSA 出处证明 |
axios@1.14.1 (妥协) | ifstap@proton[.]me | 直接 CLI 发布 | 无 |
axios@0.30.4 (妥协) | ifstap@proton[.]me | 直接 CLI 发布 | 无 |
从具有 SLSA 来源的受信任 OIDC 发布者流程到具有更改电子邮件的直接 CLI 发布,这显然表明存在未经授权的访问。
时间线
- 2026-02-1817 :19 UTC-
axios@0.30.3由jasonsaayman@gmail[.]com - 2026-03-2719 :01 UTC-
axios@1.14.0通过 GitHub Actions OIDC 合法发布 - 2026-03-3005:57 UTC-
plain-crypto-js@4.2.0由nrwise(nrwise@proton.me) 发布 - 清除诱饵以建立注册表历史记录 - 2026-03-3023:59 UTC-
plain-crypto-js@4.2.1由nrwise发布 - 带有postinstall后门的恶意版本 - 2026-03-3100 :21 UTC-
axios@1.14.1由受损账户发布 - 已标记latest - 2026-03-3101 :00 UTC-
axios@0.30.4由受损账户发布 - 已标记legacy
受影响的软件包
axios@1.14.1- 恶意,在发现时标记为latestaxios@0.30.4- 恶意,在发现时标记为legacyplain-crypto-js@4.2.0- 清除诱饵,发布以建立注册表历史记录plain-crypto-js@4.2.1- 恶意、有效载荷运载工具 (postinstall后门)
安全版本: axios@1.14.0 (最后合法的 1.x 版本)和axios@0.30.3 (最后合法的0.30.x 版本)。
攻击者同时标记了最新通道和传统通道,最大限度地扩大了使用当前或传统 axios API 的项目的爆炸半径。
代码分析
第 1 阶段:纯密码-js 滴管程序
整个交付链都取决于 npm 的安装后生命周期钩子。安装任何一个已妥协的 axios 版本都会将plain-crypto-js@^4.2.1 作为依赖项,该依赖项声明
"scripts": {
"postinstall": "node setup.js"
}
这将导致 setup.js 在 npm 安装过程中自动执行,无需用户交互。
setup.js 文件使用双层编码方案来隐藏其行为:
- 第 1 层:字符串反转后进行 Base64 解码
- 第 2 层:使用密钥 OrDeR_7077 进行 XOR 密码,索引取决于位置(7 * i²% 10)。
所有关键字符串、模块名、URL 和 shell 命令都存储在一个编码数组 stq[] 中,并在运行时解码。解码内容揭示了运行基础设施:
特定平台交付
解码字符串表后,滴管会检查 os.platform(),然后进入三个传送例程之一。每次都会发送 HTTP POST 到http://sfrclak[.]com:8000/6202033,并带有特定平台的正文 - packages.npm.org/product0(macOS),packages.npm.org/product1(Windows),packages.npm.org/product2(Linux) - 允许 C2 从单一端点提供正确的有效载荷。packages.npm.org/前缀是一种故意让出境流量在网络日志中显示为良性 npm 注册表通信的尝试:
| Platform | 交付方式 | 第 2 阶段地点 | 伪装 |
|---|---|---|---|
| macOS | AppleScript 通过 oscript 使用 curl 下载二进制文件 | /Library/Caches/com.apple.act.mond | 苹果系统守护进程 |
| Windows | VBScript 下载 .ps1通过 curl,通过重命名后的 PowerShell (%PROGRAMDATA%\wt.exe) 执行 | %TEMP%\6202033.ps1 (瞬时) | 视窗终端 |
| Linux | 直接下载 curl 并执行 python3 | /tmp/ld.py | 无 |
反取证
滴管执行两种清理操作:
- 自删除:setup.js 通过 fs.unlink(__filename)自删除
- 软件包清单交换:名为 package.md 的干净文件(包含无安装后钩子的良性 4.2.0 版本配置)更名为 package.json、覆盖恶意版本
事后检查 node_modules/plain-crypto-js/package.json 发现没有安装后触发的痕迹。恶意的 setup.js 已经消失。只有 lockfile 和 npm 审计日志保留证据。
第 2 阶段:跨平台 RAT
三个第二阶段有效载荷:Windows 的 PowerShell、macOS 的 C++ 编译、Linux 的 Python 并不是三种不同的工具。它们是同一 RAT 规范的三种实现方式,共享相同的 C2 协议、命令集、信息格式和操作行为。这种一致性强烈地表明,这是一个由单一开发人员或紧密协调的团队根据共享的设计文档进行的工作。
共享架构
所有三个变体都具有以下相同的特性:
- C2 传输:HTTP POST
- 主体编码:Base64 编码的 JSON
- 用户代理:
mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0) - 信标间隔: 60 秒
- 会话 UID:16 个字符的随机字母数字字符串,每次执行时生成
- 外发信息类型:
FirstInfo,BaseInfo、CmdResult - 入站命令类型:
kill,peinject,runscript、rundir - 响应命令类型:
rsp_kill,rsp_peinject,rsp_runscript、rsp_rundir
欺骗的 IE8/Windows XP 用户代理字符串尤其值得注意,它在所有三个平台上都不合时宜,而它在 macOS 或 Linux 主机上的出现则是一个强有力的检测指标。
初始化和侦察
启动时,每个变体
- 生成会话 UID- 16 随机字母数字字符,包含在随后的每条 C2 报文中
- 检测操作系统和架构--报告特定平台的标识符(如 windows_x64、macOS、linux_x64)
- 枚举感兴趣的初始目录(用户配置文件、文档、桌面、配置目录)
- 发送包含 UID、操作系统标识符和目录快照的FirstInfo 信标
初始化后,植入程序进入主循环。第一个 BaseInfo 心跳包含一个全面的系统概况。所有平台收集的数据类别相同,只是底层应用程序接口不同:
| 收集的数据 | 视窗源代码 | macOS 源代码 | Linux 源代码 |
|---|---|---|---|
| 主机名 | %COMPUTERNAME% env var | gethostname() | /proc/sys/kernel/hostname |
| 用户名 | %USERNAME% env var | getuid() + getpwuid() | os.getlogin() |
| 操作系统版本 | WMI / 注册表 | sysctlbyname("kern.osproductversion") | platform.system()+ platform.release() |
| 时区 | 系统时区 | localtime_r() | datetime.timezone |
| 启动时间 | 系统正常运行时间 | sysctl("kern.boottime") | /proc/uptime |
| 安装日期 | 注册表/WMI | stat("/") 或 sysctl | /var/log/installer 或 /var/log/dpkg.log 的 ctime |
| 硬件型号 | WMI | sysctlbyname("hw.model") | /sys/class/dmi/id/product_name |
| CPU 类型 | WMI | sysctlbyname() | platform.machine() |
| Process list | 完整的 PID、会话、名称、路径 | popen("ps") (最多 1000) | 完整的 /proc 枚举(PID、PPID、用户、cmdline) |
随后的心跳是轻量级的,只包含一个时间戳,以确认植入体还活着。
指挥调度
C2 响应会被解析为 JSON 格式,类型字段决定了操作。所有三种变体都执行相同的四条命令:
kill - 自行终止。发送 rsp_kill 确认并退出。Windows 变体的持久机制(注册表键值+批处理文件)会在执行 kill 命令后继续存在,除非被明确清除;而 macOS 和 Linux 变体则没有自己的持久机制。
runscript - 执行脚本/命令。操作员的主要交互命令。接受一个 Script 字段(要执行的代码)和一个 Param 字段(参数)。当 Script 为空时,Param 将作为命令直接运行。执行机制与平台无关:
| Platform | 执行机制 |
|---|---|
| Windows | 使用 -NoProfile -ep 旁路的 PowerShell |
| macOS | 通过 /usr/bin/osascript 运行 AppleScript |
| Linux | 通过子进程运行 Shell(shell=True)或通过 python3 -c 运行 Python |
peinject - 二进制有效载荷传输。尽管命名以 Windows 为中心("PE inject" ),但所有三个平台都将其作为投放和执行二进制有效载荷的方式:
| Platform | Implementation |
|---|---|
| Windows | 通过 [System.Reflection.Assembly]::Load() 加载反射式 .NET 程序集 |
| macOS | 对二进制文件进行 Base64 解码并丢弃,使用操作员提供的参数执行。 |
| Linux | 将二进制文件 Base64 解码到 /tmp/。<random6 个字符的字符串> (隐藏文件),通过子进程 Popen() 启动。 |
Windows 的实现方式是在内存中执行,不丢弃文件,但没有禁用 AMSI,而 AMSI 肯定会在程序集加载时发出信号。macOS 和 Linux 变体采用了更简单的方法,即把二进制文件写入磁盘并直接执行。
rundir - 目录枚举。接受路径并返回详细的文件列表(名称、大小、类型、创建/修改时间戳、目录的子文件数)。允许操作员交互式浏览文件系统。
能力概要
| 功能 | Windows (PowerShell) | macOS (C++) | Linux (Python) |
|---|---|---|---|
| 持久化 | 注册表运行键 + 隐藏的 .bat | 无 | 无 |
| 脚本执行 | PowerShell | 通过 osascript 运行 AppleScript | Shell 或 Python 内联 |
| 二进制注入 | 反射式 .NET 负载注入 cmd.exe | 二进制下拉 + 执行 | 二进制文件下放到 /tmp/ + 执行 |
| 反取证 | 隐藏窗口、临时文件清理 | 隐藏的临时文件 .scpt | 隐藏的 /tmp/.XXXXXX 文件 |
归属
由plain-crypto-js 安装后钩子提供的 macOS Mach-O 二进制文件与WAVESHAPER 有明显重叠,后者是 Mandiant 追踪到的一个 C++ 后门,归因于UNC1069(一个与朝鲜有关联的威胁集群)。
结论
这一活动表明,npm 生态系统作为供应链攻击载体仍具有吸引力。通过入侵 JavaScript 生态系统中最受依赖的软件包之一的单个维护者账户,攻击者获得了一个潜在覆盖数百万环境的交付机制。
该工具包最可靠的检测指标也是其最奇特的设计选择:IE8/Windows XP 用户代理字符串在所有三个平台变体中都被硬编码为相同的字符串。虽然它为 C2 服务器端路由提供了一致的协议指纹,但在任何现代网络上都很容易被检测到,而且在 macOS 和 Linux 主机上会立即出现异常。
Elastic Security Labs 将继续监控这一活动集群,并在有任何其他发现时更新本帖。
MITRE ATT&CK
Elastic 使用MITRE ATT&CK框架来记录高级持续性威胁针对企业网络使用的常见策略、技术和程序。
战术
策略代表了技术或子技术的原因。 这是对手的战术目标:采取行动的原因。
技术
技术代表对手如何通过采取行动来实现战术目标。
- 供应链妥协:妥协软件依赖关系
- 命令和脚本解释器:JavaScript
- 命令和脚本解释器:PowerShell
- 命令和脚本解释器:AppleScript
- Command and Scripting Interpreter: Unix Shell
- Command and Scripting Interpreter: Python
- 启动或登录自动启动执行:注册表运行键
- 混淆文件或信息
- 伪装
- 隐藏文件和目录
- 进程注入
- Indicator Removal: File Deletion
- 系统信息发现
- 流程发现
- 文件和目录发现
- Application Layer Protocol: Web Protocols
- 非标准端口
- 数据编码:标准编码
- Ingress 工具转移
观察结果
本研究讨论了以下可观察的结果。
| 可观测 | 类型 | 名称 | 参考 |
|---|---|---|---|
617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101 | SHA-256 | 6202033.ps1 | 视窗有效载荷 |
92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a | SHA-256 | com.apple.act.mond | MacOS 有效载荷 |
fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf | SHA-256 | ld.py | Linux 有效载荷 |
sfrclak[.]com | 域 | C2 | |
142.11.206[.]73 | IPv4 地址 | C2 |
参考资料
上述研究参考了以下内容:
