Vulnerabilidades encontradas no plugin Patreon WordPress

Publicados: 2021-03-26

Durante uma auditoria interna do plug-in do Patreon para WordPress, a equipe do Jetpack Scan encontrou vários pontos fracos que permitiriam que alguém assumisse um site.

Essas vulnerabilidades foram divulgadas aos autores do plugin, que prontamente lançaram a versão 1.7.2, que corrige todos esses problemas. Se você estiver executando uma versão mais antiga do plug-in, atualize hoje!

Leia todos os detalhes técnicos. Se isso passar pela sua cabeça, não se preocupe. Oferecemos o Jetpack Scan para lidar com a verificação de malware e atualizações ou remoção automatizadas para você.

Nossa equipe identificou vários vetores de ataque, incluindo vulnerabilidades de divulgação de arquivos locais, falsificação de solicitações entre sites (CSRF) e scripts refletidos entre sites (XSS).

As vulnerabilidades de divulgação de arquivos locais são bugs que os malfeitores podem usar para obter acesso a informações críticas, como chaves secretas de um site e credenciais de banco de dados. As vulnerabilidades Reflected Cross-Site Scripting e Cross-Site Request Forgery são problemas que permitem que os invasores executem ações específicas em nome de usuários desavisados, enganando-os a clicar em links maliciosos cuidadosamente criados.

Se explorados, alguns deles podem permitir que indivíduos mal-intencionados assumam sites vulneráveis.

