
Jellyfin Server 12.2 - 高 - リモート - SSRF - gzip data:image/png GHSA-cf3c の残存物が依然として http と file を取得する
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · jellyfin-svg-gzip
分類: SSRF + ファイル読み取り + memex
到達範囲: リモート(認証済みユーザーなら誰でも POST /UserImage、ラスタライズは未認証の GET /UserImage)
Jellyfin Server 12.2 (ca0f16eb) - Jellyfin。Svg.Skia 3.7.0。
GHSA-cf3c-8m59-2vhx はプロフィール SVG 上の外側の http および file href を閉じた。12.2 は依然として Svg.Skia 3.7.0 を固定している。SvgDocument.ResolveExternalImages = ExternalType.None は 3.7.0 の ImageDrawable では無視される。SvgSecurityValidator.ValidateDataUri は、メディアタイプが正確に image/svg+xml でないあらゆる data URI に対して、gzip 走査の前に許可を返す。Svg.Skia の GetImageFromDataUri は、mimeType.StartsWith("image/") と gzip マジックにより、Jellyfin による再スキャンなしで LoadSvgz を呼び出す。内側の SVG の http(s) / file href は WebRequest.Create に渡される。これが元の GHSA-cf3c のシンクである。
認証済みユーザーなら誰でも、gzip-png でラップされた SVG をアップロードできる。そのプロフィール画像を未認証で GET すると、ラスタライズ中にサーバーが攻撃者の http / https / file:// を取得する。
| ID | CVE 未割当 |
| 分類 | SSRF + ファイル読み取り + memex |
| 到達範囲 | リモート。 任意のユーザーが POST /UserImage。ラスタライズは未認証の GET /UserImage?userId= |
| CWE | CWE-918 / CWE-611 / CWE-400 |
| CVSS | High: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:L |
| 製品 | Jellyfin Server |
| 影響範囲 | 12.2 (ca0f16eb7c195f720a1493ed469a27c4657db0c6)、イメージ jellyfin/jellyfin:12.2、Svg.Skia 3.7.0 |
| 認証 | アップロードは認証済み。ラスタライズは未認証。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
Jellyfin 12.2 leftovers シリーズの残り #2。姉妹記事 #1 Suggestions IDOR。同じ固定: playlist ItemIds、FFmpeg colon-slash。
アクターはサインイン済みの Jellyfin ユーザーなら誰でもよい。プロフィール画像は管理者専用ではない。ラスタライズにセッションは不要。
| 軸 | メソッド + パス | 得られるもの | 根拠 |
|---|---|---|---|
| 偵察 | POST /UserImage(Content-Type: image/svg+xml、BASE64 ボディ)の後、未認証の GET /UserImage?userId= | Skia がラスタライズする間に、サーバーが攻撃者の http/https(ループバック、RFC1918、リンクローカル/IMDS)を GET する | ラボで実証済み。 オラクルのホスト名 oracle:8080、hits=1、パス内に証跡 |
| 偵察 | 同上 | リクエスト元がダウンロードする PNG/WebP/JPEG に file:// のバイト列が描画される(画像としてデコードできる場合) | 推測。GHSA-cf3c と同じ WebRequest.Create シンク |
| 可用性 | 同上、内側は file:///dev/urandom | マネージドヒープ上に保持される無制限の読み取り。再アップロードなしで、以降の画像 GET のたびに繰り返される | 推測。GHSA-cf3c で計測済み |
| 完全性 | なし | ユーザーポリシーの書き込み、プラグインのインストール、セッション窃取はいずれも不可 | 対象外 |
閉じたまま: 外側 SVG 上の直接的な http/file href(ラボ:GET は image/svg+xml のまま、オラクル 0)。ネストされた data:image/svg+xml(gzip を含めて再スキャン)。DTD SYSTEM。GHSA-vcmh のインライン XSS(Content-Disposition: attachment とラスタライズ)。プラグイン画像のトラバーサル。Magick/PDF。RCE ではない。セッション XSS ではない。SSRF のボディは Skia が描画するものであり、生の HTTP レスポンスではない。
12.2 は GHSA-cf3c のプリスキャンをすでに出荷済みのタグだ。それでも私はこれにこだわった。まだフェッチを行うライブラリの手前にバリデータを追加するパッチは贈り物だ。バリデータが何をたどるかを読み、次にライブラリがまだ何をパースするのかを問う。
Directory.Packages.props は依然として Svg.Skia 3.7.0 を固定している。上流の wieslawsoltes/Svg.Skia#448(#501 で修正済み):ImageDrawable は ResolveExternalImages を一切参照しない。Jellyfin の 3 つの ExternalType.None 代入は、この固定バージョンでは no-op だ。Renovate #17076 はこのタグには含まれていない。
つまりプリスキャンが唯一のゲートとなる。ValidateReference はフラグメントでも data: でもないすべての href を拒否する。ネストされた image/svg+xml は gzip を含めて再パースされる。SvgSecurityValidator.cs:169-173 のコメントには、その他のメディアタイプはラスタであり、0x1F 0x8B の走査の前に許可を返すと書かれている。Svg.Skia 3.7.0 の GetImageFromDataUri はこれと矛盾する:gzip マジックを持つ任意の image/* は LoadSvgz となる。
すでに記録済みの誤った道:ネガティブコントロールが image/svg+xml のままであることを理由に GHSA-cf3c をクローズ済みとみなすこと。ネストされた data:image/svg+xml の gzip(再スキャン済み)。DTD SYSTEM。GHSA-vcmh のインライン XSS。プラグイン画像のトラバーサル。Magick/PDF。管理者の RemoteImages/Download(意図されたアートワークのフェッチ)。この残存問題ではないピクセルボム DoS。リバースシェル。すべて芝居だ。
python3 jellyfin-svg-gzip-Abraxas-Labs.py
または:
cd lab
./run.sh
ループバックのみ: Jellyfin http://127.0.0.1:18780、oracle http://127.0.0.1:18781。イメージ jellyfin/jellyfin:12.2。Oracle は 1x1 PNG を返し、リクエストパスをログに記録する。Skia が取得するのは Compose のホスト名 oracle:8080 である。
ネガティブ: 画像 href が http://oracle:8080/negative.png であるプロフィール SVG を POST する。GET は image/svg+xml のままで、oracle は 0。ポジティブ: href が http://oracle:8080/JELLYFIN-SVG-SVGSKIA-WITNESS.png である内部 SVG を gzip 圧縮し、外側の SVG で data:image/png;base64 としてラップする。GET は image/png で、oracle は 1。
SUCCESS jellyfin-svg-gzip gzip-png-ssrf hits=1 negative=0 JELLYFIN-SVG-SVGSKIA-WITNESS
証拠のみ。エクスプロイトペイロードなし。リバースシェルなし。許可されたラボ。ループバック。
宣言されたメディアタイプが image/svg+xml でない場合でも、SvgSecurityValidator 内で gzip およびネストされた data URI を処理する。または、Svg.Skia を ImageDrawable の ExternalType.None 無視(upstream #448 / #501。renovate #17076 はこのタグには含まれない)より後のバージョンに更新する。両方でもよい。ライブラリのフラグが意図されたキルスイッチである。バリデータは、ライブラリが何をパースするかについて虚偽を述べるべきではない。
ca0f16eb7c195f720a1493ed469a27c4657db0c6)SvgSecurityValidator.cs · SkiaEncoder.cs · ImageController.csGNU Affero GPL v3.0。LICENSE を参照。ループバックラボ専用。保証なし。