mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
150 lines
8.8 KiB
Python
Executable File
150 lines
8.8 KiB
Python
Executable File
import argparse
|
|
import argcomplete
|
|
import sys
|
|
from argparse import RawTextHelpFormatter
|
|
from os import listdir
|
|
from os.path import dirname
|
|
from os.path import join as path_join
|
|
import nxc
|
|
from nxc.paths import NXC_PATH
|
|
from nxc.loaders.protocolloader import ProtocolLoader
|
|
from nxc.helpers.logger import highlight
|
|
from nxc.helpers.args import DisplayDefaultsNotNone
|
|
from nxc.logger import nxc_logger, setup_debug_logging
|
|
import importlib.metadata
|
|
|
|
|
|
def gen_cli_args():
|
|
setup_debug_logging()
|
|
|
|
try:
|
|
VERSION, COMMIT = importlib.metadata.version("netexec").split("+")
|
|
DISTANCE, COMMIT = COMMIT.split(".")
|
|
except ValueError:
|
|
VERSION = importlib.metadata.version("netexec")
|
|
COMMIT = ""
|
|
DISTANCE = ""
|
|
CODENAME = "SmoothOperator"
|
|
|
|
generic_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
|
|
generic_group = generic_parser.add_argument_group("Generic Options")
|
|
generic_group.add_argument("--version", action="store_true", help="Display nxc version")
|
|
generic_group.add_argument("-t", "--threads", type=int, dest="threads", default=256, help="set how many concurrent threads to use")
|
|
generic_group.add_argument("--timeout", default=None, type=int, help="max timeout in seconds of each thread")
|
|
generic_group.add_argument("--jitter", metavar="INTERVAL", type=str, help="sets a random delay between each authentication")
|
|
|
|
output_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
|
|
output_group = output_parser.add_argument_group("Output Options")
|
|
output_group.add_argument("--no-progress", action="store_true", help="do not displaying progress bar during scan")
|
|
output_group.add_argument("--log", metavar="LOG", help="export result into a custom file")
|
|
log_level = output_group.add_mutually_exclusive_group()
|
|
log_level.add_argument("--verbose", action="store_true", help="enable verbose output")
|
|
log_level.add_argument("--debug", action="store_true", help="enable debug level information")
|
|
|
|
dns_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
|
|
dns_group = dns_parser.add_argument_group("DNS")
|
|
dns_group.add_argument("-6", dest="force_ipv6", action="store_true", help="Enable force IPv6")
|
|
dns_group.add_argument("--dns-server", action="store", help="Specify DNS server (default: Use hosts file & System DNS)")
|
|
dns_group.add_argument("--dns-tcp", action="store_true", help="Use TCP instead of UDP for DNS queries")
|
|
dns_group.add_argument("--dns-timeout", action="store", type=int, default=3, help="DNS query timeout in seconds")
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description=rf"""
|
|
. .
|
|
.| |. _ _ _ _____
|
|
|| || | \ | | ___ | |_ | ____| __ __ ___ ___
|
|
\\( )// | \| | / _ \ | __| | _| \ \/ / / _ \ / __|
|
|
.=[ ]=. | |\ | | __/ | |_ | |___ > < | __/ | (__
|
|
/ /˙-˙\ \ |_| \_| \___| \__| |_____| /_/\_\ \___| \___|
|
|
˙ \ / ˙
|
|
˙ ˙
|
|
|
|
The network execution tool
|
|
Maintained as an open source project by @NeffIsBack, @MJHallenbeck, @_zblurx
|
|
|
|
For documentation and usage examples, visit: https://www.netexec.wiki/
|
|
|
|
{highlight('Version', 'red')} : {highlight(VERSION)}
|
|
{highlight('Codename', 'red')}: {highlight(CODENAME)}
|
|
{highlight('Commit', 'red')} : {highlight(COMMIT)}
|
|
""",
|
|
formatter_class=RawTextHelpFormatter,
|
|
parents=[generic_parser, output_parser, dns_parser]
|
|
)
|
|
|
|
# we do module arg parsing here so we can reference the module_list attribute below
|
|
module_parser = argparse.ArgumentParser(add_help=False, formatter_class=DisplayDefaultsNotNone)
|
|
mgroup = module_parser.add_argument_group("Modules")
|
|
mgroup.add_argument("-M", "--module", choices=get_module_names(), action="append", metavar="MODULE", help="module to use")
|
|
mgroup.add_argument("-o", metavar="MODULE_OPTION", nargs="+", default=[], dest="module_options", help="module options")
|
|
mgroup.add_argument("-L", "--list-modules", nargs="?", type=str, const="", help="list available modules")
|
|
mgroup.add_argument("--options", dest="show_module_options", action="store_true", help="display module options")
|
|
|
|
subparsers = parser.add_subparsers(title="Available Protocols", dest="protocol")
|
|
|
|
std_parser = argparse.ArgumentParser(add_help=False, parents=[generic_parser, output_parser, dns_parser], formatter_class=DisplayDefaultsNotNone)
|
|
std_parser.add_argument("target", nargs="+" if not (module_parser.parse_known_args()[0].list_modules is not None or module_parser.parse_known_args()[0].show_module_options or generic_parser.parse_known_args()[0].version) else "*", type=str, help="the target IP(s), range(s), CIDR(s), hostname(s), FQDN(s), file(s) containing a list of targets, NMap XML or .Nessus file(s)")
|
|
credential_group = std_parser.add_argument_group("Authentication")
|
|
credential_group.add_argument("-u", "--username", metavar="USERNAME", dest="username", nargs="+", default=[], help="username(s) or file(s) containing usernames")
|
|
credential_group.add_argument("-p", "--password", metavar="PASSWORD", dest="password", nargs="+", default=[], help="password(s) or file(s) containing passwords")
|
|
credential_group.add_argument("-id", metavar="CRED_ID", nargs="+", default=[], type=str, dest="cred_id", help="database credential ID(s) to use for authentication")
|
|
credential_group.add_argument("--ignore-pw-decoding", action="store_true", help="Ignore non UTF-8 characters when decoding the password file")
|
|
credential_group.add_argument("--no-bruteforce", action="store_true", help="No spray when using file for username and password (user1 => password1, user2 => password2)")
|
|
credential_group.add_argument("--continue-on-success", action="store_true", help="continues authentication attempts even after successes")
|
|
credential_group.add_argument("--gfail-limit", metavar="LIMIT", type=int, help="max number of global failed login attempts")
|
|
credential_group.add_argument("--ufail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per username")
|
|
credential_group.add_argument("--fail-limit", metavar="LIMIT", type=int, help="max number of failed login attempts per host")
|
|
|
|
kerberos_group = std_parser.add_argument_group("Kerberos Authentication")
|
|
kerberos_group.add_argument("-k", "--kerberos", action="store_true", help="Use Kerberos authentication")
|
|
kerberos_group.add_argument("--use-kcache", action="store_true", help="Use Kerberos authentication from ccache file (KRB5CCNAME)")
|
|
kerberos_group.add_argument("--aesKey", metavar="AESKEY", nargs="+", help="AES key to use for Kerberos Authentication (128 or 256 bits)")
|
|
kerberos_group.add_argument("--kdcHost", metavar="KDCHOST", help="FQDN of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter")
|
|
|
|
certificate_group = std_parser.add_argument_group("Certificate Authentication")
|
|
certificate_group.add_argument("--pfx-cert", metavar="PFXCERT", help="Use certificate authentication from pfx file .pfx")
|
|
certificate_group.add_argument("--pfx-base64", metavar="PFXB64", help="Use certificate authentication from pfx file encoded in base64")
|
|
certificate_group.add_argument("--pfx-pass", metavar="PFXPASS", help="Password of the pfx certificate")
|
|
certificate_group.add_argument("--pem-cert", metavar="PEMCERT", help="Use certificate authentication from PEM file")
|
|
certificate_group.add_argument("--pem-key", metavar="PEMKEY", help="Private key for the PEM format")
|
|
|
|
p_loader = ProtocolLoader()
|
|
protocols = p_loader.get_protocols()
|
|
|
|
try:
|
|
for protocol in protocols:
|
|
protocol_object = p_loader.load_protocol(protocols[protocol]["argspath"])
|
|
subparsers = protocol_object.proto_args(subparsers, [std_parser, module_parser])
|
|
except Exception as e:
|
|
nxc_logger.exception(f"Error loading proto_args from proto_args.py file in protocol folder: {protocol} - {e}")
|
|
|
|
argcomplete.autocomplete(parser, always_complete_options=False)
|
|
args = parser.parse_args()
|
|
|
|
if len(sys.argv) == 1:
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
if args.version:
|
|
print(f"{VERSION} - {CODENAME} - {COMMIT} - {DISTANCE}")
|
|
sys.exit(1)
|
|
|
|
# Multiply output_tries by 10 to enable more fine granural control, see exec methods
|
|
if hasattr(args, "get_output_tries"):
|
|
args.get_output_tries = args.get_output_tries * 10
|
|
|
|
return args, [CODENAME, VERSION, COMMIT, DISTANCE]
|
|
|
|
|
|
def get_module_names():
|
|
"""Get module names without initializing them"""
|
|
modules = []
|
|
modules_paths = [
|
|
path_join(dirname(nxc.__file__), "modules"),
|
|
path_join(NXC_PATH, "modules"),
|
|
]
|
|
|
|
for path in modules_paths:
|
|
modules.extend([module[:-3] for module in listdir(path) if module[-3:] == ".py" and module != "example_module.py"])
|
|
return sorted(modules, key=str.casefold)
|