diff --git a/AWS/c2.yml b/AWS/c2.yml index 6f3335b..1c8bf07 100644 --- a/AWS/c2.yml +++ b/AWS/c2.yml @@ -53,6 +53,12 @@ ami_id: "{{ ami_map[aws_c2_region] }}" when: ami_map is defined and aws_c2_region in ami_map + # Add AMI username mapping + - name: Determine correct SSH user for the AMI + set_fact: + ami_ssh_user: >- + {% if ami_id == 'ami-061b17d332829ab1c' %}kali{% else %}ubuntu{% endif %} + - name: Create EC2 key pair amazon.aws.ec2_key: name: "{{ c2_name }}" @@ -206,40 +212,70 @@ name: "c2" groups: "c2servers" ansible_host: "{{ c2_ip }}" - ansible_user: "{{ ssh_user }}" + ansible_user: "{{ ami_ssh_user | default('kali') }}" ansible_ssh_private_key_file: "~/.ssh/{{ c2_name }}.pem" ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes" + ansible_python_interpreter: "/usr/bin/python3" -# Rest of the playbook for configuring the C2 server +# Configure C2 server with a proper structure - name: Configure C2 server hosts: c2servers - become: true - gather_facts: true - vars_files: - - vars.yaml + become: yes vars: redirector_ip: "{{ hostvars['localhost']['redirector_ip'] | default('127.0.0.1') }}" c2_subdomain: "{{ c2_subdomain | default('mail') }}" - - # Include the rest of your C2 configuration tasks here tasks: + - name: Download Kali archive keyring to temporary location + get_url: + url: https://archive.kali.org/archive-keyring.gpg + dest: /tmp/kali-archive-keyring.gpg + mode: "0644" + force: yes + register: keyring_download + + - name: Install Kali archive keyring + command: install -m 0644 /tmp/kali-archive-keyring.gpg /usr/share/keyrings/kali-archive-keyring.gpg + when: keyring_download is changed + - name: Wait for apt to be available apt: update_cache: yes register: apt_result until: apt_result is success - retries: 5 + retries: 10 delay: 10 + - name: Install Rust compiler + apt: + name: + - cargo + - rustc + - libssl-dev + - pkg-config + state: present + register: rust_install + until: rust_install is success + retries: 3 + delay: 5 + + - name: Clean up any failed pipx installations + file: + path: "{{ item }}" + state: absent + with_items: + - "/root/.local/state/pipx/venvs/netexec" + - "/root/.local/state/pipx/venvs/trevorspray" + ignore_errors: yes + - name: Include common tool installation tasks include_tasks: "../tasks/install_tools.yml" - + - name: Include common C2 configuration tasks include_tasks: "../tasks/configure_c2.yml" - + - name: Include common security hardening tasks include_tasks: "../tasks/security_hardening.yml" - + - name: Include common mail server configuration tasks include_tasks: "../tasks/configure_mail.yml" diff --git a/AWS/cleanup.yml b/AWS/cleanup.yml index 83a0e54..0eff18d 100644 --- a/AWS/cleanup.yml +++ b/AWS/cleanup.yml @@ -1,242 +1,260 @@ --- -# AWS Cleanup Playbook (Fixed) +# AWS Cleanup Playbook -- name: Clean up AWS infrastructure +- name: Clean up AWS resources hosts: localhost - connection: local gather_facts: false + connection: local vars_files: - vars.yaml vars: - aws_region: "{{ aws_region | default(aws_region_choices | random) }}" - cleanup_redirector: "{{ (redirector_name is defined and redirector_name != '') | ternary(true, false) }}" - cleanup_c2: "{{ (c2_name is defined and c2_name != '') | ternary(true, false) }}" - confirm_cleanup: "{{ confirm_cleanup | default(true) }}" - delay_seconds: 30 - # Initialize cleaned resources list - cleaned_resources: - instances: [] - security_groups: [] - key_pairs: [] - internet_gateways: [] - subnets: [] - route_tables: [] - vpcs: [] + delete_results: {} tasks: - - name: Validate required AWS credentials - assert: - that: - - aws_access_key is defined and aws_access_key != "" - - aws_secret_key is defined and aws_secret_key != "" - fail_msg: "AWS credentials are required. Set aws_access_key and aws_secret_key." - - - name: Confirm cleanup if required + - name: Confirm cleanup pause: - prompt: "WARNING: This will permanently delete all infrastructure. Type 'yes' to continue" - register: confirmation - when: confirm_cleanup + prompt: "This will delete all AWS resources for deployment ID {{ deployment_id }}. Continue? (yes/no)" + register: confirm_deletion + when: confirm_cleanup | default(true) | bool + + - name: Check confirmation + assert: + that: confirm_deletion.user_input | default('yes') | lower == 'yes' + fail_msg: "Cleanup cancelled by user" + when: confirm_cleanup | default(true) | bool + + # C2 server cleanup + - name: Terminate C2 instances + amazon.aws.ec2_instance: + state: absent + region: "{{ aws_region }}" + filters: + "tag:Name": "{{ c2_name }}" + register: c2_instances_result + when: cleanup_c2 | default(true) | bool + + # Redirector cleanup + - name: Terminate redirector instances + amazon.aws.ec2_instance: + state: absent + region: "{{ aws_region }}" + filters: + "tag:Name": "{{ redirector_name }}" + register: redirector_instances_result + when: cleanup_redirector | default(true) | bool - - name: Exit if not confirmed - meta: end_play - when: confirm_cleanup and confirmation.user_input != 'yes' - - # Find EC2 instances - - name: Find redirector instance ID - command: > - aws ec2 describe-instances - --filters "Name=tag:Name,Values={{ redirector_name }}" - --query "Reservations[*].Instances[*].InstanceId" - --output text - --region {{ aws_region }} - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - register: redirector_id_result - failed_when: false - changed_when: false - when: cleanup_redirector - - - name: Find C2 instance ID - command: > - aws ec2 describe-instances - --filters "Name=tag:Name,Values={{ c2_name }}" - --query "Reservations[*].Instances[*].InstanceId" - --output text - --region {{ aws_region }} - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - register: c2_id_result - failed_when: false - changed_when: false - when: cleanup_c2 - - - name: Set instance IDs as facts - set_fact: - redirector_instance_id: "{{ redirector_id_result.stdout | trim }}" - cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + [redirector_id_result.stdout | trim]}, recursive=True) }}" - when: cleanup_redirector and redirector_id_result.stdout is defined and redirector_id_result.stdout | trim != "" - - - name: Set C2 instance ID as fact - set_fact: - c2_instance_id: "{{ c2_id_result.stdout | trim }}" - cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + [c2_id_result.stdout | trim]}, recursive=True) }}" - when: cleanup_c2 and c2_id_result.stdout is defined and c2_id_result.stdout | trim != "" - - # Terminate EC2 instances - - name: Terminate redirector instance + # Tracker cleanup + - name: Terminate tracker instances amazon.aws.ec2_instance: state: absent - instance_ids: - - "{{ redirector_instance_id }}" region: "{{ aws_region }}" - aws_access_key: "{{ aws_access_key }}" - aws_secret_key: "{{ aws_secret_key }}" - when: cleanup_redirector and redirector_instance_id is defined and redirector_instance_id != "" - register: redirector_termination - - - name: Terminate C2 instance - amazon.aws.ec2_instance: - state: absent - instance_ids: - - "{{ c2_instance_id }}" - region: "{{ aws_region }}" - aws_access_key: "{{ aws_access_key }}" - aws_secret_key: "{{ aws_secret_key }}" - when: cleanup_c2 and c2_instance_id is defined and c2_instance_id != "" - register: c2_termination - - - name: Wait for instances to be fully terminated + filters: + "tag:Name": "{{ tracker_name | default('t-' + deployment_id) }}" + register: tracker_instances_result + when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool + + # We need to wait a bit for instances to terminate before we can clean up security groups + - name: Wait for instances to terminate pause: seconds: 30 - when: - - (redirector_termination is defined and redirector_termination.changed) or - (c2_termination is defined and c2_termination.changed) - - # Find VPCs - - name: Find VPCs by redirector name - command: > - aws ec2 describe-vpcs - --filters "Name=tag:Name,Values=*{{ redirector_name }}*" - --query "Vpcs[].VpcId" - --output text - --region {{ aws_region }} - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - register: redirector_vpcs - failed_when: false - changed_when: false - when: cleanup_redirector - - - name: Find VPCs by C2 name - command: > - aws ec2 describe-vpcs - --filters "Name=tag:Name,Values=*{{ c2_name }}*" - --query "Vpcs[].VpcId" - --output text - --region {{ aws_region }} - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - register: c2_vpcs - failed_when: false - changed_when: false - when: cleanup_c2 - - - name: Combine VPC IDs into a list - set_fact: - vpc_ids: "{{ ((redirector_vpcs.stdout | default('') | trim | split('\n') | select('string') | list) + - (c2_vpcs.stdout | default('') | trim | split('\n') | select('string') | list)) | unique }}" - when: (redirector_vpcs.stdout | default('') | trim != '') or (c2_vpcs.stdout | default('') | trim != '') - - - name: Find shared infrastructure resources by deployment ID - command: > - aws ec2 describe-vpcs - --filters "Name=tag:deployment_id,Values={{ deployment_id }}" - --query "Vpcs[].VpcId" - --output text - --region {{ aws_region }} - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - register: infra_vpcs - failed_when: false - changed_when: false - - - name: Add shared infrastructure VPCs to cleanup list - set_fact: - vpc_ids: "{{ vpc_ids | default([]) + (infra_vpcs.stdout | default('') | trim | split('\n') | select('string') | list) }}" - when: infra_vpcs.stdout | default('') | trim != '' + when: cleanup_c2 | default(true) | bool or cleanup_redirector | default(true) | bool or (cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool) - - name: Remove infrastructure state file if it exists - file: - path: "infrastructure_state.json" - state: absent - - # Process each VPC - - name: Process each VPC - include_tasks: process_vpc.yml - loop: "{{ vpc_ids | default([]) }}" - loop_control: - loop_var: vpc_id - when: vpc_ids is defined and vpc_ids | length > 0 - # Delete key pairs - - name: Delete redirector key pair - amazon.aws.ec2_key: - name: "{{ redirector_name }}" - state: absent - region: "{{ aws_region }}" - aws_access_key: "{{ aws_access_key }}" - aws_secret_key: "{{ aws_secret_key }}" - when: cleanup_redirector and redirector_name is defined and redirector_name != "" - register: redirector_key_deleted - - - name: Delete C2 key pair + - name: Delete C2 EC2 key pair amazon.aws.ec2_key: name: "{{ c2_name }}" - state: absent region: "{{ aws_region }}" - aws_access_key: "{{ aws_access_key }}" - aws_secret_key: "{{ aws_secret_key }}" - when: cleanup_c2 and c2_name is defined and c2_name != "" - register: c2_key_deleted - - - name: Track deleted key pairs for redirector - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [redirector_name]}, recursive=True) }}" - when: redirector_key_deleted is defined and redirector_key_deleted.changed - - - name: Track deleted key pairs for C2 - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [c2_name]}, recursive=True) }}" - when: c2_key_deleted is defined and c2_key_deleted.changed - - # Remove local key files - - name: Remove redirector SSH key file - file: - path: "~/.ssh/{{ redirector_name }}.pem" state: absent - when: cleanup_redirector and redirector_name is defined and redirector_name != "" - - - name: Remove C2 SSH key file - file: - path: "~/.ssh/{{ c2_name }}.pem" + register: c2_key_result + when: cleanup_c2 | default(true) | bool + + - name: Delete redirector EC2 key pair + amazon.aws.ec2_key: + name: "{{ redirector_name }}" + region: "{{ aws_region }}" state: absent - when: cleanup_c2 and c2_name is defined and c2_name != "" - - # Summary of cleanup - - name: Cleanup complete message + register: redirector_key_result + when: cleanup_redirector | default(true) | bool + + - name: Delete tracker EC2 key pair + amazon.aws.ec2_key: + name: "{{ tracker_name | default('t-' + deployment_id) }}" + region: "{{ aws_region }}" + state: absent + register: tracker_key_result + when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool + + # Security Groups + - name: Delete C2 security group + amazon.aws.ec2_security_group: + name: "{{ c2_name }}-sg" + region: "{{ aws_region }}" + state: absent + register: c2_sg_result + ignore_errors: yes + when: cleanup_c2 | default(true) | bool + + - name: Delete redirector security group + amazon.aws.ec2_security_group: + name: "{{ redirector_name }}-sg" + region: "{{ aws_region }}" + state: absent + register: redirector_sg_result + ignore_errors: yes + when: cleanup_redirector | default(true) | bool + + - name: Delete tracker security group + amazon.aws.ec2_security_group: + name: "{{ tracker_name | default('t-' + deployment_id) }}-sg" + region: "{{ aws_region }}" + state: absent + register: tracker_sg_result + ignore_errors: yes + when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool + + # VPC Resources + - name: Get VPCs + amazon.aws.ec2_vpc_net_info: + region: "{{ aws_region }}" + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: vpc_info + + - name: Get subnets + amazon.aws.ec2_vpc_subnet_info: + region: "{{ aws_region }}" + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: subnet_info + + - name: Get route tables + amazon.aws.ec2_vpc_route_table_info: + region: "{{ aws_region }}" + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: route_table_info + + - name: Get internet gateways + amazon.aws.ec2_vpc_igw_info: + region: "{{ aws_region }}" + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: igw_info + + # Get and delete any remaining network interfaces in these VPCs + - name: Get network interfaces in VPCs + amazon.aws.ec2_eni_info: + region: "{{ aws_region }}" + filters: + vpc-id: "{{ item.vpc_id }}" + loop: "{{ vpc_info.vpcs }}" + register: eni_info + + - name: Delete network interfaces + amazon.aws.ec2_eni: + region: "{{ aws_region }}" + eni_id: "{{ item.1.network_interface_id }}" + state: absent + force_detach: true + loop: "{{ eni_info.results | subelements('network_interfaces', skip_missing=true) }}" + register: eni_deleted + ignore_errors: yes + + # Delete VPC resources + - name: Delete route tables + amazon.aws.ec2_vpc_route_table: + region: "{{ aws_region }}" + vpc_id: "{{ item.vpc_id }}" + route_table_id: "{{ item.id }}" + state: absent + loop: "{{ route_table_info.route_tables }}" + register: route_tables_deleted + ignore_errors: yes + + - name: Delete internet gateways + amazon.aws.ec2_vpc_igw: + region: "{{ aws_region }}" + vpc_id: "{{ item.attachments[0].vpc_id }}" + state: absent + loop: "{{ igw_info.internet_gateways }}" + register: igws_deleted + ignore_errors: yes + + - name: Delete subnets + amazon.aws.ec2_vpc_subnet: + region: "{{ aws_region }}" + vpc_id: "{{ item.vpc_id }}" + cidr: "{{ item.cidr_block }}" + state: absent + loop: "{{ subnet_info.subnets }}" + register: subnets_deleted + ignore_errors: yes + + # Wait before trying to delete VPCs to allow AWS to catch up on dependency deletions + - name: Wait for AWS to process subnet and gateway deletions + pause: + seconds: 15 + + - name: Delete VPCs + amazon.aws.ec2_vpc_net: + region: "{{ aws_region }}" + vpc_id: "{{ item.id }}" + state: absent + loop: "{{ vpc_info.vpcs }}" + register: vpcs_deleted + ignore_errors: yes + + # Create summary of deleted resources + - name: Collect all deleted resources + set_fact: + resource_summary: + ec2_instances: + c2: "{{ c2_instances_result.instance_ids | default([]) }}" + redirector: "{{ redirector_instances_result.instance_ids | default([]) }}" + tracker: "{{ tracker_instances_result.instance_ids | default([]) }}" + key_pairs: + c2: "{{ c2_key_result.key.name | default('') | ternary([c2_key_result.key.name], []) }}" + redirector: "{{ redirector_key_result.key.name | default('') | ternary([redirector_key_result.key.name], []) }}" + tracker: "{{ tracker_key_result.key.name | default('') | ternary([tracker_key_result.key.name], []) }}" + security_groups: + c2: "{{ c2_sg_result.group_id | default('') | ternary([c2_sg_result.group_id], []) }}" + redirector: "{{ redirector_sg_result.group_id | default('') | ternary([redirector_sg_result.group_id], []) }}" + tracker: "{{ tracker_sg_result.group_id | default('') | ternary([tracker_sg_result.group_id], []) }}" + vpc_resources: + route_tables: "{{ route_tables_deleted.results | default([]) | map(attribute='item.id', default='') | select() | list }}" + internet_gateways: "{{ igws_deleted.results | default([]) | map(attribute='gateway_id', default='') | select() | list }}" + subnets: "{{ subnets_deleted.results | default([]) | map(attribute='subnet.id', default='') | select() | list }}" + network_interfaces: "{{ eni_deleted.results | default([]) | map(attribute='interface.id', default='') | select() | list }}" + vpcs: "{{ vpcs_deleted.results | default([]) | map(attribute='vpc.id', default='') | select() | list }}" + when: not disable_summary | default(false) + + # Display summary of deleted resources + - name: Display cleanup summary debug: msg: - - "AWS infrastructure cleanup complete!" - - "Resources that were cleaned up:" - - "- Instances: {{ cleaned_resources.instances | length }} {{ cleaned_resources.instances | join(', ') }}" - - "- Security Groups: {{ cleaned_resources.security_groups | length }} {{ cleaned_resources.security_groups | join(', ') }}" - - "- Internet Gateways: {{ cleaned_resources.internet_gateways | length }} {{ cleaned_resources.internet_gateways | join(', ') }}" - - "- Subnets: {{ cleaned_resources.subnets | length }} {{ cleaned_resources.subnets | join(', ') }}" - - "- Route Tables: {{ cleaned_resources.route_tables | length }} {{ cleaned_resources.route_tables | join(', ') }}" - - "- VPCs: {{ cleaned_resources.vpcs | length }} {{ cleaned_resources.vpcs | join(', ') }}" - - "- Key Pairs: {{ cleaned_resources.key_pairs | length }} {{ cleaned_resources.key_pairs | join(', ') }}" \ No newline at end of file + - "==========================================================" + - "CLEANUP SUMMARY FOR DEPLOYMENT ID: {{ deployment_id }}" + - "==========================================================" + - "EC2 INSTANCES DELETED:" + - " C2: {{ resource_summary.ec2_instances.c2 }}" + - " Redirector: {{ resource_summary.ec2_instances.redirector }}" + - " Tracker: {{ resource_summary.ec2_instances.tracker }}" + - "" + - "KEY PAIRS DELETED:" + - " C2: {{ resource_summary.key_pairs.c2 }}" + - " Redirector: {{ resource_summary.key_pairs.redirector }}" + - " Tracker: {{ resource_summary.key_pairs.tracker }}" + - "" + - "SECURITY GROUPS DELETED:" + - " C2: {{ resource_summary.security_groups.c2 }}" + - " Redirector: {{ resource_summary.security_groups.redirector }}" + - " Tracker: {{ resource_summary.security_groups.tracker }}" + - "" + - "VPC RESOURCES DELETED:" + - " Route Tables: {{ resource_summary.vpc_resources.route_tables }}" + - " Internet Gateways: {{ resource_summary.vpc_resources.internet_gateways }}" + - " Subnets: {{ resource_summary.vpc_resources.subnets }}" + - " Network Interfaces: {{ resource_summary.vpc_resources.network_interfaces }}" + - " VPCs: {{ resource_summary.vpc_resources.vpcs }}" + - "==========================================================" + when: not disable_summary | default(false) \ No newline at end of file diff --git a/AWS/redirector.yml b/AWS/redirector.yml index e6ed0fe..20cb5cf 100644 --- a/AWS/redirector.yml +++ b/AWS/redirector.yml @@ -9,7 +9,7 @@ - vars.yaml vars: # Default values - ssh_user: "{{ ssh_user | default('kali') }}" + ssh_user: "{{ ssh_user | default('ubuntu') }}" # Changed from 'kali' to 'ubuntu' aws_region: "{{ aws_region | default(aws_region_choices | random) }}" instance_type: "{{ aws_instance_type | default('t2.micro') }}" deployment_id: "{{ deployment_id | default('') }}" @@ -17,6 +17,19 @@ shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}" # Check for shared infrastructure use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) }}" + # Ubuntu AMI IDs for different regions (Ubuntu 22.04 LTS) + ubuntu_ami_map: + us-east-1: "ami-0aa2b7722dc1b5612" + us-east-2: "ami-06c4532923d4ba1ec" + us-west-1: "ami-0573b70afecda915d" + us-west-2: "ami-0c79c59ac2c572b87" + eu-west-1: "ami-0694d931cee176e7d" + eu-west-2: "ami-0505148b3591e4c07" + eu-central-1: "ami-06dd92ecc74fdfb36" + ap-southeast-1: "ami-0df7a207adb9748c7" + ap-southeast-2: "ami-0df4b2961410d4cff" + ap-northeast-1: "ami-0014b5f031a76c1b1" + sa-east-1: "ami-0af6e9042ea5a4e3e" tasks: - name: Validate AWS credentials @@ -51,9 +64,8 @@ - name: Set AMI ID for selected region set_fact: - ami_id: "{{ ami_map[aws_redirector_region] }}" - when: ami_map is defined and aws_redirector_region in ami_map - + ami_id: "{{ ubuntu_ami_map[aws_redirector_region] | default(ubuntu_ami_map['us-east-1']) }}" + - name: Create EC2 key pair amazon.aws.ec2_key: name: "{{ redirector_name }}" @@ -190,9 +202,10 @@ name: "redirector" groups: "redirectors" ansible_host: "{{ redirector_ip }}" - ansible_user: "{{ ssh_user }}" + ansible_user: "ubuntu" # Change this from 'kali' to 'ubuntu' ansible_ssh_private_key_file: "~/.ssh/{{ redirector_name }}.pem" ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes" + ansible_python_interpreter: "/usr/bin/python3" # Rest of the playbook for configuring the redirector - name: Configure redirector @@ -205,11 +218,7 @@ c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}" # Include the rest of your redirector configuration tasks here - tasks: - - name: Update apt cache - apt: - update_cache: yes - + tasks: - name: Include common redirector configuration tasks include_tasks: "../tasks/configure_redirector.yml" diff --git a/deploy.py b/deploy.py index 0128689..d8ec332 100644 --- a/deploy.py +++ b/deploy.py @@ -382,14 +382,8 @@ def interactive_setup(deployment_id=None): # Debug mode config['debug'] = input("Enable debug mode? (y/n) [default: n]: ").lower() == 'y' - # SSH key if not already set - if 'ssh_key' not in config or not config['ssh_key']: - ssh_key = input("\nPath to SSH Private Key [leave blank to generate new key]: ") - if ssh_key: - config['ssh_key'] = os.path.expanduser(ssh_key) - else: - # Generate SSH key using the deployment ID - config['ssh_key'] = generate_ssh_key(deployment_id) + # Always generate a new SSH key using the deployment ID + config['ssh_key'] = generate_ssh_key(deployment_id) # Generate instance names with consistent deployment ID config['redirector_name'] = f"r-{deployment_id}" @@ -445,7 +439,7 @@ def load_vars_file(provider): provider_dir = PROVIDER_DIRS[provider] vars_file = f"{provider_dir}/vars.yaml" - if os.path.exists(vars_file): + if (os.path.exists(vars_file)): try: with open(vars_file, 'r') as f: vars_data = yaml.safe_load(f) or {} diff --git a/tasks/security_hardening.yml b/tasks/security_hardening.yml new file mode 100644 index 0000000..70994fb --- /dev/null +++ b/tasks/security_hardening.yml @@ -0,0 +1,139 @@ +--- +# Security hardening tasks for C2 server + +- name: Check if system is updated + apt: + update_cache: yes + register: apt_update_result + until: apt_update_result is success + retries: 5 + delay: 5 + +- name: Install security packages + apt: + name: + - fail2ban + - ufw + - unattended-upgrades + - debsums + - aide + - rkhunter + - logrotate + state: present + register: package_install + until: package_install is success + retries: 3 + delay: 5 + +- name: Configure UFW default policies + ufw: + state: enabled + policy: deny + direction: incoming + ignore_errors: yes + +- name: Allow required ports through firewall + ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: + - "22" + - "80" + - "443" + - "{{ havoc_teamserver_port | default('40056') }}" + - "{{ havoc_http_port | default('8080') }}" + - "{{ gophish_admin_port | default('3333') }}" + ignore_errors: yes + +- name: Set up fail2ban SSH jail + copy: + dest: /etc/fail2ban/jail.d/sshd.conf + content: | + [sshd] + enabled = true + port = ssh + filter = sshd + logpath = /var/log/auth.log + maxretry = 5 + bantime = 3600 + mode: '0644' + notify: Restart fail2ban + +- name: Enable automatic security updates + copy: + dest: /etc/apt/apt.conf.d/20auto-upgrades + content: | + APT::Periodic::Update-Package-Lists "1"; + APT::Periodic::Unattended-Upgrade "1"; + APT::Periodic::AutocleanInterval "7"; + mode: '0644' + +- name: Create log cleaning script if zero-logs is enabled + copy: + dest: /root/Tools/clean-logs.sh + content: | + #!/bin/bash + # Log cleaning script + echo "Cleaning system logs at $(date)" + + # Clear auth logs + echo "" > /var/log/auth.log + echo "" > /var/log/auth.log.1 + + # Clear syslog + echo "" > /var/log/syslog + echo "" > /var/log/syslog.1 + + # Clear application specific logs + find /var/log -type f -name "*.log" -exec truncate -s 0 {} \; + + # Clear bash history + cat /dev/null > ~/.bash_history + history -c + + echo "Log cleaning completed at $(date)" + mode: '0700' + when: zero_logs | default(false) | bool + +# SSH Hardening +- name: Harden SSH configuration + lineinfile: + path: /etc/ssh/sshd_config + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + state: present + loop: + - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' } + - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' } + - { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' } + - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' } + - { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' } + - { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' } + - { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' } + register: ssh_config_updated + +- name: Configure system resource limits + pam_limits: + domain: "*" + limit_type: "{{ item.limit_type }}" + limit_item: "{{ item.limit_item }}" + value: "{{ item.value }}" + loop: + - { limit_type: soft, limit_item: nofile, value: 65535 } + - { limit_type: hard, limit_item: nofile, value: 65535 } + - { limit_type: soft, limit_item: nproc, value: 4096 } + - { limit_type: hard, limit_item: nproc, value: 4096 } + +# Replace handlers with direct service restart tasks +- name: Restart SSH service + service: + name: ssh + state: restarted + when: ssh_config_updated.changed + +- name: Restart fail2ban service + service: + name: fail2ban + state: restarted + when: ansible_facts.services['fail2ban.service'] is defined