Files
Remcos-v7.2.2-crah/server_only.py
T

384 lines
14 KiB
Python
Raw Normal View History

2026-08-27 11:22:11 -06:00
"""
Standalone fake server + DNS redirect.
Stays running until you press Ctrl+C.
Launch Remcos/KeyGen yourself while this is running.
Run as Administrator!
"""
import http.server
import os
import socket
import socketserver
import ssl
import subprocess
import sys
import threading
import time
from datetime import datetime
from urllib.parse import urlparse, parse_qs
VERSION = "7.2.2"
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
CERT_DIR = os.path.join(SCRIPT_DIR, "certs")
CA_CERT = os.path.join(CERT_DIR, "ca.crt")
CA_KEY = os.path.join(CERT_DIR, "ca.key")
SRV_CERT = os.path.join(CERT_DIR, "server.crt")
SRV_KEY = os.path.join(CERT_DIR, "server.key")
NRPT_BASE = r"HKLM:\System\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig"
NRPT_GUIDS = [
("{b1a2c3d4-0001-aaaa-bbbb-000000000001}", [".breakingsec.io", "breakingsec.io"]),
("{b1a2c3d4-0001-aaaa-bbbb-000000000002}", [".ip-api.com", "pro.ip-api.com", "ip-api.com"]),
("{b1a2c3d4-0001-aaaa-bbbb-000000000003}", [".breakingsecurity.net", "breakingsecurity.net"]),
]
REDIRECT_DOMAINS = {"breakingsec.io", "www.breakingsec.io", "breakingsecurity.net",
"www.breakingsecurity.net", "pro.ip-api.com"}
REAL_DNS = "8.8.8.8"
GEO_RESPONSE = "\n".join([
"success", "US", "United States", "NA", "North America",
"CA", "California", "Los Angeles", "Los Angeles", "90001",
"34.0522", "-118.2437", "America/Los_Angeles",
"ISP", "ISP Corp", "AS0000", "1.2.3.4",
])
# ============================================================
# SSL Certs
# ============================================================
def generate_certs():
os.makedirs(CERT_DIR, exist_ok=True)
if os.path.exists(SRV_CERT) and os.path.exists(CA_CERT):
print("[*] Certs exist, reusing.")
return True
print("[*] Generating SSL certificates...")
try:
subprocess.run(["openssl", "req", "-x509", "-newkey", "rsa:2048", "-nodes",
"-keyout", CA_KEY, "-out", CA_CERT, "-days", "3650",
"-subj", "/CN=Remcos Test CA"], capture_output=True, check=True)
csr = os.path.join(CERT_DIR, "server.csr")
ext = os.path.join(CERT_DIR, "ext.cnf")
with open(ext, "w") as f:
f.write("[v3_req]\nsubjectAltName=DNS:breakingsec.io,DNS:*.breakingsec.io,"
"DNS:breakingsecurity.net,DNS:*.breakingsecurity.net,"
"DNS:pro.ip-api.com,DNS:*.ip-api.com,DNS:localhost\n"
"basicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\n"
"extendedKeyUsage=serverAuth\n")
subprocess.run(["openssl", "req", "-newkey", "rsa:2048", "-nodes",
"-keyout", SRV_KEY, "-out", csr, "-subj", "/CN=breakingsec.io"],
capture_output=True, check=True)
subprocess.run(["openssl", "x509", "-req", "-in", csr, "-CA", CA_CERT,
"-CAkey", CA_KEY, "-CAcreateserial", "-out", SRV_CERT, "-days", "3650",
"-extfile", ext, "-extensions", "v3_req"], capture_output=True, check=True)
print("[+] Certificates generated.")
return True
except Exception as e:
print(f"[-] Cert generation failed: {e}")
return False
def install_ca():
r = subprocess.run(["certutil", "-addstore", "-f", "Root", CA_CERT],
capture_output=True, text=True)
if r.returncode == 0:
print("[+] CA cert installed in trust store.")
else:
print(f"[-] CA install failed: {r.stderr[:100]}")
def remove_ca():
subprocess.run(["certutil", "-delstore", "Root", "Remcos Test CA"],
capture_output=True)
# ============================================================
# NRPT
# ============================================================
def setup_nrpt():
print("[*] Setting NRPT rules...")
for guid, domains in NRPT_GUIDS:
names_str = ",".join(f"'{d}'" for d in domains)
ps = f"""
$p = '{NRPT_BASE}\\{guid}'
New-Item -Path $p -Force | Out-Null
Set-ItemProperty -Path $p -Name 'Name' -Value @({names_str}) -Type MultiString
Set-ItemProperty -Path $p -Name 'GenericDNSServers' -Value '127.0.0.1' -Type String
Set-ItemProperty -Path $p -Name 'ConfigOptions' -Value 8 -Type DWord
Set-ItemProperty -Path $p -Name 'Version' -Value 2 -Type DWord
"""
r = subprocess.run(["powershell", "-Command", ps], capture_output=True, text=True, timeout=10)
if r.returncode == 0:
print(f" [+] {', '.join(domains)} -> 127.0.0.1")
else:
print(f" [-] {domains[0]}: {r.stderr.strip()[:80]}")
subprocess.run(["ipconfig", "/flushdns"], capture_output=True, timeout=10)
subprocess.run(["powershell", "-Command", "Clear-DnsClientCache; Register-DnsClient"],
capture_output=True, timeout=10)
def cleanup_nrpt():
for guid, _ in NRPT_GUIDS:
ps = f"Remove-Item -Path '{NRPT_BASE}\\{guid}' -Recurse -Force -ErrorAction SilentlyContinue"
subprocess.run(["powershell", "-Command", ps], capture_output=True, timeout=10)
subprocess.run(["ipconfig", "/flushdns"], capture_output=True, timeout=10)
# ============================================================
# DNS Server
# ============================================================
class DNSHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0]
sock = self.request[1]
try:
domain = self._parse_domain(data).lower().rstrip(".")
redirect = any(domain == d or domain.endswith("." + d)
for d in REDIRECT_DOMAINS)
if redirect:
resp = self._build_response(data, "127.0.0.1")
sock.sendto(resp, self.client_address)
else:
fwd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
fwd.settimeout(3)
fwd.sendto(data, (REAL_DNS, 53))
try:
r, _ = fwd.recvfrom(4096)
sock.sendto(r, self.client_address)
except socket.timeout:
pass
fwd.close()
except:
pass
def _parse_domain(self, data):
parts, idx = [], 12
while idx < len(data):
l = data[idx]
if l == 0: break
idx += 1
parts.append(data[idx:idx+l].decode("ascii", errors="replace"))
idx += l
return ".".join(parts)
def _build_response(self, query, ip):
resp = bytearray(query[:2]) + b'\x81\x80' + query[4:6] + b'\x00\x01\x00\x00\x00\x00'
idx = 12
while idx < len(query):
if query[idx] == 0:
idx += 5
break
idx += 1 + query[idx]
resp += query[12:idx]
resp += b'\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04'
resp += socket.inet_aton(ip)
return bytes(resp)
# ============================================================
# HTTP/HTTPS Server
# ============================================================
class FakeHandler(http.server.BaseHTTPRequestHandler):
def log_message(self, fmt, *args):
ts = datetime.now().strftime("%H:%M:%S")
print(f" [{ts}] {fmt % args}")
def send_text(self, text, code=200):
data = text.encode("utf-8")
self.send_response(code)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(data)))
self.send_header("Connection", "close")
self.end_headers()
self.wfile.write(data)
def route(self):
path = urlparse(self.path).path.lower()
host = self.headers.get("Host", "")
qs = parse_qs(urlparse(self.path).query)
print(f" -> {self.command} {self.path} (Host: {host})")
# Dump ALL headers for debugging
for h_name, h_val in self.headers.items():
print(f" {h_name}: {h_val}")
if "whitelist" in path:
print(f" <- Whitelist: EMPTY")
self.send_text("")
return
if "signalabuse" in path:
print(f" <- Abuse absorbed")
self.send_text("")
return
if "licpost" in path or ("keygen" in path and "lic" in path.lower()):
lic_raw = qs.get("LIC", [""])[0]
parts = lic_raw.split("|")
print(f" ***** KeyGen LicPost! *****")
print(f" Parts: {parts}")
# Try response matching request format: pipe-delimited after "0\n"
key = parts[0] if len(parts) > 0 else ""
email = parts[1] if len(parts) > 1 else ""
# Format: 0\nkey|email|product|expiry|type|version
resp = f"0\n{key}|{email}|Remcos|20301231|Pro|7.2.2"
print(f" <- Responding: '{resp}'")
self.send_text(resp)
return
if "upd_pro" in path:
print(f" <- Version: {VERSION}")
self.send_text(VERSION + "\n")
return
# PeriodicCheck - license validation with hash + expiry
if "periodiccheck" in path:
lic = qs.get("LIC", ["?"])[0]
resp = "49ef9592748fac8986f0d360454dbab0\n20301231\nRemcos"
print(f" ***** PeriodicCheck (LIC={lic[:24]}) -> {repr(resp)} *****")
self.send_text(resp)
return
# Auth/license check - sign with our private key
if "auth" in path or "check" in path or "verify" in path or "validate" in path:
print(f" ***** Auth endpoint: {self.path} *****")
self.send_text("0\n20301231\nPro\n7.2.2")
return
if "onlinecheck" in path:
print(f" <- OnlineCheck: {VERSION}")
self.send_text(VERSION + "\n")
return
if "/line" in path or "ip-api" in host:
print(f" <- GeoIP")
self.send_text(GEO_RESPONSE + "\n")
return
print(f" *** UNKNOWN ENDPOINT: {self.path} ***")
print(f" *** Host: {host} ***")
# Return "0" instead of empty - empty might cause range check errors
self.send_text("0")
def do_GET(self): self.route()
def do_POST(self):
cl = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(cl) if cl > 0 else b""
if body:
try: print(f" POST body: {body[:300].decode('utf-8', errors='replace')}")
except: print(f" POST body: {body[:100].hex()}")
self.route()
# ============================================================
# Main
# ============================================================
def main():
print("=" * 60)
print(" Fake Server (standalone) - stays running")
print(" Launch Remcos/KeyGen yourself while this runs")
print("=" * 60)
if not ctypes.windll.shell32.IsUserAnAdmin():
print("[-] Need Administrator! Right-click -> Run as admin")
return 1
# Setup
generate_certs()
install_ca()
# CA bundle for OpenSSL apps
ca_bundle = os.path.join(CERT_DIR, "ca_bundle.pem")
try:
import certifi
system_ca = certifi.where()
except ImportError:
system_ca = None
with open(ca_bundle, "w") as out:
with open(CA_CERT) as f: out.write(f.read() + "\n")
if system_ca and os.path.exists(system_ca):
with open(system_ca) as f: out.write(f.read())
os.environ["SSL_CERT_FILE"] = ca_bundle
os.environ["SSL_CERT_DIR"] = CERT_DIR
# Start servers
dns = socketserver.UDPServer(("127.0.0.1", 53), DNSHandler)
threading.Thread(target=dns.serve_forever, daemon=True).start()
print("[+] DNS on 127.0.0.1:53")
http_srv = http.server.HTTPServer(("0.0.0.0", 80), FakeHandler)
threading.Thread(target=http_srv.serve_forever, daemon=True).start()
print("[+] HTTP on 0.0.0.0:80")
try:
class LoggingHTTPS(http.server.HTTPServer):
def handle_error(self, request, client_address):
print(f" [SSL ERROR] from {client_address}: {sys.exc_info()[1]}")
https_srv = LoggingHTTPS(("0.0.0.0", 443), FakeHandler)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain(SRV_CERT, SRV_KEY)
https_srv.socket = ctx.wrap_socket(https_srv.socket, server_side=True)
threading.Thread(target=https_srv.serve_forever, daemon=True).start()
print("[+] HTTPS on 0.0.0.0:443")
except Exception as e:
print(f"[-] HTTPS failed: {e}")
# Port 45000 - Viotto packer license validation (raw TCP protocol!)
def handle_viotto_client(conn, addr):
print(f"\n *** PORT 45000 CONNECTION from {addr} ***")
conn.settimeout(5)
try:
# Read whatever the client sends
data = conn.recv(4096)
print(f" *** RECEIVED ({len(data)} bytes): {data[:200].hex()}")
try:
print(f" *** AS TEXT: {data[:200].decode('ascii', errors='replace')}")
except:
pass
# Echo back for now - we need to see the protocol first
conn.sendall(data)
print(f" *** Echoed {len(data)} bytes back")
except socket.timeout:
print(f" *** PORT 45000: recv timeout (client didn't send data)")
except Exception as e:
print(f" *** PORT 45000 error: {e}")
finally:
conn.close()
def viotto_server():
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 45000))
srv.listen(5)
print("[+] Raw TCP on 0.0.0.0:45000 (Viotto license port!)")
while True:
conn, addr = srv.accept()
threading.Thread(target=handle_viotto_client, args=(conn, addr), daemon=True).start()
threading.Thread(target=viotto_server, daemon=True).start()
# NRPT
setup_nrpt()
# Verify
time.sleep(1)
for domain in ["breakingsec.io", "breakingsecurity.net"]:
try:
result = socket.getaddrinfo(domain, 443)
ip = result[0][4][0]
status = "OK" if ip == "127.0.0.1" else f"WRONG ({ip})"
print(f" {domain} -> {ip} [{status}]")
except Exception as e:
print(f" {domain} -> ERROR: {e}")
print()
print("=" * 60)
print(" RUNNING. Now launch KeyGen.exe or Remcos manually.")
print(" Press Ctrl+C to stop and clean up.")
print("=" * 60)
print()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
print("\n[*] Cleaning up...")
cleanup_nrpt()
print("[+] NRPT removed")
remove_ca()
print("[+] CA removed")
import ctypes
if __name__ == "__main__":
sys.exit(main())