Unauthenticated Privilege Escalation Vulnerability in RH – Real Estate Theme

Published 22 January 2025
Table of Contents

Easy Real Estate Plugin

Unauthenticated Privilege Escalation

32K
CVSS 9.8

This blog post discusses about the findings on the RealHome theme and the plugin that is installed with it Easy Real Estate. Currently there are no known updates to fix this issue so if you are a user of the theme and plugin disabling them temporarily is recommended until the issues are fixed.

If you are a Patchstack customer, you are protected from this vulnerability already, and no further action is required from you.

For plugin developers, we have security audit services and Enterprise API for hosting companies.

About the Real Homes Theme

The RealHome theme (premium version), which has nearly 32,000 sales, is one of the popular premium themes specially designed to be used for real estate websites. It provides design variations, a high level of customization, and advanced functionality. It also comes with multiple plugins/add-ons for extended features. One of those plugins, Easy Real Estate is also exploitable by a similar type of vulnerability.

The security vulnerabilities

The theme suffers from an unauthenticated privilege escalation vulnerability. As a result, it could have allowed any unauthenticated user to increase their privileges and take over the WordPress site by performing a series of HTTP requests.

RealHolmes Theme: Unauthenticated Privilege Escalation

This vulnerability occurred because the code that handles user input didn’t have any authorization or nonce check. If registration is enabled on the settings any attacker can takeover the website.

The theme also didn’t check if the user is calling the inspiry_ajax_register action with a $user_role parameter and has permission to create Administrator role accounts, allowing anyone to generate one. Patchstack assigned CVE-2024-32444 to this vulnerability.

The main vulnerability existed in the function inspiry_ajax_register:

function inspiry_ajax_register() {

		// First check the nonce, if it fails the function will break
		check_ajax_referer( 'inspiry-ajax-register-nonce', 'inspiry-secure-register' );

		if ( class_exists( 'Easy_Real_Estate' ) ) {
			/* Verify Google reCAPTCHA */
			ere_verify_google_recaptcha();
		}

		// Nonce is checked, Get to work
		$info                  = array();
		$info['user_nicename'] = $info['nickname'] = $info['display_name'] = $info['first_name'] = $info['user_login'] = sanitize_user( $_POST['register_username'] );
		$info['user_pass']     = wp_generate_password( 12 );
		$info['user_email']    = sanitize_email( $_POST['register_email'] );

		if ( inspiry_is_user_sync_enabled() && empty( $_POST['user_role'] ) ) {
			echo json_encode( array(
				'success' => false,
				'message' => esc_html__( 'Please select a user role.', 'framework' ),
			) );
			die();
		}

		// Assigning a user role
		if ( ! empty( $_POST['user_role'] ) ) {
			$info['role'] = sanitize_text_field( $_POST['user_role'] );
		} else {
			$info['role'] = get_option( 'default_role', 'subscriber' );
		}

		// Register the user
		$user_register = wp_insert_user( $info );

		if ( is_wp_error( $user_register ) ) {

			$error = $user_register->get_error_codes();
			if ( in_array( 'empty_user_login', $error ) ) {
				echo json_encode( array(
					'success' => false,
					'message' => $user_register->get_error_message( 'empty_user_login' )
				) );
			} elseif ( in_array( 'existing_user_login', $error ) ) {
				echo json_encode( array(
					'success' => false,
					'message' => esc_html__( 'This username already exists.', 'framework' )
				) );
			} elseif ( in_array( 'existing_user_email', $error ) ) {
				echo json_encode( array(
					'success' => false,
					'message' => esc_html__( 'This email is already registered.', 'framework' )
				) );
			} else {
				echo json_encode( array(
					'success' => false,
					'message' => $user_register->get_error_message()
				) );
			}

		} else {

			/**
			 * Add user meta for the custom user fields if values are set for them.
			 */
			$user_fields = apply_filters( 'inspiry_additional_user_fields', array() );
			if ( is_array( $user_fields ) && ! empty( $user_fields ) ) {
				foreach ( $user_fields as $field ) {

					// Check if field is enabled for the Register Form
					if ( empty( $field['show'] ) || ! is_array( $field['show'] ) || ! in_array( 'register_form', $field['show'] ) ) {
						continue;
					}

					// Validate field data and add it as user meta
					if ( ! empty( $field['id'] ) && ! empty( $_POST[ $field['id'] ] ) ) {
						add_user_meta( $user_register, sanitize_key( $field['id'] ), sanitize_text_field( $_POST[ $field['id'] ] ) );
					}
				}
			}

			// Send email notification to newly registered user and admin
			if ( class_exists( 'Easy_Real_Estate' ) ) {
				ere_new_user_notification( $user_register, $info['user_pass'] );
			}

			// Insert Role Post
			if ( inspiry_is_user_sync_enabled() ) {
				$role       = $_POST['user_role'];
				$user_roles = inspiry_user_sync_roles();

				if ( array_key_exists( $role, $user_roles ) ) {

                    // Updating in existing user meta
					update_user_meta( $user_register, 'inspiry_user_role', $role );

                    // Assigning a user role

					inspiry_insert_role_post( $user_register, $role );
				}
			}

			echo json_encode( array(
				'success' => true,
				'message' => esc_html__( 'Registration is complete. Check your email for details!', 'framework' ),
			) );

		}

		die();
	}

