跳转到帖子

背景

近几年在代码审计和应急处置里,遇到的供应链投毒样本明显多了起来。它们不一定追求复杂的漏洞利用,更多是借助开发者信任链:包管理器、构建脚本、CI 环境变量、发布流水线等。一旦开发或构建环境被读取到敏感信息,影响范围往往比单点 Web 漏洞更大。

这篇文章整理一次典型投毒样本的静态分析过程,重点放在识别思路、防护点和排查方法上。文中不提供可直接复用的攻击代码,也不讨论绕过检测或持久化控制,只讨论如何判断风险、定位行为和做工程侧加固。

样本场景

样本来自一次内部依赖排查:某个看似正常的 npm 包在安装阶段触发异常网络访问。包名、域名和哈希这里都做了脱敏处理。初步现象包括:

  • 安装依赖时执行了额外脚本。
  • 脚本读取了环境变量、用户目录下的配置文件。
  • 存在对外 HTTP 请求,目标域名与项目业务无关。
  • 包的公开描述与代码实际功能明显不匹配。

这类样本的关键不在于“技术多高级”,而在于它混进了开发流程。很多团队对线上流量有监控,但对 CI Runner、开发机和构建容器的出站行为监控并不充分。

技术分析思路

分析供应链样本时,我一般按以下顺序做静态检查:

  • 先看包元信息:package.json、安装脚本、入口文件、依赖列表。
  • 再看执行链路:preinstall、install、postinstall、prepare 等生命周期脚本。
  • 检查可疑能力:文件读取、环境变量读取、进程执行、网络请求、编码混淆。
  • 最后做影响面判断:可能读取哪些凭据、触发条件是什么、是否只在特定系统执行。

以 npm 包为例,package.json 是优先关注点。生命周期脚本经常被滥用,因为开发者执行 npm install 时很容易忽略它们。

{
  "name": "example-helper",
  "version": "1.2.3",
  "main": "index.js",
  "scripts": {
    "postinstall": "node ./scripts/setup.js"
  }
}

正常包也会使用 postinstall,比如编译原生扩展、下载平台相关资源等。但如果一个简单工具包在安装阶段读取用户目录、访问网络、执行系统命令,就需要提高警惕。

关键文件定位

本次样本的入口在 scripts/setup.js。文件做了简单变量拆分和字符串拼接,没有复杂加壳,但足以绕过只看关键字的粗糙检查。整理后可以看到几个典型动作:

  • 读取 process.env。
  • 枚举用户主目录下的若干配置文件。
  • 将结果组装为 JSON。
  • 发起外连请求。

安全分析时不需要还原成可运行的攻击代码,只要确认行为边界即可。可以用关键词辅助定位:

grep -R "process.env\|require('fs')\|require(\"fs\")\|http.request\|https.request\|child_process" -n .

如果仓库较大,也可以先把压缩和构建产物排除掉:

grep -R "process.env\|child_process\|https.request" -n . \
  --exclude-dir=node_modules \
  --exclude-dir=dist \
  --exclude-dir=build

实际排查时,除了显式 require,还要注意动态导入和间接调用。例如通过字符串拼接得到模块名,或者把网络请求封装在第三方依赖里。遇到明显混淆时,可以优先关注以下模式:

  • 大量无意义变量名和字符串数组。
  • Buffer.from、atob、fromCharCode 等编码还原逻辑。
  • eval、Function 构造器、vm.runInNewContext。
  • 异常捕获后静默退出,避免安装失败引起注意。

敏感信息读取点

供应链投毒最常见的目标是开发和构建环境里的凭据。需要重点关注以下位置:

位置风险说明
环境变量CI Token、云厂商 AK/SK、Webhook、数据库连接串可能在其中
~/.npmrc可能包含私有源 token
~/.git-credentials可能包含 Git 凭据,风险较高
~/.ssh私钥读取属于高危行为,应立即隔离分析
项目 .env常见于后端服务配置,容易包含密钥和连接串

需要强调一点:发现样本尝试读取这些文件,并不等于已经成功泄露。最终还要结合执行环境、权限、网络出口、日志证据判断。但从响应角度看,只要存在读取和外连行为,就应按凭据暴露处理。

网络行为判断

静态分析中,网络目标通常会被写死、拆分或编码。可以从以下几类线索入手:

  • http、https、dns、net、tls 相关模块调用。
  • URL、域名、IP、路径片段字符串。
  • base64 或十六进制编码后的字符串。
  • 请求头中伪装成正常统计、错误上报或版本检查的字段。

对于 CI 环境,建议保留安装依赖阶段的出站连接日志。没有日志时,很难确认是否发生过数据外传。工程上可以通过代理或防火墙策略限制构建容器只访问必要源,例如包仓库、制品库和代码仓库。

# 示例:在 Linux 环境中查看近期可疑连接记录,具体路径依发行版和审计配置而定
journalctl --since "2 hours ago" | grep -Ei "npm|node|curl|wget|https"

