Drupal 11.4.8 – Hoch – Remote – Upload – CKEditor 5 Bild-Upload umgeht weiterhin FileIsImage
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-ckeditor-fileisimage
Klasse: Unbeschränkter Upload / gespeichertes XSS Reichweite: Remote
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-009 fügte FileIsImage bei JSON:API- und REST-Bildfeldern hinzu. CKEditor5ImageController::getImageUploadValidators gibt weiterhin nur FileExtension, FileSizeLimit und FileImageDimensions zurück. FileImageDimensions kehrt ohne Verstoß zurück, wenn die Datei kein gültiges Bild ist. Die Dateinamenerweiterung ist die verbleibende Prüfung.
Ein Benutzer eines Textformats mit CKEditor 5-Bildupload kann Nicht-Bild-Bytes namens x.png an /ckeditor5/upload-image/{editor} senden und erhält 201 plus eine öffentliche Datei-URL.
| ID | noch keine CVE |
| Klasse | Unbeschränkter Upload / gespeichertes XSS bei Sniffing |
| Reichweite | Remote (authentifizierter Formatbenutzer) |
| CWE | CWE-434, CWE-79 |
| CVSS | Mittel: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Produkt | Drupal core |
| Betroffen | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| Auth | authentifizierter Benutzer eines Textformats mit CKEditor 5-Bildupload (basic_html / full_html bei Standard) |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Benötigt ein Konto, das ein Format verwenden kann, dessen Editor image_upload.status auf true hat. Bei Standard sind das basic_html und full_html. Ein völlig Fremder ohne Konto kann diese Route nicht erreichen (_entity_access: editor.use plus CSRF).
| Berechtigung | Methode / Sink | Art | Lab-bewiesen oder abgeleitet |
|---|---|---|---|
Nicht-Bild-Bytes in eine öffentliche .png unter sites/default/files/inline-images/ schreiben | POST /ckeditor5/upload-image/{editor} multipart upload | Integrität | Lab-bewiesen. x.png lieferte 201 und url=/sites/default/files/inline-images/x.png |
| Diese Bytes über die öffentliche Datei-URL zurücklesen | GET der JSON-url | Recon | Lab-bewiesen. 200, 49 Bytes, Body enthielt DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS |
| Gespeichertes XSS bei einem Besucher, wenn der Webserver oder Browser die Datei als HTML/JS sniffed | Dieselbe öffentliche URL, Content-Type nicht image | Integrität (Besucher-Origin) | Abgeleitet. Dieses Lab änderte Apache MIME nicht. Drupal speicherte die Bytes. |
| Ein echtes Bild über dieselbe Route hochladen | Kontrolle control.png 1x1 PNG | beabsichtigt | Lab-bewiesen. 201 |
Geschlossen bei diesem Überbleibsel: PHP/RCE über .php (lab-bewiesen 422 FileExtension); unauthentifizierter Upload; JSON:API/REST ImageItem (diese Pfade fügen bereits FileIsImage hinzu); LPE; eine Shell auf der Standard-Bild-Erweiterungs-Allowlist.
Ich habe Drupal 11.4.8 nach der SA-CORE-Welle 2026 gepinnt. JSON:API fügt die fehlende Constraint bereits hinzu:
if (\is_a($field_definition->getItemDefinition()->getClass(), ImageItem::class, TRUE) && !array_key_exists('FileIsImage', $validators)) {
$validators['FileIsImage'] = [];
}
REST FileUploadResource.php macht dasselbe. CKEditor 5 blieb bei Dateiname + Größe + Dimensionen:
return [
'FileExtension' => [
'extensions' => implode(' ', $allowed_extensions),
],
'FileSizeLimit' => [
'fileLimit' => $max_filesize,
],
'FileImageDimensions' => [
'maxDimensions' => $max_dimensions,
],
];
FileImageDimensionsConstraintValidator kehrt ohne Verstoß zurück, wenn die Datei kein gültiges Bild ist. Hub drupal:11.4 driftete auf 11.4.9; dieser Pin ist composer-exakt drupal/recommended-project:11.4.8. 11.4.0 entfernte Article aus Standard, daher wendet das Image nach der Installation core/recipes/article_content_type an, damit /node/add/article CKEditor 5 lädt.
Bereits dokumentierte Irrwege: FileImageDimensions als MIME-Prüfung zu behandeln (es sind Dimensionen bei einem gültigen Bild und ansonsten ein No-op); eine PHP-Shell auf der Standard-Allowlist zu behaupten (.php ist 422); das floatende Hub-Tag zu verwenden und zu beobachten, wie 11.4.9 auftaucht. Theater: eine Reverse Shell. Das Orakel ist 201 bei gefälschtem x.png plus 422 bei denselben Bytes namens x.php.
Überbleibsel desselben Pins: oEmbed Second-Hop SSRF.
python3 drupal-ckeditor-fileisimage-Abraxas-Labs.py
oder
cd lab
./run.sh
Ziel nur http://127.0.0.1:19500. Live Drupal 11.4.8 Standard auf 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
Füge 'FileIsImage' => [] zu CKEditor5ImageController::getImageUploadValidators hinzu. Behalte FileExtension, damit .php 422 bleibt. Bild-Medientypen in der Medienbibliothek sollten ImageItem statt eines generischen FileItem verwenden, damit sie dieselbe Constraint erben.
61044508071749629aaf3380aa85971e94df9e84)CKEditor5ImageController.phpGNU Affero GPL v3.0. Siehe LICENSE. Nur Loopback-Lab. Keine Gewährleistung.