Sicurezza informatica

wp2shell: due bug innocui, un sito perso. Come funziona wp2shell

wp2shell: due bug innocui, un sito perso. Come funziona wp2shell

Il 17 luglio 2026 WordPress ha rilasciato la versione 7.0.2, insieme alle correzioni per i rami più vecchi (6.9.5 e 6.8.6). Non è un aggiornamento come gli altri. Chiude una vulnerabilità che permette di eseguire codice da remoto senza alcuna autenticazione: niente password, niente account, niente. E dato che è già sfruttata in attacchi reali, la raccomandazione è secca: aggiornate subito.

Fin qui la notizia, che trovate ovunque. Quello che raramente si spiega è come funziona. E vale la pena capirlo, perché questa falla è un piccolo capolavoro di logica, e perché il modo in cui è stata scoperta racconta qualcosa sul mestiere della sicurezza informatica che sta cambiando sotto i nostri occhi.

Se non gestite WordPress, saltate pure alla fine: la lezione che conta è là. Ma se vi affascina come si rompe un sistema apparentemente solido, restate. Cerco di raccontarlo senza dare per scontato che siate sviluppatori.

Due difetti innocui che insieme diventano un'arma

La catena si chiama wp2shell e non nasce da un errore, ma da due. Presi singolarmente sono quasi trascurabili. Combinati, portano un estraneo dal nulla al controllo totale del sito.

Difetto uno: il fattorino che sbaglia i pacchi (CVE-2026-63030)

WordPress ha un'API "batch", un endpoint che serve a spedire più richieste in un colpo solo invece di una per volta. Immaginatela come uno sportello che accetta una pila di moduli tutti insieme.

Lo sportello lavora in due tempi. Prima controlla tutti i moduli uno per uno: sono compilati bene? i permessi sono in regola? Mette gli esiti dei controlli in una lista, e i moduli veri in un'altra lista, in parallelo. Poi, in un secondo giro, prende i risultati dei controlli e li abbina ai moduli per eseguirli.

Il difetto sta in una singola istruzione. Quando un modulo è malformato, il codice fa continue: salta al successivo. Ma così facendo avanza di una posizione nella lista dei controlli e non in quella dei moduli. Da quel momento le due liste sono sfasate di uno.

Il risultato è surreale: la richiesta A viene controllata con le regole della richiesta A, ma eseguita con il gestore della richiesta B. È come un fattorino che verifica l'indirizzo sul pacco numero uno e poi consegna il pacco numero due. Tutti i controlli di sicurezza vengono superati solo che si applicavano a qualcos'altro.

In gergo si chiama desync, disallineamento. E basta a scavalcare le validazioni di WordPress.

Difetto due: la porta chiusa solo se bussi nel modo giusto (CVE-2026-60137)

Il secondo problema è una classica SQL injection, il tipo di falla che permette di iniettare comandi nel database.

C'è un parametro dell'API, author__not_in, che serve a escludere certi autori dai risultati. WordPress lo "pulisce" per impedire abusi: se gli passi una lista di valori, controlla ogni elemento e lo forza a essere un numero. Blindato.

Ma c'è un buco nella logica. Se invece della lista gli passi un valore singolo, il controllo non scatta affatto: il dato passa intatto e finisce dritto dentro una query SQL. In condizioni normali questo buco è irraggiungibile, perché per arrivare a quel parametro devi passare da un altro controllo che impone la forma a lista.

Tenete a mente questo dettaglio: la porta pericolosa esiste, ma è protetta da una seconda porta che obbliga a bussare nel modo giusto.

E qui le due falle si stringono la mano

Avete già capito dove va a finire.

Il primo difetto il fattorino confuso permette di far controllare la richiesta da un gestore che non guarda author__not_in, e poi eseguirla dal gestore che invece lo usa. La seconda porta viene semplicemente aggirata. A quel punto l'aggressore infila il suo valore singolo malevolo, tipo 0) OR 1=1 --, e la SQL injection è servita.

Gli autori dell'analisi hanno dovuto incastrare due disallineamenti annidati uno dentro l'altro, perché l'endpoint batch di per sé non accetta le richieste nella forma giusta. Una scatola cinese di errori logici. Ma il principio è quello: un difetto sblocca l'altro.

Dalla lettura del database al controllo del sito

Una SQL injection che legge il database sarebbe già grave. Ma qui succede qualcosa di più raffinato, e a tratti quasi elegante nella sua perfidia.

