场景:2026年10月,某金融科技公司内部CI/CD流水线突然构建失败,排查发现核心业务依赖的私有npm包被篡改。安全团队介入后,一条从开源生态到内网渗透的完整攻击链浮出水面。
攻击 / 事件时间线
初始投毒
攻击者通过钓鱼获取了某开源项目维护者的npm账号权限,在event-stream风格的流行包中植入恶意依赖flatmap-stream。该依赖在安装时执行postinstall脚本,从C2服务器下载加密的payload并写入~/.npm/_logs/隐藏目录。恶意包同时更新了版本号,利用语义化版本自动升级机制进入下游项目。
npmpostinstall脚本C2服务器
内网渗透
payload在开发机执行后,通过child_process调用系统命令收集环境变量、SSH密钥和.npmrc中的私有仓库凭证。攻击者利用窃取的凭证登录企业私有npm仓库,在内部包@company/auth-sdk中注入后门,实现供应链的二次扩散。后门通过dns.lookup()向*.evil.com发起DNS查询回传数据,规避流量检测。
child_processSSH密钥窃取DNS隧道
横向移动
攻击者利用私有包后门在CI/CD流水线中执行curl下载Cobalt Strike beacon,通过scheduled task实现持久化。随后使用mimikatz抓取域管凭证,以PsExec横向移动至构建服务器和制品库,篡改Docker镜像并植入挖矿木马。整个过程中,攻击者使用certutil进行文件编码传输,绕过EDR检测。
Cobalt StrikeMimikatzPsExeccertutil
告警触发
安全团队收到SIEM告警:构建服务器出现异常外连185.xxx.xxx.xxx:443,同时Sysmon日志显示powershell.exe执行了Base64编码命令。进一步排查发现,npm包flatmap-stream的package.json中scripts.postinstall字段包含可疑的node -e调用,且该包在npm官方仓库已被标记为恶意。
SIEMSysmonnpm audit
蓝队视角 · 发现与处置
SOC团队立即启动应急响应:首先隔离受影响的构建服务器和开发机,阻断与C2的通信;然后通过npm ls flatmap-stream定位所有受影响项目,回滚至安全版本。使用YARA规则扫描内网所有节点,查找~/.npm/_logs/下的异常文件。同时重置所有npm账号密码和CI/CD凭证,启用npm的--ignore-scripts选项重建流水线。通过DNS日志分析,确认数据外传范围并通知受影响客户。
涉及关键技术 / 工具
npm postinstall脚本滥用DNS隧道数据回传Mimikatz凭证窃取与PsExec横向移动
防护经验总结
- 在CI/CD中强制使用
npm ci --ignore-scripts,禁止安装时执行任意脚本,并对私有包实施签名验证。 - 部署Sysmon并配置规则监控
node.exe和powershell.exe的异常子进程创建及网络连接,重点关注~/.npm/_logs/目录写入行为。 - 建立内部npm镜像仓库,对所有第三方包进行安全扫描和版本锁定,禁止直接使用公共源,并定期审计依赖树中的可疑包。
#供应链攻击#npm投毒#红蓝对抗