Vulnérabilités trouvées dans le plugin Patreon WordPress

Publié: 2021-03-26

Lors d'un audit interne du plugin Patreon pour WordPress, l'équipe de Jetpack Scan a trouvé plusieurs points faibles qui permettraient à quelqu'un de reprendre un site web.

Ces vulnérabilités ont été divulguées aux auteurs du plugin, qui ont rapidement publié la version 1.7.2, qui corrige tous ces problèmes. Si vous utilisez une ancienne version du plugin, veuillez mettre à jour aujourd'hui !

Lisez la suite pour tous les détails techniques. Si cela vous dépasse, ne vous inquiétez pas. Nous proposons Jetpack Scan pour gérer l'analyse des logiciels malveillants et les mises à niveau ou la suppression automatisées pour vous.

Notre équipe a identifié divers vecteurs d'attaque, notamment les vulnérabilités Local File Disclosure, Cross-Site Request Forgery (CSRF) et Reflected Cross-Site Scripting (XSS).

Les vulnérabilités de divulgation de fichiers locaux sont des bogues que les acteurs malveillants peuvent utiliser pour accéder à des informations critiques, telles que les clés secrètes d'un site Web et les informations d'identification de la base de données. Les vulnérabilités Reflected Cross-Site Scripting et Cross-Site Request Forgery sont des problèmes qui permettent aux attaquants d'effectuer des actions spécifiques au nom d'utilisateurs peu méfiants en les incitant à cliquer sur des liens malveillants soigneusement conçus.

S'ils sont exploités, certains d'entre eux pourraient permettre à des individus malveillants de prendre le contrôle de sites Web vulnérables.

Vulnérabilité de divulgation de fichiers locaux
Versions concernées : < 1.7.0
Identifiant 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 );

Patreon-Connect contenait une vulnérabilité de divulgation de fichiers locaux qui pouvait être exploitée par toute personne visitant le site. En utilisant ce vecteur d'attaque, un attaquant pourrait divulguer des fichiers internes importants comme wp-config.php, qui contient les informations d'identification de la base de données et les clés cryptographiques utilisées dans la génération de nonces et de cookies.

Si elle est exploitée avec succès, cette faille de sécurité pourrait conduire à une prise de contrôle complète du site par de mauvais acteurs.

XSS reflété sur le formulaire de connexion
Versions concernées : < 1.7.2
Identifiant 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>';

Patreon-Connect s'accroche au formulaire de connexion de WordPress (wp-login.php) et propose de permettre aux utilisateurs de s'authentifier sur le site à l'aide de leur compte Patreon. Malheureusement, une partie de la logique de journalisation des erreurs en arrière-plan permettait aux entrées contrôlées par l'utilisateur d'être reflétées sur la page de connexion, non épurées.

Pour exploiter avec succès cette vulnérabilité, un attaquant doit inciter sa victime à visiter un lien piégé contenant du code Javascript malveillant. Étant donné que Javascript s'exécute dans le contexte du navigateur de la victime, un attaquant peut ajuster le code caché dans ce lien pour faire tout ce que les privilèges de cet utilisateur lui permettent de faire.

Si cette attaque réussit contre un administrateur, le script peut prendre complètement le contrôle du site.

XSS reflété sur l'action AJAX 'patreon_save_attachment_patreon_level'
Versions concernées : < 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>';

Le plugin utilise également un crochet AJAX pour mettre à jour le niveau de promesse requis par les abonnés Patreon pour accéder à une pièce jointe donnée. Cette action est accessible pour les comptes d'utilisateurs avec le privilège 'manage_options' (c'est-à-dire uniquement les administrateurs).

Malheureusement, l'un des paramètres utilisés dans ce point de terminaison AJAX n'est pas filtré avant d'être renvoyé à l'utilisateur, de sorte que le risque qu'il représente est le même que la vulnérabilité XSS précédente que nous avons décrite.

CSRF permettant aux attaquants d'écraser/créer des métadonnées utilisateur
Versions concernées : < 1.7.0
Identifiant 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 );
		
	}

Certains points de terminaison n'ont pas validé la demande qu'ils ont reçue suite à une action légitime d'un utilisateur, ce que vous pouvez faire en utilisant des nonces. L'un de ces points de terminaison non protégés permettait à des individus malveillants de créer un lien piégé qui écraserait ou créerait des métadonnées utilisateur arbitraires sur le compte de la victime une fois visité.

S'il est exploité, ce bogue peut être utilisé pour écraser la méta "wp_capabilities", qui contient les rôles et privilèges du compte utilisateur concerné. Cela les empêcherait essentiellement d'accéder au site, les empêchant d'accéder au contenu payant.

CSRF permettant aux attaquants de déconnecter des sites de Patreon
Versions concernées : < 1.7.0
Identifiant 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;
			}
			

Celle-ci est similaire à la dernière vulnérabilité en ce sens qu'il s'agit du même type d'attaque (CSRF) mais qu'elle cible les administrateurs. Ce vecteur d'attaque particulier fonctionne comme le précédent. Un attaquant doit demander à un administrateur connecté de visiter un lien spécialement conçu.

Étant donné que ce point de terminaison spécifique peut déconnecter un site de Patreon, les attaquants ciblant ce vecteur d'attaque peuvent également faire exactement cela, ce qui empêcherait la synchronisation du nouveau contenu avec le site.

Chronologie

  • Tentative de contact initiale (infructueuse) – 4 décembre
  • Deuxième tentative de contact – 11 décembre
  • Les auteurs reconnaissent le rapport – 15 décembre
  • La version 1.7.0 est sortie – 5 janvier
  • Nous signalons deux problèmes XSS supplémentaires – 9 mars
  • Les auteurs accusent réception du deuxième rapport – 9 mars
  • La version 1.7.2 est sortie – 11 mars

Conclusion

Nous vous recommandons de vérifier la version actuelle du plugin Patreon-Connect que vous utilisez sur votre site et, si ce n'est pas la 1.7.2, de la mettre à jour dès que possible !

Chez Jetpack, nous travaillons dur pour nous assurer que vos sites Web sont protégés contre ces types de vulnérabilités. Pour garder une longueur d'avance sur toute nouvelle menace, consultez Jetpack Scan, qui comprend l'analyse de sécurité et la suppression automatisée des logiciels malveillants.

Crédits

Cette divulgation de sécurité a été rendue possible grâce à George Stephanis, Fioravante Souza, Miguel Neto, Benedict Singer et Marc Montpas.