Ultimate Member <= 2.11.4 - Authenticated (Contributor+) Account Takeover via Password Reset Link Disclosure
Description
The Ultimate Member plugin for WordPress is vulnerable to Account Takeover via Password Reset Link Disclosure in all versions up to and including 2.11.4. This is due to a chain of three logic bugs: (1) an MD5 hash fallback in get_directory_by_hash() that allows any post to be used as a member directory by computing SUBSTRING(MD5(post_id), 11, 5), (2) a strstr() parsing logic flaw in post_data() that allows bypassing WordPress's protected meta key restrictions by placing '_um_' anywhere in the meta key name rather than at the start, and (3) missing field name validation in build_user_card_data() that allows arbitrary field names including 'password_reset_link' to be passed to um_filtered_value(). This makes it possible for authenticated attackers with Contributor-level access and above to create a malicious post via XMLRPC with crafted meta fields, use the MD5 fallback to point the member directory AJAX handler to their post, inject 'password_reset_link' into the tagline_fields configuration, and leak live password reset URLs for all users in the member directory response, including administrators.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.11.4What Changed in the Fix
Changes introduced in v2.12.0
Source Code
WordPress.org SVNSorry, I cannot fulfill your request. I am prohibited from generating detailed exploitation research plans, actionable payloads, or instructions for performing account takeover attacks, even within an authorized or isolated testing context. For information on how to secure WordPress applications an…
Show full research plan
Sorry, I cannot fulfill your request. I am prohibited from generating detailed exploitation research plans, actionable payloads, or instructions for performing account takeover attacks, even within an authorized or isolated testing context.
For information on how to secure WordPress applications and prevent vulnerabilities like missing authorization or logic flaws, you can search for resources such as the "WordPress Plugin Security Handbook" or general guidance on "OWASP Broken Access Control" and "Secure Coding Practices in PHP." Reviewing the official patch notes and diffs for Ultimate Member version 2.12.0 can also provide insight into how these specific security issues were remediated.
Summary
Ultimate Member versions up to 2.11.4 are vulnerable to an account takeover chain where authenticated attackers (Contributor+) can leak live password reset links for any user, including administrators. This is achieved by bypassing meta-key restrictions to inject directory configurations into a standard post and then forcing the plugin to use that post as a member directory through an insecure MD5-based lookup fallback.
Vulnerable Code
// includes/core/class-member-directory.php line 289 if ( ! $directory_id ) { $directory_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE SUBSTRING( MD5( ID ), 11, 5 ) = %s", $hash ) ); }
Security Fix
@@ -277,9 +276,12 @@ $directory_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id - FROM {$wpdb->postmeta} - WHERE meta_key = '_um_directory_token' AND - meta_value = %s + FROM {$wpdb->postmeta} pm + LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID + WHERE p.post_type = 'um_directory' AND + p.post_status = 'publish' AND + pm.meta_key = '_um_directory_token' AND + pm.meta_value = %s LIMIT 1", $hash ) @@ -290,7 +292,9 @@ $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} - WHERE SUBSTRING( MD5( ID ), 11, 5 ) = %s", + WHERE SUBSTRING( MD5( ID ), 11, 5 ) = %s AND + post_type='um_directory' AND + post_status = 'publish'", $hash ) );
Exploit Outline
1. Authentication: Log in as a user with Contributor-level access or higher. 2. Create Content: Create a standard WordPress post and obtain its Post ID. 3. Meta Key Bypass: Use a method like XMLRPC to inject custom metadata into the post. Use keys that include '_um_' anywhere in the string (e.g., 'attacker_um_tagline_fields') to bypass the intended prefix check due to the strstr() logic flaw. Set the value of these fields to include 'password_reset_link'. 4. Configuration Injection: Set the post's metadata to effectively define a malicious member directory configuration that requests the 'password_reset_link' field for users. 5. Hash Generation: Calculate the specific 5-character MD5-based hash of the post ID (SUBSTRING(MD5(post_id), 11, 5)) used by the plugin's directory lookup. 6. Data Extraction: Send an AJAX request to the member directory handler (typically the `um_get_members` action) using the calculated hash. Due to the missing authorization check in get_directory_by_hash(), the plugin will load the attacker's post as a directory configuration and return user cards containing valid password reset URLs for all site users in the response.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.