Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
jellyfin-suggestions-idor — Jellyfin Server 12.2 - High - Remote - IDOR - GET /Items/Suggestions omit-userId가 숨겨진 라이브러리 Path와 ID를 덤프함 | Kitploit
도구/GitHubGitHub/abraxas/jellyfin-suggestions-idor
Vulnerability AnalysisWeb Application ExploitationInformation GatheringWeb SecurityPenetration TestingAPI SecurityLabs & Practice
GitHub
abraxas/jellyfin-suggestions-idor

jellyfin-suggestions-idor

Jellyfin Server 12.2 - High - Remote - IDOR - GET /Items/Suggestions omit-userId가 숨겨진 라이브러리 Path와 ID를 덤프함

저장소 보기
11일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Abraxas Labs - jellyfin-suggestions-idor

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  jellyfin-suggestions-idor

jellyfin-suggestions-idor

Jellyfin Server 12.2 - Jellyfin

분류: IDOR. 도달 범위: 원격 (인증된 비관리자 누구나).

GET /Items/Suggestions는 [Authorize]만 적용됩니다. userId가 생략되면 SuggestionsController.GetSuggestions는 user = null로 설정하고 RequestHelpers.GetUserId를 절대 호출하지 않습니다. InternalItemsQuery(null)은 SetUser를 호출하지 않습니다. LibraryManager.GetItemsResult는 AddUserToQuery를 건너뜁니다. new DtoOptions()에는 ItemFields.Path가 포함됩니다. GetBaseItemDtos(..., user: null)은 IsVisible을 건너뜁니다.

GHSA-9x85는 GetUserId를 가르쳤습니다(생략 시 클레임으로 이동, 외부 GUID는 403). ItemsController.GetItems는 항상 이를 사용합니다. Suggestions는 그렇지 않았습니다. 레거시 GET /Users/{userId}/Suggestions는 항상 라우트 GUID가 있으므로, 그 형제 엔드포인트는 GetUserId를 거칩니다.

제한된 계정이 할당되지 않은 라이브러리의 제목, ID, 개요, 제공자 ID, 파일시스템 Path를 덤프합니다. 그 GUID들은 인증 없는 GET /Videos/{id}/stream에서 재생됩니다.

ID아직 CVE 없음
CWECWE-639 / CWE-862
CVSSHigh: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
제품Jellyfin Server
영향 받음v12.2 (ca0f16eb7c195f720a1493ed469a27c4657db0c6), 이미지 jellyfin/jellyfin:12.2
인증인증됨 (비관리자 누구나, 자녀 / 숨김 라이브러리 계정 포함)
라이선스GNU Affero GPL v3.0
랩127.0.0.1:18790 전용

Jellyfin 12.2 leftovers의 잔여물 #1. 동일 핀, 다른 팩: jellyfin-svg-gzip (GHSA-cf3c 잔여물 gzip data:image/png), jellyfin-playlist-itemids (GHSA-9x85 잔여물 ItemIds + 인증 없는 스트림), jellyfin-ffmpeg-colonslash (GHSA-wwwm 잔여물 .strm URL 따옴표). 이 팩은 숨김 라이브러리를 덤프하는 팩입니다.

공격자가 할 수 있는 일

인증된 비관리자 누구나, 자녀 / 숨김 라이브러리 / MaxParentalRating 계정 포함. 일반 사용자 토큰이 필요합니다. 관리자도, API 키도 필요 없습니다. 비밀번호를 변경하지 않습니다. 관리자를 생성하지 않습니다. 할당되지 않은 라이브러리(파일시스템 Path 포함)를 인벤토리화한 뒤, 그 GUID들을 재생합니다.

권한 테이블 (전수). Signal-Server Dropwizard admin과 동일한 기준: 메서드 + 경로, 해당 호출이 부여하는 것, 정찰 vs 무결성 vs 가용성, 랩에서 입증됨 vs 추론됨, 닫힌 채로 유지되는 인접 표면.

축메서드 + 경로부여되는 권한출처
정찰userId 없이 GET /Items/Suggestions 호출 (선택적 limit / mediaType / type)범위가 제한되지 않은 재귀적 항목 목록: Name, Id, Overview, provider ID, 파일시스템 Path, 호출자가 할당되지 않은 라이브러리의 이미지 메타데이터. 숨겨진 사용자에게만 부여된 폴더도 포함된다. 폴더 ACL, 연령 등급, 허용 태그는 적용되지 않는다.실험실에서 입증됨. 제한된 labuser (EnableAllFolders=false, EnabledFolders=PublicB만): GET /Items witness=0; Suggestions witness=1
정찰limit을 생략한 동일 호출InternalItemsQuery.Limit이 설정되지 않은 채로 남아, 리포지토리가 전체 일치 집합(전체 항목 테이블, 무작위 순서)을 반환한다소스 (SuggestionsController.cs:70-95)
정찰해당 목록에서 얻은 GUID로 인증 없이 GET /Videos/{itemId}/stream 호출jellyfin UID로서 해당 파일의 바이트소스 (VideosController에 클래스 수준 [Authorize]가 없음; StreamingHelpers의 GetItemById가 사용자 없이 호출됨). 스트림은 이 팩이 아닌 형제 잔여물 jellyfin-playlist-itemids에서 실험실 검증됨
무결성Suggestions에 없음비밀번호, 정책, 즐겨찾기, 세션 쓰기 없음종결
가용성Suggestions에 없음일반적인 쿼리 비용 외에 DoS 없음종결

