漏洞概述
protobuf.js(protobufjs npm 包)存在严重代码注入漏洞,攻击者可通过精心构造的 protobuf schema 类型名称实现完全远程代码执行。该漏洞编号为 GHSA-xq3m-2v4x-88gg,CVSS 评分 9.4(严重)。
根本原因
protobuf.js 使用 @protobufjs/codegen 模块,通过字符串连接构建 JavaScript 函数,并通过 Function() 构造函数执行。来自 protobuf 模式的类型名称直接插入到生成的函数标识符中,而没有任何清理。
易受攻击的代码路径位于 src/type.js:
// Type.generateConstructor builds a constructor function:
var gen = util.codegen(["p"], mtype.name); // mtype.name is UNSANITIZED
// ... adds body lines ...
return gen; // gen() later calls Function(source)()
代码生成器 toString() 构建:
function NAME(p){
body
}
注入技术
设计的类型名称结构如下:
X(p){PAYLOAD};if(true){//
经过代码生成器处理后,生成如下代码:
return function X(p){PAYLOAD};if(true){//(p){
if(p)for(var ks=Object.keys(p),i=0;i<ks.length;++i)if(p[ks[i]]!=null)
this[ks[i]]=p[ks[i]]
}
解析器将其视为:返回的函数成为类型构造函数。当 protobuf.js 使用该构造函数创建或解码消息(new ctor(props))时,注入的有效负载将以完整的 Node.js 权限执行。
攻击链
Attacker crafts .proto schema with malicious type name
|
v
App loads schema (Root.fromJSON, protobuf.load, gRPC config)
|
v
Type.generateConstructor() → codegen → Function()
| (unsanitized name injected into function source)
v
new ctor(props) called during .create() / .decode() / .encode()
|
v
PAYLOAD EXECUTES — child_process, fs, net, process.env
影响
利用漏洞可使攻击者获得以下权限:
- 通过
child_process.execSync() 执行操作系统命令
- 文件系统访问——读/写任意文件
- 环境变量——凭据、API 密钥、数据库 URL
- 网络访问——数据泄露、横向移动
- 进程控制——反向 shell、持久化
受影响的下游软件包包括 @grpc/proto-loader、Firebase SDK 和 Google Cloud SDK。
概念验证(PoC)概述
该漏洞利用程序分为 4 个阶段:
- 第一阶段:通过精心构造的类型名称注入代码,修改
globalThis 以证明可以执行任意代码。
- 第二阶段:通过
child_process.execSync() 执行 id 命令,并将输出写入 /tmp/pwned.txt。
- 第三阶段:捕获内联命令输出(
id、uname -a、/etc/os-release)。
- 第四阶段:显示生成的函数源代码,准确展示注入过程。
截图演示
利用(protobufjs 7.5.4)
所有三个阶段都确认了代码执行——全局修改、操作系统命令执行写入 /tmp/pwned.txt 以及内联命令输出捕获:

代码生成分析
生成的函数源代码展示了类型名称注入是如何跳出函数模板的:

补丁验证(protobufjs 7.5.5)
同样的漏洞利用代码攻击修复后的版本,所有注入尝试都会被阻止:

修复提交
这行代码修复了类型名称在代码生成之前去除所有非单词字符的问题:

攻击流程
从精心设计的攻击模式到代码执行的端到端攻击流程:

漏洞概要

项目地址
该 PoC 已开源至 GitHub:
https://github.com/dinosn/CVE-protobufjs-GHSA-xq3m-2v4x-88gg
本文由云栈社区整理发布,更多安全与开发资源可访问 云栈社区。