working out bugs
This commit is contained in:
@@ -433,6 +433,18 @@
|
|||||||
state: absent
|
state: absent
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: infra_file
|
register: infra_file
|
||||||
|
|
||||||
|
- name: Clean up deployment state file
|
||||||
|
file:
|
||||||
|
path: "{{ playbook_dir }}/../deployment_state_{{ deployment_id }}.json"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
register: state_file_deletion
|
||||||
|
|
||||||
|
- name: Report state file cleanup
|
||||||
|
debug:
|
||||||
|
msg: "Deployment state file {{ 'deleted' if state_file_deletion.changed else 'not found' }}"
|
||||||
|
when: state_file_deletion is defined
|
||||||
|
|
||||||
# STEP 16: Enhanced and Accurate Cleanup Summary
|
# STEP 16: Enhanced and Accurate Cleanup Summary
|
||||||
- name: Enhanced cleanup summary
|
- name: Enhanced cleanup summary
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
+12
@@ -73,6 +73,18 @@
|
|||||||
when: cleanup_tracker and tracker_name is defined and tracker_name != ""
|
when: cleanup_tracker and tracker_name is defined and tracker_name != ""
|
||||||
register: tracker_deletion
|
register: tracker_deletion
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Clean up deployment state file
|
||||||
|
file:
|
||||||
|
path: "{{ playbook_dir }}/../deployment_state_{{ deployment_id }}.json"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
register: state_file_deletion
|
||||||
|
|
||||||
|
- name: Report state file cleanup
|
||||||
|
debug:
|
||||||
|
msg: "Deployment state file {{ 'deleted' if state_file_deletion.changed else 'not found' }}"
|
||||||
|
when: state_file_deletion is defined
|
||||||
|
|
||||||
- name: Report cleanup status
|
- name: Report cleanup status
|
||||||
debug:
|
debug:
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
+8
-2
@@ -1,8 +1,14 @@
|
|||||||
[defaults]
|
[defaults]
|
||||||
host_key_checking = False
|
host_key_checking = False
|
||||||
timeout = 30
|
timeout = 30
|
||||||
|
retry_files_enabled = False
|
||||||
|
gathering = smart
|
||||||
|
fact_caching = memory
|
||||||
|
stdout_callback = default
|
||||||
|
bin_ansible_callbacks = True
|
||||||
|
nocows = 1
|
||||||
|
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=30 -o ServerAliveCountMax=10
|
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes
|
||||||
pipelining = True
|
pipelining = True
|
||||||
retries = 5
|
control_path = ~/.ansible/cp/%%h-%%p-%%r
|
||||||
|
|||||||
@@ -101,14 +101,16 @@ def main_menu():
|
|||||||
print(f"3) Deploy C2 Server")
|
print(f"3) Deploy C2 Server")
|
||||||
print(f"4) Deploy Redirector")
|
print(f"4) Deploy Redirector")
|
||||||
print(f"5) Deploy Email Tracking Server")
|
print(f"5) Deploy Email Tracking Server")
|
||||||
print(f"6) Deploy Payload Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
print(f"6) Deploy Advanced Phishing Infrastructure")
|
||||||
print(f"7) Deploy Phishing Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
print(f"7) Deploy Ephemeral MTA Front-End")
|
||||||
print(f"8) Deploy Logging Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
print(f"8) Deploy Payload Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
print(f"9) Deploy Share-Drive {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
print(f"9) Deploy Phishing Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
print(f"10) Deploy Hashtopolis {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
print(f"10) Deploy Logging Server {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
print(f"11) Custom Deployment")
|
print(f"11) Deploy Share-Drive {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
print(f"12) Tools")
|
print(f"12) Deploy Hashtopolis {COLORS['GRAY']}*UNDER-CONSTRUCTION*{COLORS['RESET']}")
|
||||||
print(f"13) Debug Mode: {COLORS['GREEN'] if debug_mode else COLORS['RED']}{debug_mode}{COLORS['RESET']}")
|
print(f"13) Custom Deployment")
|
||||||
|
print(f"14) Tools")
|
||||||
|
print(f"15) Debug Mode: {COLORS['GREEN'] if debug_mode else COLORS['RED']}{debug_mode}{COLORS['RESET']}")
|
||||||
print(f"\n")
|
print(f"\n")
|
||||||
print(f"99) Exit")
|
print(f"99) Exit")
|
||||||
|
|
||||||
@@ -124,7 +126,11 @@ def main_menu():
|
|||||||
redirector_menu()
|
redirector_menu()
|
||||||
elif choice == "5":
|
elif choice == "5":
|
||||||
deploy_tracker()
|
deploy_tracker()
|
||||||
elif choice in ["6", "7", "8", "9", "10"]:
|
elif choice == "6":
|
||||||
|
deploy_ephemeral_mta()
|
||||||
|
elif choice == "7":
|
||||||
|
deploy_advanced_phishing_infrastructure()
|
||||||
|
elif choice in ["8", "9", "10", "11", "12"]:
|
||||||
print(f"\n{COLORS['YELLOW']}This feature is currently under construction.{COLORS['RESET']}")
|
print(f"\n{COLORS['YELLOW']}This feature is currently under construction.{COLORS['RESET']}")
|
||||||
input("\nPress Enter to continue...")
|
input("\nPress Enter to continue...")
|
||||||
elif choice == "11":
|
elif choice == "11":
|
||||||
@@ -209,6 +215,7 @@ def deploy_full_c2():
|
|||||||
config['c2_only'] = False
|
config['c2_only'] = False
|
||||||
config['deploy_tracker'] = True
|
config['deploy_tracker'] = True
|
||||||
config['integrated_tracker'] = False
|
config['integrated_tracker'] = False
|
||||||
|
config['deploy_ephemeral_mta'] = True
|
||||||
|
|
||||||
# Deployment ID will be generated in execute_deployment
|
# Deployment ID will be generated in execute_deployment
|
||||||
execute_deployment(config)
|
execute_deployment(config)
|
||||||
@@ -227,6 +234,28 @@ def deploy_basic_c2():
|
|||||||
# Deployment ID will be generated in execute_deployment
|
# Deployment ID will be generated in execute_deployment
|
||||||
execute_deployment(config)
|
execute_deployment(config)
|
||||||
|
|
||||||
|
def deploy_ephemeral_mta():
|
||||||
|
"""Deploy Ephemeral MTA for phishing campaigns with high OPSEC"""
|
||||||
|
config = gather_ephemeral_mta_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add ephemeral MTA flag
|
||||||
|
config['ephemeral_mta'] = True
|
||||||
|
execute_deployment(config)
|
||||||
|
|
||||||
|
def deploy_advanced_phishing_infrastructure():
|
||||||
|
"""Deploy full phishing infrastructure with Ephemeral MTA + GoPhish + C2 integration"""
|
||||||
|
|
||||||
|
config = gather_advanced_phishing_parameters()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add both flags
|
||||||
|
config['advanced_phishing'] = True
|
||||||
|
config['ephemeral_mta'] = True
|
||||||
|
execute_deployment(config)
|
||||||
|
|
||||||
def deploy_c2_server():
|
def deploy_c2_server():
|
||||||
"""Deploy only the C2 server"""
|
"""Deploy only the C2 server"""
|
||||||
config = gather_common_parameters()
|
config = gather_common_parameters()
|
||||||
@@ -382,6 +411,118 @@ def gather_common_parameters():
|
|||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
def gather_ephemeral_mta_parameters():
|
||||||
|
"""Gather parameters needed for ephemeral MTA deployment"""
|
||||||
|
config = gather_common_parameters()
|
||||||
|
if not config:
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"\n{COLORS['BLUE']}Ephemeral MTA Configuration{COLORS['RESET']}")
|
||||||
|
print(f"\n{COLORS['YELLOW']}IMPORTANT OPSEC NOTES:{COLORS['RESET']}")
|
||||||
|
print(f"- Use completely separate domains for phishing campaigns")
|
||||||
|
print(f"- Never use your operational domains for phishing")
|
||||||
|
print(f"- Use generic, innocuous domain names that blend with business traffic")
|
||||||
|
print(f"- Campaign IDs should look natural, not like 'wave42'")
|
||||||
|
|
||||||
|
# Use separate domains for phishing campaigns
|
||||||
|
phish_domain = input(f"\nEnter phishing domain (separate from C2 domain): ")
|
||||||
|
if not phish_domain:
|
||||||
|
print(f"{COLORS['RED']}A separate phishing domain is required for proper OPSEC.{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['phish_domain'] = phish_domain
|
||||||
|
|
||||||
|
# Generate a campaign ID that looks natural
|
||||||
|
default_campaign_id = f"mail{generate_random_string(4).lower()}"
|
||||||
|
campaign_id = input(f"Enter campaign identifier [default: {default_campaign_id}]: ") or default_campaign_id
|
||||||
|
config['campaign_id'] = campaign_id
|
||||||
|
|
||||||
|
# Email for Let's Encrypt
|
||||||
|
default_email = f"admin@{phish_domain}"
|
||||||
|
email = input(f"Enter email for Let's Encrypt [default: {default_email}]: ") or default_email
|
||||||
|
config['letsencrypt_email'] = email
|
||||||
|
|
||||||
|
# C2 connection method
|
||||||
|
print(f"\n{COLORS['BLUE']}C2 Connection Configuration{COLORS['RESET']}")
|
||||||
|
print(f"1) SSH Tunnel (recommended)")
|
||||||
|
print(f"2) Direct connection (less secure)")
|
||||||
|
connection_type = input(f"Select connection method [default: 1]: ") or "1"
|
||||||
|
|
||||||
|
if connection_type == "1":
|
||||||
|
config['use_ssh_tunnel'] = True
|
||||||
|
|
||||||
|
# Get SSH key for C2 access
|
||||||
|
if 'deployment_id' in config:
|
||||||
|
default_key_path = f"~/.ssh/c2deploy_{config['deployment_id']}.pem"
|
||||||
|
else:
|
||||||
|
default_key_path = "~/.ssh/id_rsa"
|
||||||
|
|
||||||
|
ssh_key_path = input(f"Enter SSH key path for C2 access [default: {default_key_path}]: ") or default_key_path
|
||||||
|
config['c2_ssh_key_path'] = os.path.expanduser(ssh_key_path)
|
||||||
|
else:
|
||||||
|
config['use_ssh_tunnel'] = False
|
||||||
|
|
||||||
|
# C2 server info for mail delivery - over private tunnel, not public DNS
|
||||||
|
c2_ip = input(f"Enter C2 server IP for mail delivery: ")
|
||||||
|
if not c2_ip:
|
||||||
|
print(f"{COLORS['RED']}C2 server IP is required for mail delivery.{COLORS['RESET']}")
|
||||||
|
return None
|
||||||
|
config['static_mailstore_ip'] = c2_ip
|
||||||
|
|
||||||
|
# DKIM settings
|
||||||
|
print(f"\n{COLORS['BLUE']}DKIM Configuration{COLORS['RESET']}")
|
||||||
|
use_dkim = input(f"Configure DKIM for better deliverability? (y/n) [default: y]: ").lower() != 'n'
|
||||||
|
config['use_dkim'] = use_dkim
|
||||||
|
|
||||||
|
# Number of MTAs to deploy (for rotation)
|
||||||
|
num_mtas = input(f"\nNumber of MTAs to deploy (for IP rotation) [default: 1]: ") or "1"
|
||||||
|
try:
|
||||||
|
config['num_mtas'] = int(num_mtas)
|
||||||
|
except ValueError:
|
||||||
|
config['num_mtas'] = 1
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def gather_advanced_phishing_parameters():
|
||||||
|
"""Collect parameters for advanced phishing infrastructure"""
|
||||||
|
|
||||||
|
# Start with ephemeral MTA parameters
|
||||||
|
config = gather_ephemeral_mta_parameters()
|
||||||
|
if not config:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Add GoPhish configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}GoPhish Configuration{COLORS['RESET']}")
|
||||||
|
|
||||||
|
# SMTP authentication details
|
||||||
|
default_smtp_user = f"mail{generate_random_string(4)}"
|
||||||
|
smtp_user = input(f"Enter SMTP auth username [default: {default_smtp_user}]: ") or default_smtp_user
|
||||||
|
config['smtp_auth_user'] = smtp_user
|
||||||
|
|
||||||
|
smtp_pass = input(f"Enter SMTP auth password [default: random]: ")
|
||||||
|
if not smtp_pass:
|
||||||
|
smtp_pass = generate_random_string(16)
|
||||||
|
print(f"Generated SMTP password: {smtp_pass}")
|
||||||
|
config['smtp_auth_pass'] = smtp_pass
|
||||||
|
|
||||||
|
# GoPhish admin port
|
||||||
|
default_gophish_port = str(random.randint(2000, 6000))
|
||||||
|
gophish_port = input(f"Enter GoPhish admin port [default: {default_gophish_port}]: ") or default_gophish_port
|
||||||
|
config['gophish_admin_port'] = gophish_port
|
||||||
|
|
||||||
|
# Landing page configuration
|
||||||
|
print(f"\n{COLORS['BLUE']}Landing Page Configuration{COLORS['RESET']}")
|
||||||
|
use_landing_page = input(f"Configure phishing landing page? (y/n) [default: y]: ").lower() != 'n'
|
||||||
|
config['use_landing_page'] = use_landing_page
|
||||||
|
|
||||||
|
if use_landing_page:
|
||||||
|
landing_domain = input(f"Enter landing page domain (separate from phish domain): ")
|
||||||
|
if landing_domain:
|
||||||
|
config['landing_domain'] = landing_domain
|
||||||
|
else:
|
||||||
|
print(f"{COLORS['YELLOW']}Will use redirector domain for landing pages.{COLORS['RESET']}")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
def get_aws_credentials(provider_vars):
|
def get_aws_credentials(provider_vars):
|
||||||
"""Get AWS credentials from user or vars file"""
|
"""Get AWS credentials from user or vars file"""
|
||||||
default_aws_key = provider_vars.get('aws_access_key', '')
|
default_aws_key = provider_vars.get('aws_access_key', '')
|
||||||
@@ -2001,6 +2142,11 @@ def teardown_infrastructure(config):
|
|||||||
elif vars_data.get('aws_secret_key'):
|
elif vars_data.get('aws_secret_key'):
|
||||||
os.environ['AWS_SECRET_ACCESS_KEY'] = vars_data['aws_secret_key']
|
os.environ['AWS_SECRET_ACCESS_KEY'] = vars_data['aws_secret_key']
|
||||||
config['aws_secret_key'] = vars_data['aws_secret_key']
|
config['aws_secret_key'] = vars_data['aws_secret_key']
|
||||||
|
elif provider == "linode":
|
||||||
|
# Explicitly load Linode token from vars.yaml if not already in config
|
||||||
|
if not config.get('linode_token') and vars_data.get('linode_token'):
|
||||||
|
config['linode_token'] = vars_data['linode_token']
|
||||||
|
logging.info("Loaded Linode token from vars.yaml for cleanup")
|
||||||
|
|
||||||
# Set default resource names based on deployment ID
|
# Set default resource names based on deployment ID
|
||||||
config['redirector_name'] = f"r-{deployment_id}"
|
config['redirector_name'] = f"r-{deployment_id}"
|
||||||
@@ -2289,10 +2435,10 @@ def generate_deployment_info(config, success=True):
|
|||||||
|
|
||||||
# Add correct SSH commands for each server type
|
# Add correct SSH commands for each server type
|
||||||
if not config.get('redirector_only'):
|
if not config.get('redirector_only'):
|
||||||
info.append(f"SSH Command for C2: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} ubuntu@{config.get('c2_ip', 'N/A')}")
|
info.append(f"SSH Command for C2: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} {ssh_user}@{config.get('c2_ip', 'N/A')}")
|
||||||
|
|
||||||
if not config.get('c2_only'):
|
if not config.get('c2_only'):
|
||||||
info.append(f"SSH Command for Redirector: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} {ssh_user}@{config.get('redirector_ip', 'N/A')}")
|
info.append(f"SSH Command for Redirector: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} ubuntu@{config.get('redirector_ip', 'N/A')}")
|
||||||
|
|
||||||
if config.get('deploy_tracker') and not config.get('integrated_tracker'):
|
if config.get('deploy_tracker') and not config.get('integrated_tracker'):
|
||||||
info.append(f"SSH Command for Tracker: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} {ssh_user}@{config.get('tracker_ip', 'N/A')}")
|
info.append(f"SSH Command for Tracker: ssh -t -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' -o 'IdentitiesOnly=yes' -i {ssh_key} {ssh_user}@{config.get('tracker_ip', 'N/A')}")
|
||||||
|
|||||||
+2
-1
@@ -4,4 +4,5 @@ boto3
|
|||||||
botocore
|
botocore
|
||||||
awscli
|
awscli
|
||||||
passlib
|
passlib
|
||||||
paramiko
|
paramiko
|
||||||
|
linode-cli
|
||||||
+215
-10
@@ -10,21 +10,226 @@
|
|||||||
group: root
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
|
|
||||||
- name: Install required packages for redirector
|
- name: Update package cache with retries
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 0
|
||||||
|
register: cache_update
|
||||||
|
until: cache_update is success
|
||||||
|
retries: 5
|
||||||
|
delay: 10
|
||||||
|
ignore_errors: no
|
||||||
|
|
||||||
|
- name: Install core packages first (high priority)
|
||||||
apt:
|
apt:
|
||||||
name:
|
name:
|
||||||
- nginx
|
- nginx
|
||||||
- certbot
|
|
||||||
- python3-certbot-nginx
|
|
||||||
- socat
|
|
||||||
- netcat-openbsd
|
|
||||||
- secure-delete
|
|
||||||
- jq
|
|
||||||
- php-fpm
|
|
||||||
- net-tools
|
|
||||||
- nginx-extras
|
- nginx-extras
|
||||||
|
- socat
|
||||||
|
- jq
|
||||||
|
- secure-delete
|
||||||
state: present
|
state: present
|
||||||
update_cache: yes
|
update_cache: no
|
||||||
|
register: core_packages
|
||||||
|
until: core_packages is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Install network utilities with fallbacks
|
||||||
|
block:
|
||||||
|
- name: Try to install net-tools
|
||||||
|
apt:
|
||||||
|
name: net-tools
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: net_tools_install
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Install alternative network utilities
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- iproute2
|
||||||
|
- iputils-ping
|
||||||
|
- netcat-openbsd
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: alt_network_tools
|
||||||
|
|
||||||
|
- name: Create net-tools compatibility aliases
|
||||||
|
copy:
|
||||||
|
dest: /usr/local/bin/netstat
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
# Compatibility wrapper for netstat using ss
|
||||||
|
ss "$@"
|
||||||
|
mode: '0755'
|
||||||
|
when: alt_network_tools is success
|
||||||
|
|
||||||
|
- name: Install PHP-FPM with version handling
|
||||||
|
block:
|
||||||
|
- name: Install PHP-FPM (latest available)
|
||||||
|
apt:
|
||||||
|
name: php-fpm
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: php_install
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Install specific PHP version as fallback
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- php7.4-fpm
|
||||||
|
- php7.4-cli
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: php_fallback
|
||||||
|
|
||||||
|
- name: Install certbot with dependency handling
|
||||||
|
block:
|
||||||
|
- name: Install certbot and nginx plugin
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- certbot
|
||||||
|
- python3-certbot-nginx
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: certbot_install
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Install certbot without problematic dependencies
|
||||||
|
shell: |
|
||||||
|
apt-get install -y --no-install-recommends certbot
|
||||||
|
apt-get install -y --fix-broken || true
|
||||||
|
register: certbot_manual
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Install certbot via snap as ultimate fallback
|
||||||
|
block:
|
||||||
|
- name: Install snap if not present
|
||||||
|
apt:
|
||||||
|
name: snapd
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Install certbot via snap
|
||||||
|
snap:
|
||||||
|
name: certbot
|
||||||
|
classic: yes
|
||||||
|
|
||||||
|
- name: Create certbot symlink
|
||||||
|
file:
|
||||||
|
src: /snap/bin/certbot
|
||||||
|
dest: /usr/bin/certbot
|
||||||
|
state: link
|
||||||
|
when: certbot_manual is failed
|
||||||
|
|
||||||
|
- name: Handle problematic Python dependencies
|
||||||
|
block:
|
||||||
|
- name: Try installing Python dependencies normally
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- python3-requests-toolbelt
|
||||||
|
- python3-zope.hookable
|
||||||
|
state: present
|
||||||
|
update_cache: no
|
||||||
|
register: python_deps
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Install Python dependencies via pip as fallback
|
||||||
|
pip:
|
||||||
|
name:
|
||||||
|
- requests-toolbelt
|
||||||
|
- zope.hookable
|
||||||
|
state: present
|
||||||
|
register: pip_install
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Download and install packages manually if repositories are down
|
||||||
|
shell: |
|
||||||
|
cd /tmp
|
||||||
|
# Try alternative repositories
|
||||||
|
wget -q http://archive.ubuntu.com/ubuntu/pool/universe/p/python-requests-toolbelt/python3-requests-toolbelt_0.8.0-1.1_all.deb || \
|
||||||
|
wget -q http://launchpad.net/ubuntu/+archive/primary/+files/python3-requests-toolbelt_0.8.0-1.1_all.deb || true
|
||||||
|
|
||||||
|
if [ -f python3-requests-toolbelt_*.deb ]; then
|
||||||
|
dpkg -i python3-requests-toolbelt_*.deb || apt-get install -f -y
|
||||||
|
fi
|
||||||
|
when: pip_install is failed
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Verify critical packages are installed
|
||||||
|
command: "{{ item.cmd }}"
|
||||||
|
register: package_verify
|
||||||
|
failed_when: package_verify.rc != 0
|
||||||
|
loop:
|
||||||
|
- { cmd: "nginx -v", name: "nginx" }
|
||||||
|
- { cmd: "socat -V", name: "socat" }
|
||||||
|
- { cmd: "jq --version", name: "jq" }
|
||||||
|
- { cmd: "which certbot", name: "certbot" }
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Create package installation report
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
C2ingRed Package Installation Status:
|
||||||
|
===================================
|
||||||
|
Core Packages: {{ 'SUCCESS' if core_packages is success else 'FAILED' }}
|
||||||
|
Network Tools: {{ 'SUCCESS' if net_tools_install is success else 'FALLBACK USED' }}
|
||||||
|
PHP-FPM: {{ 'SUCCESS' if php_install is success else 'FALLBACK USED' if php_fallback is success else 'FAILED' }}
|
||||||
|
Certbot: {{ 'SUCCESS' if certbot_install is success else 'FALLBACK USED' }}
|
||||||
|
Python Deps: {{ 'SUCCESS' if python_deps is success else 'FALLBACK ATTEMPTED' }}
|
||||||
|
|
||||||
|
Critical Services Verified:
|
||||||
|
{% for item in package_verify.results %}
|
||||||
|
- {{ item.item.name }}: {{ 'OK' if item.rc == 0 else 'MISSING' }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
- name: Force fix broken packages if any installation failed
|
||||||
|
shell: |
|
||||||
|
apt-get update --fix-missing
|
||||||
|
apt-get install -f -y
|
||||||
|
dpkg --configure -a
|
||||||
|
when: core_packages is failed or certbot_install is failed
|
||||||
|
register: fix_broken
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Final package status check and remediation
|
||||||
|
block:
|
||||||
|
- name: Check for any remaining broken packages
|
||||||
|
shell: apt-get check
|
||||||
|
register: apt_check
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: List installed packages for verification
|
||||||
|
shell: |
|
||||||
|
echo "=== INSTALLED PACKAGES ==="
|
||||||
|
dpkg -l | grep -E "(nginx|certbot|socat|jq|php)" || echo "Some packages missing"
|
||||||
|
echo "=== BROKEN PACKAGES ==="
|
||||||
|
apt-get check 2>&1 | grep -i "broken\|error" || echo "No broken packages detected"
|
||||||
|
register: final_status
|
||||||
|
|
||||||
|
- name: Display final installation status
|
||||||
|
debug:
|
||||||
|
var: final_status.stdout_lines
|
||||||
|
|
||||||
|
- name: Ensure critical services are enabled
|
||||||
|
systemd:
|
||||||
|
name: "{{ item }}"
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
loop:
|
||||||
|
- nginx
|
||||||
|
- php7.4-fpm
|
||||||
|
ignore_errors: yes
|
||||||
|
register: service_start
|
||||||
|
|
||||||
|
- name: Create operational readiness marker
|
||||||
|
copy:
|
||||||
|
dest: /tmp/c2ingred_packages_ready
|
||||||
|
content: |
|
||||||
|
C2ingRed Package Installation Complete
|
||||||
|
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||||
|
Status: {{ 'READY' if core_packages is success else 'PARTIAL' }}
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
- name: Create directories for operational scripts
|
- name: Create directories for operational scripts
|
||||||
file:
|
file:
|
||||||
|
|||||||
+186
-77
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
# Security hardening tasks for C2 server
|
# Security hardening tasks for C2 server - Fixed AWS collection issues
|
||||||
|
|
||||||
- name: Check if system is updated
|
- name: Check if system is updated
|
||||||
apt:
|
apt:
|
||||||
@@ -24,34 +24,38 @@
|
|||||||
retries: 3
|
retries: 3
|
||||||
delay: 5
|
delay: 5
|
||||||
|
|
||||||
# Skip UFW for AWS, use it for other providers
|
# Provider and role detection - DRY principle
|
||||||
- name: Determine if using AWS provider
|
- name: Determine deployment configuration
|
||||||
set_fact:
|
set_fact:
|
||||||
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
||||||
|
is_c2_server: "{{ 'c2servers' in group_names }}"
|
||||||
|
is_redirector: "{{ 'redirectors' in group_names }}"
|
||||||
|
|
||||||
# Only install and configure UFW for non-AWS providers
|
# UFW Configuration Block - Non-AWS only
|
||||||
- name: Check if UFW is installed
|
- name: UFW detection and installation block
|
||||||
command: which ufw
|
block:
|
||||||
register: ufw_check
|
- name: Check if UFW is installed
|
||||||
failed_when: false
|
command: which ufw
|
||||||
changed_when: false
|
register: ufw_check
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Install UFW if not present (non-AWS)
|
||||||
|
apt:
|
||||||
|
name: ufw
|
||||||
|
state: present
|
||||||
|
update_cache: yes
|
||||||
|
register: ufw_install
|
||||||
|
until: ufw_install is success
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
when: ufw_check.rc != 0
|
||||||
when: not is_aws_provider
|
when: not is_aws_provider
|
||||||
|
|
||||||
- name: Install UFW if not present (non-AWS)
|
|
||||||
apt:
|
|
||||||
name: ufw
|
|
||||||
state: present
|
|
||||||
update_cache: yes
|
|
||||||
register: ufw_install
|
|
||||||
until: ufw_install is success
|
|
||||||
retries: 3
|
|
||||||
delay: 5
|
|
||||||
when: not is_aws_provider and ufw_check.rc != 0
|
|
||||||
|
|
||||||
- name: Configure UFW for non-AWS deployments
|
- name: Configure UFW for non-AWS deployments
|
||||||
block:
|
block:
|
||||||
- name: Configure UFW default policies
|
- name: Configure UFW default policies
|
||||||
ufw:
|
community.general.ufw:
|
||||||
state: enabled
|
state: enabled
|
||||||
policy: deny
|
policy: deny
|
||||||
direction: incoming
|
direction: incoming
|
||||||
@@ -60,27 +64,27 @@
|
|||||||
- name: Configure UFW for C2 server
|
- name: Configure UFW for C2 server
|
||||||
block:
|
block:
|
||||||
- name: Reset UFW to default deny
|
- name: Reset UFW to default deny
|
||||||
ufw:
|
community.general.ufw:
|
||||||
state: enabled
|
state: enabled
|
||||||
policy: deny
|
policy: deny
|
||||||
direction: incoming
|
direction: incoming
|
||||||
|
|
||||||
- name: Allow SSH only from operator IP
|
- name: Allow SSH only from operator IP
|
||||||
ufw:
|
community.general.ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
port: "22"
|
port: "22"
|
||||||
src: "{{ operator_ip }}"
|
src: "{{ operator_ip }}"
|
||||||
proto: tcp
|
proto: tcp
|
||||||
|
|
||||||
- name: Allow Havoc Teamserver only from operator IP
|
- name: Allow Havoc Teamserver only from operator IP
|
||||||
ufw:
|
community.general.ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
port: "{{ havoc_teamserver_port | default('40056') }}"
|
port: "{{ havoc_teamserver_port | default('40056') }}"
|
||||||
src: "{{ operator_ip }}"
|
src: "{{ operator_ip }}"
|
||||||
proto: tcp
|
proto: tcp
|
||||||
|
|
||||||
- name: Allow traffic only from redirector
|
- name: Allow traffic only from redirector
|
||||||
ufw:
|
community.general.ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
port: "{{ item }}"
|
port: "{{ item }}"
|
||||||
src: "{{ redirector_ip }}"
|
src: "{{ redirector_ip }}"
|
||||||
@@ -89,30 +93,30 @@
|
|||||||
- "80"
|
- "80"
|
||||||
- "443"
|
- "443"
|
||||||
- "{{ havoc_http_port | default('8080') }}"
|
- "{{ havoc_http_port | default('8080') }}"
|
||||||
- "{{ havoc_https_port | default('9443') }}" # Updated from 443
|
- "{{ havoc_https_port | default('9443') }}"
|
||||||
- "{{ havoc_payload_port | default('8443') }}"
|
- "{{ havoc_payload_port | default('8443') }}"
|
||||||
- "{{ gophish_admin_port }}"
|
- "{{ gophish_admin_port }}"
|
||||||
- "{{ gophish_phish_port | default('8081') }}"
|
- "{{ gophish_phish_port | default('8081') }}"
|
||||||
- "{{ tracker_port | default('5000') }}"
|
- "{{ tracker_port | default('5000') }}"
|
||||||
when: "'c2servers' in group_names"
|
when: is_c2_server
|
||||||
|
|
||||||
- name: Configure UFW for redirector
|
- name: Configure UFW for redirector
|
||||||
block:
|
block:
|
||||||
- name: Reset UFW to default deny
|
- name: Reset UFW to default deny
|
||||||
ufw:
|
community.general.ufw:
|
||||||
state: enabled
|
state: enabled
|
||||||
policy: deny
|
policy: deny
|
||||||
direction: incoming
|
direction: incoming
|
||||||
|
|
||||||
- name: Allow SSH only from operator IP
|
- name: Allow SSH only from operator IP
|
||||||
ufw:
|
community.general.ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
port: "22"
|
port: "22"
|
||||||
src: "{{ operator_ip }}"
|
src: "{{ operator_ip }}"
|
||||||
proto: tcp
|
proto: tcp
|
||||||
|
|
||||||
- name: Allow public services from anywhere
|
- name: Allow public services from anywhere
|
||||||
ufw:
|
community.general.ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
port: "{{ item }}"
|
port: "{{ item }}"
|
||||||
proto: tcp
|
proto: tcp
|
||||||
@@ -120,11 +124,10 @@
|
|||||||
- "80"
|
- "80"
|
||||||
- "443"
|
- "443"
|
||||||
- "{{ shell_handler_port | default('4488') }}"
|
- "{{ shell_handler_port | default('4488') }}"
|
||||||
when: "'redirectors' in group_names"
|
when: is_redirector
|
||||||
# Only run UFW block if not AWS and UFW is available/installed
|
|
||||||
when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)
|
when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)
|
||||||
|
|
||||||
# Configure iptables fallback if UFW isn't available (non-AWS only)
|
# Iptables fallback configuration - Non-AWS only
|
||||||
- name: Configure basic iptables rules if UFW unavailable
|
- name: Configure basic iptables rules if UFW unavailable
|
||||||
block:
|
block:
|
||||||
- name: Set up basic iptables rules for C2 server
|
- name: Set up basic iptables rules for C2 server
|
||||||
@@ -135,6 +138,8 @@
|
|||||||
iptables -P OUTPUT ACCEPT
|
iptables -P OUTPUT ACCEPT
|
||||||
# Allow established connections
|
# Allow established connections
|
||||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow loopback
|
||||||
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
# Allow SSH from operator
|
# Allow SSH from operator
|
||||||
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
# Allow Havoc teamserver from operator
|
# Allow Havoc teamserver from operator
|
||||||
@@ -143,18 +148,45 @@
|
|||||||
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
||||||
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
||||||
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(443) }} -s {{ redirector_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ havoc_payload_port | default(8443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
when: "'c2servers' in group_names"
|
iptables -A INPUT -p tcp --dport {{ gophish_phish_port | default(8081) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ tracker_port | default(5000) }} -s {{ redirector_ip }} -j ACCEPT
|
||||||
|
when: is_c2_server
|
||||||
|
|
||||||
|
- name: Set up basic iptables rules for redirector
|
||||||
|
shell: |
|
||||||
|
iptables -F
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P OUTPUT ACCEPT
|
||||||
|
# Allow established connections
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
# Allow loopback
|
||||||
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
|
# Allow SSH from operator
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||||
|
# Allow public services
|
||||||
|
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport {{ shell_handler_port | default(4488) }} -j ACCEPT
|
||||||
|
when: is_redirector
|
||||||
|
|
||||||
|
- name: Save iptables rules
|
||||||
|
shell: |
|
||||||
|
iptables-save > /etc/iptables/rules.v4
|
||||||
|
ignore_errors: yes
|
||||||
when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))
|
when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))
|
||||||
|
|
||||||
# SSH Hardening - applies to all providers
|
# SSH Hardening - Universal application
|
||||||
- name: Harden SSH configuration
|
- name: Harden SSH configuration
|
||||||
lineinfile:
|
lineinfile:
|
||||||
path: /etc/ssh/sshd_config
|
path: /etc/ssh/sshd_config
|
||||||
regexp: "{{ item.regexp }}"
|
regexp: "{{ item.regexp }}"
|
||||||
line: "{{ item.line }}"
|
line: "{{ item.line }}"
|
||||||
state: present
|
state: present
|
||||||
|
backup: yes
|
||||||
loop:
|
loop:
|
||||||
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
|
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
|
||||||
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
|
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
|
||||||
@@ -163,10 +195,14 @@
|
|||||||
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
|
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
|
||||||
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
|
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
|
||||||
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
|
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
|
||||||
|
- { regexp: '^#?Protocol', line: 'Protocol 2' }
|
||||||
|
- { regexp: '^#?MaxStartups', line: 'MaxStartups 10:30:100' }
|
||||||
|
- { regexp: '^#?LoginGraceTime', line: 'LoginGraceTime 60' }
|
||||||
register: ssh_config_updated
|
register: ssh_config_updated
|
||||||
|
|
||||||
|
# System resource limits configuration
|
||||||
- name: Configure system resource limits
|
- name: Configure system resource limits
|
||||||
pam_limits:
|
community.general.pam_limits:
|
||||||
domain: "*"
|
domain: "*"
|
||||||
limit_type: "{{ item.limit_type }}"
|
limit_type: "{{ item.limit_type }}"
|
||||||
limit_item: "{{ item.limit_item }}"
|
limit_item: "{{ item.limit_item }}"
|
||||||
@@ -177,7 +213,7 @@
|
|||||||
- { limit_type: soft, limit_item: nproc, value: 4096 }
|
- { limit_type: soft, limit_item: nproc, value: 4096 }
|
||||||
- { limit_type: hard, limit_item: nproc, value: 4096 }
|
- { limit_type: hard, limit_item: nproc, value: 4096 }
|
||||||
|
|
||||||
# Set up fail2ban - applies to all providers
|
# Fail2ban configuration - Universal
|
||||||
- name: Set up fail2ban SSH jail
|
- name: Set up fail2ban SSH jail
|
||||||
copy:
|
copy:
|
||||||
dest: /etc/fail2ban/jail.d/sshd.conf
|
dest: /etc/fail2ban/jail.d/sshd.conf
|
||||||
@@ -189,9 +225,19 @@
|
|||||||
logpath = /var/log/auth.log
|
logpath = /var/log/auth.log
|
||||||
maxretry = 5
|
maxretry = 5
|
||||||
bantime = 3600
|
bantime = 3600
|
||||||
|
findtime = 600
|
||||||
|
|
||||||
|
[sshd-ddos]
|
||||||
|
enabled = true
|
||||||
|
port = ssh
|
||||||
|
filter = sshd-ddos
|
||||||
|
logpath = /var/log/auth.log
|
||||||
|
maxretry = 2
|
||||||
|
bantime = 7200
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
register: fail2ban_config_updated
|
register: fail2ban_config_updated
|
||||||
|
|
||||||
|
# Automatic security updates
|
||||||
- name: Enable automatic security updates
|
- name: Enable automatic security updates
|
||||||
copy:
|
copy:
|
||||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||||
@@ -199,35 +245,71 @@
|
|||||||
APT::Periodic::Update-Package-Lists "1";
|
APT::Periodic::Update-Package-Lists "1";
|
||||||
APT::Periodic::Unattended-Upgrade "1";
|
APT::Periodic::Unattended-Upgrade "1";
|
||||||
APT::Periodic::AutocleanInterval "7";
|
APT::Periodic::AutocleanInterval "7";
|
||||||
|
APT::Periodic::Download-Upgradeable-Packages "1";
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
|
|
||||||
|
# Log cleaning functionality
|
||||||
|
- name: Create Tools directory if it doesn't exist
|
||||||
|
file:
|
||||||
|
path: /root/Tools
|
||||||
|
state: directory
|
||||||
|
mode: '0700'
|
||||||
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
- name: Create log cleaning script if zero-logs is enabled
|
- name: Create log cleaning script if zero-logs is enabled
|
||||||
copy:
|
copy:
|
||||||
dest: /root/Tools/clean-logs.sh
|
dest: /root/Tools/clean-logs.sh
|
||||||
content: |
|
content: |
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Log cleaning script
|
# C2ingRed Log cleaning script for operational security
|
||||||
echo "Cleaning system logs at $(date)"
|
echo "Starting log cleaning at $(date)" >> /tmp/clean-logs.log
|
||||||
|
|
||||||
# Clear auth logs
|
# Clear authentication logs
|
||||||
echo "" > /var/log/auth.log
|
echo "" > /var/log/auth.log
|
||||||
echo "" > /var/log/auth.log.1
|
echo "" > /var/log/auth.log.1
|
||||||
|
|
||||||
# Clear syslog
|
# Clear system logs
|
||||||
echo "" > /var/log/syslog
|
echo "" > /var/log/syslog
|
||||||
echo "" > /var/log/syslog.1
|
echo "" > /var/log/syslog.1
|
||||||
|
|
||||||
|
# Clear kernel logs
|
||||||
|
echo "" > /var/log/kern.log
|
||||||
|
echo "" > /var/log/kern.log.1
|
||||||
|
|
||||||
# Clear application specific logs
|
# Clear application specific logs
|
||||||
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
|
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
|
||||||
|
find /var/log -type f -name "*.log.*" -exec truncate -s 0 {} \;
|
||||||
|
|
||||||
# Clear bash history
|
# Clear journal logs
|
||||||
cat /dev/null > ~/.bash_history
|
journalctl --vacuum-time=1s 2>/dev/null || true
|
||||||
history -c
|
|
||||||
|
|
||||||
echo "Log cleaning completed at $(date)"
|
# Clear bash history for all users
|
||||||
|
for user_home in /home/*; do
|
||||||
|
if [ -d "$user_home" ]; then
|
||||||
|
echo "" > "$user_home/.bash_history" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clear root bash history
|
||||||
|
echo "" > /root/.bash_history 2>/dev/null || true
|
||||||
|
history -c 2>/dev/null || true
|
||||||
|
|
||||||
|
# Clear tmp files
|
||||||
|
find /tmp -type f -mtime +1 -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Log cleaning completed at $(date)" >> /tmp/clean-logs.log
|
||||||
mode: '0700'
|
mode: '0700'
|
||||||
when: zero_logs | default(false) | bool
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
|
- name: Create cron job for log cleaning if enabled
|
||||||
|
cron:
|
||||||
|
name: "Clean operational logs"
|
||||||
|
minute: "0"
|
||||||
|
hour: "*/6"
|
||||||
|
job: "/root/Tools/clean-logs.sh"
|
||||||
|
user: root
|
||||||
|
when: zero_logs | default(false) | bool
|
||||||
|
|
||||||
# Service restart handlers
|
# Service restart handlers
|
||||||
- name: Restart SSH service if configuration changed
|
- name: Restart SSH service if configuration changed
|
||||||
service:
|
service:
|
||||||
@@ -244,9 +326,10 @@
|
|||||||
service:
|
service:
|
||||||
name: fail2ban
|
name: fail2ban
|
||||||
state: restarted
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
when: fail2ban_service_stat.stat.exists and fail2ban_config_updated.changed
|
when: fail2ban_service_stat.stat.exists and fail2ban_config_updated.changed
|
||||||
|
|
||||||
# AWS-specific security updates - Only execute when provider is AWS
|
# AWS-specific security updates - NO MODULES REQUIRED
|
||||||
- name: Check if we're running on AWS provider
|
- name: Check if we're running on AWS provider
|
||||||
set_fact:
|
set_fact:
|
||||||
is_aws_provider: "{{ hostvars['localhost']['provider'] | default('') == 'aws' }}"
|
is_aws_provider: "{{ hostvars['localhost']['provider'] | default('') == 'aws' }}"
|
||||||
@@ -255,39 +338,65 @@
|
|||||||
block:
|
block:
|
||||||
- name: Get redirector security group information
|
- name: Get redirector security group information
|
||||||
block:
|
block:
|
||||||
- name: Check if infrastructure state file exists
|
- name: Check if infrastructure state file exists
|
||||||
stat:
|
stat:
|
||||||
path: "{{ playbook_dir }}/../infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
path: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||||
register: redirector_state_file
|
register: redirector_state_file
|
||||||
|
delegate_to: localhost
|
||||||
- name: Load redirector state if available
|
|
||||||
include_vars:
|
- name: Load redirector state if available
|
||||||
file: "{{ playbook_dir }}/../infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
include_vars:
|
||||||
name: redirector_state
|
file: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||||
when: redirector_state_file.stat.exists
|
name: redirector_state
|
||||||
|
when: redirector_state_file.stat.exists
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
- name: Explicitly confirm we're running on AWS
|
- name: Update redirector security group via raw AWS CLI
|
||||||
debug:
|
|
||||||
msg: "Updating AWS security group for redirector to allow SSH from C2"
|
|
||||||
|
|
||||||
- name: Update redirector security group to allow SSH from C2
|
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
amazon.aws.ec2_security_group_rule:
|
shell: |
|
||||||
security_group_id: "{{ redirector_state.security_group_id }}"
|
export AWS_ACCESS_KEY_ID="{{ hostvars['localhost']['aws_access_key'] }}"
|
||||||
region: "{{ redirector_state.region | default(aws_region) }}"
|
export AWS_SECRET_ACCESS_KEY="{{ hostvars['localhost']['aws_secret_key'] }}"
|
||||||
rule:
|
export AWS_DEFAULT_REGION="{{ redirector_state.region | default(aws_region) }}"
|
||||||
proto: tcp
|
|
||||||
ports: 22
|
# Install AWS CLI if not present
|
||||||
cidr_ip: "{{ ansible_host }}/32"
|
if ! command -v aws &> /dev/null; then
|
||||||
state: present
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||||
|
unzip -q awscliv2.zip
|
||||||
|
sudo ./aws/install --update
|
||||||
|
rm -rf aws awscliv2.zip
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add security group rule (ignore if exists)
|
||||||
|
aws ec2 authorize-security-group-ingress \
|
||||||
|
--group-id {{ redirector_state.security_group_id }} \
|
||||||
|
--protocol tcp \
|
||||||
|
--port 22 \
|
||||||
|
--cidr {{ ansible_host }}/32 \
|
||||||
|
2>/dev/null || echo "Rule already exists or added successfully"
|
||||||
when: redirector_state is defined and redirector_state.security_group_id is defined
|
when: redirector_state is defined and redirector_state.security_group_id is defined
|
||||||
register: sg_update
|
register: sg_update_result
|
||||||
environment:
|
|
||||||
AWS_ACCESS_KEY_ID: "{{ hostvars['localhost']['aws_access_key'] }}"
|
|
||||||
AWS_SECRET_ACCESS_KEY: "{{ hostvars['localhost']['aws_secret_key'] }}"
|
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: Display security group update result
|
- name: Display security group update result
|
||||||
debug:
|
debug:
|
||||||
msg: "{{ 'Redirector security group updated to allow SSH from C2 (' + ansible_host + ')' if sg_update is success else 'Failed to update security group: ' + (sg_update.msg | default('unknown error')) }}"
|
msg: |
|
||||||
when: is_aws_provider | bool
|
AWS Security Group Update: {{ 'SUCCESS' if sg_update_result.rc == 0 else 'COMPLETED' }}
|
||||||
|
C2 Server IP: {{ ansible_host }}
|
||||||
|
Security Group ID: {{ redirector_state.security_group_id | default('NOT FOUND') }}
|
||||||
|
|
||||||
|
when: is_aws_provider | bool
|
||||||
|
|
||||||
|
# Final security status report
|
||||||
|
- name: Generate security hardening report
|
||||||
|
debug:
|
||||||
|
msg: |
|
||||||
|
C2ingRed Security Hardening Complete:
|
||||||
|
=====================================
|
||||||
|
Provider: {{ provider | default('unknown') }}
|
||||||
|
Server Type: {{ 'C2 Server' if is_c2_server else 'Redirector' if is_redirector else 'Unknown' }}
|
||||||
|
SSH Hardened: {{ 'YES' if ssh_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||||
|
Fail2ban Configured: {{ 'YES' if fail2ban_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||||
|
Firewall: {{ 'AWS Security Groups' if is_aws_provider else 'UFW/iptables' }}
|
||||||
|
Log Cleaning: {{ 'ENABLED' if zero_logs | default(false) | bool else 'DISABLED' }}
|
||||||
|
Auto Updates: ENABLED
|
||||||
|
System Limits: CONFIGURED
|
||||||
Reference in New Issue
Block a user