
Drupal 11.4.8 - 高 - リモート - アップロード - CKEditor 5 の画像アップロードが依然として FileIsImage をスキップする
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-ckeditor-fileisimage
クラス: 無制限アップロード / 格納型 XSS 到達性: リモート
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-009 は JSON:API および REST の画像フィールドに FileIsImage を追加した。CKEditor5ImageController::getImageUploadValidators は依然として FileExtension、FileSizeLimit、FileImageDimensions のみを返す。FileImageDimensions はファイルが有効な画像でない場合、違反なしで返る。残るチェックはファイル名拡張子だけである。
CKEditor 5 の画像アップロードが有効なテキストフォーマットのユーザーは、x.png という名前の非画像バイト列を /ckeditor5/upload-image/{editor} に POST し、201 と公開ファイル URL を得ることができる。
| ID | CVE 未採番 |
| クラス | 無制限アップロード / スニッフィングされた場合の格納型 XSS |
| 到達性 | リモート (認証済みフォーマットユーザー) |
| CWE | CWE-434, CWE-79 |
| CVSS | Medium: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| 製品 | Drupal core |
| 影響を受けるバージョン | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| 認証 | CKEditor 5 の画像アップロードが有効なテキストフォーマットの認証済みユーザー (Standard では basic_html / full_html) |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1 のみ |
エディタで image_upload.status が true のフォーマットを使用できるアカウントが必要である。Standard では basic_html と full_html が該当する。アカウントを持たない完全な部外者はこのルートに到達できない (_entity_access: editor.use と CSRF)。
| 権限 | メソッド / シンク | 種別 | ラボ実証または推測 |
|---|---|---|---|
非画像バイト列を sites/default/files/inline-images/ 配下の公開 .png に書き込む | POST /ckeditor5/upload-image/{editor} multipart upload | 完全性 | ラボ実証済み。x.png は 201 と url=/sites/default/files/inline-images/x.png を返した |
| 公開ファイル URL でそのバイト列を読み戻す | JSON の url に対する GET | 偵察 | ラボ実証済み。200、49 バイト、ボディに DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS を含む |
| Web サーバーまたはブラウザがファイルを HTML/JS としてスニッフィングした場合、訪問者に格納型 XSS | 同じ公開 URL、Content-Type は image ではない | 完全性 (訪問者のオリジン) | 推測。このラボでは Apache MIME を変更していない。Drupal はバイト列を保存した。 |
| 同じルートで本物の画像をアップロードする | コントロール control.png 1x1 PNG | 意図された動作 | ラボ実証済み。201 |
この残存部分でクローズ済み: .php 経由の PHP/RCE (ラボ実証済み 422 FileExtension)、未認証アップロード、JSON:API/REST ImageItem (これらのパスは既に FileIsImage を追加している)、LPE、デフォルトの画像拡張子許可リスト上のシェル。
2026 年の SA-CORE の波の後、Drupal 11.4.8 にピン留めした。JSON:API は既に欠落している制約を追加している:
if (\is_a($field_definition->getItemDefinition()->getClass(), ImageItem::class, TRUE) && !array_key_exists('FileIsImage', $validators)) {
$validators['FileIsImage'] = [];
}
REST の FileUploadResource.php も同様である。CKEditor 5 はファイル名 + サイズ + 寸法のまま残された:
return [
'FileExtension' => [
'extensions' => implode(' ', $allowed_extensions),
],
'FileSizeLimit' => [
'fileLimit' => $max_filesize,
],
'FileImageDimensions' => [
'maxDimensions' => $max_dimensions,
],
];
FileImageDimensionsConstraintValidator はファイルが有効な画像でない場合、違反なしで返る。ハブの drupal:11.4 は 11.4.9 にフロートした。このピンは composer で正確に drupal/recommended-project:11.4.8 である。11.4.0 で Standard から Article が削除されたため、このイメージはインストール後に core/recipes/article_content_type を適用し、/node/add/article が CKEditor 5 をロードするようにしている。
既に記録済みの誤った道: FileImageDimensions を MIME チェックとして扱うこと (これは有効な画像に対する寸法であり、それ以外ではノーオペレーションである)、デフォルトの許可リスト上で PHP シェルを主張すること (.php は 422)、フローティングのハブタグを使用して 11.4.9 が立ち上がるのを見ること。茶番: リバースシェル。オラクルは偽の x.png に対する 201 と、同じバイト列を x.php と名付けた場合の 422 である。
同じピンの残存部分: oEmbed second-hop SSRF。
python3 drupal-ckeditor-fileisimage-Abraxas-Labs.py
または
cd lab
./run.sh
ターゲットは http://127.0.0.1:19500 のみ。php:8.4-apache-trixie 上のライブ Drupal 11.4.8 Standard、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
CKEditor5ImageController::getImageUploadValidators に 'FileIsImage' => [] を追加する。.php が 422 のままになるよう FileExtension は維持する。Media Library の画像メディアタイプは、同じ制約を継承するよう、汎用の FileItem ではなく ImageItem を使用すべきである。
61044508071749629aaf3380aa85971e94df9e84)CKEditor5ImageController.phpGNU Affero GPL v3.0。LICENSE を参照。ループバックラボのみ。無保証。