이 핀에서는 종결 상태로 유지됨

축메서드 + 경로종결된 이유
정찰GET /Items?userId= 및 GET /Items?parentId=<hiddenFolder>항상 GetUserId + IsVisible 적용 (ItemsController.cs:265, 342-350)
정찰GET /Playlists/{id}/Items?userId=GetUserId 적용 (PlaylistsController.cs:524). GHSA-9x85 계열, 패치됨
정찰GET /Items/Suggestions?userId=<other>외부 GUID도 여전히 GetUserId에 도달하며 비관리자에게는 403을 반환한다. 실험실에서 입증됨 (impersonate-403=yes)
정찰레거시 GET /Users/{userId}/Suggestions라우트 GUID가 필수이므로 실제로 GetUserId를 호출한다
무결성POST /Users/Password?userId=AssertCanUpdateUser 적용
무결성POST /Users/{id}/PolicyRequiresElevation 적용
무결성디바이스, 세션, AddAdditionalUser권한 상승 또는 자신의 세션만 가능
정찰GET /Users / GET /Users/{id}UserDto + 정책(폴더 GUID, 관리자 비트)이며, 라이브러리 내용이나 해시는 아님. 가구 구성원 열거이며, 이 잔여물과 무관

플러그인 DLL RCE, 리버스 셸, 비밀번호 탈취를 주장하는 것이 아니다. 이 덤프는 호출자가 할당되지 않은 라이브러리의 카탈로그(및 Path)이다. GUID로 스트리밍하는 후속 동작은 오래된 Jellyfin HTML5/DLNA 동작이며, 이 잔여물은 그 ID를 열거하는 부분이다.

발견 경위

v12.2는 12.0 GHSA 물결을 종결했다. 그래도 나는 그 태그에 머물며 RequestHelpers.GetUserId 옆의 모든 userId 쿼리를 읽었다. Items는 항상 이를 사용한다. Suggestions는 분기한다: 빈 userId -> user = null, GetUserId는 절대 호출되지 않음. 그것이 잔여물이다.

run.sh는 두 개의 영화 라이브러리(PrivateA는 witness 이름으로, PublicB)를 시드하고, 마법사를 완료하고, EnableAllFolders=false 및 EnabledFolders=PublicB만으로 labuser를 생성한 뒤, GET /Items와 GET /Items/Suggestions를 비교한다.

이미 기록된 잘못된 방향들: GET /Items를 유출로 간주함(범위가 제한됨); Suggestions?userId=<admin>을 유출로 간주함(403); 레거시 /Users/{userId}/Suggestions 라우트를 구멍으로 간주함(GUID가 있으므로 GetUserId를 호출함); 인증 없는 스트림을 이 팩의 버그로 주장함(형제 잔여물); 리버스 셸. 다 연극이다.

클라이언트 버그는 제품 버그처럼 보인다. http.client를 가리는 헬퍼는 패킷을 절대 보내지 않는다. HTTPResponse의 .recv()는 .read()가 아니다. 이 점을 한 번 언급하는 이유는 시간을 잡아먹었고, 잠시 동안 12.2가 일을 끝낸 것처럼 보였기 때문이다.

실험실

python3 jellyfin-suggestions-idor-Abraxas-Labs.py

또는

cd lab
./run.sh

오직 http://127.0.0.1:18790만 대상으로 합니다. 이미지 jellyfin/jellyfin:12.2. Docker가 필요합니다. 런처는 lab/로 chdir한 후 run.sh를 exec합니다.

IOC user-items http=200 witness=0
IOC user-suggestions http=200 witness=1
IOC impersonate-suggestions http=403
SUCCESS jellyfin-suggestions-idor items-hidden=yes suggestions-has-witness=yes impersonate-403=yes JELLYFIN-SUGGESTIONS-IDOR-WITNESS

제한된 labuser는 /Items에서 PrivateA를 볼 수 없습니다. 동일한 토큰은 userId 없이 /Items/Suggestions에서 witness를 봅니다. admin GUID를 전달해도 여전히 403이 발생합니다.

수정 방법

ItemsController가 이미 하는 것처럼 userId가 비어 있을 때 RequestHelpers.GetUserId를 호출합니다. 외부 GUID에 대해서는 403을 유지합니다.

var requestUserId = RequestHelpers.GetUserId(User, userId);
user = _userManager.GetUserById(requestUserId);

userId.IsNullOrEmpty() -> user = null 분기를 제거하십시오. 패치된 빌드에 대해 loopback 클라이언트를 다시 실행하십시오. 제한된 labuser Suggestions가 /Items와 일치해야 합니다(witness=0).

그때까지 "/Items의 범위를 지정했다"를 "BaseItemDto를 반환하는 모든 쿼리의 범위를 지정했다"로 간주하지 마십시오. 빈 userId와 user = null은 인스턴스 전체 카탈로그입니다.

참고 자료

도구 다운로드