如果有统一出口代理,优先查代理日志。重点关注构建任务启动前后几分钟内的未知域名、低信誉域名、非业务域名。

本地复现的安全边界

样本分析不建议直接在办公机或真实 CI 上执行。更稳妥的方式是隔离环境静态分析,必要时使用无敏感信息、无外网或受控网络的沙箱环境观察行为。

可执行的安全做法包括:

  • 使用临时虚拟机或容器,不挂载真实用户目录。
  • 禁用或限制外网,只允许访问内部抓包代理。
  • 准备空的 HOME 目录,避免真实凭据被读取。
  • 执行前后对文件系统和进程行为做快照对比。
  • 不要把真实 token、私钥、配置文件放进复现环境。

如果只是确认安装脚本是否存在,可以使用忽略脚本参数完成依赖安装:

npm install --ignore-scripts

在排查未知包时,这是一个很实用的习惯。pnpm、yarn 也有类似能力,团队可以在安全基线里统一要求。

代码审计关注点

这类样本在代码层面经常有一些共性,不一定每条都恶意,但组合出现时风险会明显升高:

  • 小工具包却包含安装阶段脚本。
  • 安装阶段读取 HOME、SSH、npm、git 配置。
  • 异常处理全部吞掉,没有日志。
  • 根据操作系统、用户名、主机名、CI 标识决定是否执行。
  • 通过编码、压缩、字符串拼接隐藏真实域名和路径。
  • 依赖包发布时间很新,但下载量短期异常增长。
  • 包名与知名库相似,存在拼写混淆。

审计时可以把“安装期执行”和“运行期执行”分开看。运行期代码至少还需要业务调用路径触发,而安装期脚本往往在依赖安装时自动执行,风险更隐蔽。

应急处置建议

如果确认项目依赖中存在投毒包,建议按下面顺序处理:

  • 暂停相关 CI 任务,保留构建日志、依赖锁文件和制品。
  • 隔离执行过安装流程的 Runner、构建容器和开发机。
  • 确认包版本范围,排查 lock 文件中实际解析到的版本。
  • 检查出站访问日志,确认是否访问过可疑域名或 IP。
  • 轮换可能暴露的凭据,包括 npm token、Git token、云密钥、Webhook。
  • 清理缓存中的恶意包,避免后续构建继续命中。
  • 将依赖固定到安全版本,并通过内部源或制品库做准入。

这里不要只删除 package.json 里的依赖。很多情况下 lock 文件、包管理器缓存、CI 缓存仍然会保留旧版本。应急时要同时处理缓存和制品。

# 示例:查看 lock 文件中实际使用的包版本
npm ls example-helper

# 清理 npm 本地缓存需结合团队策略执行
npm cache verify

如果确认凭据可能被读取,轮换密钥比争论“是否一定泄露”更重要。尤其是长期有效、权限较大的 CI Token 和云访问密钥,应优先处理。

工程侧防护

供应链风险很难靠个人谨慎完全解决,需要在工程流程中设置防线:

  • 启用 lock 文件审查,避免依赖版本漂移。
  • CI 默认使用 npm install --ignore-scripts 或在白名单包上允许脚本。
  • 构建容器最小权限运行,不挂载宿主机敏感目录。
  • CI 凭据按项目最小授权,避免组织级高权限 token 下发到普通任务。
  • 限制构建环境出站访问,只允许必要的包源和内部服务。
  • 内部制品库做包准入和缓存,减少直接拉取公网包。
  • 对新增依赖、维护者变更、安装脚本变更做自动告警。

很多团队会做 SCA 扫描,但默认只关注已公开漏洞编号。供应链投毒往往没有 CVE,也不一定能被传统漏洞库命中。因此还需要行为规则:安装脚本、外连、敏感文件读取、混淆代码等。

几个容易忽略的点

  • devDependencies 也有风险。CI 安装开发依赖时同样会执行脚本。
  • prepare 脚本在某些安装场景也会触发,不能只看 postinstall。
  • 删除依赖不等于删除影响,已经泄露的 token 仍需轮换。
  • 私有源不等于绝对安全,内部包也可能被账号接管或发布流程污染。
  • 不要在真实开发机上运行未知样本,尤其不要带着个人 SSH 和云凭据分析。

总结

供应链投毒的核心问题不是单个脚本多复杂,而是它利用了开发流程中的默认信任。对防守方来说,长期有效的做法是把依赖安装、构建环境、凭据管理和网络出口都纳入安全边界。

实际落地可以先从三件事开始:依赖安装默认限制脚本、CI 凭据最小化、构建环境出站访问可观测。做到这三点,即使遇到类似投毒样本,也能明显降低影响范围,并且更快完成定位和处置。

漏洞验证与修复流程示意图
漏洞成因、验证条件与修复闭环示意

0篇意见

推荐意见

没有意见。

游客
抱歉,你的帖子内容包括我们不允许的字词。请编辑你的帖子,删除下面高亮的屏蔽字。
添加意见…