Headline
CVE-2023-4277: class-realia-post-type-user.php in realia/tags/1.4.0/includes/post-types – WordPress Plugin Repository
The Realia plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 1.4.0. This is due to missing nonce validation on the ‘process_change_profile_form’ function. This makes it possible for unauthenticated attackers to change user email via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
1<?php23if ( ! defined( ‘ABSPATH’ ) ) {4 exit;5}67/**8 * Class Realia_Post_Type_User9 *10 * @class Realia_Post_Type_User11 * @package Realia/Classes/Post_Types12 * @author Pragmatic Mates13 */14class Realia_Post_Type_User {15 /**16 * Initialize custom post type17 *18 * @access public19 * @return void20 */21 public static function init() {22 add_filter( 'cmb2_meta_boxes’, array( __CLASS__, ‘fields’ ) );23 add_action( 'init’, array( __CLASS__, ‘process_change_profile_form’ ), 9999 );24 add_action( 'init’, array( __CLASS__, ‘process_change_password_form’ ), 9999 );25 add_action( 'init’, array( __CLASS__, ‘process_login_form’ ), 9999 );26 add_action( 'init’, array( __CLASS__, ‘process_register_form’ ), 9999 );2728 add_action( 'pre_get_posts’, array( __CLASS__, ‘media_files’ ) );29 add_filter( 'wp_count_attachments’, array( __CLASS__, ‘recount_attachments’ ) );30 add_action( 'init’, array( __CLASS__, ‘set_subscriber_permissions’ ) );31 add_filter( 'show_admin_bar’, array( __CLASS__, ‘show_admin_bar_for_admins_only’ ) );32 }3334 /**35 * Defines custom fields36 *37 * @access public38 * @param array $metaboxes39 * @return array40 */41 public static function fields( array $metaboxes ) {42 if ( is_super_admin() ) {43 $fields = array(44 array(45 ‘id’ => 'phone’,46 ‘name’ => __( 'Phone’, ‘realia’ ),47 ‘type’ => 'text’,48 ),49 array(50 ‘id’ => REALIA_USER_PREFIX . 'package_title’,51 ‘name’ => __( 'Package Information’, ‘realia’ ),52 ‘type’ => 'title’,53 ),54 array(55 ‘id’ => REALIA_USER_PREFIX . 'package’,56 ‘name’ => __( 'Package’, ‘realia’ ),57 ‘type’ => 'select’,58 ‘options’ => Realia_Packages::get_packages_choices( true, true, true, true ),59 ),60 array(61 ‘id’ => REALIA_USER_PREFIX . 'package_valid’,62 ‘name’ => __( 'Valid’, ‘realia’ ),63 ‘type’ => 'text_date_timestamp’,64 ),65 );6667 if ( get_theme_mod( 'realia_submission_enable_agents’, false ) ) {68 $agents = array();69 $agents_objects = Realia_Query::get_agents();7071 if ( ! empty( $agents_objects->posts ) && is_array( $agents_objects->posts ) ) {72 foreach ( $agents_objects->posts as $agent ) {73 $agents[ $agent->ID ] = $agent->post_title;74 }75 }7677 $fields[] = array(78 ‘id’ => REALIA_USER_PREFIX . 'agent_title’,79 ‘name’ => __( 'Agent’, ‘realia’ ),80 ‘type’ => 'title’,81 );8283 $fields[] = array(84 ‘id’ => REALIA_USER_PREFIX . 'agent_object’,85 ‘name’ => __( 'Agent object’, ‘realia’ ),86 ‘type’ => 'select’,87 ‘show_option_none’ => true,88 ‘options’ => $agents,89 );90 }9192 $metaboxes[‘user_general’] = array(93 ‘id’ => REALIA_USER_PREFIX .’general’,94 ‘title’ => __( 'General’, ‘realia’ ),95 ‘object_types’ => array( ‘user’ ),96 ‘context’ => 'normal’,97 ‘priority’ => 'high’,98 ‘show_names’ => true,99 ‘fields’ => $fields,100 );101 }102103 return $metaboxes;104 }105106 /**107 * Process change profile form108 *109 * @access public110 * @return void111 */112 public static function process_change_profile_form() {113 if ( ! isset( $_POST[‘change_profile_form’] ) ) {114 return;115 }116 $user = wp_get_current_user();117118 $nickname = sanitize_user( $_POST[‘nickname’] );119 $email = sanitize_email( $_POST[‘email’] );120 $first_name = sanitize_text_field( $_POST[‘first_name’] );121 $last_name = sanitize_text_field( $_POST[‘last_name’] );122 $phone = sanitize_text_field( $_POST[‘phone’] );123124 if ( empty( $nickname ) ) {125 $_SESSION[‘messages’][] = array( 'warning’, __( 'Nickname is required.’, ‘realia’ ) );126 return;127 }128129 if ( empty( $email ) ) {130 $_SESSION[‘messages’][] = array( 'warning’, __( 'E-mail is required.’, ‘realia’ ) );131 return;132 }133134 update_user_meta( $user->ID, 'nickname’, $nickname );135136 update_user_meta( $user->ID, 'user_email’, $email );137 wp_update_user( array(138 ‘ID’ => $user->ID,139 ‘user_email’ => $email,140 ) );141 update_user_meta( $user->ID, 'last_name’, $last_name );142 update_user_meta( $user->ID, 'first_name’, $first_name );143 update_user_meta( $user->ID, 'phone’, $phone );144145 $_SESSION[‘messages’][] = array( 'success’, __( 'Profile has been successfully updated.’, ‘realia’ ) );146 }147148 /**149 * Process change password form150 *151 * @access public152 * @return void153 */154 public static function process_change_password_form() {155 if ( ! isset( $_POST[‘change_password_form’] ) ) {156 return;157 }158159 $old_password = sanitize_text_field( $_POST[‘old_password’] );160 $new_password = sanitize_text_field( $_POST[‘new_password’] );161 $retype_password = sanitize_text_field( $_POST[‘retype_password’] );162163 if ( empty( $old_password ) || empty( $new_password ) || empty( $retype_password ) ) {164 $_SESSION[‘messages’][] = array( 'warning’, __( 'All fields are required.’, ‘realia’ ) );165 return;166 }167168 if ( $new_password != $retype_password ) {169 $_SESSION[‘messages’][] = array( 'warning’, __( 'New and retyped password are not same.’, ‘realia’ ) );170 }171172 $user = wp_get_current_user();173174 if ( ! wp_check_password( $old_password, $user->data->user_pass, $user->ID ) ) {175 $_SESSION[‘messages’][] = array( 'warning’, __( 'Your old password is not correct.’, ‘realia’ ) );176 return;177 }178179 wp_set_password( $new_password, $user->ID );180 $_SESSION[‘messages’][] = array( 'success’, __( 'Your password has been successfully changed.’, ‘realia’ ) );181 }182183 /**184 * Process login form185 *186 * @access public187 * @return void188 */189 public static function process_login_form() {190 if ( ! isset( $_POST[‘login_form’] ) ) {191 return;192 }193194 $redirect = site_url();195 if ( ! empty( $_SERVER[‘HTTP_REFERER’] ) ) {196 $redirect = $_SERVER[‘HTTP_REFERER’];197 }198199 if ( empty( $_POST[‘login’] ) || empty( $_POST[‘password’] ) ) {200 $_SESSION[‘messages’][] = array( 'warning’, __( 'Login and password are required.’, ‘realia’ ) );201 wp_redirect( $redirect );202 exit();203 }204205 $login = sanitize_text_field( $_POST[‘login’] );206 $password = sanitize_text_field( $_POST[‘password’] );207208 $user = wp_signon( array(209 ‘user_login’ => $login,210 ‘user_password’ => $password,211 ) );212213 if ( is_wp_error( $user ) ) {214 $_SESSION[‘messages’][] = array( 'danger’, $user->get_error_message() );215 wp_redirect( $redirect );216 exit();217 }218219 $_SESSION[‘messages’][] = array( 'success’, __( 'You have been successfully logged in.’, ‘realia’ ) );220 $after_login_page_id = get_theme_mod( ‘realia_general_after_login_page’ );221 wp_redirect( $after_login_page_id ? get_permalink( $after_login_page_id ) : site_url() );222 exit();223 }224225 /**226 * Process register form227 *228 * @access public229 * @return void230 */231 public static function process_register_form() {232 if ( ! isset( $_POST[‘register_form’] ) ) {233 return;234 }235236 if ( ! get_option( ‘users_can_register’ ) ) {237 $_SESSION[‘messages’][] = array( 'danger’, __( 'Registrations are not allowed.’, ‘realia’ ) );238 wp_redirect( $_SERVER[‘HTTP_REFERER’] );239 exit();240 }241242 if ( empty( $_POST[‘name’] ) || empty( $_POST[‘email’] ) ) {243 $_SESSION[‘messages’][] = array( 'danger’, __( 'Username and e-mail are required.’, ‘realia’ ) );244 wp_redirect( $_SERVER[‘HTTP_REFERER’] );245 exit();246 }247248 $name = sanitize_user( $_POST[‘name’] );249 $email = sanitize_email( $_POST[‘email’] );250 $password = sanitize_text_field( $_POST[‘password’] );251 $first_name = sanitize_text_field( $_POST[‘first_name’] );252 $last_name = sanitize_text_field( $_POST[‘last_name’] );253 $phone = sanitize_text_field( $_POST[‘phone’] );254255 $user_id = username_exists( $name );256257 if ( ! empty( $user_id ) ) {258 $_SESSION[‘messages’][] = array( 'danger’, __( 'User already exists.’, ‘realia’ ) );259 wp_redirect( $_SERVER[‘HTTP_REFERER’] );260 exit();261 }262263 if ( $_POST[‘password’] != $_POST[‘password_retype’] ) {264 $_SESSION[‘messages’][] = array( 'danger’, __( 'Passwords must be same.’, ‘realia’ ) );265 wp_redirect( $_SERVER[‘HTTP_REFERER’] );266 exit();267 }268269 $terms_id = get_theme_mod( 'realia_submission_terms’, false );270271 if ( $terms_id && empty( $_POST[‘agree_terms’] ) ) {272 $_SESSION[‘messages’][] = array( 'danger’, __( 'You must agree terms & conditions.’, ‘realia’ ) );273 wp_redirect( $_SERVER[‘HTTP_REFERER’] );274 exit();275 }276277 if ( $_POST[‘password’] != $_POST[‘password_retype’] ) {278 $_SESSION[‘messages’][] = array( 'danger’, __( 'Passwords must be same.’, ‘realia’ ) );279 wp_redirect( $_SERVER[‘HTTP_REFERER’] );280 exit();281 }282283 $user = wp_create_user( $name, $password, $email );284285 if ( is_wp_error( $user ) ) {286 $_SESSION[‘messages’][] = array( 'danger’, $user->get_error_message() );287 wp_redirect( site_url() );288 exit();289 }290291 // ‘admin’ / 'both’292 wp_new_user_notification( $user, null, ‘both’ );293294 update_user_meta( $user, 'last_name’, $last_name );295 update_user_meta( $user, 'first_name’, $first_name );296 update_user_meta( $user, 'phone’, $phone );297298 $_SESSION[‘messages’][] = array(299 'success’,300 __( 'You have been successfully registered.’, ‘realia’ ),301 );302303 $after_register_page_id = get_theme_mod( ‘realia_general_after_register_page’ );304 wp_redirect( $after_register_page_id ? get_permalink( $after_register_page_id ) : site_url() );305 exit();306 }307308 /**309 * In media library display only current user’s files310 *311 * @access public312 * @param array $wp_query313 * @return void314 */315 public static function media_files( $wp_query ) {316 global $current_user;317318 if ( ! current_user_can( ‘manage_options’ ) && ( is_admin() && $wp_query->query[‘post_type’] === ‘attachment’ ) ) {319 $wp_query->set( 'author’, $current_user->ID );320 }321 }322323 /**324 * Count of items in media library325 *326 * @access public327 * @param $counts_in328 * @return int329 */330 public static function recount_attachments( $counts_in ) {331 global $wpdb;332 global $current_user;333334 $and = wp_post_mime_type_where( ‘’ );335 $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = ‘attachment’ AND post_status != ‘trash’ AND post_author = {$current_user->ID} $and GROUP BY post_mime_type", ARRAY_A );336337 $counts = array();338 foreach ( (array) $count as $row ) {339 $counts[ $row[‘post_mime_type’] ] = $row[‘num_posts’];340 }341342 $counts[‘trash’] = $wpdb->get_var( “SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = ‘attachment’ AND post_author = {$current_user->ID} AND post_status = ‘trash’ $and” );343 return $counts;344 }345346 /**347 * Allow subscribers to upload images348 *349 * @access public350 * @return void351 */352 public static function set_subscriber_permissions( ) {353 $subscriber = get_role( ‘subscriber’ );354 $subscriber->add_cap( ‘upload_files’ );355 $subscriber->add_cap( ‘delete_posts’ );356 $subscriber->add_cap( ‘edit_post’ );357 }358359 /**360 * Disable admin bar for subscribers361 *362 * @access public363 * @param string $content364 * @return string365 */366 public static function show_admin_bar_for_admins_only( $content ) {367 return current_user_can( ‘administrator’ ) ? $content : false;368 }369}370371Realia_Post_Type_User::init();