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에는 사이트를 방문하는 모든 사람이 남용할 수 있는 로컬 파일 공개 취약점이 포함되어 있습니다. 이 공격 벡터를 사용하여 공격자는 nonce 및 쿠키 생성에 사용되는 데이터베이스 자격 증명 및 암호화 키가 포함된 wp-config.php와 같은 중요한 내부 파일을 유출할 수 있습니다.

악용에 성공하면 이 보안 결함으로 인해 악의적인 사용자가 사이트를 완전히 장악할 수 있습니다.

로그인 양식에 반영된 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는 피해자의 브라우저 컨텍스트에서 실행되기 때문에 공격자는 해당 링크에 숨겨진 코드를 조정하여 이 사용자의 권한이 허용하는 모든 작업을 수행할 수 있습니다.

이 공격이 관리자에 대해 성공하면 스크립트가 사이트를 완전히 장악할 수 있습니다.

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" 메타를 덮어쓸 수 있습니다. 이렇게 하면 기본적으로 사이트에서 차단되어 유료 콘텐츠에 액세스할 수 없게 됩니다.

공격자가 Patreon에서 사이트 연결을 끊도록 허용하는 CSRF
영향을 받는 버전: < 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일
  • 2차 접촉 시도 - 12월 11일
  • 저자는 보고서를 인정합니다 – 12월 15일
  • 버전 1.7.0 릴리스 – 1월 5일
  • 3월 9일에 2개의 추가 XSS 문제를 보고합니다.
  • 저자는 두 번째 보고서를 인정합니다 – 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 덕분에 가능했습니다.