Un solo clic di un amministratore su un link malevolo, e su un sito WordPress può finire una shell. È questo il senso di Click2Shell, la catena di vulnerabilità scoperta da Paulos Yibelo della piattaforma di penetration testing autonomo pwn.ai e corretta con il rilascio di WordPress 7.1.1 il 17 settembre, un aggiornamento di sicurezza che chiude in tutto undici falle. Il problema non ha ricevuto un identificativo CVE ufficiale, ma dal 18 settembre esistono in rete il report tecnico completo e un proof of concept funzionante: chi non ha ancora aggiornato sta correndo un rischio che ieri era teorico e oggi non lo è più.

La falla risiede nel Core di WordPress, non in un plugin o in un tema di terze parti. Riguarda quindi, per definizione, tutte le installazioni fino alla 7.1.0 compresa.

Cosa è successo: un valore letto due volte, in due modi diversi

Il meccanismo è elegante e vale la pena capirlo, perché la classe di errore si ripresenta continuamente nelle applicazioni web.

WordPress consente a un amministratore di sfogliare, previsualizzare e installare i temi del catalogo ufficiale di WordPress.org senza uscire dal pannello di amministrazione. In quel flusso lo slug del tema — il suo identificativo testuale — viaggia dentro l'URL, e viene letto due volte da due pezzi di codice diversi che lo trattano in modo diverso.

Lato server, la Themes API di WordPress.org lo sanifica: una stringa come twentytwenty"]> viene ripulita e torna dall'API come un innocuo twentytwenty. Lato browser, invece, il JavaScript di wp-admin prende lo stesso valore grezzo e lo inserisce direttamente in un selettore jQuery senza alcuna sanificazione. Questa asimmetria è tutta la vulnerabilità: uno slug costruito ad arte convince la pagina che l'amministratore ha cliccato «Installa» su un tema completamente diverso da quello che sta guardando.

Il risultato è un'installazione silenziosa e forzata: un tema qualsiasi del catalogo ufficiale finisce sul sito senza che nessuno l'abbia chiesto.

Dalla fase uno alla compromissione del server

Un tema inattivo, di per sé, è sostanzialmente inerte. Esiste però un momento in cui WordPress esegue il codice di un tema che non è attivo: l'anteprima nel Customizer. È il perno della seconda fase.

Nella catena dimostrata da pwn.ai il secondo stadio è un tema reale del catalogo, Mobile Repair Zone 2.5.4. Il primo link installa il tema; un secondo link apre il Customizer con quel tema in anteprima, il che manda in esecuzione il suo functions.php e registra i suoi hook — fra cui un handler AJAX che accettava l'URL di un plugin da scaricare senza verifica del nonce e senza alcun controllo di capability. Passando a quell'azione l'URL di un archivio ZIP controllato dall'attaccante, WordPress lo tratta come un normale plugin: lo scarica e lo esegue lato server. Nessuna domanda.

Da lì, l'attaccante ha tutto quello che serve. Esecuzione di codice PHP significa lettura e modifica dei file, accesso ai dati degli utenti e, soprattutto, accesso a wp-config.php, che contiene le credenziali del database e le chiavi segrete di autenticazione. Da quel punto si creano amministratori fittizi, si iniettano script nelle pagine dei visitatori, si esfiltra il contenuto del database.

Un dettaglio va sottolineato, perché è quello che rende la vicenda più grave di quanto sembri: Yibelo ha dimostrato la catena con un tema specifico, ma la falla nel Core permette di forzare l'installazione di qualunque tema vulnerabile presente nel catalogo. Rimuovere o correggere Mobile Repair Zone non chiude il problema. Solo la 7.1.1 lo chiude.

Il requisito del clic non è una consolazione

L'attacco non richiede all'aggressore alcun account su WordPress, nessun nonce di installazione, nessun privilegio. Richiede però che un amministratore autenticato carichi l'URL malevolo. Un visitatore qualsiasi non può innescarlo, e nemmeno un account Autore o Editore, che non hanno il permesso di installare temi.

Questo requisito viene comunemente letto come fattore attenuante. Nella pratica italiana, come nota anche l'analisi di Patchstack, è un fattore di esposizione, e le vie sono due. La prima è il phishing mirato: un messaggio credibile a una persona precisa, che deve cliccare mentre è loggata. La seconda, più insidiosa, è una XSS già presente sul sito: quando un amministratore visualizza la pagina infetta, la richiesta parte automaticamente dal suo browser, senza clic consapevoli. In quel caso l'attaccante aveva già un piede dentro, e Click2Shell è solo il modo più rapido per trasformarlo in controllo completo.

Cosa significa per le PMI e le agenzie web italiane

WordPress è l'ossatura della presenza online delle piccole e medie imprese italiane: siti vetrina, e-commerce WooCommerce, portali associativi, siti di comuni e scuole. Il profilo di rischio, però, non è uniforme, e vale la pena distinguere.

Il caso peggiore è quello delle agenzie e dei liberi professionisti che gestiscono decine o centinaia di siti. Lì il vettore trova il terreno ideale: una singola persona tiene aperte contemporaneamente più sessioni amministrative, naviga tutto il giorno fra email di clienti, ticket, anteprime e segnalazioni, e clicca link per lavoro. Un messaggio ben confezionato — «il sito del cliente mostra questo errore, guarda qui» — è esattamente lo scenario che Click2Shell richiede. E la compromissione non resta su un sito: le agenzie riusano credenziali, chiavi API e account di hosting, e da un pannello compromesso si arriva spesso agli altri.

