Vulnerabilidade grave corrigida no UpdraftPlus 1.22.3

Publicados: 2022-02-18

Durante uma auditoria interna do plug-in UpdraftPlus, descobrimos uma vulnerabilidade arbitrária de download de backup que pode permitir que usuários com poucos privilégios, como assinantes, baixem os backups mais recentes de um site.

Se explorada, a vulnerabilidade pode conceder aos invasores acesso a informações privilegiadas do banco de dados do site afetado (por exemplo, nomes de usuário e senhas com hash).

Relatamos a vulnerabilidade aos autores do plug-in e eles lançaram recentemente a versão 1.22.3 para solucioná-la. As atualizações automáticas forçadas também foram enviadas devido à gravidade desse problema. Se o seu site ainda não tiver, recomendamos que você atualize para a versão mais recente (1.22.3) e tenha uma solução de segurança estabelecida em seu site, como o Jetpack Security.

Você pode encontrar o próprio conselho do UpdraftPlus aqui.

Detalhes

Nome do plugin: UpdraftPlus
URI do plug-in: https://wordpress.org/plugins/updraftplus/
Autor: https://updraftplus.com/

A vulnerabilidade

Downloads de backup arbitrários

Versões afetadas: Todas as versões entre 1.16.7 e 1.22.3 (versão gratuita), e
CVE-ID: CVE-2022-0633
ID WPVDB: d257c28f-3c7e-422b-a5c2-e618ed3c0bf3
CVSSv3.1: 8,5
CWSS: 87,6

O plug-in usa “nonces” e carimbos de data/hora personalizados para identificar backups com segurança. Dado o conhecimento do referido nonce e timestamp pode dar a alguém acesso a alguns dos recursos do plug-in, é crucial garantir que essas informações sejam acessíveis apenas para aqueles que precisam legitimamente delas.

Infelizmente, como vamos demonstrar, não foi o caso.

Vazamento Nonce

O primeiro culpado foi localizado no UpdraftPlus_Admin::process_status_in_heartbeat método.

	/**
	 * 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;
	}

Ele não garantiu adequadamente que o usuário que enviava essa solicitação de pulsação fosse um administrador (por exemplo, por meio de funções como current_user_can), o que era um problema, pois a primeira coisa que essa função tenta fazer é pegar a lista de tarefas de backup ativas por meio do método get_activejobs_list .

Um invasor pode, assim, criar uma solicitação maliciosa visando esse retorno de chamada de pulsação para obter acesso a informações sobre o backup mais recente do site até o momento, que conterá, entre outras coisas, o nonce de um backup.

Download de backup

Existem algumas maneiras de baixar backups no UpdraftPlus, a maioria dos quais foi devidamente protegida.

	/**
	 * 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
		}
	}
}

Infelizmente, o método UpdraftPlus_Admin::maybe_download_backup_from_email, que está ligado a admin_init, também não validou diretamente as funções dos usuários.

Embora tenha aplicado algumas verificações indiretamente, como verificar a variável global $pagenow , pesquisas anteriores mostraram que essa variável pode conter entradas arbitrárias do usuário. Os maus atores podem usar esse endpoint para baixar backups de arquivos e banco de dados com base nas informações que vazaram do bug de pulsação mencionado acima.

Linha do tempo

14-02-2022 – Contato inicial com UpdraftPlus
15-02-2022 – Enviamos a eles detalhes sobre esta vulnerabilidade
16/02/2022 – O UpdraftPlus 1.22.3 é lançado, as atualizações automáticas forçadas são lançadas

Conclusão

Recomendamos que você verifique qual versão do plugin UpdraftPlus seu site está usando e, se estiver dentro do intervalo afetado, atualize-o o mais rápido possível!

Na Jetpack, trabalhamos duro para garantir que seus sites estejam protegidos contra esses tipos de vulnerabilidades. Recomendamos que você tenha um plano de segurança para seu site que inclua verificação e backups de arquivos maliciosos. O Jetpack Security é uma ótima opção de segurança do WordPress para garantir que seu site e visitantes estejam seguros.

Créditos

Pesquisador original: Marc Montpas

Agradecemos ao restante da equipe do Jetpack Scan pelos comentários, ajuda e correções.