
Stirling-PDF v3.2.0 - Crítico - Remoto - Resto de RUNSCRIPT en H2 - 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
Clase: resto de RUNSCRIPT de H2 de GHSA-mrr8. Alcance: ROLE_ADMIN remoto.
POST /api/v1/database/import-database está protegido con @PreAuthorize("hasRole('ADMIN')"). Se supone que validateSqlContent detiene CREATE ALIAS. La lista de denegación es CREATE\s+(FORCE\s+)?ALIAS. El parseCreate de H2 permite OR REPLACE antes de ALIAS, por lo que CREATE OR REPLACE ALIAS … FOR "java.lang.…" coincide con la lista de permitidos \bCREATE\b y no coincide con la lista de denegación. El validador sanitiza una copia. verifyBackup y la producción ejecutan RUNSCRIPT FROM ? sobre el archivo original.
GHSA-mrr8-934j-4g8m / CVE-2026-85714 cerró las cadenas originales FILE_READ / CREATE ALIAS / CSVWRITE. Este resto es el hueco de OR REPLACE en ese mismo validador.
Una importación con ROLE_ADMIN crea un alias de Java que la lista de denegación debería detener. Una descarga de copia de seguridad posterior contiene SQL del atacante. El RCE del host mediante FILE_READ / FileUtils del aviso original es inferido, no probado en laboratorio en este paquete.
| ID | aún sin CVE |
| 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 |
| Producto | Stirling-PDF |
| Afectado | v3.2.0 (a7e593728dd9aa81e75318a949789d3c2e9ee754), imagen stirlingtools/stirling-pdf:3.2.0-fat |
| Autenticación | ROLE_ADMIN, H2 embebido por defecto. Primer administrador por defecto admin / stirling hasta que se cambie |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:18152 |
Resto de la serie Stirling-PDF v3.2.0 leftovers. Hermano: stirling-storage-folder-idor (raíz de almacenamiento implícita de la carpeta de procesamiento). Este paquete es el resto de la importación de H2.
ROLE_ADMIN en login-on proprietary/fat con el H2 embebido por defecto. El primer administrador por defecto es admin / stirling cuando initialLogin está vacío. No necesitan acceso no autenticado. La imagen Lite y las fuentes de datos PostgreSQL no incluyen este controlador.
Tabla de privilegios (exhaustiva). Mismo criterio que Signal-Server Dropwizard admin: método + ruta, qué concede esa llamada, reconocimiento vs integridad vs disponibilidad, probado en laboratorio vs inferido, superficie adyacente que permanece cerrada.
| Eje | Método + ruta | Concede | Procedencia |
|---|---|---|---|
| Integridad | ROLE_ADMIN POST /api/v1/database/import-database con CREATE OR REPLACE ALIAS lab_nano FOR "java.lang.System.nanoTime" más INSERT INTO lab_w VALUES('STIRLING-H2-IMPORT-WITNESS') | 200 importIntoDatabaseSuccessed. Alias de Java creado. SQL del atacante confirmado bajo RUNSCRIPT | Probado en laboratorio |
| Reconocimiento | ROLE_ADMIN GET /api/v1/database/createDatabaseBackup luego GET /api/v1/database/download/backup_202610172328.sql | La copia de seguridad de 50432 bytes contiene STIRLING-H2-IMPORT-WITNESS | Probado en laboratorio |
| Reconocimiento / archivo del host | la misma importación envolviendo FILE_READ('/etc/os-release') en EXECUTE IMMEDIATE | 500 Backup verification failed. Los bytes del host no están en una copia de seguridad | Extra de laboratorio FALLO |
| Integridad / RCE | alias org.h2.store.fs.FileUtils más CSVWRITE de un .pth de user-site de Python, luego conversión de office | Ejecución de comandos como la cuenta de servicio | Inferido de GHSA-mrr8. No probado en laboratorio aquí |
| Disponibilidad | ninguna reclamada | La importación puede reemplazar tablas de la aplicación | Inferido. No es el oráculo del laboratorio |
Permanece cerrado en este pin
| Eje | Método + ruta | Por qué está cerrado |
|---|---|---|
| Integridad | POST /api/v1/database/import-database sin autenticación | 401 Authentication required. La seguridad de método ADMIN permanece activa cuando HTTP es permitAll |
| Integridad | importación de ROLE_ADMIN de un CREATE ALIAS simple | 500 SQL script contains disallowed operations and was rejected |
| Integridad | imagen lite / DISABLE_ADDITIONAL_FEATURES | DatabaseController ausente |
| Integridad | fuente de datos PostgreSQL personalizada | @Conditional(H2SQLCondition.class) |
No estoy reclamando una reverse shell, y no estoy reclamando FILE_READ del host como probado en laboratorio. Lo que queda es el fallo de la lista de denegación que permite que CREATE OR REPLACE ALIAS … FOR "java.lang.…" pase a través de RUNSCRIPT.
v3.2.0 todavía incluye el validador de GHSA-mrr8. Me detuve en esa etiqueta y leí DENIED_PATTERNS. La línea del alias es CREATE\s+(FORCE\s+)?ALIAS. El analizador de H2 acepta CREATE OR REPLACE ALIAS. Las pruebas cubren las cadenas obvias CREATE ALIAS / FILE_READ(. No cubren OR REPLACE.
El laboratorio inicia sesión como admin predeterminado, completa change-password-on-login, importa un CREATE ALIAS denegado (500), luego importa CREATE OR REPLACE ALIAS más un testigo INSERT (200). Una descarga de copia de seguridad contiene el testigo.
Caminos equivocados: tratar la importación sin autenticación como dentro del alcance (401); tratar EXECUTE IMMEDIATE + FILE_READ como lo que queda (verifyBackup 500); tratar el CREATE ALIAS original sin ofuscar como todavía activo (está denegado).
python3 stirling-h2-import-leftover-Abraxas-Labs.py
o
cd lab
./run.sh
Dirígete solo a http://127.0.0.1:18152. Imagen stirlingtools/stirling-pdf:3.2.0-fat. Se requiere Docker. Login activado. El lanzador hace chdir a lab/ y ejecuta 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
Amplía la lista de denegación para que OR REPLACE no pueda situarse entre CREATE y ALIAS. Ejecuta validateSqlContent sobre los mismos bytes que RUNSCRIPT ejecutará. Deniega EXECUTE IMMEDIATE a menos que el SQL interno también se analice.
Pattern.compile("(?i)\\bCREATE\\s+(OR\\s+REPLACE\\s+)?(FORCE\\s+)?ALIAS\\b")