Got attack box and c2-redirector working

This commit is contained in:
n0mad1k
2025-08-21 16:25:00 -04:00
parent 1450a55e50
commit 9bef2e7d31
93 changed files with 14924 additions and 3727 deletions
+208
View File
@@ -0,0 +1,208 @@
#!/usr/bin/env python3
"""
SSH utilities for C2ingRed deployment system
"""
import os
import subprocess
import logging
import re
import glob
from .common import COLORS, generate_random_string
def generate_ssh_key(deployment_id=None):
"""Generate an SSH key for deployment with proper tracking for cleanup"""
# Use deployment_id if provided, otherwise generate random suffix
if not deployment_id:
deployment_id = generate_random_string(6)
ssh_key_path = os.path.expanduser(f"~/.ssh/c2deploy_{deployment_id}")
ssh_key_pub_path = f"{ssh_key_path}.pub"
# Check if key already exists
if os.path.exists(ssh_key_path):
logging.info(f"SSH key already exists at {ssh_key_path}")
return ssh_key_path
try:
# Generate the SSH key
subprocess.run([
"ssh-keygen", "-t", "rsa", "-b", "4096",
"-f", ssh_key_path, "-q", "-N", ""
], check=True)
# Set proper permissions
os.chmod(ssh_key_path, 0o600)
# Track generated keys for cleanup
if not hasattr(generate_ssh_key, 'generated_keys'):
generate_ssh_key.generated_keys = []
generate_ssh_key.generated_keys.append(ssh_key_path)
logging.info(f"Generated SSH key: {ssh_key_path}")
return ssh_key_path
except subprocess.CalledProcessError as e:
logging.error(f"Failed to generate SSH key: {e}")
return None
def get_ssh_public_key(private_key_path):
"""Get the public key content from a private key file"""
public_key_path = f"{private_key_path}.pub"
if not os.path.exists(public_key_path):
logging.error(f"Public key file not found: {public_key_path}")
return None
try:
with open(public_key_path, 'r') as f:
return f.read().strip()
except Exception as e:
logging.error(f"Failed to read public key: {e}")
return None
def extract_attack_box_ip_from_logs(config):
"""Extract attack box IP from deployment logs or Ansible output"""
deployment_id = config.get('deployment_id', 'unknown')
# Check deployment log file first
log_files_to_check = [
f"logs/deployment_{deployment_id}.log",
# Also check archived logs
f"logs/archive/deployment_{deployment_id}.log"
]
# Check for timestamped archived logs
archive_pattern = f"logs/archive/*_deployment_{deployment_id}.log"
archived_logs = glob.glob(archive_pattern)
if archived_logs:
# Get the most recent archived log
log_files_to_check.append(max(archived_logs, key=os.path.getmtime))
for log_file in log_files_to_check:
if os.path.exists(log_file):
try:
with open(log_file, 'r') as f:
content = f.read()
# Look for various IP patterns in the log
ip_patterns = [
r'"attack_box_ip":\s*"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"',
r'attack_box_ip.*?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'"ipv4":\s*\["([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"\]',
r'ansible_host["\s]*=[\s]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'instance_ip["\s]*:[\s]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'Target: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'IP["\s]*:[\s]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
# Look for IP in Ansible task output patterns
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s+:\s+ok=',
r'PLAY RECAP.*?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'changed: \[([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\]',
r'ok: \[([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\]'
]
for pattern in ip_patterns:
match = re.search(pattern, content)
if match:
ip = match.group(1)
logging.info(f"Extracted attack box IP from logs: {ip}")
return ip
except Exception as e:
logging.warning(f"Could not read deployment log {log_file}: {e}")
# Check deployment info file
info_file = f"logs/deployment_info_{deployment_id}.txt"
if os.path.exists(info_file):
try:
with open(info_file, 'r') as f:
content = f.read()
# Look for IP in SSH command or other contexts
ip_patterns = [
r'root@([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'Instance IP:\s*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})',
r'IP["\s]*:[\s]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'
]
for pattern in ip_patterns:
match = re.search(pattern, content)
if match:
ip = match.group(1)
logging.info(f"Extracted attack box IP from deployment info: {ip}")
return ip
except Exception as e:
logging.warning(f"Could not read deployment info: {e}")
logging.warning("Could not extract attack box IP from logs")
return None
def ssh_to_instance(config):
"""SSH into an instance after deployment"""
ssh_key_path = config.get('ssh_key_path', '').replace('.pub', '')
# Handle attack box deployments
if config.get('attack_box_deployment'):
instance_ip = config.get('attack_box_ip')
instance_name = config.get('attack_box_name', 'attack box')
# If no IP stored in config, try to extract from deployment logs
if not instance_ip:
instance_ip = extract_attack_box_ip_from_logs(config)
# Determine which instance to connect to for C2 deployments
elif config.get('c2_only') or (not config.get('redirector_only') and not config.get('deploy_tracker')):
# Connect to C2 server
instance_ip = config.get('c2_ip')
instance_name = config.get('c2_name', 'C2 server')
elif config.get('redirector_only'):
# Connect to redirector
instance_ip = config.get('redirector_ip')
instance_name = config.get('redirector_name', 'redirector')
elif config.get('deploy_tracker') and not config.get('integrated_tracker'):
# Connect to tracker
instance_ip = config.get('tracker_ip')
instance_name = config.get('tracker_name', 'tracker')
else:
# Default to C2 server
instance_ip = config.get('c2_ip')
instance_name = config.get('c2_name', 'C2 server')
if not instance_ip:
print(f"{COLORS['RED']}No instance IP found for SSH connection{COLORS['RESET']}")
return
ssh_user = config.get('ssh_user', 'root')
print(f"{COLORS['GREEN']}Connecting to {instance_name} ({instance_ip})...{COLORS['RESET']}")
ssh_command = [
"ssh",
"-i", ssh_key_path,
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-o", "IdentitiesOnly=yes",
f"{ssh_user}@{instance_ip}"
]
try:
subprocess.run(ssh_command)
except KeyboardInterrupt:
print(f"\n{COLORS['YELLOW']}SSH session ended{COLORS['RESET']}")
except Exception as e:
print(f"{COLORS['RED']}SSH connection failed: {e}{COLORS['RESET']}")
def cleanup_ssh_keys(deployment_id=None, keep_keys=False):
"""Clean up generated SSH keys"""
if keep_keys:
return
if hasattr(generate_ssh_key, 'generated_keys'):
for key_path in generate_ssh_key.generated_keys:
# Only remove keys we generated for this deployment
if deployment_id and f"_{deployment_id}" in key_path:
try:
if os.path.exists(key_path):
os.remove(key_path)
if os.path.exists(f"{key_path}.pub"):
os.remove(f"{key_path}.pub")
logging.info(f"Removed SSH key: {key_path}")
except Exception as e:
logging.error(f"Failed to remove SSH key {key_path}: {e}")