
Stirling-PDF v3.2.0 – Hoch – Remote – IDOR – Auflistung des Speicherstamms des Verarbeitungsordners und Überschreiben von Peer-PDFs
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · stirling-storage-folder-idor
Stirling-PDF 3.2.0 – Stirling Tools
Klasse: IDOR. Reichweite: Remote ROLE_USER.
POST /api/v1/processing-folders hat kein @PreAuthorize über einen eingeloggten Benutzer hinaus. FolderAccessGuard impliziert das gesamte lokale Speicher-basePath (./storage), selbst wenn policies.allowedFolderRoots leer ist. LocalStorageProvider schreibt {ownerId}/{uuid}_{filename}. Ein ROLE_USER kann directory: "storage/<victimUserId>" setzen, die PDFs dieses Eigentümers auflisten und sie mit replace=true direkt vor Ort überschreiben.
Der direkte /api/v1/storage/files/{id} ist gepatcht (findByIdAndOwner). Der Lab-GET der Opferdatei als Peer liefert 403. Der Überrest ist die implizierte Wurzel des Processing-Ordners, nicht die Storage-CRUD-API.
Ein ROLE_USER listet die gespeicherten PDF-Namen eines anderen Benutzers auf und überschreibt diese Blobs. Der Download des Opfers liefert die manipulierte Datei zurück.
| ID | noch keine 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 |
| Produkt | Stirling-PDF |
| Betroffen | v3.2.0 (a7e593728dd9aa81e75318a949789d3c2e9ee754), Image stirlingtools/stirling-pdf:3.2.0-fat, Login aktiv, storage.enabled=true |
| Auth | ROLE_USER im Standard-Team |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1:18154 |
Überrest der Serie Stirling-PDF v3.2.0 leftovers. Verwandt: stirling-h2-import-leftover (H2 CREATE OR REPLACE ALIAS). Dieses Paket ist der Storage-IDOR.
Jeder eingeloggte menschliche ROLE_USER bei aktiviertem Login im proprietären/fat-Modus mit aktiviertem lokalem Speicher (Template-Standard). Das offizielle Compose ist Login-deaktiviert plus DISABLE_ADDITIONAL_FEATURES=true; dieses Deployment liefert 403 auf /api/v1/storage und lässt diesen Controller weg. Das HIT-Deployment ist Template mit Login aktiv plus fat.
Privilegientabelle (vollständig). Gleicher Maßstab wie Signal-Server Dropwizard admin.
| Achse | Methode + Pfad | Gewährt | Herkunft |
|---|---|---|---|
| Recon | ROLE_USER GET /api/v1/user/users | Numerische userId für Admin, Peer und STIRLING-PDF-BACKEND-API-USER | Im Lab nachgewiesen |
| Recon | POST /api/v1/processing-folders {directory:"storage/1"} dann GET /api/v1/processing-folders/{id}/files | Name, Größe, mtime der gespeicherten PDF des Admins (5341de35-8729-49cf-92d0-c8284e05bfc5_victim-lab.pdf) | Im Lab nachgewiesen |
| Integrität | POST /api/v1/processing-folders/{id}/sweep mit /api/v1/security/add-watermark dann Opfer-Range GET /api/v1/storage/files/1/download | In-Place-Überschreiben. Opfer-206 / 3450 Bytes enthält STIRLING-STORAGE-FOLDER-IDOR-WITNESS | Im Lab nachgewiesen (replace=true) |
| Vertraulichkeit | gleicher Sweep plus eine Team-outputId / ausgehender Schritt, den der Angreifer lesen kann | Kopie der PDF-Bytes des Opfers | Abgeleitet. Nicht erforderlich für Auflisten/Überschreiben |
Bleibt bei diesem Pin geschlossen
| Achse | Methode + Pfad | Warum geschlossen |
|---|---|---|
| Recon | GET /api/v1/storage/files/{id} einer nicht geteilten Datei | 403 Access denied. Im Lab nachgewiesen an Datei-ID 1 |
| Recon | unauth /api/v1/storage/** | 403, wenn Login deaktiviert ist (ensureStorageEnabled) |
| Integrität | Ordner-UUID-CRUD über Eigentümer hinweg | findByIdAndOwner |
| Integrität | LocalStorageProvider .. / absoluter Schlüssel | Path.startsWith(basePath) nach Normalisierung |
| Integrität | Ultra-Lite-Image | proprietärer Processing-Folder-Controller fehlt |
GET /api/v1/user/users, das STIRLING-PDF-BACKEND-API-USER auflistet, ist ein zusätzlicher IOC. Ich habe es nicht als eigenes Leftover gemeldet. Ein Download des Opfers ohne Range liefert nach dem Überschreiben 500er, weil FileStorageController weiterhin die ursprüngliche DB-sizeBytes angibt. Range funktioniert. Der Watermark-Text ist Identity-H in FlateDecode; das Orakel entpackt die Streams.
3.x fügte lokalen Speicher und Processing-Folder hinzu. Storage-CRUD ist eigentümerbeschränkt. FolderAccessGuard.serverStorageRoots gibt Path.of(basePath) für den gesamten Baum zurück, nicht basePath/{currentUserId}. storage/<victimId> startsWith dieses implizierte Root.
Das Lab erstellt peeruser als ROLE_USER, lädt als Admin ein Opfer-PDF hoch, weist nach, dass ein direkter Storage-GET 403 liefert, richtet einen Processing-Folder auf storage/1, listet den UUID-präfixierten Namen auf, führt einen Watermark-Sweep durch und lädt dann als Opfer per Range-Download herunter.
Irrwege: direkten Storage-IDOR als weiterhin offen zu behandeln (403); das offizielle Compose mit deaktiviertem Login als HIT-Deploy zu behandeln (Storage 403, Controller fehlt); eine für Angreifer lesbare Byte-Kopie ohne outputId zu behaupten.
python3 stirling-storage-folder-idor-Abraxas-Labs.py
oder
cd lab
./run.sh
Ziel ist ausschließlich http://127.0.0.1:18154. Image stirlingtools/stirling-pdf:3.2.0-fat. Docker erforderlich. Login aktiviert. Der Launcher führt chdir in lab/ aus und startet run.sh per 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
Begrenze das implizierte Speicher-Stammverzeichnis auf basePath/{currentUserId} für die Festplatte directory auf Mehrbenutzer-Servern. Verweigere storage/<otherId> so, wie findByIdAndOwner bereits fremde Datei-IDs verweigert. Berechne die angegebene sizeBytes nach einem In-Place-Umschreiben neu.
Führe den Loopback-Client erneut gegen einen gepatchten Build aus: directory=storage/1 als peeruser muss 403 ergeben, und listed-peer muss leer bleiben.
Bis dahin behandle "Ich habe /api/v1/storage/files/{id} gepatcht" nicht als "Ich habe jede API abgesichert, die einen Festplattenpfad unter ./storage entgegennimmt."