↓ Salta al contenuto principale

PHP2Shell: la patch è facile, sapere dove applicarla no

Il 21 ottobre il progetto PHP ha rilasciato le versioni 8.5.12, 8.4.27, 8.3.36 e 8.2.35 per correggere due vulnerabilità che in pochi giorni hanno preso il nome di PHP2Shell. Sono due falle nell’interprete, non in un framework o in un CMS: riguardano qualsiasi installazione di PHP che serve richieste web.

Leggendo gli advisory mi sono accorto che la parte tecnica, per chi deve difendersi, è la più semplice. La patch c’è, la mitigazione temporanea è una riga di configurazione. Il problema vero arriva prima: sapere dove gira PHP. Su questo la maggior parte delle organizzazioni non ha una risposta pronta, e sospetto che valga anche per molte di quelle che pensano di averla.

Cosa sono le due CVE
#

Riassumo quello che ho capito dagli advisory di PHP, dal repository dell’NCSC olandese e dall’analisi di Qualys. Non ho riprodotto l’exploit e non ho intenzione di farlo su sistemi che non sono miei.

  • CVE-2026-109618: corruzione di memoria legata alla gestione dell’out-of-memory. Quando una richiesta esaurisce la memoria, PHP può abbandonarla con strutture inizializzate solo in parte, e la fase di chiusura della richiesta le tratta come valide.
  • CVE-2026-109619: stato globale che appartiene a una richiesta e sopravvive fino alla richiesta successiva sullo stesso worker (un use-after-free). Uno dei percorsi passa per la funzione di upload progress delle sessioni. Oltre all’esecuzione di codice può far trapelare memoria, quindi password, token, chiavi API.

Entrambe hanno CVSS v4.0 pari a 9.2 e permettono esecuzione remota di codice senza autenticazione, con i privilegi dell’utente del web server. Il vettore dice AC:H/AT:P: lo sfruttamento dipende da build, allocatore e scheduling dei worker, quindi non è affidabile al primo colpo. Su Apache con mod_php, che il progetto PHP considera la configurazione più a rischio, è stata dimostrata una RCE con i limiti predefiniti e una richiesta per tentativo. Sono coinvolti anche PHP-FPM, php-cgi, FrankenPHP e LiteSpeed.

Sullo sfruttamento reale: Qualys riporta che Cloudflare ha visto traffico di attacco, inclusi tentativi di aggirare le sue regole, e che su GitHub circolano proof of concept. Ho letto anche di una campagna con decine di server compromessi, ma la fonte è un solo vendor e non sono riuscito a verificarla, quindi la lascio fuori.

La parte facile: patch e mitigazione
#

Le versioni corrette sono 8.5.12, 8.4.27, 8.3.36 e 8.2.35. Per 7.4, 8.0 e 8.1, fuori supporto, PHP ha pubblicato solo backport minimi; per i pacchetti delle distribuzioni contano gli advisory di Debian, Ubuntu, Red Hat e degli altri.

Se non si può aggiornare subito, PHP ha consigliato il 23 ottobre di disattivare l’upload progress delle sessioni fino al prossimo bugfix release:

; php.ini, fino al prossimo rilascio di manutenzione
session.upload_progress.enabled = 0

Dopo il cambio, o dopo l’aggiornamento, vanno riavviati tutti i worker. Qualys aggiunge altre impostazioni (limiti su post_max_size, max_input_nesting_level, fatal_error_backtraces=0 su 8.5, pm.max_requests=1 su FPM se il costo è accettabile), ma il progetto PHP è chiaro sul fatto che nessuna di queste è una correzione completa.

Fin qui niente di diverso da cento altri bollettini. È il passo successivo che mi interessa.

Il numero inaspettato
#

Il repository dell’NCSC olandese tiene una lista dei prodotti che contengono PHP e del loro stato rispetto a PHP2Shell. Stamattina, 30 ottobre, conteneva:

StatoProdotti
Vulnerabili217
Corretti165
In verifica345
Non coinvolti201
Sconosciuti1
Totale tracciati929

Dentro ci sono le interfacce web dei firewall Check Point, Cisco Expressway, il server di Broadcom Carbon Black App Control, centralini VitalPBX. Sophos ha pubblicato un hotfix per i firewall con regole WAF aggiuntive. Sono tutti prodotti in cui PHP non si vede: nessuno li cataloga come “server PHP”, e spesso l’amministratore non può aggiornare l’interprete a mano, deve aspettare il vendor.