Il secondo caso rilevante è quello degli e-commerce. Accesso a wp-config.php significa accesso al database, e in un WooCommerce il database contiene nomi, indirizzi, email, telefoni e storico ordini dei clienti. Non è un incidente informatico: è una violazione di dati personali ai sensi dell'articolo 4 del GDPR.

Da qui derivano obblighi precisi, che nelle realtà piccole vengono sistematicamente sottovalutati. Se l'accesso non autorizzato al database è probabile o accertato, il titolare deve valutare la notifica al Garante entro 72 ore dalla conoscenza del fatto (articolo 33) e, quando il rischio per gli interessati è elevato, la comunicazione agli interessati stessi (articolo 34). Sul piano delle misure, l'articolo 32 richiede un livello di sicurezza adeguato al rischio: la gestione tempestiva degli aggiornamenti di una piattaforma con un exploit pubblico è, senza giri di parole, il minimo sindacale che un'autorità si aspetta di trovare documentato.

C'è poi una dimensione contrattuale che molte agenzie fingono di non vedere. Chi gestisce il sito di un cliente e ne tratta i dati per suo conto è responsabile del trattamento ai sensi dell'articolo 28, con un contratto che deve prevedere misure di sicurezza e obbligo di informare senza ritardo il titolare in caso di violazione. Un sito compromesso perché non si è applicato in tempo un aggiornamento con PoC pubblico è, nella migliore delle ipotesi, una conversazione difficile; nella peggiore, un inadempimento contrattuale con danno documentabile.

Per i soggetti rientranti in NIS2 — il decreto legislativo 138/2024 include fornitori di servizi digitali e di servizi gestiti ICT fra i soggetti importanti — si aggiunge l'obbligo di misure di gestione delle vulnerabilità documentate previsto dall'articolo 21 e, in caso di incidente significativo, la pre-notifica al CSIRT Italia entro 24 ore e la notifica entro 72.

Un'osservazione sulla configurazione

La parte più utile di questa vicenda non è la patch: è quello che rivela sulle configurazioni di produzione. Patchstack segnala che sui siti dove è attiva la costante DISALLOW_FILE_MODS l'installazione forzata non può avvenire, e l'impatto si fermerebbe al livello dell'iniezione, senza arrivare a temi o plugin nuovi.

Questo dovrebbe far riflettere. Un sito in produzione non ha bisogno di poter installare temi e plugin dal pannello web: gli aggiornamenti si gestiscono da un flusso controllato, con versionamento e ambiente di staging. Disattivare la modifica dei file dal pannello non è una mitigazione di Click2Shell — è igiene di configurazione che avrebbe ridotto l'impatto di questa falla e di buona parte di quelle degli ultimi cinque anni. In Italia la configurazione predefinita dell'hosting condiviso va nella direzione opposta, perché la modificabilità da pannello è percepita come comodità commerciale. È una scelta che si paga a rate.

Cosa fare subito

  • Aggiornare a WordPress 7.1.1 su tutte le installazioni. È l'unica correzione della falla nel Core. Il PoC è pubblico: la finestra di comodo è chiusa.
  • Verificare i temi installati e la data di installazione, in particolare su siti amministrati fra il 17 e il 21 settembre. Un tema che nessuno ricorda di aver scelto è il segnale della fase uno.
  • Controllare i plugin presenti, compresi quelli non elencati nel pannello: la catena termina con l'installazione di un plugin arbitrario. Ispezionare la directory wp-content/plugins da filesystem o via FTP, non solo dalla schermata di amministrazione.
  • Controllare la directory wp-content/mu-plugins (must-use plugins): è un percorso classico di persistenza che il pannello non mostra.
  • Se emergono tracce di compromissione, ruotare le chiavi in wp-config.php (AUTH_KEY, SALT e affini) per invalidare tutte le sessioni, cambiare la password del database e le credenziali amministrative, e rivedere l'elenco degli utenti con ruolo amministratore.
  • Attivare DISALLOW_FILE_MODS negli ambienti di produzione e spostare gli aggiornamenti su un flusso controllato.
  • Ridurre le sessioni amministrative permanenti: non tenere il pannello loggato nel browser usato per leggere posta e ticket, e non usare l'account amministratore per la redazione dei contenuti. Un Editore non può innescare Click2Shell; un amministratore sì.
  • Attivare l'autenticazione a più fattori sugli account amministrativi. Non blocca questa catena, ma limita il danno delle credenziali già raccolte da campagne precedenti.
  • Nelle agenzie: censire quante installazioni si gestiscono, con quali account, e verificare che non ci sia riuso di credenziali fra clienti. Il perimetro reale dell'incidente, in caso di compromissione, è quello.

La lezione tecnica, come osserva Patchstack, va oltre il singolo selettore. Quando un parametro passato nell'URL viene elaborato sia lato server sia lato client, va sanificato su entrambi i lati: è un pattern che ricompare ogni volta che due pezzi di codice interpretano lo stesso input in modo indipendente. Vale per WordPress e vale per qualunque applicazione web che qualcuno stia scrivendo in questo momento.