
Jellyfin Server 12.2 – Hoch – Remote nach .strm-Plant – FFmpeg-Argument-Injection – EncodingUtils -i Überbleibsel von GHSA-wwwm
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · jellyfin-ffmpeg-colonslash
Klasse: FFmpeg-Argument-Injection
Reichweite: Remote nach dem Platzieren einer .strm-Datei in einer Bibliothek (Schreibzugriff auf einen gescannten Medienordner, danach unauthentifizierter Stream)
Jellyfin Server v12.2 (ca0f16eb7c195f720a1493ed469a27c4657db0c6) - Jellyfin. Image jellyfin/jellyfin:12.2.
GHSA-wwwm-px48-fpvq / PR 17685 fügte EscapeProcessArgument auf die Konvertierungs-argv und den file:--i-Zweig hinzu. Bei Nicht-File-Protokollen wird der rohe Pfad weiterhin ohne diese Escapierung in Anführungszeichen gesetzt (EncodingUtils.cs:14-71). ManagedFileSystem.IsPathFile ist false für ://, das nicht file:// ist. TranscodeManager baut ProcessStartInfo.Arguments weiterhin als einen einzigen String.
Eine gescannte Bibliotheks-.strm, deren erste Zeile eine http-URL mit " enthält, wird als Http klassifiziert. Uri.TryCreate akzeptiert diese URL. Ein unauthentifiziertes GET /Videos/{id}/stream (ohne static) startet ffmpeg. Das Lab-Log lautet:
-i "http://127.0.0.1/a" JELLYFIN-FFMPEG-COLONSLASH-WITNESS "x"
Control LabControl.mkv bleibt ein Argument: -i file:"/media/movies/LabControl.mkv".
Ein POSIX-Dateiname mit :// trifft diesen Sink nicht. Ein Slash kann kein Dateiname sein. Die Lab-Pflanze a://b"…"x.mkv wird als /media/movies/a:/b"…"x.mkv gespeichert und nimmt den escaped File-Zweig. Reichen Sie keine Dateinamen-Variante mit Doppelpunkt-Slash ein. Ich behaupte kein Plugin-DLL-RCE. Das Lab beweist nur die argv-Aufteilung.
Übriggebliebenes #4 der Serie Jellyfin 12.2 leftovers.
| ID | noch keine CVE |
| Klasse | FFmpeg-Argument-Injection (CWE-88) |
| Reichweite | Remote nach einer Bibliotheks-.strm-Pflanze, dann unauth Stream |
| CWE | CWE-88 |
| CVSS | Hoch: 7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N |
| Produkt | Jellyfin Server |
| Betroffen | v12.2 (ca0f16eb) Image jellyfin/jellyfin:12.2 |
| Auth | Bibliotheks-Schreibzugriff für die Pflanze; der Stream ist unauthentifiziert |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Dasselbe Pflanzenmodell wie bei GHSA-wwwm: eine .strm in einen gescannten Medienordner schreiben (NAS / Samba / Gast-Freigabe). Danach kann jeder, der TCP zum Server öffnen kann, GET /Videos/{id}/stream ohne Authorization und ohne static ausführen. Das ist die vollständige Berechtigungsmenge. Nichts in dieser Liste ist ein Shell- oder Plugin-DLL-RCE.
| Achse | Methode + Pfad | Gewährt | Herkunft |
|---|---|---|---|
| Integrität / argv | unauth GET /Videos/{id}/stream nach einer Bibliotheks-.strm-Pflanze | Zusätzliche ffmpeg-Argumente außerhalb der -i-Anführungszeichen | Im Lab bewiesen. TranscodeManager-Log |
| Recon | dasselbe plus -vf drawtext=textfile= | Host-Dateibytes im Transcode | Abgeleitetes Gadget; nicht ausgeführt |
| Integrität | -attach / -dump_attachment | Schreibzugriff mit jellyfin-UID | Abgeleitet; Plugin-Laden nicht gezeigt |
| RCE | nicht behauptet | - | - |
ProcessBuilder. Kein Plugin-DLL-RCE. Die alte GHSA-866x-Kette ist historisch und wird hier nicht gezeigt.:// wird zu einem Verzeichnis (a:) plus einer Datei. Der kanonische Path enthält kein ://, daher trifft er den escaped file:--i-Zweig.level TryParse ist geschlossen..strm- / file://-Pfade werden verworfen (ProbeProvider behält nur http / https / rtsp / rtp).EncoderAppPath kann nicht über die Encoding-Config-API gesetzt werden..strm (GHSA-j2hf) bleibt geschlossen.Ich habe jellyfin/jellyfin v12.2 gepinnt. Zwanzig Quellcode-Jagden, dann vier unabhängige Loopback-Labs. PR 17685 hat Konvertierungs-argv und file: -i escaped. Die Http-/rtsp-Wrapper blieben als "%s". Die erste Pflanze, die ich versuchte, war ein POSIX-Dateiname mit ://. Diese Pflanze ist ein Verzeichnis. Das Übriggebliebene, das zündet, ist eine .strm, deren URL bereits :// und " enthält.
Fehlweg, in dieser Reihenfolge: den path.Contains("://")-Kurzschluss von GetFileInputArgument als Dateinamen-Bug zu behandeln. Slash ist ein Trenner. Der File-Zweig escaped bereits. Der Nicht-File-Zweig nicht.
Geschwister auf diesem Pin: jellyfin-suggestions-idor, jellyfin-svg-gzip, jellyfin-playlist-itemids.
Loopback-Client: jellyfin-ffmpeg-colonslash-Abraxas-Labs.py. Stack: lab/ (docker-compose.yml, poc.py, run.sh). Nur autorisiertes Lab. Es spricht mit Loopback.
python3 jellyfin-ffmpeg-colonslash-Abraxas-Labs.py
Oder:
cd lab
./run.sh
Nur http://127.0.0.1:18810 anvisieren. Image jellyfin/jellyfin:12.2. Compose-Projekt jellyfin-ffmpeg-colonslash. Witness JELLYFIN-FFMPEG-COLONSLASH-WITNESS.
poc.py schreibt LabControl.mkv (Kontrolle, ein -i file:"...") und LabPlant.strm, dessen URL http://127.0.0.1/a" JELLYFIN-FFMPEG-COLONSLASH-WITNESS "x ist. Unauth GET /Videos/{id}/stream (ohne static) protokolliert den Quote-Break. Letzte Zeile:
SUCCESS jellyfin-ffmpeg-colonslash argv-split=yes plant-i=quote-break control-id=f603a52f649bcf822b333c4d5f21cc86 plant-id=d7aabf0935bb524e1667b1ff9bb945d9 JELLYFIN-FFMPEG-COLONSLASH-WITNESS
Rufe EscapeProcessArgument in jedem GetInputArgument-Zweig auf, einschließlich Http und rtsp. Behalte das Umhüllen bei, aber maskiere die Anführungszeichen der inneren Zeichenkette so, wie es der file:-Zweig bereits tut.