Più di un terzo della lista è ancora «in verifica» a nove giorni dalla patch. Questo significa che per centinaia di prodotti nemmeno il produttore sa ancora dire se è esposto.

Poi c’è il dato di Qualys, che va preso per quello che è (la telemetria di un singolo vendor sui propri clienti), ma dà un ordine di grandezza: 167 milioni di installazioni PHP osservate, di cui circa 110 milioni su versioni fuori supporto e 44 milioni su rami supportati ma non aggiornati. Nelle prime dodici ore ne risultavano patchate circa 199.000.

Cosa vuol dire inventario, per PHP2Shell
#

Prima pensavo all’asset inventory come a un elenco di macchine. Questa vulnerabilità mi ha costretto a vederlo come un elenco di domande, e un elenco di host risponde solo alla prima.

  1. Dove gira PHP? Non solo sui server applicativi: appliance, VM dimenticate in DMZ, immagini container, NAS, centralini, strumenti interni installati da un altro team anni fa.
  2. Con quale SAPI? mod_php è il caso peggiore, PHP-FPM ha condizioni diverse. Senza questo dato non si possono fissare le priorità.
  3. È esposto? Un PHP raggiungibile da internet e uno su una rete di gestione isolata non hanno la stessa urgenza.
  4. Chi lo aggiorna? Il pacchetto della distribuzione, l’immagine base di un container, un binario compilato a mano, oppure il vendor dell’appliance. Sono quattro processi diversi con quattro tempi diversi.
  5. Di chi è? Se non c’è un nome accanto al sistema, la patch non la applica nessuno.

C’è anche una trappola sulla versione. Le distribuzioni fanno backport delle correzioni senza cambiare il numero di versione principale: un PHP 8.2 di Debian può essere corretto anche se la stringa non dice 8.2.35. Un inventario che confronta solo php -v con la lista delle versioni sicure produce falsi positivi da una parte e falsa sicurezza dall’altra. Bisogna guardare la versione del pacchetto e l’advisory della distribuzione.

Da dove partirei su un singolo host Linux
#

Questi sono i comandi che userei per rispondere alle domande sopra su una macchina. Non sostituiscono uno strumento di inventario, ma servono a capire cosa quello strumento dovrebbe raccogliere.

# Quali pacchetti PHP sono installati (versione del pacchetto, non solo di PHP)
dpkg -l | grep -i php        # Debian/Ubuntu
rpm -qa | grep -i php        # RHEL e derivate

# Binari PHP fuori dal package manager (compilati a mano, bundle di prodotti)
find / -xdev -type f -name 'php*' -perm -u+x 2>/dev/null

# Apache carica mod_php?
apachectl -M 2>/dev/null | grep -i php

# Processi PHP in esecuzione e porte in ascolto
ps aux | grep -E 'php-fpm|php-cgi|frankenphp|lsphp' | grep -v grep
ss -ltnp | grep -i php

# Stato della mitigazione
php -i | grep -i 'session.upload_progress.enabled'

Per i container il discorso si sposta sulle immagini: va controllato quale versione di PHP contiene ogni immagine in uso, e questo lo fa meglio uno scanner di immagini che un comando lanciato a mano.

L’header X-Powered-By lo lascerei perdere. Molte configurazioni lo disattivano, e la sua assenza non dice che PHP non c’è.

Riflessioni finali
#

La patch di PHP2Shell richiede dieci minuti per server. Scoprire quali server esistono, e quali prodotti hanno PHP dentro, può richiedere settimane, e in quelle settimane l’exploit resta disponibile per chiunque.

Per questo l’asset inventory mi sembra il controllo meno appariscente e più decisivo del vulnerability management. Quando esce una CVE critica su un componente così diffuso, la velocità con cui un’organizzazione risponde dipende quasi del tutto da un lavoro fatto prima: sapere cosa ha, con quale configurazione, chi ne risponde e chi può aggiornarlo.

Restano aperte due cose. La prima è come si inventaria davvero il software dentro le appliance, dove non hai accesso alla shell e dipendi dalla lista pubblicata dal vendor; la risposta onesta, per ora, è che non lo so. La seconda è il ruolo degli SBOM: in teoria risolvono esattamente questo problema, in pratica non ho ancora visto un vendor di appliance fornirne uno utilizzabile. È uno dei temi che voglio studiare nelle prossime settimane.

Fonti
#