Vulnerabilidade de divulgação de arquivos locais
Versões afetadas: < 1.7.0
ID CVE: CVE-2021-24227
CVSSv3: 7,5
CWSS: 83,6

	public static function servePatronOnlyImage( $image=false ) {

		if ( ( !isset( $image ) OR !$image ) AND isset( $_REQUEST['patron_only_image'] ) ) {
			$image = $_REQUEST['patron_only_image'];
		}
		
		if ( !$image OR $image == '') {
			// This is not a rewritten image request. Exit.
			return;
		}

		if ( !( isset( $_REQUEST['patreon_action'] ) AND $_REQUEST['patreon_action'] == 'serve_patron_only_image' ) ) {
			return;	
		}

		$upload_locations = wp_upload_dir();

		// We want the base upload location so we can account for any changes to date based subfolders in case there are

		$upload_dir = substr( wp_make_link_relative( $upload_locations['baseurl'] ) , 1 );	

		$image = get_site_url() . '/' . $upload_dir . '/' . $image;
		
		if ( current_user_can( 'manage_options' ) ) {
			Patreon_Protect::readAndServeImage( $image );	
		}			
		
		// Below define can be defined in any plugin to bypass core locking function and use a custom one from plugin
		// It is independent of the plugin load order since it checks if it is defined.
		// It can be defined by any plugin until right before the_content filter is run.

		if ( apply_filters( 'ptrn/bypass_image_filtering', defined( 'PATREON_BYPASS_IMAGE_FILTERING' ) ) ) {
			Patreon_Protect::readAndServeImage( $image );
		}
	
		// Check if the image is protected:

		$attachment_id = attachment_url_to_postid( $image );
	
		// attachment_url_to_postid returns 0 if it cant find the attachment post id
		
		if ( $attachment_id == 0 ) {
			
			// Couldnt determine attachment post id. Try to get id from thumbnail
			$attachment_id = Patreon_Protect::getAttachmentIDfromThumbnailURL( $image );
	
			//No go. Have to get out and serve the image normally
			if ( $attachment_id == 0 OR !$attachment_id ) {
				Patreon_Protect::readAndServeImage( $image );

O Patreon-Connect continha uma vulnerabilidade de divulgação de arquivo local que poderia ser abusada por qualquer pessoa que visitasse o site. Usando esse vetor de ataque, um invasor pode vazar arquivos internos importantes como wp-config.php, que contém credenciais de banco de dados e chaves criptográficas usadas na geração de nonces e cookies.

Se explorada com sucesso, essa falha de segurança pode levar a uma invasão completa do site por agentes mal-intencionados.

XSS refletido no formulário de login
Versões Afetadas: < 1.7.2
ID CVE: CVE-2021-24228
CVSSv3: 8,8
CWSS: 80,6

	public static function processPatreonMessages() {
		
		$patreon_error = '';
		if ( isset( $_REQUEST['patreon_error'] ) ) {
			
			// If any specific error message is sent from Patreon, prepare it
			$patreon_error = ' - Patreon returned: ' . $_REQUEST['patreon_error'];
			
		}

		if ( isset( $_REQUEST['patreon_message'] ) ) {
			
			return '<p class="patreon_message">' . apply_filters( 'ptrn/error_message', self::$messages_map[ $_REQUEST['patreon_message'] ] . $patreon_error ) . '</p>';

O Patreon-Connect conecta-se ao formulário de login do WordPress (wp-login.php) e oferece para permitir que os usuários se autentiquem no site usando sua conta do Patreon. Infelizmente, parte da lógica de log de erros nos bastidores permitia que a entrada controlada pelo usuário fosse refletida na página de login, sem limpeza.

Para explorar com sucesso essa vulnerabilidade, um invasor precisa enganar sua vítima para que visite um link armadilhado contendo código Javascript malicioso. Como o Javascript é executado no contexto do navegador da vítima, um invasor pode ajustar o código oculto nesse link para fazer o que os privilégios desse usuário permitirem.

Se esse ataque for bem-sucedido contra um administrador, o script pode assumir completamente o controle do site.

XSS refletido na ação AJAX 'patreon_save_attachment_patreon_level'
Versões Afetadas: < 1.7.2
ID CVE: CVE-2021-24229
CVSSv3: 8,8
CWSS: 80,6

		$args = array (
			'attachment_id' => $attachment_id,
			'patreon_level' => $_REQUEST['patreon_attachment_patreon_level'],
			'message' => $message,
		);
		
		echo self::make_image_lock_interface( $args	);
	public function make_image_lock_interface( $args = array() ) {
		
		$interface = '';
		
		$interface .=  '<div class="patreon_image_lock_modal_content">';
		$interface .=  '<span class="patreon_image_lock_modal_close">&times;</span>';

		$interface .=  ' <form id="patreon_attachment_patreon_level_form" action="/wp-admin/admin-ajax.php" method="post">';
		$interface .=  '<h1 class="patreon_image_locking_interface_heading">Lock Image</h1>';
		$interface .=  '<div class="patreon_image_locking_interface_level">';
		$interface .=  '<span class="patreon_image_locking_interface_input_prefix">$<input id="patreon_attachment_patreon_level" type="text" name="patreon_attachment_patreon_level" value="' . $args['patreon_level'] . '" / ></span>';

O plugin também usa um gancho AJAX para atualizar o nível de promessa exigido pelos assinantes do Patreon para acessar um determinado anexo. Esta ação é acessível para contas de usuário com o privilégio 'manage_options' (ou seja, apenas administradores).

Infelizmente, um dos parâmetros usados ​​neste endpoint AJAX não é higienizado antes de ser impresso de volta para o usuário, então o risco que ele representa é o mesmo da vulnerabilidade XSS anterior que descrevemos.

CSRF permitindo que invasores substituam/criem meta de usuário
Versões afetadas: < 1.7.0
ID CVE: CVE-2021-24230
CVSSv3: 6,5
CWSS: 42

	public function toggle_option() {
		
		if( !( is_admin() && current_user_can( 'manage_options' ) ) ) {
			return;
		}
		
		$current_user = wp_get_current_user();
		
		$option_to_toggle = $_REQUEST['toggle_id'];
		
		$current_value = get_user_meta( $current_user->ID, $option_to_toggle, true );
		
		$new_value = 'off';
		
		if( !$current_value OR $current_value == 'off' ) {
			$new_value = 'on';			
		}
		
		update_user_meta( $current_user->ID, $option_to_toggle, $new_value );
		
	}

Alguns endpoints não validaram que a solicitação recebida foi enviada após uma ação legítima de um usuário, o que você pode fazer usando nonces. Um desses endpoints desprotegidos permitia que indivíduos mal-intencionados criassem um link armadilhado que substituiria ou criaria metadados de usuário arbitrários na conta da vítima uma vez visitada.

Se explorado, este bug pode ser usado para sobrescrever a meta “wp_capabilities”, que contém as funções e privilégios da conta de usuário afetada. Fazer isso basicamente os bloquearia do site, impedindo-os de acessar conteúdo pago.

CSRF permitindo que invasores desconectem sites do Patreon
Versões afetadas: < 1.7.0
ID CVE : CVE-2021-24231
CVSSv3: 6,5
CWSS: 26,1

			if ( isset( $_REQUEST['patreon_wordpress_action'] ) AND $_REQUEST['patreon_wordpress_action'] == 'disconnect_site_from_patreon' AND is_admin() AND current_user_can( 'manage_options' ) ) {

			// Admin side, user is admin level. Perform action:
			
			// To disconnect the site from a particular creator account, we will delete all options related to creator account, but we will leave other plugin settings and post gating values untouched
			
			$options_to_delete = array(
				'patreon-custom-page-name',
				'patreon-fetch-creator-id',
				'patreon-creator-tiers',
				'patreon-creator-last-name',
				'patreon-creator-first-name',
				'patreon-creator-full-name',
				'patreon-creator-url',
				'patreon-campaign-id',
				'patreon-creators-refresh-token-expiration',
				'patreon-creator-id',
				'patreon-setup-wizard-last-call-result',
				'patreon-creators-refresh-token',
				'patreon-creators-access-token',
				'patreon-client-secret',
				'patreon-client-id',
				'patreon-setup_is_being_done',
				'patreon-setup-done',
				'patreon-currency-sign',
			);
			
			// Ask the API to delete this client:
			
			$creator_access_token = get_option( 'patreon-creators-access-token', false );
			$client_id 			  = get_option( 'patreon-client-id', false );
				
			// Exceptions until v1 v2 transition is complete
			
			$api_version = get_option( 'patreon-installation-api-version' );

			if ( $api_version == '1' ) {

				// Delete override - proceed with deleting local options
				
				foreach ( $options_to_delete as $key => $value ) {
					delete_option( $options_to_delete[$key] );
				}
				
				update_option( 'patreon-installation-api-version', '2' );
				update_option( 'patreon-can-use-api-v2', true );
				
				wp_redirect( admin_url( 'admin.php?page=patreon_wordpress_setup_wizard&setup_stage=reconnect_0') );
				exit;
			}
			

Esta é semelhante à última vulnerabilidade, pois é o mesmo tipo de ataque (CSRF), mas tem como alvo os administradores. Esse vetor de ataque específico funciona como o anterior. Um invasor precisa obter um administrador conectado para visitar um link especialmente criado.

Como esse endpoint específico pode desconectar um site do Patreon, os invasores que visam esse vetor de ataque também podem fazer exatamente isso, o que impediria que o novo conteúdo fosse sincronizado com o site.

Linha do tempo

  • Tentativa de contato inicial (sem sucesso) – 4 de dezembro
  • Segunda tentativa de contato – 11 de dezembro
  • Os autores reconhecem o relatório – 15 de dezembro
  • A versão 1.7.0 é lançada – 5 de janeiro
  • Relatamos dois problemas adicionais de XSS – 9 de março
  • Os autores reconhecem o segundo relatório – 9 de março
  • A versão 1.7.2 é lançada – 11 de março

Conclusão

Recomendamos que você verifique a versão atual do plug-in Patreon-Connect que está usando em seu site e, se não for 1.7.2, atualize-o o mais rápido possível!

Na Jetpack, trabalhamos duro para garantir que seus sites estejam protegidos contra esses tipos de vulnerabilidades. Para ficar um passo à frente de qualquer nova ameaça, confira o Jetpack Scan, que inclui verificação de segurança e remoção automatizada de malware.

Créditos

Essa divulgação de segurança foi possível graças a George Stephanis, Fioravante Souza, Miguel Neto, Benedict Singer e Marc Montpas.