Patreon WordPress 插件中发现的漏洞

已发表: 2021-03-26

在对 WordPress 的 Patreon 插件进行内部审计期间,Jetpack Scan 团队发现了几个弱点,这些弱点会允许某人接管一个网站。

这些漏洞已披露给插件作者,他们立即发布了 1.7.2 版,修复了所有这些问题。 如果您正在运行旧版本的插件,请立即更新!

请继续阅读以了解所有技术细节。 如果这超出了您的想象,请不要担心。 我们提供 Jetpack Scan 来为您处理恶意软件扫描和自动升级或删除。

我们的团队确定了各种攻击媒介,包括本地文件泄露、跨站点请求伪造 (CSRF) 和反射跨站点脚本 (XSS) 漏洞。

本地文件泄露漏洞是不良行为者可以用来访问关键信息的错误,例如网站的密钥和数据库凭据。 反射的跨站点脚本和跨站点请求伪造漏洞是攻击者能够通过诱使他们单击精心制作的恶意链接来代表毫无戒心的用户执行特定操作的问题。

如果被利用,其中一些可能会使恶意个人接管易受攻击的网站。

本地文件泄露漏洞
受影响的版本: < 1.7.0
CVE ID: 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 包含一个本地文件泄露漏洞,任何访问该站点的人都可能滥用该漏洞。 使用此攻击向量,攻击者可以泄露重要的内部文件,如 wp-config.php,其中包含用于生成随机数和 cookie 的数据库凭据和加密密钥。

如果成功利用,此安全漏洞可能会导致不法分子完全接管网站。

登录表单上的反射 XSS
受影响的版本: < 1.7.2
CVE ID: 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 挂钩 WordPress 登录表单 (wp-login.php),并允许用户使用他们的 Patreon 帐户在网站上进行身份验证。 不幸的是,场景背后的一些错误记录逻辑允许用户控制的输入反映在登录页面上,未经处理。

要成功利用此漏洞,攻击者需要诱骗受害者访问包含恶意 Javascript 代码的诱杀链接。 由于 Javascript 在受害者的浏览器上下文中运行,攻击者可以调整隐藏在该链接中的代码,以执行该用户权限允许他执行的任何操作。

如果此攻击成功针对管理员,则该脚本可以完全接管该站点。

在 AJAX 操作“patreon_save_attachment_patreon_level”上反映 XSS
受影响的版本: < 1.7.2
CVE ID: 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>';

该插件还使用 AJAX 挂钩来更新 Patreon 订阅者访问给定附件所需的承诺级别。 具有“manage_options”权限的用户帐户(即只有管理员)可以访问此操作。

不幸的是,这个 AJAX 端点中使用的参数之一在打印回用户之前没有经过清理,因此它所代表的风险与我们之前描述的 XSS 漏洞相同。

CSRF 允许攻击者覆盖/创建用户元
受影响的版本: < 1.7.0
CVE ID: 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 );
		
	}

一些端点没有验证它收到的请求是根据用户的合法操作发送的,您可以使用 nonce 来执行此操作。 这些未受保护的端点之一允许恶意个人制作一个诱杀链接,一旦访问,该链接将覆盖或创建受害者帐户上的任意用户元数据。

如果被利用,此漏洞可用于覆盖“wp_capabilities”元数据,其中包含受影响用户帐户的角色和权限。 这样做基本上会将他们锁定在网站之外,阻止他们访问付费内容。

CSRF 允许攻击者断开站点与 Patreon 的连接
受影响的版本: < 1.7.0
CVE ID :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;
			}
			

这个漏洞与上一个漏洞相似,因为它是同一种攻击 (CSRF),但针对的是管理员。 这个特定的攻击向量与之前的一样。 攻击者需要登录管理员才能访问特制链接。

由于此特定端点可以断开站点与 Patreon 的连接,因此针对此攻击媒介的攻击者也可以这样做,这将阻止新内容同步到站点。

时间线

  • 初次联系尝试(不成功)– 12 月 4 日
  • 第二次联系尝试 – 12 月 11 日
  • 作者承认报告 - 12 月 15 日
  • 1.7.0 版发布 – 1 月 5 日
  • 我们报告了另外两个 XSS 问题——3 月 9 日
  • 作者承认第二份报告 – 3 月 9 日
  • 1.7.2 版发布 – 3 月 11 日

结论

我们建议您检查您在网站上使用的 Patreon-Connect 插件的当前版本,如果不是 1.7.2,请尽快更新!

在 Jetpack,我们努力确保您的网站免受此类漏洞的影响。 要领先任何新威胁一步,请查看 Jetpack Scan,其中包括安全扫描和自动恶意软件删除。

学分

多亏了 George Stephanis、Fioravante Souza、Miguel Neto、Benedict Singer 和 Marc Montpas,这项安全披露才得以实现。