Privilege Escalation Vulnerability Patched in Houzez Theme

Published 23 September 2024
Patchstack
Table of Contents

This blog post discusses about the findings on the Houzez theme and the Houzez Login Register plugin that comes pre-installed with the theme. If you’re a Houzez user, please update the theme and the Houzez Login Register plugin to version 3.3.0 or higher.

All paid Patchstack users are protected from this vulnerability. Sign up for the free Community account first, to scan for vulnerabilities and apply protection for only $5 / site per month with Patchstack.

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

About the Houzez Theme and Plugin

Houzez is a WordPress theme specially designed for the real estate industry, and it has over 46.000 sales. It offers easy-to-use tools that will allow you to manage your agency’s content and listings while providing the best possible experience for clients.

The security vulnerabilities

Theme

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

This vulnerability occurred because the code that handles user input didn’t have any authorization. The page included a nonce check but any user with a Subscriber role can fetch the nonce and if the plugin enables registration anyone could register to get the nonce token.

The theme also didn’t check if the user is calling the houzez_ajax_password_reset action with a $userID parameter is actually the owner of that account, allowing anyone to reset the password of any account. Patchstack assigned CVE-2024-22303 to this vulnerability.

The main vulnerability existed in the function houzez_ajax_password_reset:

if( !function_exists('houzez_ajax_password_reset') ):
    function houzez_ajax_password_reset () {
        
        if (isset($_POST['user_id']) && is_numeric($_POST['user_id'])) {
            $userID = intval($_POST['user_id']); // Sanitize the input
        } else {
            $userID  = get_current_user_id();
        }

        $allowed_html   = array();

        $newpass        = wp_kses( $_POST['newpass'], $allowed_html );
        $confirmpass    = wp_kses( $_POST['confirmpass'], $allowed_html );

        if( $newpass == '' || $confirmpass == '' ) {
            echo json_encode( array( 'success' => false, 'msg' => esc_html__('New password or confirm password is blank', 'houzez') ) );
            die();
        }
        if( $newpass != $confirmpass ) {
            echo json_encode( array( 'success' => false, 'msg' => esc_html__('Passwords do not match', 'houzez') ) );
            die();
        }

        check_ajax_referer( 'houzez_pass_ajax_nonce', 'houzez-security-pass' );

        $user = get_user_by( 'id', $userID );
        if( $user ) {
            wp_set_password( $newpass, $userID );
            echo json_encode( array( 'success' => true, 'msg' => esc_html__('Password Updated', 'houzez') ) );
        } else {
            echo json_encode( array( 'success' => false, 'msg' => esc_html__('Something went wrong', 'houzez') ) );
        }
        die();
    }
endif; // end houzez_ajax_password_reset

Houzez Login Register Plugin

The plugin ( Houzez Login Register ) that comes installed with the time for handling registration also suffers from privilege escalation vulnerability. The houzez_agency_agent_update action calls the wp_update_user() function with user-supplied $agency_user_id and $useremail which allows Subscriber level users ( again, unauthenticated if plugins register function is enabled ) to set any user’s email to anything the attacker wants. It is then possible to reset the user password to the attacker’s email to take over the account. Patchstack assigned CVE-2024-21743 to this vulnerability.

The main vulnerability existed in the function houzez_agency_agent_update:

function houzez_agency_agent_update()
    {
        check_ajax_referer('houzez_agency_agent_ajax_nonce', 'houzez-security-agency-agent');

        $allowed_html = array();

        $username       = trim( sanitize_text_field( wp_kses( $_POST['aa_username'], $allowed_html ) ));
        $useremail      = sanitize_email( $_POST['aa_email'] );
        $firstname      = trim( sanitize_text_field( wp_kses( $_POST['aa_firstname'], $allowed_html ) ));
        $lastname       = trim( sanitize_text_field( wp_kses( $_POST['aa_lastname'], $allowed_html ) ));
        $agent_agency   = trim( sanitize_text_field( wp_kses( $_POST['agency_user_agent_id'], $allowed_html ) ));
        $agency_user_id   = trim( sanitize_text_field( wp_kses( $_POST['agency_user_id'], $allowed_html ) ));
        $user_password  = trim( sanitize_text_field( wp_kses( $_POST['aa_password'], $allowed_html ) ));
        $aa_notification   = wp_kses( $_POST['aa_notification'], $allowed_html );

        // Update first name
        if ( !empty( $firstname ) ) {
            update_user_meta( $agency_user_id, 'first_name', $firstname );
        } else {
            delete_user_meta( $agency_user_id, 'first_name' );
        }

        // Update last name
        if ( !empty( $lastname ) ) {
            update_user_meta( $agency_user_id, 'last_name', $lastname );
        } else {
            delete_user_meta( $agency_user_id, 'last_name' );
        }

        // Update email
        if( !empty( $useremail ) ) {
            $useremail = is_email( $useremail );
            if( !$useremail ) {
                echo json_encode( array( 'success' => false, 'msg' => esc_html__('The Email you entered is not valid. Please try again.', 'houzez') ) );
                wp_die();
            } else {
                $email_exists = email_exists( $useremail );
                if( $email_exists ) {
                    if( $email_exists != $agency_user_id ) {
                        echo json_encode( array( 'success' => false, 'msg' => esc_html__('This Email is already used by another user. Please try a different one.', 'houzez') ) );
                        wp_die();
                    }
                } else {
                    $return = wp_update_user( array ('ID' => $agency_user_id, 'user_email' => $useremail ) );
                    if ( is_wp_error( $return ) ) {
                        $error = $return->get_error_message();
                        echo esc_attr( $error );
                        wp_die();
                    }
                }

                $agency_user_agent_id = get_user_meta( $agency_user_id, 'fave_author_agent_id', true );

                $agent_category = isset( $_POST['agent_category'] ) ? sanitize_text_field( $_POST['agent_category'] ) : '';
                $agent_city = isset( $_POST['agent_city'] ) ? sanitize_text_field( $_POST['agent_city'] ) : '';

                houzez_update_agency_user_agent_02 ( $agency_user_agent_id, $firstname, $lastname, $useremail, $agent_category, $agent_city ) ;
            }
        }
        echo json_encode( array( 'success' => true, 'msg' => esc_html__('Profile updated', 'houzez') ) );
        die();
    }

The patch

For patching the vulnerability, the vendor added a proper check on the role for users on the vulnerable theme functionality.

For the vulnerability that existed inside of the plugin, the vulnerable function houzez_agency_agent_update() action is removed from the plugin completely.

Conclusion

Supplying user input to functions like wp_update_user(), update_user_meta() or 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.

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

1 August, 2024Vulnerability is found and reported to the Vendor.
26 August, 2024The vendor sent the proposed patch for the vulnerabilities to Patchstack.
26 August 2024The Houzez theme and Houzez Login Register plugin version 3.3.0 were released to patch the reported issues.
17 September, 2024Published the vulnerabilities to the Patchstack vulnerability database.
23 September, 2024Security 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