abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · jellyfin-ffmpeg-colonslash
类别: FFmpeg 参数注入
影响范围: 在媒体库中植入 .strm 文件后可远程利用(需为被扫描媒体文件夹的写入者,随后无需认证即可发起流请求)
Jellyfin Server v12.2(ca0f16eb7c195f720a1493ed469a27c4657db0c6)- Jellyfin。镜像 jellyfin/jellyfin:12.2。
GHSA-wwwm-px48-fpvq / PR 17685 在转码 argv 和 file: 的 -i 分支上添加了 EscapeProcessArgument。非 File 协议仍会将原始路径用引号包裹,而不进行该转义(EncodingUtils.cs:14-71)。对于不是 file:// 的 ://,ManagedFileSystem.IsPathFile 返回 false。TranscodeManager 仍将 ProcessStartInfo.Arguments 构建为单个字符串。
被扫描媒体库中的 .strm 文件,若其第一行是包含 " 的 http URL,则会被归类为 Http。Uri.TryCreate 接受该 URL。未经认证的 GET /Videos/{id}/stream(不带 static)会启动 ffmpeg。实验日志如下:
-i "http://127.0.0.1/a" JELLYFIN-FFMPEG-COLONSLASH-WITNESS "x"
控制参数 LabControl.mkv 仍作为一个参数:-i file:"/media/movies/LabControl.mkv"。
包含 :// 的 POSIX 文件名不会触发此 sink。 斜杠不能作为文件名的一部分。实验环境中的植入文件 a://b"…"x.mkv 会被存储为 /media/movies/a:/b"…"x.mkv,并走转义后的 File 分支。不要提交带冒号斜杠的文件名变体。我并未声称存在插件 DLL RCE。实验仅证明了 argv 拆分。
Jellyfin 12.2 leftovers 系列的第 #4 篇遗留问题。
| ID | 暂无 CVE |
| 类别 | FFmpeg 参数注入(CWE-88) |
| 可达性 | 在媒体库植入 .strm 后远程可达,随后无需认证即可访问流 |
| CWE | CWE-88 |
| CVSS | 高危:7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N |
| 产品 | Jellyfin Server |
| 受影响版本 | v12.2(ca0f16eb)镜像 jellyfin/jellyfin:12.2 |
| 认证 | 植入需要媒体库写入权限;流访问无需认证 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅限 127.0.0.1 |
与 GHSA-wwwm 相同的植入模型:将 .strm 写入被扫描的媒体文件夹(NAS / Samba / 访客共享)。随后,任何能向服务器发起 TCP 连接的人都可以在无 Authorization、无 static 的情况下 GET /Videos/{id}/stream。这就是完整的权限集合。此列表中的任何一项都不是 shell 或插件 DLL RCE。
| 维度 | 方法 + 路径 | 授予能力 | 来源 |
|---|---|---|---|
| 完整性 / argv | 在媒体库植入 .strm 后,未认证 GET /Videos/{id}/stream | 在 -i 引号之外注入额外的 ffmpeg 参数 | 实验已证明。 TranscodeManager 日志 |
| 侦察 | 同上,外加 -vf drawtext=textfile= | 在转码过程中读取主机文件字节 | 推断的 gadget;未实际运行 |
| 完整性 | -attach / -dump_attachment | 以 jellyfin UID 写入 | 推断;未展示插件加载 |
| RCE | 未声称 | - | - |
ProcessBuilder。无插件 DLL RCE。旧的 GHSA-866x 链属于历史问题,此处未展示。:// 的 POSIX 文件名会变成目录(a:)加文件。规范化后的 Path 不含 ://,因此会走转义后的 file: -i 分支。level TryParse 已修复。.strm 的本地 / file:// 路径会被丢弃(ProbeProvider 仅保留 http / https / rtsp / rtp)。EncoderAppPath 无法通过编码配置 API 设置。.strm(GHSA-j2hf)仍处于修复状态。我固定了 jellyfin/jellyfin v12.2。进行了二十次源码排查,随后进行了四个独立的回环实验。PR 17685 转义了转换 argv 和 file: -i。Http / rtsp 包装器仍保留为 "%s"。我尝试的第一个植入是包含 :// 的 POSIX 文件名。该植入是一个目录。真正触发的是 URL 已包含 :// 和 " 的 .strm。
按此顺序的错误方向:将 GetFileInputArgument 的 path.Contains("://") 快捷判断视为文件名缺陷。斜杠是分隔符。File 分支已经转义。非 File 分支则没有。
此固定版本上的同类项目:jellyfin-suggestions-idor、jellyfin-svg-gzip、jellyfin-playlist-itemids。
回环客户端:jellyfin-ffmpeg-colonslash-Abraxas-Labs.py。环境栈:lab/(docker-compose.yml、poc.py、run.sh)。仅限授权实验环境。它仅与回环地址通信。
python3 jellyfin-ffmpeg-colonslash-Abraxas-Labs.py
或:
cd lab
./run.sh
仅针对 http://127.0.0.1:18810。镜像 jellyfin/jellyfin:12.2。Compose 项目 jellyfin-ffmpeg-colonslash。见证标记 JELLYFIN-FFMPEG-COLONSLASH-WITNESS。
poc.py 写入 LabControl.mkv(对照组,一个 -i file:"...")和 LabPlant.strm,其 URL 为 http://127.0.0.1/a" JELLYFIN-FFMPEG-COLONSLASH-WITNESS "x。未认证的 GET /Videos/{id}/stream(不带 static)会记录引号断裂。最后一行:
SUCCESS jellyfin-ffmpeg-colonslash argv-split=yes plant-i=quote-break control-id=f603a52f649bcf822b333c4d5f21cc86 plant-id=d7aabf0935bb524e1667b1ff9bb945d9 JELLYFIN-FFMPEG-COLONSLASH-WITNESS
在每个 GetInputArgument 分支上调用 EscapeProcessArgument,包括 Http 和 rtsp。保留外层包装,但像 file: 分支那样对内层字符串进行引号转义。
MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs:14-71Emby.Server.Implementations/IO/ManagedFileSystem.cs:533-541MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs:417-431Jellyfin.Api/Controllers/VideosController.cs:314-318, 483-486Abraxas Labs - abraxaslabs.tech - github.com/abraxas - @abraxas_null - [email protected]
GNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。不提供任何担保。