Got attack box and c2-redirector working
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
C2 infrastructure deployment module
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
# Add the project root to the path so we can import utils
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from utils.common import (
|
||||
COLORS, clear_screen, print_banner, generate_deployment_id,
|
||||
setup_logging, get_public_ip, confirm_action, wait_for_input,
|
||||
archive_old_logs
|
||||
)
|
||||
from utils.provider_utils import select_provider, gather_provider_config
|
||||
from utils.ssh_utils import generate_ssh_key
|
||||
from utils.naming_utils import get_deployment_name_with_options
|
||||
|
||||
def gather_c2_parameters():
|
||||
"""Collect parameters specific to C2 deployments"""
|
||||
clear_screen()
|
||||
print_banner()
|
||||
print(f"{COLORS['WHITE']}C2 INFRASTRUCTURE SETUP{COLORS['RESET']}")
|
||||
print(f"{COLORS['WHITE']}========================{COLORS['RESET']}")
|
||||
|
||||
config = {}
|
||||
|
||||
# Generate deployment ID
|
||||
config['deployment_id'] = generate_deployment_id()
|
||||
print(f"Deployment ID: {COLORS['CYAN']}{config['deployment_id']}{COLORS['RESET']}")
|
||||
|
||||
# Provider selection
|
||||
provider = select_provider()
|
||||
if not provider:
|
||||
return None
|
||||
config['provider'] = provider
|
||||
|
||||
# Get provider-specific configuration
|
||||
provider_config = gather_provider_config(provider)
|
||||
if not provider_config:
|
||||
return None
|
||||
config.update(provider_config)
|
||||
|
||||
# C2-specific configuration
|
||||
print(f"\n{COLORS['BLUE']}C2 Configuration{COLORS['RESET']}")
|
||||
|
||||
# Domain configuration
|
||||
domain = input(f"Domain for C2 infrastructure [required]: ")
|
||||
if not domain:
|
||||
print(f"{COLORS['RED']}A domain is required for C2 deployments{COLORS['RESET']}")
|
||||
return None
|
||||
config['domain'] = domain
|
||||
|
||||
# Subdomain configuration
|
||||
config['c2_subdomain'] = input("C2 server subdomain [default: mail]: ") or "mail"
|
||||
|
||||
# Instance naming options
|
||||
config['redirector_name'] = get_deployment_name_with_options(
|
||||
deployment_type='redirector',
|
||||
deployment_id=config['deployment_id'],
|
||||
prefix='r-'
|
||||
)
|
||||
|
||||
config['c2_name'] = get_deployment_name_with_options(
|
||||
deployment_type='c2',
|
||||
deployment_id=config['deployment_id'],
|
||||
prefix='s-'
|
||||
)
|
||||
|
||||
# C2 Framework selection
|
||||
print(f"\n{COLORS['BLUE']}C2 Framework Selection:{COLORS['RESET']}")
|
||||
print(f"1) Havoc")
|
||||
print(f"2) Cobalt Strike")
|
||||
print(f"3) Sliver")
|
||||
print(f"4) Mythic")
|
||||
print(f"5) Custom")
|
||||
|
||||
framework_choice = input("Select C2 framework [default: 1]: ") or "1"
|
||||
frameworks = {
|
||||
"1": "havoc",
|
||||
"2": "cobaltstrike",
|
||||
"3": "sliver",
|
||||
"4": "mythic",
|
||||
"5": "custom"
|
||||
}
|
||||
config['c2_framework'] = frameworks.get(framework_choice, "havoc")
|
||||
|
||||
# Email for Let's Encrypt
|
||||
default_email = f"admin@{config['domain']}"
|
||||
config['letsencrypt_email'] = input(f"Email for Let's Encrypt [default: {default_email}]: ") or default_email
|
||||
|
||||
# Get operator IP for security
|
||||
suggested_ip = get_public_ip()
|
||||
if suggested_ip:
|
||||
operator_ip = input(f"Your public IP for secure access [detected: {suggested_ip}]: ") or suggested_ip
|
||||
else:
|
||||
operator_ip = input("Your public IP for secure access: ")
|
||||
config['operator_ip'] = operator_ip
|
||||
|
||||
# SSH key generation
|
||||
ssh_key_path = generate_ssh_key(config['deployment_id'])
|
||||
if not ssh_key_path:
|
||||
print(f"{COLORS['RED']}Failed to generate SSH key{COLORS['RESET']}")
|
||||
return None
|
||||
config['ssh_key_path'] = f"{ssh_key_path}.pub"
|
||||
|
||||
# SMTP Configuration for email services
|
||||
print(f"\n{COLORS['BLUE']}SMTP Configuration{COLORS['RESET']}")
|
||||
config['smtp_auth_user'] = input("SMTP authentication username [default: admin]: ") or "admin"
|
||||
|
||||
import secrets
|
||||
import string
|
||||
def generate_random_password(length=16):
|
||||
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
||||
password = ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||
return password
|
||||
|
||||
default_password = generate_random_password()
|
||||
smtp_password = input(f"SMTP authentication password [default: random generated]: ")
|
||||
config['smtp_auth_pass'] = smtp_password if smtp_password else default_password
|
||||
|
||||
print(f"{COLORS['GREEN']}SMTP Credentials:{COLORS['RESET']}")
|
||||
print(f" Username: {config['smtp_auth_user']}")
|
||||
print(f" Password: {config['smtp_auth_pass']}")
|
||||
print(f"{COLORS['YELLOW']}Note: These credentials will be saved in the deployment info file{COLORS['RESET']}")
|
||||
|
||||
# Security Configuration
|
||||
print(f"\n{COLORS['BLUE']}Security Configuration{COLORS['RESET']}")
|
||||
zero_logs_choice = input("Enable zero-logs configuration? (y/n) [default: y]: ").lower()
|
||||
config['zero_logs'] = zero_logs_choice != 'n' # Default to True unless explicitly 'n'
|
||||
|
||||
# Post-deployment options
|
||||
config['ssh_after_deploy'] = confirm_action("SSH into instance after deployment?", default=True)
|
||||
|
||||
return config
|
||||
|
||||
def c2_menu():
|
||||
"""Display the C2 submenu and handle user selection"""
|
||||
while True:
|
||||
clear_screen()
|
||||
print_banner()
|
||||
print(f"{COLORS['WHITE']}C2 INFRASTRUCTURE MENU{COLORS['RESET']}")
|
||||
print(f"{COLORS['WHITE']}======================={COLORS['RESET']}")
|
||||
print(f"1) C2 Server Only {COLORS['GREEN']}*QUICK*{COLORS['RESET']} {COLORS['GRAY']}(Basic setup){COLORS['RESET']}")
|
||||
print(f"2) Havoc C2 Server {COLORS['GRAY']}(Modern C2 framework){COLORS['RESET']}")
|
||||
print(f"3) Sliver Server {COLORS['GRAY']}(Go-based C2){COLORS['RESET']}")
|
||||
print(f"4) Cobalt Strike Server {COLORS['GRAY']}(Commercial C2){COLORS['RESET']}")
|
||||
print(f"5) Mythic Server {COLORS['GRAY']}(Cross-platform C2){COLORS['RESET']}")
|
||||
print(f"6) C2 + Redirector {COLORS['GRAY']}(C2 with traffic redirection){COLORS['RESET']}")
|
||||
print(f"7) Full C2 Infrastructure {COLORS['GRAY']}(Complete multi-tier setup){COLORS['RESET']}")
|
||||
print(f"99) Return to Main Menu")
|
||||
|
||||
choice = input(f"\nSelect an option: ")
|
||||
|
||||
if choice == "1":
|
||||
deploy_c2_only()
|
||||
elif choice == "2":
|
||||
deploy_havoc_c2()
|
||||
elif choice == "3":
|
||||
deploy_sliver_c2()
|
||||
elif choice == "4":
|
||||
deploy_cobaltstrike_c2()
|
||||
elif choice == "5":
|
||||
deploy_mythic_c2()
|
||||
elif choice == "6":
|
||||
deploy_c2_with_redirector()
|
||||
elif choice == "7":
|
||||
deploy_full_c2()
|
||||
elif choice == "99":
|
||||
return
|
||||
else:
|
||||
print(f"\n{COLORS['RED']}Invalid option. Please try again.{COLORS['RESET']}")
|
||||
wait_for_input()
|
||||
|
||||
def deploy_c2_only():
|
||||
"""Deploy C2 server only"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
config['deployment_type'] = 'c2_only'
|
||||
config['c2_only'] = True
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying C2 server only...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_c2_with_redirector():
|
||||
"""Deploy C2 server with redirector"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
# Additional redirector configuration
|
||||
config['redirector_subdomain'] = input("Redirector subdomain [default: cdn]: ") or "cdn"
|
||||
|
||||
config['deployment_type'] = 'c2_with_redirector'
|
||||
config['deploy_redirector'] = True
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying C2 server with redirector...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_full_c2():
|
||||
"""Deploy full C2 infrastructure"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
# Additional configuration for full deployment
|
||||
config['redirector_subdomain'] = input("Redirector subdomain [default: cdn]: ") or "cdn"
|
||||
|
||||
config['deployment_type'] = 'full_c2'
|
||||
config['deploy_redirector'] = True
|
||||
config['deploy_tracker'] = confirm_action("Deploy email tracker?", default=False)
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying full C2 infrastructure...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_havoc_c2():
|
||||
"""Deploy Havoc C2 server specifically"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
config['c2_framework'] = 'havoc'
|
||||
config['deployment_type'] = 'havoc_c2'
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying Havoc C2 server...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_cobaltstrike_c2():
|
||||
"""Deploy Cobalt Strike server specifically"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
config['c2_framework'] = 'cobaltstrike'
|
||||
config['deployment_type'] = 'cobaltstrike_c2'
|
||||
|
||||
# Cobalt Strike specific configuration
|
||||
license_path = input("Path to Cobalt Strike license file [optional]: ")
|
||||
if license_path:
|
||||
config['cobaltstrike_license'] = license_path
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying Cobalt Strike server...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_sliver_c2():
|
||||
"""Deploy Sliver C2 server specifically"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
config['c2_framework'] = 'sliver'
|
||||
config['deployment_type'] = 'sliver_c2'
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying Sliver C2 server...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def deploy_mythic_c2():
|
||||
"""Deploy Mythic C2 server specifically"""
|
||||
config = gather_c2_parameters()
|
||||
if not config:
|
||||
return
|
||||
|
||||
config['c2_framework'] = 'mythic'
|
||||
config['deployment_type'] = 'mythic_c2'
|
||||
|
||||
print(f"\n{COLORS['GREEN']}Deploying Mythic C2 server...{COLORS['RESET']}")
|
||||
execute_c2_deployment(config)
|
||||
|
||||
def execute_c2_deployment(config):
|
||||
"""Execute C2 infrastructure deployment"""
|
||||
clear_screen()
|
||||
print_banner()
|
||||
print(f"\n{COLORS['GREEN']}Starting C2 deployment...{COLORS['RESET']}")
|
||||
|
||||
# Archive old logs before starting new deployment
|
||||
print(f"Archiving old logs...")
|
||||
archive_old_logs(max_logs_to_keep=5) # Keep last 5 deployments
|
||||
|
||||
# Set up logging
|
||||
log_file = setup_logging(config['deployment_id'], "c2_deployment")
|
||||
|
||||
# Display configuration summary
|
||||
print(f"\n{COLORS['CYAN']}Deployment Summary:{COLORS['RESET']}")
|
||||
print(f"Deployment Type: {config['deployment_type']}")
|
||||
print(f"Deployment ID: {config['deployment_id']}")
|
||||
print(f"Provider: {config['provider']}")
|
||||
print(f"Domain: {config['domain']}")
|
||||
print(f"C2 Framework: {config['c2_framework']}")
|
||||
|
||||
# Confirm deployment
|
||||
if not confirm_action(f"\n{COLORS['YELLOW']}Proceed with C2 deployment?{COLORS['RESET']}", default=False):
|
||||
print(f"\n{COLORS['YELLOW']}Deployment cancelled.{COLORS['RESET']}")
|
||||
return
|
||||
|
||||
# Execute the actual deployment using the deployment engine
|
||||
from utils.deployment_engine import deploy_infrastructure
|
||||
success = deploy_infrastructure(config)
|
||||
|
||||
if success:
|
||||
print(f"\n{COLORS['GREEN']}C2 infrastructure deployed successfully!{COLORS['RESET']}")
|
||||
|
||||
if config.get('ssh_after_deploy'):
|
||||
from utils.ssh_utils import ssh_to_instance
|
||||
ssh_to_instance(config)
|
||||
else:
|
||||
print(f"\n{COLORS['RED']}C2 infrastructure deployment failed.{COLORS['RESET']}")
|
||||
|
||||
wait_for_input()
|
||||
|
||||
if __name__ == "__main__":
|
||||
c2_menu()
|
||||
@@ -0,0 +1,150 @@
|
||||
#!/bin/bash
|
||||
# secure_payload_sync.sh - OPSEC-focused payload distribution
|
||||
|
||||
# Configuration
|
||||
C2_PAYLOAD_DIR="/root/Tools/Havoc/payloads"
|
||||
REDIRECTOR_IP="{{ redirector_ip }}"
|
||||
REDIRECTOR_USER="root"
|
||||
SSH_KEY_PATH="/root/.ssh/id_ed25519"
|
||||
REMOTE_PAYLOAD_DIR="/var/www/resources"
|
||||
ENCRYPTED_TRANSFER=true
|
||||
LOG_FILE="/root/Tools/logs/payload_sync.log"
|
||||
LOG_RETENTION_DAYS=3
|
||||
MAX_RANDOM_DELAY=300 # Max random delay in seconds
|
||||
|
||||
# Create minimal timestamped log with auto-rotation
|
||||
log() {
|
||||
mkdir -p $(dirname $LOG_FILE)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> $LOG_FILE
|
||||
find $(dirname $LOG_FILE) -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
|
||||
}
|
||||
|
||||
# Add random delay for OPSEC
|
||||
sleep_random() {
|
||||
DELAY=$((RANDOM % $MAX_RANDOM_DELAY))
|
||||
log "Adding random delay of $DELAY seconds"
|
||||
sleep $DELAY
|
||||
}
|
||||
|
||||
# Generate payload manifest and check for changes
|
||||
check_for_changes() {
|
||||
if [ ! -d "$C2_PAYLOAD_DIR" ]; then
|
||||
log "ERROR: Payload directory not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
MANIFEST_FILE="$TMP_DIR/manifest"
|
||||
find $C2_PAYLOAD_DIR -type f -exec sha256sum {} \; | sort > $MANIFEST_FILE
|
||||
|
||||
CURRENT_HASH=$(sha256sum $MANIFEST_FILE | awk '{print $1}')
|
||||
HASH_FILE="/root/Tools/.payload_hash"
|
||||
|
||||
if [ -f "$HASH_FILE" ] && [ "$(cat $HASH_FILE)" == "$CURRENT_HASH" ]; then
|
||||
log "No payload changes detected"
|
||||
secure_delete $TMP_DIR
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo $CURRENT_HASH > $HASH_FILE
|
||||
return 0
|
||||
}
|
||||
|
||||
# Secure deletion of files/directories
|
||||
secure_delete() {
|
||||
if [ -d "$1" ]; then
|
||||
find "$1" -type f -exec shred -n 3 -z -u {} \; 2>/dev/null
|
||||
rm -rf "$1" 2>/dev/null
|
||||
elif [ -f "$1" ]; then
|
||||
shred -n 3 -z -u "$1" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Encrypt archive with random password
|
||||
encrypt_archive() {
|
||||
SRC="$1"
|
||||
DEST="$2"
|
||||
|
||||
# Generate random password
|
||||
PASSWORD=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32)
|
||||
PASS_FILE=$(mktemp)
|
||||
echo $PASSWORD > $PASS_FILE
|
||||
|
||||
# Encrypt the archive
|
||||
openssl enc -aes-256-cbc -salt -in "$SRC" -out "$DEST" -pass file:$PASS_FILE
|
||||
|
||||
# Store password temporarily for transfer
|
||||
echo $PASSWORD
|
||||
|
||||
# Securely delete password file
|
||||
secure_delete $PASS_FILE
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log "Starting secure payload sync"
|
||||
|
||||
# Add randomized timing
|
||||
sleep_random
|
||||
|
||||
# Check for payload changes
|
||||
check_for_changes || exit 0
|
||||
|
||||
# Generate random archive name for OPSEC
|
||||
RANDOM_ID=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c 12)
|
||||
ARCHIVE_NAME="updates_${RANDOM_ID}.tar.gz"
|
||||
ENCRYPTED_NAME="${ARCHIVE_NAME}.enc"
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
|
||||
# Create payload archive
|
||||
log "Creating payload archive"
|
||||
tar czf "$TEMP_DIR/$ARCHIVE_NAME" -C $(dirname $C2_PAYLOAD_DIR) $(basename $C2_PAYLOAD_DIR)
|
||||
|
||||
# Encrypt archive if enabled
|
||||
PASSWORD=""
|
||||
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||
log "Encrypting payload archive"
|
||||
PASSWORD=$(encrypt_archive "$TEMP_DIR/$ARCHIVE_NAME" "$TEMP_DIR/$ENCRYPTED_NAME")
|
||||
TRANSFER_FILE="$TEMP_DIR/$ENCRYPTED_NAME"
|
||||
else
|
||||
TRANSFER_FILE="$TEMP_DIR/$ARCHIVE_NAME"
|
||||
fi
|
||||
|
||||
# Transfer archive to redirector
|
||||
log "Transferring payloads to redirector"
|
||||
scp -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q "$TRANSFER_FILE" "$REDIRECTOR_USER@$REDIRECTOR_IP:/tmp/$ENCRYPTED_NAME"
|
||||
|
||||
# Handle remote extraction with decryption if needed
|
||||
if [ "$ENCRYPTED_TRANSFER" = true ]; then
|
||||
REMOTE_CMD="
|
||||
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||
TEMP_DIR=\$(mktemp -d)
|
||||
openssl enc -aes-256-cbc -d -in /tmp/$ENCRYPTED_NAME -out \$TEMP_DIR/$ARCHIVE_NAME -pass pass:\"$PASSWORD\"
|
||||
tar xzf \$TEMP_DIR/$ARCHIVE_NAME -C /var/www/
|
||||
# Clean up
|
||||
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME \$TEMP_DIR/$ARCHIVE_NAME 2>/dev/null
|
||||
rm -rf \$TEMP_DIR
|
||||
# Update web server if needed
|
||||
systemctl reload nginx 2>/dev/null
|
||||
"
|
||||
else
|
||||
REMOTE_CMD="
|
||||
mkdir -p $REMOTE_PAYLOAD_DIR
|
||||
tar xzf /tmp/$ENCRYPTED_NAME -C /var/www/
|
||||
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME 2>/dev/null
|
||||
systemctl reload nginx 2>/dev/null
|
||||
"
|
||||
fi
|
||||
|
||||
# Execute command on redirector
|
||||
ssh -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REDIRECTOR_USER@$REDIRECTOR_IP" "$REMOTE_CMD"
|
||||
|
||||
# Clean up local temp files
|
||||
log "Cleaning up temporary files"
|
||||
secure_delete $TEMP_DIR
|
||||
|
||||
log "Payload sync completed successfully"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
@@ -110,15 +110,15 @@
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- "../files/clean-logs.sh"
|
||||
- "../files/secure-exit.sh"
|
||||
- "../../../common/files/clean-logs.sh"
|
||||
- "../../../common/files/secure-exit.sh"
|
||||
- "../files/havoc_installer.sh"
|
||||
- "../files/havoc_shell_handler.sh"
|
||||
- "../files/secure_payload_sync.sh"
|
||||
|
||||
- name: Copy post-install script
|
||||
copy:
|
||||
src: "../files/post_install_c2.sh"
|
||||
src: "../../../common/files/post_install_c2.sh"
|
||||
dest: "/root/Tools/post_install_c2.sh"
|
||||
mode: '0700'
|
||||
owner: root
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
- name: Copy port randomization script
|
||||
copy:
|
||||
src: "../files/randomize_ports.sh"
|
||||
src: "../../../common/files/randomize_ports.sh"
|
||||
dest: "/root/Tools/randomize_ports.sh"
|
||||
mode: '0700'
|
||||
owner: root
|
||||
@@ -271,7 +271,7 @@
|
||||
|
||||
- name: Create NGINX configuration fragment for redirector
|
||||
template:
|
||||
src: "../templates/redirector-havoc-fragment.j2"
|
||||
src: "../../redirectors/templates/redirector-havoc-fragment.j2"
|
||||
dest: "/root/Tools/redirector-config.conf"
|
||||
mode: '0644'
|
||||
owner: root
|
||||
@@ -300,7 +300,7 @@
|
||||
minute: "0"
|
||||
hour: "*/6"
|
||||
job: "/root/Tools/clean-logs.sh > /dev/null 2>&1"
|
||||
when: zero_logs | bool
|
||||
when: zero_logs is defined and zero_logs | bool
|
||||
|
||||
- name: Ensure SSH key for redirector access is available
|
||||
block:
|
||||
|
||||
Reference in New Issue
Block a user