Jellyfin Server 12.2 - उच्च - रिमोट - IDOR - सार्वजनिक प्लेलिस्ट ItemIds GHSA-9x85 का अवशेष, फिर अनधिकृत स्ट्रीम
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · jellyfin-playlist-itemids
Class: IDOR Reach: Remote (कोई भी उपयोगकर्ता जो सार्वजनिक प्लेलिस्ट देख सकता है)
Jellyfin Server v12.2 (ca0f16eb7c195f720a1493ed469a27c4657db0c6) - Jellyfin
GHSA-9x85 ने GET /Playlists/{id}/Items को GetUserId और Where(i => i.Item2.IsVisible(user)) के साथ पैच किया। GET /Playlists/{id} को वह फ़िल्टर नहीं दिया गया। ItemIds वह GetManageableItems() है जिसमें चाइल्ड पर कोई IsVisible नहीं है। GetPlaylistForUser केवल प्लेलिस्ट की दृश्यता की आवश्यकता रखता है।
CreatePlaylistDto.IsPublic का डिफ़ॉल्ट true है। OpenAccess प्लेलिस्ट अन्य उपयोगकर्ताओं के लिए IsVisible होती हैं (HasParentalAllowedChild अभी भी दूसरे उपयोगकर्ता को प्लेलिस्ट देखने देता है)। अन-ऑथ GET /Videos/{id}/stream में कोई [Authorize] नहीं है। StreamingHelpers बिना किसी उपयोगकर्ता के GetItemById लोड करता है।
जो उपयोगकर्ता सार्वजनिक प्लेलिस्ट देख सकता है, वह ItemIds से निजी चाइल्ड GUIDs पढ़ता है, फिर बिना टोकन के फ़ाइलों को स्ट्रीम करता है।
| ID | अभी तक कोई CVE नहीं |
| Class | IDOR (GHSA-9x85 का प्लेलिस्ट ItemIds अवशेष, फिर अन-ऑथ स्ट्रीम) |
| Reach | Remote (कोई भी उपयोगकर्ता जो सार्वजनिक प्लेलिस्ट देख सकता है) |
| CWE | CWE-639, CWE-862 |
| CVSS | High: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Product | Jellyfin Server |
| Affected | v12.2 (ca0f16eb) इमेज jellyfin/jellyfin:12.2 |
| Auth | प्लेलिस्ट GET के लिए प्रमाणित; स्ट्रीम के लिए कोई नहीं |
| License | GNU Affero GPL v3.0 |
| Lab | केवल 127.0.0.1:18800 |
Jellyfin 12.2 leftovers का अवशेष #3। अवशेष #1 (सबसे महत्वपूर्ण): jellyfin-suggestions-idor। समान पिन: jellyfin-svg-gzip · jellyfin-ffmpeg-colonslash।
पीड़ित और हमलावर एक ही सर्वर पर दो उपयोगकर्ता हैं जिनकी लाइब्रेरी अलग-अलग हैं (बच्चे बनाम वयस्क, या एक छिपा हुआ फ़ोल्डर)। पीड़ित एक निजी फ़िल्म को सार्वजनिक प्लेलिस्ट में डालता है। बॉडी-क्रिएट IsPublic का डिफ़ॉल्ट true है, इसलिए यह सामान्य स्थिति है, कोई शेयर नहीं। हमलावर एक प्रतिबंधित खाते से लॉग इन करता है, प्लेलिस्ट ऑब्जेक्ट पढ़ता है, फिर बिना Authorization हेडर के फ़ाइल प्राप्त करता है।
यह उन लाइब्रेरी में मीडिया के GUIDs हैं जिनमें हमलावर को असाइन नहीं किया गया है, फिर स्ट्रीम के माध्यम से पूरी फ़ाइल। यह प्लेलिस्ट-टाइटल एनम नहीं है। Add/create अभी भी गैर-दृश्यमान आइटम छोड़ देते हैं।
| Method | Path | Privilege |
|---|---|---|
| GET | /Playlists/{playlistId} | दृश्यमान प्लेलिस्ट के चाइल्ड GUIDs (GetManageableItems() से ItemIds, चाइल्ड पर कोई IsVisible नहीं)। साथ ही Shares[].UserId / CanEdit (शेयरी userIds)। लैब: B का GET /Playlists/{id}/Items खाली; उसी id का GET /Playlists/{id} ने निजी GUID a2bf95146e44897be6fb09020a82eb52 सूचीबद्ध किया। |
GetPlaylistForUser केवल प्लेलिस्ट के स्वयं दृश्यमान होने की आवश्यकता रखता है। OpenAccess और HasParentalAllowedChild (जो अनुमत-टैग जाँच को छोड़ देता है) पर्याप्त है। पैच किया गया Items रूट नियंत्रण है: यह अभी भी फ़िल्टर करता है।
| विधि | पथ | विशेषाधिकार |
|---|---|---|
| GET | /Videos/{itemId}/stream?static=true | निजी मीडिया बाइट्स। कोई [Authorize] नहीं। StreamingHelpers बिना किसी उपयोगकर्ता के GetItemById<BaseItem>(id) करता है। लैब: अनऑथ 200, 1142 बाइट्स, बॉडी में साक्ष्य JELLYFIN-PLAYLIST-ITEMIDS-WITNESS। |
| GET | /Audio/{itemId}/stream | ऑडियो के लिए वही सिंक। वही हेल्पर, वही अनस्कोप्ड लुकअप। |
प्रमाणित HLS GET /Videos/{itemId}/master.m3u8 वही GetItemById पथ है (DynamicHlsController में क्लास-स्तरीय [Authorize] है)। लैब ने अनऑथ प्रोग्रेसिव स्ट्रीम का परीक्षण किया, HLS का नहीं।
| विधि | पथ | विशेषाधिकार |
|---|---|---|
| POST | /Playlists/{id}/Items और Ids बनाना | बंद। Playlist.GetPlaylistItems IsVisible चलाता है। निजी GUIDs हटा दिए जाते हैं, लिंक नहीं किए जाते। |
GetItemById(id, user))।EnableCollectionManagement डिफ़ॉल्ट false; FilterLinkedChildrenPerUser)।ValidateTranscodePath लेगेसी HLS सेगमेंट्स को ट्रांसकोड डिर में रखता है)।userId प्रतिरूपण (GetUserId विदेशी id पर 403 देता है)।GET /Playlists/{id}/Items लिस्टिंग (पैच किया गया रूट; लैब items-filtered=yes)।कोई पासवर्ड/पॉलिसी राइट नहीं। कोई प्लगइन इंस्टॉल नहीं। कोई शेल नहीं।
इस लैब में अकेले फ़ोल्डर ACL (EnabledFolders) ने /Items पर चाइल्ड को छिपाया नहीं। AllowedTags=["lab-public"] ने IsVisible को इसे हटाने पर मजबूर किया। ItemIds और अनऑथ स्ट्रीम उस फ़िल्टर से परामर्श नहीं करते।
मैंने jellyfin/jellyfin v12.2 (ca0f16eb) को पिन किया। 12.0 GHSA लहर के अवशेषों पर बीस स्रोत खोजें। GHSA-9x85 ने GetPlaylistItems को चिल्ड्रन फ़िल्टर करना सिखाया। मैंने पूछा कि क्या GetPlaylist को वही Where मिला। उसे नहीं मिला। स्ट्रीम एंडपॉइंट्स को कभी उपयोगकर्ता-स्कोप्ड GetItemById नहीं मिला।
गलत मोड़: EnabledFolders को Items छिपाने वाला मानना। मूवी IsVisible पैरेंटल/टैग्स है, फ़ोल्डर ACL नहीं। लैब को AllowedTags सेट करना पड़ा ताकि पैच किया गया Items रूट खाली हो जाए। वही नियंत्रण है। अवशेष इसका उपयोग नहीं करता।
git clone https://github.com/abraxas/jellyfin-playlist-itemids
cd jellyfin-playlist-itemids
python3 jellyfin-playlist-itemids-Abraxas-Labs.py
या:
cd lab
./run.sh
केवल http://127.0.0.1:18800 को लक्षित करें। इमेज jellyfin/jellyfin:12.2। run.sh दो छोटी mp4 फ़ाइलें सीड करता है (PrivateA साक्षी फ़ाइलनाम, PublicB डमी)। विज़ार्ड labadmin बनाता है, दोनों फ़ोल्डर, फिर labuser जिसमें EnableAllFolders=false, EnabledFolders=PublicB, AllowedTags=["lab-public"]। एडमिन निजी मूवी को एक सार्वजनिक प्लेलिस्ट पर रखता है। लूपबैक। केवल-साक्षी। सीड करने के लिए Docker और ffmpeg आवश्यक है।
SUCCESS JELLYFIN-PLAYLIST-ITEMIDS items-filtered=yes itemids-leak=yes unauth-stream=200 openAccess=yes playlist=e4798134497195ff4733dde62428e8d8 private=a2bf95146e44897be6fb09020a82eb52 witness-in-stream=yes witness-in-playlist-json=yes JELLYFIN-PLAYLIST-ITEMIDS-WITNESS
रीप्ले: python3 jellyfin-playlist-itemids-Abraxas-Labs.py।
GetPlaylistItems से मेल खाते हुए ItemIds को IsVisible(user) से फ़िल्टर करें। स्ट्रीम GetItemById को किसी उपयोगकर्ता तक सीमित करें, या VideosController.GetVideoStream (और उसके ऑडियो समकक्ष) पर [Authorize] लगाएँ।