
Stirling-PDF v3.2.0 - Critico - Remoto - Residuo di H2 RUNSCRIPT - CREATE OR REPLACE ALIAS import-database
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · stirling-h2-import-leftover
Stirling-PDF 3.2.0 - Stirling Tools
Classe: residuo H2 RUNSCRIPT di GHSA-mrr8. Portata: ROLE_ADMIN remoto.
POST /api/v1/database/import-database è @PreAuthorize("hasRole('ADMIN')"). validateSqlContent dovrebbe bloccare CREATE ALIAS. La denylist è CREATE\s+(FORCE\s+)?ALIAS. H2 parseCreate consente OR REPLACE prima di ALIAS, quindi CREATE OR REPLACE ALIAS … FOR "java.lang.…" corrisponde alla allowlist \bCREATE\b e sfugge alla denylist. Il validatore sanifica una copia. verifyBackup e la produzione eseguono RUNSCRIPT FROM ? sul file originale.
GHSA-mrr8-934j-4g8m / CVE-2026-85714 ha chiuso le stringhe originali FILE_READ / CREATE ALIAS / CSVWRITE. Questo residuo è la lacuna OR REPLACE su quello stesso validatore.
Un import ROLE_ADMIN crea un alias Java che la denylist dovrebbe bloccare. Un successivo download di backup contiene SQL dell'attaccante. L'RCE tramite FILE_READ / FileUtils sull'host dall'advisory originale è dedotto, non dimostrato in laboratorio in questo pacchetto.
| ID | nessuna CVE al momento |
| CWE | CWE-94 / CWE-184 |
| CVSS | 9.1 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H |
| Prodotto | Stirling-PDF |
| Affetto | v3.2.0 (a7e593728dd9aa81e75318a949789d3c2e9ee754), immagine stirlingtools/stirling-pdf:3.2.0-fat |
| Auth | ROLE_ADMIN, H2 embedded predefinito. Primo admin predefinito admin / stirling finché non viene cambiato |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1:18152 |
Residuo della serie Stirling-PDF v3.2.0 leftovers. Correlato: stirling-storage-folder-idor (processing-folder implicito nella radice di storage). Questo pacchetto è il residuo dell'import H2.
ROLE_ADMIN su login-on proprietary/fat con l'H2 embedded predefinito. Il primo admin predefinito è admin / stirling quando initialLogin è vuoto. Non serve essere non autenticati. L'immagine Lite e i datasource PostgreSQL non includono questo controller.
Tabella dei privilegi (esaustiva). Stesso criterio di Signal-Server Dropwizard admin: metodo + percorso, cosa concede quella chiamata, ricognizione vs integrità vs disponibilità, dimostrato in laboratorio vs dedotto, superficie adiacente che resta chiusa.
| Asse | Metodo + percorso | Concede | Provenienza |
|---|---|---|---|
| Integrità | ROLE_ADMIN POST /api/v1/database/import-database con CREATE OR REPLACE ALIAS lab_nano FOR "java.lang.System.nanoTime" più INSERT INTO lab_w VALUES('STIRLING-H2-IMPORT-WITNESS') | 200 importIntoDatabaseSuccessed. Alias Java creato. SQL dell'attaccante confermato sotto RUNSCRIPT | Dimostrato in laboratorio |
| Ricognizione | ROLE_ADMIN GET /api/v1/database/createDatabaseBackup poi GET /api/v1/database/download/backup_202610172328.sql | Il backup da 50432 byte contiene STIRLING-H2-IMPORT-WITNESS | Dimostrato in laboratorio |
| Ricognizione / file host | stesso import che incapsula FILE_READ('/etc/os-release') in EXECUTE IMMEDIATE | 500 Backup verification failed. I byte dell'host non sono in un backup | Extra di laboratorio FALLITO |
| Integrità / RCE | alias org.h2.store.fs.FileUtils più CSVWRITE di un file .pth nella user-site di Python, poi conversione office | Esecuzione di comandi come l'account del servizio | Dedotto da GHSA-mrr8. Non testato in laboratorio qui |
| Disponibilità | nessuna rivendicata | L'import può sostituire le tabelle dell'applicazione | Dedotto. Non è l'oracolo di laboratorio |
Resta chiuso su questo pin
| Asse | Metodo + percorso | Perché è chiuso |
|---|---|---|
| Integrità | POST /api/v1/database/import-database non autenticato | 401 Authentication required. La sicurezza a livello di metodo ADMIN resta attiva quando HTTP è permitAll |
| Integrità | import ROLE_ADMIN di un semplice CREATE ALIAS | 500 SQL script contains disallowed operations and was rejected |
| Integrità | immagine lite / DISABLE_ADDITIONAL_FEATURES | DatabaseController assente |
| Integrità | datasource PostgreSQL personalizzato | @Conditional(H2SQLCondition.class) |
Non sto rivendicando una reverse shell, e non sto rivendicando FILE_READ sull'host come dimostrato in laboratorio. Ciò che resta è la lacuna nella denylist che lascia passare CREATE OR REPLACE ALIAS … FOR "java.lang.…" attraverso RUNSCRIPT.
v3.2.0 distribuisce ancora il validatore di GHSA-mrr8. Mi sono fermato su quel tag e ho letto DENIED_PATTERNS. La riga dell'alias è CREATE\s+(FORCE\s+)?ALIAS. Il parser di H2 accetta CREATE OR REPLACE ALIAS. I test coprono le stringhe ovvie CREATE ALIAS / FILE_READ(. Non coprono OR REPLACE.
Il laboratorio effettua l'accesso come admin predefinito, completa change-password-on-login, importa un CREATE ALIAS negato (500), poi importa CREATE OR REPLACE ALIAS più un INSERT testimone (200). Un download del backup contiene il testimone.
Vicoli ciechi: considerare l'import non autenticato come in scope (401); considerare EXECUTE IMMEDIATE + FILE_READ come la lacuna residua (verifyBackup 500); considerare il CREATE ALIAS originale non offuscato come ancora attivo (viene negato).
python3 stirling-h2-import-leftover-Abraxas-Labs.py
o
cd lab
./run.sh
Prendi di mira solo http://127.0.0.1:18152. Immagine stirlingtools/stirling-pdf:3.2.0-fat. Docker richiesto. Login attivo. Il launcher esegue chdir in lab/ ed esegue run.sh.
IOC unauth-import http=401
IOC negative-import http=500 ... disallowed operations ...
IOC leftover-import bypass=create-or-replace-alias http=200 ... importIntoDatabaseSuccessed
IOC download file=backup_202610172328.sql http=200 bytes=50432 witness=1
SUCCESS stirling-h2-import-leftover negative-denied=yes bypass=create-or-replace-alias backup-has-witness=yes file=backup_202610172328.sql unauth-import=401 STIRLING-H2-IMPORT-WITNESS
Estendi la denylist in modo che OR REPLACE non possa trovarsi tra CREATE e ALIAS. Esegui validateSqlContent sugli stessi byte che RUNSCRIPT eseguirà. Nega EXECUTE IMMEDIATE a meno che anche l'SQL interno non venga analizzato.
Pattern.compile("(?i)\\bCREATE\\s+(OR\\s+REPLACE\\s+)?(FORCE\\s+)?ALIAS\\b")
Esegui di nuovo il client di loopback su una build con patch: l'import residuo deve restituire 400/500 come già fa il semplice CREATE ALIAS.