Drupal 11.4.8 - Alta - Remoto - Upload - Il caricamento delle immagini di CKEditor 5 salta ancora FileIsImage
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-ckeditor-fileisimage
Classe: Upload non limitato / XSS memorizzato Portata: Remota
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-009 ha aggiunto FileIsImage sui campi immagine di JSON:API e REST. CKEditor5ImageController::getImageUploadValidators restituisce ancora solo FileExtension, FileSizeLimit e FileImageDimensions. FileImageDimensions ritorna senza violazione quando il file non è un'immagine valida. L'estensione del nome file è il controllo rimanente.
Un utente di un formato di testo con upload immagini di CKEditor 5 può inviare in POST byte non-immagine denominati x.png a /ckeditor5/upload-image/{editor} e ottenere 201 più un URL pubblico del file.
| ID | nessuna CVE al momento |
| Classe | Upload non limitato / XSS memorizzato se rilevato |
| Portata | Remota (utente autenticato del formato) |
| CWE | CWE-434, CWE-79 |
| CVSS | Medio: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Prodotto | Drupal core |
| Affetto | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| Auth | utente autenticato di un formato di testo con upload immagini di CKEditor 5 (basic_html / full_html su Standard) |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Serve un account che possa usare un formato il cui editor abbia image_upload.status true. Su Standard sono basic_html e full_html. Un estraneo completo senza account non può raggiungere questa rotta (_entity_access: editor.use più CSRF).
| Privilegio | Metodo / sink | Tipo | Provato in lab o dedotto |
|---|---|---|---|
Scrivere byte non-immagine in un .png pubblico sotto sites/default/files/inline-images/ | POST /ckeditor5/upload-image/{editor} multipart upload | integrità | Provato in lab. x.png ha restituito 201 e url=/sites/default/files/inline-images/x.png |
| Rileggere quei byte all'URL pubblico del file | GET dell'url JSON | ricognizione | Provato in lab. 200, 49 byte, il corpo conteneva DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS |
| XSS memorizzato in un visitatore se il web server o il browser rileva il file come HTML/JS | Stesso URL pubblico, Content-Type non image | integrità (origine del visitatore) | Dedotto. Questo lab non ha modificato il MIME di Apache. Drupal ha memorizzato i byte. |
| Caricare un'immagine reale attraverso la stessa rotta | Controllo control.png PNG 1x1 | previsto | Provato in lab. 201 |
Chiuso su questo residuo: PHP/RCE tramite .php (provato in lab 422 FileExtension); upload non autenticato; ImageItem di JSON:API/REST (quei percorsi aggiungono già FileIsImage); LPE; una shell sulla allowlist predefinita delle estensioni immagine.
Ho fissato Drupal 11.4.8 dopo l'ondata SA-CORE del 2026. JSON:API aggiunge già il vincolo mancante:
if (\is_a($field_definition->getItemDefinition()->getClass(), ImageItem::class, TRUE) && !array_key_exists('FileIsImage', $validators)) {
$validators['FileIsImage'] = [];
}
REST FileUploadResource.php fa lo stesso. CKEditor 5 è stato lasciato su nome file + dimensione + dimensioni:
return [
'FileExtension' => [
'extensions' => implode(' ', $allowed_extensions),
],
'FileSizeLimit' => [
'fileLimit' => $max_filesize,
],
'FileImageDimensions' => [
'maxDimensions' => $max_dimensions,
],
];
FileImageDimensionsConstraintValidator ritorna senza violazione quando il file non è un'immagine valida. L'hub drupal:11.4 è passato a 11.4.9; questo pin è composer-exact drupal/recommended-project:11.4.8. 11.4.0 ha rimosso Article da Standard, quindi l'immagine applica core/recipes/article_content_type dopo l'installazione affinché /node/add/article carichi CKEditor 5.
Vicoli ciechi già registrati: trattare FileImageDimensions come un controllo MIME (sono dimensioni su un'immagine valida, e un no-op altrimenti); sostenere una shell PHP sulla allowlist predefinita (.php è 422); usare il tag hub fluttuante e vedere comparire 11.4.9. Teatro: una reverse shell. L'oracolo è 201 su x.png falso più 422 sugli stessi byte denominati x.php.
Residui dello stesso pin: oEmbed second-hop SSRF.
python3 drupal-ckeditor-fileisimage-Abraxas-Labs.py
oppure
cd lab
./run.sh
Target solo http://127.0.0.1:19500. Drupal 11.4.8 Standard live su php:8.4-apache-trixie, SQLite.
SUCCESS drupal-ckeditor-fileisimage png-http=201 php-http=422 control-png-http=201 editor=basic_html stored-http=200 stored-has-witness=yes url=/sites/default/files/inline-images/x.png DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS
Aggiungere 'FileIsImage' => [] a CKEditor5ImageController::getImageUploadValidators. Mantenere FileExtension affinché .php resti 422. I media type immagine nella Media Library dovrebbero usare ImageItem invece di un generico FileItem in modo da ereditare lo stesso vincolo.
61044508071749629aaf3380aa85971e94df9e84)CKEditor5ImageController.phpGNU Affero GPL v3.0. Vedi LICENSE. Solo lab su loopback. Nessuna garanzia.