2023-03-24 18:11:02 +00:00
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
from rich.console import Console
|
|
|
|
|
|
|
|
|
|
|
|
def get_cli_args():
|
2023-09-20 15:59:16 +00:00
|
|
|
parser = argparse.ArgumentParser(description="Script for running end to end tests for nxc")
|
2023-10-14 18:29:01 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"-t",
|
|
|
|
"--target",
|
|
|
|
dest="target",
|
|
|
|
required=True
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-u",
|
|
|
|
"--user",
|
|
|
|
"--username",
|
|
|
|
dest="username",
|
|
|
|
required=True
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-p",
|
|
|
|
"--pass",
|
|
|
|
"--password",
|
|
|
|
dest="password",
|
|
|
|
required=True
|
|
|
|
)
|
2023-05-02 15:17:59 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"-k",
|
|
|
|
"--kerberos",
|
|
|
|
action="store_true",
|
|
|
|
required=False,
|
|
|
|
help="Use kerberos authentication",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-v",
|
|
|
|
"--verbose",
|
|
|
|
action="store_true",
|
|
|
|
required=False,
|
|
|
|
help="Display full command output",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-e",
|
|
|
|
"--errors",
|
|
|
|
action="store_true",
|
|
|
|
required=False,
|
|
|
|
help="Display errors from commands",
|
|
|
|
)
|
2023-10-14 18:29:01 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--poetry",
|
|
|
|
action="store_true",
|
|
|
|
required=False,
|
|
|
|
help="Use poetry to run commands",
|
|
|
|
)
|
2023-10-20 19:02:37 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--protocols",
|
|
|
|
nargs="+",
|
|
|
|
default=[],
|
|
|
|
required=False,
|
|
|
|
help="Protocols to test",
|
|
|
|
)
|
2023-03-24 18:11:02 +00:00
|
|
|
|
2023-10-14 18:16:28 +00:00
|
|
|
return parser.parse_args()
|
2023-03-24 18:11:02 +00:00
|
|
|
|
|
|
|
|
2023-04-07 14:31:23 +00:00
|
|
|
def generate_commands(args):
|
2023-03-24 18:11:02 +00:00
|
|
|
lines = []
|
|
|
|
file_loc = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
|
|
|
|
commands_file = os.path.join(file_loc, "e2e_commands.txt")
|
|
|
|
|
|
|
|
with open(commands_file) as file:
|
|
|
|
for line in file:
|
2023-03-27 05:50:22 +00:00
|
|
|
if line.startswith("#"):
|
|
|
|
continue
|
2023-03-24 18:11:02 +00:00
|
|
|
line = line.strip()
|
2023-10-20 19:02:37 +00:00
|
|
|
if args.protocols:
|
|
|
|
if line.split()[1] in args.protocols:
|
|
|
|
lines.append(replace_command(args, line))
|
|
|
|
else:
|
|
|
|
lines.append(replace_command(args, line))
|
2023-03-24 18:11:02 +00:00
|
|
|
return lines
|
|
|
|
|
2023-10-20 19:02:37 +00:00
|
|
|
def replace_command(args, line):
|
|
|
|
kerberos = "-k " if args.kerberos else ""
|
|
|
|
|
|
|
|
line = line.replace("TARGET_HOST", args.target).replace("LOGIN_USERNAME", f'"{args.username}"').replace("LOGIN_PASSWORD", f'"{args.password}"').replace("KERBEROS ", kerberos)
|
|
|
|
if args.poetry:
|
|
|
|
line = f"poetry run {line}"
|
|
|
|
return line
|
|
|
|
|
2023-03-24 18:11:02 +00:00
|
|
|
|
2023-04-07 14:31:23 +00:00
|
|
|
def run_e2e_tests(args):
|
2023-03-24 18:11:02 +00:00
|
|
|
console = Console()
|
2023-04-07 14:31:23 +00:00
|
|
|
tasks = generate_commands(args)
|
2023-03-24 18:11:02 +00:00
|
|
|
|
2023-04-07 14:31:23 +00:00
|
|
|
result = subprocess.Popen(
|
2023-09-14 21:07:15 +00:00
|
|
|
"netexec --version",
|
2023-04-07 14:31:23 +00:00
|
|
|
shell=True,
|
|
|
|
stdout=subprocess.PIPE,
|
2023-05-02 15:17:59 +00:00
|
|
|
stderr=subprocess.STDOUT,
|
2023-04-07 14:31:23 +00:00
|
|
|
)
|
2023-03-24 18:11:02 +00:00
|
|
|
version = result.communicate()[0].decode().strip()
|
|
|
|
|
2023-09-20 15:59:16 +00:00
|
|
|
with console.status(f"[bold green] :brain: Running {len(tasks)} test commands for nxc v{version}..."):
|
2023-03-26 05:20:08 +00:00
|
|
|
passed = 0
|
|
|
|
failed = 0
|
2023-04-07 14:31:23 +00:00
|
|
|
|
2023-03-24 18:11:02 +00:00
|
|
|
while tasks:
|
|
|
|
task = tasks.pop(0)
|
2023-11-13 17:17:04 +00:00
|
|
|
console.log(f"Running command: {task!s}")
|
2023-04-07 14:31:23 +00:00
|
|
|
result = subprocess.Popen(
|
|
|
|
str(task),
|
|
|
|
shell=True,
|
|
|
|
stdin=subprocess.PIPE,
|
|
|
|
stdout=subprocess.PIPE,
|
2023-05-02 15:17:59 +00:00
|
|
|
stderr=subprocess.STDOUT,
|
2023-04-07 14:31:23 +00:00
|
|
|
)
|
2023-03-24 18:11:02 +00:00
|
|
|
# pass in a "y" for things that prompt for it (--ndts, etc)
|
|
|
|
text = result.communicate(input=b"y")[0]
|
|
|
|
return_code = result.returncode
|
2023-04-07 14:31:23 +00:00
|
|
|
|
2023-03-24 18:11:02 +00:00
|
|
|
if return_code == 0:
|
|
|
|
console.log(f"{task.strip()} :heavy_check_mark:")
|
2023-03-26 05:20:08 +00:00
|
|
|
passed += 1
|
2023-03-24 18:11:02 +00:00
|
|
|
else:
|
|
|
|
console.log(f"[bold red]{task.strip()} :cross_mark:[/]")
|
2023-03-26 05:20:08 +00:00
|
|
|
failed += 1
|
2023-04-07 14:31:23 +00:00
|
|
|
|
2023-04-08 16:39:49 +00:00
|
|
|
if args.errors:
|
|
|
|
raw_text = text.decode("utf-8")
|
|
|
|
if "error" in raw_text.lower() or "failure" in raw_text.lower():
|
2023-11-13 17:17:04 +00:00
|
|
|
console.log("[bold red]Error Detected:")
|
|
|
|
console.log(f"{raw_text}")
|
2023-04-08 16:39:49 +00:00
|
|
|
|
2023-04-07 14:31:23 +00:00
|
|
|
if args.verbose:
|
|
|
|
# this prints sorta janky, but it does its job
|
|
|
|
console.log(f"[*] Results:\n{text.decode('utf-8')}")
|
2023-03-26 05:20:08 +00:00
|
|
|
console.log(f"Tests [bold green] Passed: {passed} [bold red] Failed: {failed}")
|
2023-03-24 18:11:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2023-04-07 14:31:23 +00:00
|
|
|
parsed_args = get_cli_args()
|
|
|
|
run_e2e_tests(parsed_args)
|