Update (2024-11-13): Expanded on this topic during a co-presented talk for the Cyber Security Society. See more here.

CVE reversing is the process of creating a proof-of-concept (PoC) based on the differences between the code of a vulnerable software version and its patched version. By looking at the diffs, it’s possible to identify the vulnerability in the original code.

I recently obtained two CVEs for stored XSS and SQLi in a plugin with over 400 active installations (CVE-2024-43967, CVE-2024-43966). These vulnerabilities required at least Editor or Admin level privileges. By practicing CVE reversing more often, I aim to better detect more complex and high-impact vulnerabilities moving forward.

I will be examining CVE-2024-6411. The plugin ProfileGrid was vulnerable to privilege escalation and was classified as a CVSS 8.8 issue.

Plugin Description

ProfileGrid is a WordPress user profile and membership plugin. It integrates with WooCommerce and bbPress, supports content restriction, sign-up pages, blog submissions, notifications, social activity, private messaging, etc.

Issue Description

The ProfileGrid – User Profiles, Groups and Communities plugin for WordPress is vulnerable to privilege escalation in all versions up to, and including, 5.8.9. This is due to a lack of validation on user-supplied data in the ‘pm_upload_image’ AJAX action. This makes it possible for authenticated attackers, with Subscriber-level access and above, to update their user capabilities to Administrator.

Wordfence has also published a technical analysis regarding this issue.

Technical Details

Looking at the CVE entry, we can see that the vulnerable version is <= 5.8.9 and it was patched in version 5.9.0. We can to navigate to https://plugins.trac.wordpress.org/log/profilegrid-user-profiles-groups-and-communities/trunk and select the changes in 5.8.9 and 5.9.0.

The Trac is primarily used to monitor all the code changes in a plugin or theme. It can be a useful tool to review changes and see if any vulnerabilities were patched or introduced in the latest version.

Clicking on “View Changes” returns a page that contains all the changes in the code.

Reviewing the changes, we come across the update_user_meta function in /public/partials/crop.php.

This function is called whenever a user attempts to update their profile picture. It takes the user ID, the metadata key, and the new value to set or modify that metadata field. Meta keys are a WordPress-specific feature used to store custom fields and data for different WordPress objects like posts, users, and comments.

In the ProfileGrid plugin, the pm_user_avatar meta key is specifically used to store a user’s avatar information. If the plugin does not enforce proper validation on this $_POST request, an attacker may be able to set the user_meta field to an arbitrary value (i.e. wp_capabilities).

The pm_upload_image() function in the Profile_Magic_Public class handles the upload, editing, or deletion of the user’s profile picture.

1681public function pm_upload_image() {
1682     require 'partials/crop.php';
1683    die;
1684}

This function includes the crop.php file which handles the actual request processing. It is also linked to an AJAX action that manages profile picture uploads:

336$this->loader->add_action('wp_ajax_pm_upload_image', $plugin_public, 'pm_upload_image');

When this AJAX action is triggered, it loads the crop.php file, where the the call to update_user_meta() is also performed. The changes between versions 5.8.9 and 5.9.0 show us how the vulnerability was mitigated and how we could potentially exploit it.

Mitigation

We can see that in version 5.9.0, the vulnerability was mitigated by introducing additional validation checks. Specifically, the changes ensure that:

  • The user_idin the request matches the ID of the currently logged-in user ($current_user->ID).
  • The user_meta field is explicitly restricted to pm_user_avatar.

These changes make it so that only the profile picture metadata can be updated and only by the legitimate user.

Exploitation

Before the fix, the lack of validation on the user_meta field allowed for potential exploitation as an attacker could set the field to wp_capabilities and provide a value that grants Administrator privileges (wp_capabilities is a meta key that stores user roles and permissions). The exploit requires an attacker to be an authenticated user with Subscriber-level access and above – as only they would have existing profiles and be able to trigger the AJAX action.

PoC

We login as a Subscriber user and attempt to update our profile picture.

Using Burp Suite we can capture the request made when we click on “Crop & Save”.

We set user_meta to wp_capabilities and set the attachment_id to an array that gives an attacker administrator privileges.

So, we changed user_meta from pm_user_avatar to wp_capabilities and changed attachment_id from 367 to [administrator]=1.

After sending the request, the page refreshes and the cover image updates to an image associated with Administrator accounts. We can also notice the toolbar at the top of the WordPress dashboard which now includes options and features that are available only to Administrators.

Going to the users page in the WordPress dashboard confirms that previously Subscriber-level user now has the Administrator role, giving them full control over the WordPress site.

Conclusion

We have seen how insecure implementation of the pm_upload_image() function in the ProfileGrid plugin led to a critical privilege escalation vulnerability. The plugin developers have addressed this issue in version 5.9.0 by implementing stricter control over the metadata that can be updated through this function. This reinforces the importance of input validation in development – never trust, always verify.

Transitioning from standard web application testing to code review, especially for WordPress plugins, can be pretty challenging if you’re not familiar with the intricacies of WordPress. This process offers a way to better your understanding and become more proficient at identifying the different ways vulnerabilities can occur within this ecosystem.