Several Critical Vulnerabilities including Privilege Escalation, Authentication Bypass, and More Patched in UserPro WordPress Plugin
On May 1, 2023, the Wordfence Threat Intelligence team began the responsible disclosure process for multiple high and critical severity vulnerabilities we discovered in Kirotech’s UserPro plugin, which is actively installed on more than 20,000 WordPress websites.
Wordfence Premium, Wordfence Care, and Wordfence Response users received several firewall rules to protect against any exploits targeting these vulnerabilities on May 19, 2023. Sites still using the free version of Wordfence received the same protection on June 18, 2023. Please note that there was a delay in the release of a firewall rule while we underwent drastic changes to improve the QA of all firewall rules we release. We have no evidence to suggest that these vulnerabilities were known or targeted during this period, nor have we seen any evidence that they are currently being targeted.
We made an initial attempt to contact Kirotech, the vendor of UserPro, on May 1, 2023, but we did not receive a response until May 10, 2023, after many additional attempts. After providing full disclosure details, the developer released the first patch on July 27, 2023, and the final patch on October 31, 2023.
We urge users to update their sites to the latest patched version of UserPro, which is version 5.1.5 at the time of this writing, as soon as possible.
Technical Analysis
Password Reset to Privilege Escalation using the Sensitive Information Disclosure via Shortcode
Description: UserPro ID, ‘reset_mail’, $uniquekey);
} else {
userpro_mail($user->ID, ‘secretkey’, $uniquekey);
}
$shortcode=stripslashes($shortcode);
if (userpro_get_option(‘enable_reset_by_mail’)==’n’) {
add_action(‘userpro_pre_form_message’, ‘userpro_msg_secret_key_sent’);
$modded=str_replace(‘template=”reset”‘, ‘template=”change”‘, $shortcode);
} else {
add_action(‘userpro_pre_form_message’, ‘userpro_reset_link_sent’);
$modded=str_replace(‘template=”reset”‘, ‘template=”reset”‘, $shortcode);
}
$output[‘template’]=do_shortcode($modded);
}
break;
After the ‘uniquekey’ is generated, it is saved in the database with the update_user_meta()
function in plain text format, and then the same code is sent to the user by email with the userpro_mail()
function.
The plugin checks that the user secret key belongs to the given user with the 'change'
template in the userpro_process_form()
function:
/* change pass */
case 'change':
$output['error']=[];
if (get_current_user_id() !=$user_id) {
die();
}
if (!$form['secretkey']) {
$output['error']['secretkey']=__('You did not provide a secret key.', 'userpro');
} elseif (strlen($form['secretkey']) !=20) {
$output['error']['secretkey']=__('The secret key you entered is invalid.', 'userpro');
}
/* Form validation */
/* Here you can process custom "errors" before proceeding */
$output['error']=apply_filters('userpro_form_validation', $output['error'], $form);
if (empty($output['error'])) {
$users=get_users([
'meta_key'=> 'userpro_secret_key',
'meta_value'=> $form['secretkey'],
'meta_compare'=> '=',
]);
if (!$users[0]) {
$output['error']['secretkey']=__('The secret key is invalid or expired.', 'userpro');
} else {
add_filter('send_password_change_email', '__return_false');
$user_id=$users[0]->ID;
wp_update_user(['ID'=> $user_id, 'user_pass'=> $form['user_pass']]);
delete_user_meta($user_id, 'userpro_secret_key');
add_action('userpro_pre_form_message', 'userpro_msg_login_after_passchange');
$shortcode=stripslashes($shortcode);
$modded=str_replace('template="change"', 'template="login"', $shortcode);
$output['template']=do_shortcode($modded);
if (userpro_get_option('notify_user_password_update')=="1") {
userpro_mail($user_id, 'passwordchange', $form['user_pass']);
}
}
}
break;
Since the secret key is stored in plain text format, this means that an attacker that has access to user metadata can change the password of any user. This is an Insecure Password Reset Mechanism vulnerability (CVE-2023-2449). Unlike WordPress core, which saves the ‘user_activation_key’ used for password reset in the ‘users’ table, the plugin stores the key in the ‘usermeta’ table.
Using the Sensitive Information Disclosure via Shortcode (CVE-2023-2446) vulnerability, this key can be retrieved for any user, and combined with the Missing Authorization to Arbitrary Shortcode Execution via ‘userpro_shortcode_template’ function vulnerability (CVE-2023-2448), it is also possible to query it unauthenticated.
The reset password process looks like this:
The complete exploit process looks like this:
A safe reset password process would look like this:
In this case, the key required for the password reset will be hashed using the HashPassword() function and stored in hashed form in the database. The original key will only be sent to the user via email.
When the user clicks on the password reset link in the email, which contains the original key, the original key will be hashed with the HashPassword() function during the password reset process, and then compared with the hashed key in the database.
Since the original key would be hashed and would only be compared afterwards, it would not be possible to reset the password by knowing the hashed key in the database, because there is no process in WordPress core that allows you to enter a hashed key and compare it with the hashed key stored in the database.
As with any Arbitrary User Password Change that leads to a Privilege Escalation vulnerability, this can be used for complete site compromise. Once an attacker has gained administrative user access to a WordPress site they can then manipulate anything on the targeted site as a normal administrator would. This includes the ability to upload plugin and theme files, which can be malicious zip files containing backdoors, as well as modifying posts and pages which can be leveraged to redirect site users to malicious sites.
Missing Authorization to Arbitrary Shortcode Execution
Description: UserPro ID) && is_numeric($users[0]->ID)) {
social_profile_check($_POST[’email’], $_POST[‘id’], ‘facebook’);
$returning=$users[0]->ID;
$returning_user_login=$users[0]->user_login;
} else {
$returning=”;
}
}
The plugin uses the Facebook app ID to store the user ID in the usermeta table with AES encryption.
During the login process, it queries the user based on the provided ID, and if it finds the connected user, it logs them in.
However, if it does not find a user based on ID, the plugin tries to find the user based on the email specified in the request:
if ($_POST['email'] !='' && email_exists($_POST['email'])) {
$user_id=email_exists($_POST['email']);
$user=get_userdata($user_id);
It then logs the user in:
userpro_auto_login($user->user_login, true);
The most significant problem and vulnerability is caused by the fact that there is no connection with Facebook, and the email is not verified as coming from Facebook’s system – instead the attacker can provide the email in the request.
This makes it possible for threat actors to bypass authentication entirely and gain access to arbitrary accounts on sites running a vulnerable version of the plugin. As always, authentication bypass vulnerabilities resulting in access to high privileged user accounts make it easy for threat actors to completely compromise a vulnerable WordPress site and further infect the victim.
Since there are several different vulnerabilities in the plugin, which can be used to query users’ email, this vulnerability is critical and can be easily exploited.
Wordfence Firewall
The following graphic demonstrates the steps to exploitation an attacker might take and at which point the Wordfence firewall would block an attacker from successfully exploiting the vulnerability.
Authenticated (Subscriber+) Privilege Escalation
Description: UserPro $form_value) {
It updates the user meta with the following function:
update_user_meta( $user_id, $key, $form_value );
The most significant problem and vulnerability is caused by the fact that there are no restrictions on the profile options, so the user’s metadata can be updated arbitrarily, and there is no sanitization on the field value, so any value can be set, including an array value, which is necessary for the capability meta option.
This makes it possible for authenticated users, such as subscribers, to supply the ‘wp_capabilities’ array parameter with any desired capabilities, such as administrator, during the profile update.
As with any Privilege Escalation vulnerability, this can be used for complete site compromise. Once an attacker has gained administrative user access to a WordPress site they can then manipulate anything on the targeted site as a normal administrator would. This includes the ability to upload plugin and theme files, which can be malicious zip files containing backdoors, and modifying posts and pages which can be leveraged to redirect site users to other malicious sites.
Numerous Other Missing Authorization and Cross-Site Request Forgery Vulnerabilities
In addition to the vulnerabilities outlined above, we discovered several AJAX and POST actions without proper capability checks, which made it possible for authenticated attackers with minimal access, such as subscribers, to invoke those actions. Several of the functions were also missing nonce verification, which would make it possible for attackers to forge requests on behalf of a site administrator, or any other authenticated user considering capability checks were also missing.
Disclosure Timeline
April 26, 2023 – Initial discovery of multiple vulnerabilities in UserPro.
May 1, 2023 – We initiate contact with the plugin vendor asking that they confirm the inbox for handling the discussion.
May 10, 2023 – The vendor confirms the inbox for handling the discussion.
May 10, 2023 – We send over the full disclosure details. The vendor acknowledges the report and begins working on a fix.
May 19, 2023 – Wordfence Premium, Care, and Response users receive a firewall rule to provide protection against any exploits that may target this vulnerability.
June 18, 2023 – Wordfence Free users receive the same protection.
July 27, 2023 – A partially patched version of the plugin, 5.1.1, is released.
September 28, 2023 – A partially patched version of the plugin, 5.1.2, is released.
October 31, 2023 – A fully patched version of the plugin, 5.1.5, is released.
Please note we omitted several dates from this timeline as there were extensive back and forth communications with the developer to ensure everything got adequately patched.
Conclusion
In this blog post, we detailed multiple vulnerabilities in the UserPro plugin affecting versions 5.1.4 and earlier. The vulnerabilities have been fully addressed in version 5.1.5 of the plugin.
We encourage WordPress users to verify that their sites are updated to the latest patched version of UserPro as soon as possible.
Wordfence Premium, Wordfence Care, and Wordfence Response users received a firewall rule to protect against any exploits targeting this vulnerability on May 19, 2023. Sites still using the free version of Wordfence received the same protection on June 18, 2023.
If you know someone who uses this plugin on their site, we recommend sharing this advisory with them to ensure their site remains secure, as this vulnerability poses a significant risk.
For security researchers looking to disclose vulnerabilities responsibly, obtain a CVE ID and earn bounty rewards, you can submit your findings to Wordfence Intelligence and potentially earn a bounty!
Source: wordfence.com