
Stirling-PDF v3.2.0 - Alta - Remota - IDOR - la radice di archiviazione della cartella di elaborazione elenca e sovrascrive i PDF dei peer
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · stirling-storage-folder-idor
Stirling-PDF 3.2.0 - Stirling Tools
Classe: IDOR. Portata: Remoto ROLE_USER.
POST /api/v1/processing-folders non ha alcun @PreAuthorize oltre a quello di un utente autenticato. FolderAccessGuard implica l'intero basePath dello storage locale (./storage) anche quando policies.allowedFolderRoots è vuoto. LocalStorageProvider scrive {ownerId}/{uuid}_{filename}. Un ROLE_USER può impostare directory: "storage/<victimUserId>", elencare i PDF di quel proprietario e sovrascriverli sul posto con replace=true.
La chiamata diretta a /api/v1/storage/files/{id} è corretta (findByIdAndOwner). La GET di laboratorio del file della vittima da parte del peer restituisce 403. Ciò che rimane è la root implicita della processing-folder, non l'API CRUD dello storage.
Un ROLE_USER elenca i nomi dei PDF memorizzati di un altro utente e sovrascrive quei blob. Il download della vittima restituisce il file manomesso.
| ID | nessuna CVE al momento |
| 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 |
| Prodotto | Stirling-PDF |
| Affetto | v3.2.0 (a7e593728dd9aa81e75318a949789d3c2e9ee754), immagine stirlingtools/stirling-pdf:3.2.0-fat, login-on, storage.enabled=true |
| Auth | ROLE_USER sul team predefinito |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1:18154 |
Residuo della serie Stirling-PDF v3.2.0 leftovers. Correlato: stirling-h2-import-leftover (H2 CREATE OR REPLACE ALIAS). Questo pacchetto riguarda l'IDOR dello storage.
Qualsiasi ROLE_USER umano autenticato su un'installazione login-on proprietary/fat con storage locale abilitato (predefinito del template). Il compose ufficiale è login-off più DISABLE_ADDITIONAL_FEATURES=true; quel deployment restituisce 403 su /api/v1/storage e omette questo controller. Il deployment HIT è il template login-on più fat.
Tabella dei privilegi (esaustiva). Stesso livello di Signal-Server Dropwizard admin.
| Asse | Metodo + percorso | Concede | Provenienza |
|---|---|---|---|
| Ricognizione | ROLE_USER GET /api/v1/user/users | userId numerico per admin, peer e STIRLING-PDF-BACKEND-API-USER | Provato in laboratorio |
| Ricognizione | POST /api/v1/processing-folders {directory:"storage/1"} poi GET /api/v1/processing-folders/{id}/files | Nome, dimensione, mtime del PDF memorizzato dell'admin (5341de35-8729-49cf-92d0-c8284e05bfc5_victim-lab.pdf) | Provato in laboratorio |
| Integrità | POST /api/v1/processing-folders/{id}/sweep con /api/v1/security/add-watermark poi Range GET /api/v1/storage/files/1/download della vittima | Riscrittura sul posto. La vittima 206 / 3450 byte contiene STIRLING-STORAGE-FOLDER-IDOR-WITNESS | Provato in laboratorio (replace=true) |
| Riservatezza | stesso sweep più un outputId del team / step in uscita che l'attaccante può leggere | Copia dei byte del PDF della vittima | Dedotto. Non necessario per l'elenco/sovrascrittura |
Resta chiuso su questo pin
| Asse | Metodo + percorso | Perché è chiuso |
|---|---|---|
| Recon | GET /api/v1/storage/files/{id} di un file non condiviso | 403 Access denied. Dimostrato in laboratorio sul file id 1 |
| Recon | /api/v1/storage/** non autenticato | 403 quando il login è disattivato (ensureStorageEnabled) |
| Integrità | CRUD dell'UUID della cartella tra proprietari | findByIdAndOwner |
| Integrità | LocalStorageProvider .. / chiave assoluta | Path.startsWith(basePath) dopo la normalizzazione |
| Integrità | immagine ultra-lite | controller della cartella di elaborazione proprietario assente |
GET /api/v1/user/users che elenca STIRLING-PDF-BACKEND-API-USER è un IOC aggiuntivo. Non l'ho segnalato come residuo a sé stante. Il download della vittima senza range restituisce 500 dopo la sovrascrittura perché FileStorageController pubblicizza ancora il sizeBytes originale del DB. Il range funziona. Il testo della filigrana è Identity-H in FlateDecode; l'oracolo decomprime gli stream.
La 3.x ha aggiunto lo storage locale e le cartelle di elaborazione. Il CRUD dello storage è limitato al proprietario. FolderAccessGuard.serverStorageRoots restituisce Path.of(basePath) per l'intero albero, non basePath/{currentUserId}. storage/<victimId> startsWith quella radice implicita.
Il laboratorio crea peeruser come ROLE_USER, carica un PDF vittima come admin, dimostra che la GET diretta allo storage restituisce 403, punta una cartella di elaborazione su storage/1, elenca il nome con prefisso UUID, esegue una scansione della filigrana, quindi scarica con Range nei panni della vittima.
Vicoli ciechi: considerare l'IDOR diretto dello storage ancora aperto (403); considerare il compose ufficiale con login disattivato come il deploy HIT (storage 403, controller assente); affermare una copia byte leggibile dall'attaccante senza un outputId.
python3 stirling-storage-folder-idor-Abraxas-Labs.py
o
cd lab
./run.sh
Prendi di mira solo http://127.0.0.1:18154. Immagine stirlingtools/stirling-pdf:3.2.0-fat. Docker richiesto. Login attivo. Il launcher esegue chdir in lab/ ed esegue run.sh.
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
Limita la radice di archiviazione implicita a basePath/{currentUserId} per il disco directory sui server multiutente. Rifiuta storage/<otherId> nello stesso modo in cui findByIdAndOwner rifiuta già gli ID di file estranei. Ricalcola il valore sizeBytes pubblicizzato dopo una riscrittura sul posto.
Esegui di nuovo il client loopback su una build corretta: directory=storage/1 come peeruser deve restituire 403, e l'elenco dei peer deve rimanere vuoto.
Fino ad allora, non considerare "ho corretto /api/v1/storage/files/{id}" come "ho limitato ogni API che accetta un percorso del disco sotto ./storage".