Con l'iniezione, l'aggressore non si limita a leggere: fabbrica articoli finti che WordPress crede veri e tiene in memoria. Da questi articoli fantasma costruisce, passo dopo passo, una scala per salire di privilegi:

  • inserisce contenuti speciali che costringono WordPress a materializzare nel database i suoi oggetti finti;
  • fabbrica un tipo particolare di articolo, un changeset, che contiene modifiche alle impostazioni firmate con l'identità di un amministratore perché in WordPress ogni modifica porta con sé l'ID dell'utente la cui autorità la applicherà;
  • sfrutta la logica interna che WordPress usa per rilevare i "cicli" fra articoli imparentati, perché quella logica reimposta l'articolo senza sovrascriverne il contenuto, lasciando intatto il payload;
  • quando il changeset viene applicato, WordPress esegue wp_set_current_user() e per un istante assume l'identità dell'amministratore;
  • in quell'istante scatta un hook che riesegue l'intera richiesta iniziale, stavolta con i privilegi da amministratore.

E nella richiesta rieseguita c'era, fin dall'inizio, l'ordine di creare un nuovo account amministratore. Ordine che prima falliva per mancanza di permessi, e che ora invece va a segno.

Da lì è finita: l'aggressore entra come amministratore, carica un plugin-backdoor ed esegue codice sul server. Dal nulla, senza mai conoscere una password.

Il dettaglio che fa impressione è che nessun passaggio "buca" una password o un token. Ogni singolo pezzo abusa di un comportamento legittimo di WordPress. È una serie di mosse tutte regolari che, messe in fila, producono un risultato che nessuna di esse doveva permettere.

Chi l'ha trovata, e con cosa

Ed è qui che la storia diventa interessante oltre la tecnica.

Questa catena non è stata scoperta da un team di veterani dopo mesi di analisi. L'ha trovata Adam Kues, ricercatore di Searchlight Cyber, dando in pasto a un modello di intelligenza artificiale di OpenAI GPT-5.6 Sol Ultra una copia pulita del codice sorgente di WordPress, senza changelog e senza indizi. Solo il codice e una richiesta di analisi.

Il modello ha individuato il disallineamento, ha trovato il buco nella sanificazione, ha costruito il payload annidato per aggirare le restrizioni, ha scoperto la combinazione per materializzare gli articoli finti e ha concatenato l'intera scalata di privilegi. Ha prodotto un exploit funzionante in poco più di dieci ore di elaborazione, per un costo di circa 25 dollari di crediti API. Nessuna ricerca online, nessun database di falle note: pura analisi del codice e concatenazione logica.

Le parole di Kues valgono più di qualsiasi commento: «GPT-5.6 Sol Ultra ha impiegato quattro ore per scrivere una catena di attacco che partiva da una SQL injection e arrivava all'esecuzione remota di codice, mentre a me è servito molto più tempo anche solo per comprenderla».

Il titolo della sua ricerca è un pugno nello stomaco per il settore: i broker di exploit pagano fino a mezzo milione di dollari per una falla RCE su WordPress. Lui ne ha trovata una con 25 dollari e un modello linguistico.

Kues ha segnalato tutto a WordPress, che ha corretto e ha forzato l'aggiornamento automatico sui siti vulnerabili, installando d'ufficio la versione sicura. Una misura drastica, giustificata dal fatto che la società Patchstack sta già osservando tentativi di sfruttamento nei log dei propri clienti.

Cosa dovete fare, in concreto

Se avete un sito WordPress, la lista è breve:

  1. Verificate di essere su 7.0.2 (o 6.9.5 / 6.8.6 sui rami più vecchi). Molti siti sono già stati aggiornati d'ufficio, ma controllate: Bacheca → Aggiornamenti.
  2. Cercate account amministratore che non riconoscete. Se la falla è stata sfruttata prima della patch, potrebbe essere rimasto un utente ospite indesiderato.
  3. Controllate i plugin installati di recente, soprattutto quelli che non ricordate di aver caricato. La backdoor arriva come plugin.
  4. Se trovate qualcosa di sospetto, un aggiornamento non basta: il sito va considerato compromesso e ripulito da capo, ripartendo da un backup precedente all'attacco.

La lezione che conta, WordPress o no

Al di là del caso specifico, questa vicenda dice due cose che riguardano chiunque abbia qualcosa di esposto su internet.

La prima è che le falle più pericolose non sono quasi mai un singolo errore clamoroso. Sono combinazioni. Due comportamenti innocui che, incastrati nell'ordine giusto, aprono una porta che nessuno aveva progettato. È il motivo per cui la sicurezza non si risolve tappando la falla del mese: si costruisce a strati, dando per scontato che prima o poi un livello cederà.

La seconda è più scomoda. Il costo per trovare vulnerabilità gravi sta crollando. Quello che un tempo richiedeva un esperto e settimane di lavoro oggi può uscire da un modello in dieci ore e venticinque dollari. In questa storia lo strumento era nelle mani di un ricercatore onesto, che ha avvisato prima di chiunque altro. La prossima volta potrebbe non esserlo.

Non è un buon motivo per farsi prendere dal panico. È un ottimo motivo per smettere di rimandare gli aggiornamenti, tenere sotto controllo ciò che è esposto, e trattare la manutenzione di sicurezza come una cosa continua e non come un intervento da fare quando ci si ricorda. La difesa non deve essere geniale. Deve essere costante.

Scritto da Claudio