
Stirling-PDF v3.2.0 - High - Remote - IDOR - processing-folder 저장소 루트가 동료 PDF를 나열하고 덮어씀
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · stirling-storage-folder-idor
Stirling-PDF 3.2.0 - Stirling Tools
분류: IDOR. 도달 범위: 원격 ROLE_USER.
POST /api/v1/processing-folders에는 로그인한 사용자 외에 별도의 @PreAuthorize가 없습니다. FolderAccessGuard는 policies.allowedFolderRoots가 비어 있어도 전체 로컬 스토리지 basePath(./storage)를 암묵적으로 허용합니다. LocalStorageProvider는 {ownerId}/{uuid}_{filename} 형식으로 기록합니다. ROLE_USER는 directory: "storage/<victimUserId>"를 설정하고, 해당 소유자의 PDF를 나열한 뒤 replace=true로 제자리에서 덮어쓸 수 있습니다.
직접적인 /api/v1/storage/files/{id}는 패치되어 있습니다(findByIdAndOwner). 피어로서 피해자 파일에 대한 랩 GET 요청은 403입니다. 남아 있는 문제는 스토리지 CRUD API가 아니라 처리 폴더의 암묵적 루트입니다.
ROLE_USER가 다른 사용자가 저장한 PDF 이름을 나열하고 해당 블롭을 덮어씁니다. 피해자의 다운로드는 변조된 파일을 반환합니다.
| ID | 아직 CVE 없음 |
| CWE | CWE-639 / CWE-73 |
| CVSS | 7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N |
| 제품 | Stirling-PDF |
| 영향받는 버전 | v3.2.0 (a7e593728dd9aa81e75318a949789d3c2e9ee754), 이미지 stirlingtools/stirling-pdf:3.2.0-fat, 로그인 켜짐, storage.enabled=true |
| 인증 | 기본 팀의 ROLE_USER |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1:18154 전용 |
Stirling-PDF v3.2.0 leftovers 시리즈의 잔여 항목입니다. 자매 항목: stirling-h2-import-leftover (H2 CREATE OR REPLACE ALIAS). 이 팩은 스토리지 IDOR입니다.
로컬 스토리지가 활성화된(템플릿 기본값) login-on proprietary/fat에서 로그인한 모든 사람 ROLE_USER가 해당됩니다. 공식 compose는 login-off에 DISABLE_ADDITIONAL_FEATURES=true이며, 해당 배포에서는 /api/v1/storage가 403을 반환하고 이 컨트롤러가 포함되지 않습니다. HIT 배포는 템플릿 login-on에 fat입니다.
권한 표(전수). Signal-Server Dropwizard admin과 동일한 기준입니다.
| 축 | 메서드 + 경로 | 부여되는 것 | 출처 |
|---|---|---|---|
| 정찰 | ROLE_USER GET /api/v1/user/users | admin, 피어, STIRLING-PDF-BACKEND-API-USER의 숫자 userId | 랩 검증됨 |
| 정찰 | POST /api/v1/processing-folders {directory:"storage/1"} 후 GET /api/v1/processing-folders/{id}/files | admin이 저장한 PDF의 이름, 크기, mtime (5341de35-8729-49cf-92d0-c8284e05bfc5_victim-lab.pdf) | 랩 검증됨 |
| 무결성 | /api/v1/security/add-watermark와 함께 POST /api/v1/processing-folders/{id}/sweep 후 피해자 Range GET /api/v1/storage/files/1/download | 제자리 재작성. 피해자 206 / 3450 바이트에 STIRLING-STORAGE-FOLDER-IDOR-WITNESS 포함 | 랩 검증됨 (replace=true) |
| 기밀성 | 동일한 sweep에 더해 공격자가 읽을 수 있는 팀 outputId / 아웃바운드 단계 | 피해자 PDF 바이트의 사본 | 추론됨. 나열/덮어쓰기에는 필요하지 않음 |
이 핀에서는 닫힌 상태 유지
| 축 | 메서드 + 경로 | 차단된 이유 |
|---|---|---|
| 정찰 | 비공유 파일의 GET /api/v1/storage/files/{id} | 403 Access denied. 파일 id 1에서 실험실 검증됨 |
| 정찰 | 비인증 /api/v1/storage/** | 로그인 비활성화 시 403 (ensureStorageEnabled) |
| 무결성 | 소유자 간 폴더 UUID CRUD | findByIdAndOwner |
| 무결성 | LocalStorageProvider .. / 절대 키 | 정규화 후 Path.startsWith(basePath) |
| 무결성 | 울트라 라이트 이미지 | 독점 처리 폴더 컨트롤러 부재 |
STIRLING-PDF-BACKEND-API-USER를 나열하는 GET /api/v1/user/users는 추가 IOC입니다. 별도의 잔여 항목으로 신고하지는 않았습니다. 범위 없는 피해자 다운로드는 덮어쓰기 후 500 오류가 발생하는데, FileStorageController가 여전히 원본 DB sizeBytes를 표시하기 때문입니다. 범위 지정은 작동합니다. 워터마크 텍스트는 FlateDecode의 Identity-H이며, 오라클이 스트림을 팽창시킵니다.
3.x는 로컬 스토리지와 처리 폴더를 추가했습니다. 스토리지 CRUD는 소유자 범위로 제한됩니다. FolderAccessGuard.serverStorageRoots는 전체 트리에 대해 basePath/{currentUserId}가 아닌 Path.of(basePath)를 반환합니다. storage/<victimId>는 그 암시된 루트로 startsWith됩니다.
실험실은 peeruser를 ROLE_USER로 생성하고, 관리자로 피해자 PDF를 업로드하고, 직접 스토리지 GET이 403임을 입증하고, 처리 폴더를 storage/1로 지정하고, UUID 접두사가 붙은 이름을 나열하고, 워터마크를 스윕한 다음, 피해자로서 Range 다운로드를 수행합니다.
잘못된 접근: 직접 스토리지 IDOR을 여전히 열려 있다고 간주(403); 로그인 비활성화된 공식 compose를 HIT 배포로 간주(스토리지 403, 컨트롤러 부재); outputId 없이 공격자가 읽을 수 있는 바이트 복사본을 주장.
python3 stirling-storage-folder-idor-Abraxas-Labs.py
또는
cd lab
./run.sh
오직 http://127.0.0.1:18154만 대상으로 합니다. 이미지 stirlingtools/stirling-pdf:3.2.0-fat. Docker 필요. 로그인 켜짐. 런처는 lab/로 chdir한 후 run.sh를 exec합니다.
IOC direct-storage-get http=403
IOC processing-folders-save directory=storage/1 http=202
IOC listed-peer ... victim-lab.pdf
IOC victim-download attempt=1 http=206 bytes=3450 witness=1
SUCCESS stirling-storage-folder-idor direct-storage-403=yes listed-peer-pdf=yes download-has-witness=yes STIRLING-STORAGE-FOLDER-IDOR-WITNESS
다중 사용자 서버에서 디스크 directory에 대해 암시적 저장소 루트를 basePath/{currentUserId}로 범위를 한정하십시오. findByIdAndOwner가 이미 외부 파일 id를 거부하는 것처럼 storage/<otherId>도 거부하십시오. 제자리 재작성 후에는 광고되는 sizeBytes를 다시 계산하십시오.
패치된 빌드에 대해 루프백 클라이언트를 다시 실행하십시오: peeruser로서 directory=storage/1은 403이어야 하며, 나열된 peer는 비어 있어야 합니다.
그때까지는 "/api/v1/storage/files/{id}를 패치했다"를 "./storage 아래의 디스크 경로를 받는 모든 API의 범위를 한정했다"로 간주하지 마십시오.
a7e593728dd9aa81e75318a949789d3c2e9ee754)벤더 접수: GitHub Security Advisory 탭 또는 [email protected]. 저는 Stirling-Tools/Stirling-PDF에 공개 이슈를 열지 않습니다.
Abraxas Labs https://abraxaslabs.tech https://github.com/abraxas [email protected]