Easy Real Estate Plugin: Unauthenticated Privilege Escalation

A similar vulnerability exists on a plugin that comes installed with the theme, Easy Real Estate. Easy Real Estate provides a social media login functionality. As long as an attacker knows the administrator’s e-mail address, the plugin doesn’t verify if the email address supplied to the POST request is owned by the sender, which allows anyone to log in to any user’s account without knowing the account’s password. Patchstack assigned CVE-2024-32555 to this vulnerability.

The main vulnerability existed in the function ere_social_register():

function ere_social_register( $register_cred ) {

		/**
		 * Check for the existing user against given email.
		 * If user exists then set it as current user.
		 */
		$existing_user = get_user_by( 'email', $register_cred['user_email'] );
		if ( $existing_user ) {
			wp_clear_auth_cookie();
			wp_set_current_user( $existing_user->ID );
			wp_set_auth_cookie( $existing_user->ID );
			ere_social_login_redirect(); // Redirect the user to the edit profile page.
			exit;
		}

		/*
		* Register the user if username doesn't exist already.
		* Otherwise add a random string as suffix and register again.
		*/
		if ( username_exists( $register_cred['user_login'] ) ) {
			$register_cred['user_login'] = $register_cred['user_login'] . '_' . wp_rand( 100, 10000 );
		}
		$user_id = wp_insert_user( $register_cred );

		if ( ! is_wp_error( $user_id ) ) {

			$profile_image_id = ere_insert_social_profile_image( $register_cred['profile_image'], $register_cred['user_login'] . wp_rand( 100, 1000 ) . '.png' );
			update_user_meta( $user_id, 'profile_image_id', $profile_image_id );

			// User notification function exists in plugin.
			if ( class_exists( 'Easy_Real_Estate' ) ) {
				// Send email notification to newly registered user and admin.
				ere_new_user_notification( $user_id, $register_cred['user_pass'] );
			}

			// Login the user.
			$login_creds['user_login']    = $register_cred['user_login'];
			$login_creds['user_password'] = $register_cred['user_pass'];
			ere_social_login( $login_creds );
		}

		wp_safe_redirect( home_url() );
	}

The patch

At the time of writing this article, Patchstack hasn’t received any response from the vendor about acknowledging the security issues or any patch attempts. Patchstack first discovered the vulnerabilities on version 4.3.3 and there have been three version releases with no patch attempt to fix the mentioned issues. We will update the article if the vendor releases a patch.

Conclusion

Supplying user input to functions like wp_set_auth_cookie(), wp_update_user(), update_user_meta() or other similar functions should only be allowed under strict whitelisting options. Otherwise, the values should be checked and set by the vendor according to the right privilege levels.

Vendors shouldn’t take user input for role or custom metadata during registration to prevent scenarios like this.

Want to learn more about finding and fixing vulnerabilities?

Explore our Academy to master the art of finding and patching vulnerabilities within the WordPress ecosystem. Dive deep into detailed guides on various vulnerability types, from discovery tactics for researchers to robust fixes for developers. Join us and contribute to our growing knowledge base.

Timeline

19 September, 2024We found the vulnerabilities and started to create the reports.
23 September, 2024We reach out to the vendor regarding the vulnerabilities.
16 January, 2025Last attempt to contact and notify the vendor regarding the disclosure.
20 January, 2025Published the vulnerability to the Patchstack Vulnerability Database (No reply from vendor).
22 January, 2025Security advisory article publicly released.

Help us make the Internet a safer place

Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.

  • If you’re a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
  • If you’re a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.

The latest in Security advisories

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu