Grave vulnerabilità risolta in UpdraftPlus 1.22.3

Pubblicato: 2022-02-18

Durante un controllo interno del plug-in UpdraftPlus, abbiamo scoperto una vulnerabilità di download di backup arbitraria che potrebbe consentire agli utenti con privilegi bassi come gli abbonati di scaricare i backup più recenti di un sito.

Se sfruttata, la vulnerabilità potrebbe garantire agli aggressori l'accesso a informazioni privilegiate dal database del sito interessato (ad esempio nomi utente e password con hash).

Abbiamo segnalato la vulnerabilità agli autori del plug-in e di recente hanno rilasciato la versione 1.22.3 per risolverla. Anche gli aggiornamenti automatici forzati sono stati inviati a causa della gravità di questo problema. Se il tuo sito non lo ha già fatto, ti consigliamo vivamente di aggiornare all'ultima versione (1.22.3) e di avere una soluzione di sicurezza consolidata sul tuo sito, come Jetpack Security.

Puoi trovare l'avviso di UpdraftPlus qui.

Dettagli

Nome del plug-in: UpdraftPlus
URI del plug-in: https://wordpress.org/plugins/updraftplus/
Autore: https://updraftplus.com/

La vulnerabilità

Download di backup arbitrari

Versioni interessate: tutte le versioni comprese tra 1.16.7 e 1.22.3 (versione gratuita) e
ID CVE: CVE-2022-0633
ID WPVDB: d257c28f-3c7e-422b-a5c2-e618ed3c0bf3
CVSSv3.1: 8.5
CCSS: 87.6

Il plug-in utilizza "nonce" e timestamp personalizzati per identificare in modo sicuro i backup. Data la conoscenza di detto nonce e timestamp può consentire a qualcuno di accedere ad alcune delle funzionalità del plug-in, assicurarsi che queste informazioni siano accessibili solo a coloro che ne hanno legittimamente bisogno è fondamentale.

Purtroppo, come dimostreremo, non è stato così.

Non Perdita

Il primo colpevole si trovava su UpdraftPlus_Admin::process_status_in_heartbeat metodo.

	/**
	 * Receive Heartbeat data and respond.
	 *
	 * Processes data received via a Heartbeat request, and returns additional data to pass back to the front end.
	 *
	 * @param array $response - Heartbeat response data to pass back to front end.
	 * @param array $data     - Data received from the front end (unslashed).
	 */
	public function process_status_in_heartbeat($response, $data) {
		if (!is_array($response) || empty($data['updraftplus'])) return $response;
		try {
			$response['updraftplus'] = $this->get_activejobs_list(UpdraftPlus_Manipulation_Functions::wp_unslash($data['updraftplus']));
		} catch (Exception $e) {
			$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
			error_log($log_message);
			$response['updraftplus'] = array(
				'fatal_error' => true,
				'fatal_error_message' => $log_message
			);
		// @codingStandardsIgnoreLine
		} catch (Error $e) {
			$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
			error_log($log_message);
			$response['updraftplus'] = array(
				'fatal_error' => true,
				'fatal_error_message' => $log_message
			);
		}

		if (UpdraftPlus_Options::user_can_manage() && isset($data['updraftplus']['updraft_credentialtest_nonce'])) {
			if (!wp_verify_nonce($data['updraftplus']['updraft_credentialtest_nonce'], 'updraftplus-credentialtest-nonce')) {
				$response['updraftplus']['updraft_credentialtest_nonce'] = wp_create_nonce('updraftplus-credentialtest-nonce');
			}
		}

		$response['updraftplus']['time_now'] = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i');

		return $response;
	}

Non assicurava correttamente che l'utente che inviava questa richiesta heartbeat fosse un amministratore (ad esempio tramite funzioni come current_user_can), il che era un problema poiché la prima cosa che questa funzione tenta di fare è prendere l'elenco dei processi di backup attivi tramite il metodo get_activejobs_list .

Un utente malintenzionato potrebbe quindi creare una richiesta dannosa mirata a questo callback heartbeat per ottenere l'accesso alle informazioni sull'ultimo backup del sito fino ad oggi, che conterrà, tra le altre cose, un nonce di backup.

Download di backup

Esistono alcuni modi per scaricare i backup su UpdraftPlus, molti dei quali sono stati adeguatamente protetti.

	/**
	 * Find out if the current request is a backup download request, and proceed with the download if it is
	 */
	public function maybe_download_backup_from_email() {
		global $pagenow;
		if ((!defined('DOING_AJAX') || !DOING_AJAX) && UpdraftPlus_Options::admin_page() === $pagenow && isset($_REQUEST['page']) && 'updraftplus' === $_REQUEST['page'] && isset($_REQUEST['action']) && 'updraft_download_backup' === $_REQUEST['action']) {
			$findexes = empty($_REQUEST['findex']) ? array(0) : $_REQUEST['findex'];
			$timestamp = empty($_REQUEST['timestamp']) ? '' : $_REQUEST['timestamp'];
			$nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
			$type = empty($_REQUEST['type']) ? '' : $_REQUEST['type'];
			if (empty($timestamp) || empty($nonce) || empty($type)) wp_die(__('The download link is broken, you may have clicked the link from untrusted source', 'updraftplus'), '', array('back_link' => true));
			$backup_history = UpdraftPlus_Backup_History::get_history();
			if (!isset($backup_history[$timestamp]['nonce']) || $backup_history[$timestamp]['nonce'] !== $nonce) wp_die(__("The download link is broken or the backup file is no longer available", 'updraftplus'), '', array('back_link' => true));
			$this->do_updraft_download_backup($findexes, $type, $timestamp, 2, false, '');
			exit; // we don't need anything else but an exit
		}
	}
}

Sfortunatamente, anche il metodo UpdraftPlus_Admin::maybe_download_backup_from_email, che è collegato ad admin_init, non ha convalidato direttamente i ruoli degli utenti.

Sebbene abbia applicato alcuni controlli indirettamente, come il controllo della variabile globale $pagenow , ricerche passate hanno dimostrato che questa variabile può contenere input arbitrari dell'utente. I malintenzionati potrebbero utilizzare questo endpoint per scaricare backup di file e database in base alle informazioni trapelate dal suddetto bug del battito cardiaco.

Sequenza temporale

14-02-2022 – Primo contatto con UpdraftPlus
15-02-2022 – Inviamo loro i dettagli su questa vulnerabilità
16-02-2022 – Viene rilasciato UpdraftPlus 1.22.3, lanciati gli aggiornamenti automatici forzati

Conclusione

Ti consigliamo di controllare quale versione del plug-in UpdraftPlus sta utilizzando il tuo sito e, se rientra nell'intervallo interessato, aggiornalo il prima possibile!

In Jetpack, lavoriamo sodo per assicurarci che i tuoi siti Web siano protetti da questo tipo di vulnerabilità. Ti consigliamo di disporre di un piano di sicurezza per il tuo sito che includa la scansione e il backup di file dannosi. Jetpack Security è un'ottima opzione di sicurezza di WordPress per garantire la sicurezza del tuo sito e dei visitatori.

Crediti

Ricercatore originale: Marc Montpas

Grazie al resto del team di Jetpack Scan per feedback, aiuto e correzioni.