UpdraftPlus 1.22.3에서 수정된 심각한 취약점

게시 됨: 2022-02-18

UpdraftPlus 플러그인의 내부 감사 중에 구독자와 같은 권한이 낮은 사용자가 사이트의 최신 백업을 다운로드할 수 있는 임의의 백업 다운로드 취약점을 발견했습니다.

이 취약점을 악용하면 공격자가 영향을 받는 사이트 데이터베이스의 권한 있는 정보(예: 사용자 이름 및 해시된 암호)에 액세스할 수 있습니다.

우리는 플러그인 작성자에게 취약점을 보고했으며, 그들은 최근에 이 문제를 해결하기 위해 버전 1.22.3을 출시했습니다. 이 문제의 심각성으로 인해 강제 자동 업데이트도 푸시되었습니다. 사이트가 아직 설치되지 않은 경우 최신 버전(1.22.3)으로 업데이트하고 Jetpack Security와 같은 보안 솔루션을 사이트에 구축하는 것이 좋습니다.

여기에서 UpdraftPlus의 자체 자문을 찾을 수 있습니다.

세부

플러그인 이름: UpdraftPlus
플러그인 URI: https://wordpress.org/plugins/updraftplus/
작성자: https://updraftplus.com/

취약점

임의 백업 다운로드

영향을 받는 버전: 1.16.7과 1.22.3 사이의 모든 버전(무료 버전),
CVE-ID: CVE-2022-0633
WPVDB ID: d257c28f-3c7e-422b-a5c2-e618ed3c0bf3
CVSSv3.1: 8.5
CWSS: 87.6

플러그인은 사용자 지정 "nonce"와 타임스탬프를 사용하여 백업을 안전하게 식별합니다. 논스(nonce)와 타임스탬프(timestamp)에 대한 지식은 누군가에게 플러그인의 기능 중 상당수에 대한 액세스 권한을 부여할 수 있다는 점을 감안할 때 이 정보가 합법적으로 필요한 사람들만 액세스할 수 있도록 하는 것이 중요합니다.

불행히도 우리가 보여주겠지만 그렇지 않았습니다.

논스 누출

첫 번째 범인은 UpdraftPlus_Admin::process_status_in_heartbeat에 있었습니다. 방법.

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

이 하트비트 요청을 보내는 사용자가 관리자인지(예: current_user_can과 같은 기능을 통해) 제대로 확인하지 못했습니다. 이는 이 기능이 처음으로 시도하는 것이 get_activejobs_list 메소드를 통해 활성 백업 작업 목록을 가져오는 것이기 때문에 문제였습니다.

따라서 공격자는 이 하트비트 콜백을 대상으로 하는 악의적인 요청을 만들어 사이트의 최신 백업에 대한 정보에 액세스할 수 있으며 여기에는 백업의 임시 항목이 포함될 수 있습니다.

백업 다운로드

UpdraftPlus에서 백업을 다운로드하는 몇 가지 방법이 있으며 대부분은 적절하게 보호되어 있습니다.

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

불행히도 admin_init에 연결된 UpdraftPlus_Admin::maybe_download_backup_from_email 메소드도 사용자의 역할을 직접 검증하지 않았습니다.

$pagenow 전역 변수를 확인하는 것과 같이 간접적으로 일부 확인을 적용했지만 과거 연구에 따르면 이 변수에는 임의의 사용자 입력이 포함될 수 있습니다. 악의적인 행위자는 이 끝점을 사용하여 앞서 언급한 하트비트 버그에서 유출된 정보를 기반으로 파일 및 데이터베이스 백업을 다운로드할 수 있습니다.

타임라인

2022-02-14 – UpdraftPlus와 초기 접촉
2022-02-15 – 이 취약점에 대한 세부 정보를 보냅니다.
2022-02-16 – UpdraftPlus 1.22.3 출시, 강제 자동 업데이트 출시

결론

사이트에서 사용 중인 UpdraftPlus 플러그인의 버전을 확인하고 영향을 받는 범위 내에 있으면 가능한 한 빨리 업데이트하는 것이 좋습니다!

Jetpack에서는 이러한 유형의 취약점으로부터 웹사이트를 보호하기 위해 열심히 노력하고 있습니다. 악성 파일 검색 및 백업을 포함하는 사이트 보안 계획을 세우는 것이 좋습니다. Jetpack Security는 사이트와 방문자의 안전을 보장하는 훌륭한 WordPress 보안 옵션입니다.

크레딧

원래 연구원: 마크 몽파스

피드백, 도움 및 수정을 위해 Jetpack Scan 팀의 나머지 팀원들에게 감사드립니다.