diff --git a/.gitignore b/.gitignore index 88e2279..2d9a05e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ venv deployment* config.yml logs/ -domainhunter/ \ No newline at end of file +domainhunter/ +infrastructure_state_*.json \ No newline at end of file diff --git a/AWS/c2.yml b/AWS/c2.yml index 6743523..865cc72 100644 --- a/AWS/c2.yml +++ b/AWS/c2.yml @@ -9,7 +9,7 @@ - vars.yaml vars: # Default values - ssh_user: "{{ ssh_user | default('root') }}" + ssh_user: "{{ ssh_user | default('kali') }}" aws_region: "{{ aws_region | default(aws_region_choices | random) }}" instance_type: "{{ aws_instance_type | default('t2.medium') }}" deployment_id: "{{ deployment_id | default('') }}" @@ -17,6 +17,10 @@ # Check for shared infrastructure # Only use shared when C2 and redirector are in the same region use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}" + # AMI map comes from vars.yaml - add fallback for safety + kali_ami_map_fallback: + us-east-1: "ami-061b17d332829ab1c" + us-east-2: "ami-061b17d332829ab1c" # Fallback to us-east-1 AMI tasks: - name: Validate AWS credentials @@ -29,13 +33,13 @@ # Load shared infrastructure state if available - name: Check for shared infrastructure state stat: - path: "infrastructure_state.json" + path: "infrastructure_state_{{ deployment_id }}.json" register: infra_state_file when: use_shared_infra | bool - name: Load shared infrastructure state include_vars: - file: "infrastructure_state.json" + file: "infrastructure_state_{{ deployment_id }}.json" name: shared_infra when: use_shared_infra | bool and infra_state_file.stat.exists | default(false) @@ -48,16 +52,31 @@ set_fact: aws_c2_region: "{{ c2_region | default(aws_region) }}" when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false)) - - - name: Set AMI ID for selected region + + - name: Check if ami_map is provided in vars.yaml + debug: + msg: "ami_map is {{ 'defined' if ami_map is defined else 'NOT defined' }} in vars.yaml" + + - name: Set AMI ID for selected region (from vars.yaml) set_fact: - ami_id: "{{ ami_map[aws_c2_region] }}" - when: ami_map is defined and aws_c2_region in ami_map + ami_id: "{{ ami_map[aws_c2_region] | default(ami_map.us-east-1) }}" + when: ami_map is defined and ami_map + + - name: Set AMI ID for selected region (fallback) + set_fact: + ami_id: "{{ kali_ami_map_fallback[aws_c2_region] | default(kali_ami_map_fallback['us-east-1']) }}" + when: ami_id is not defined or ami_id == "" + + - name: Ensure we have a valid AMI ID + assert: + that: + - ami_id is defined and ami_id != "" + fail_msg: "Could not determine a valid AMI ID for region {{ aws_c2_region }}. Please add it to ami_map in vars.yaml." # Add AMI username mapping - improved with better detection - name: Determine correct SSH user for the AMI set_fact: - ami_ssh_user: "{{ 'root' if (ami_id is defined and ami_id is search('-root-')) or (ami_id is defined and ami_id == 'ami-061b17d332829ab1c') else 'ubuntu' }}" + ami_ssh_user: "{{ 'kali' if (ami_id is defined and ami_id is search('-kali-')) or (ami_id is defined and ami_id == 'ami-061b17d332829ab1c') else 'ubuntu' }}" - name: Display AMI and user information for debugging debug: diff --git a/AWS/cleanup.yml b/AWS/cleanup.yml index d6dddd8..5ebff7d 100644 --- a/AWS/cleanup.yml +++ b/AWS/cleanup.yml @@ -1,6 +1,5 @@ --- -# AWS Cleanup Playbook - +# AWS Cleanup Playbook - Comprehensive version with robust VPC removal - name: Clean up AWS resources hosts: localhost gather_facts: false @@ -8,348 +7,473 @@ vars_files: - vars.yaml vars: - delete_results: {} - vpc_cleanup_list: [] - aws_detailed_logging: true - + aws_region: "{{ aws_region | default(aws_region_choices | random) }}" + confirm_cleanup: "{{ confirm_cleanup | default(true) }}" + deployment_id: "{{ deployment_id | default('') }}" + redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}" + c2_name: "{{ c2_name | default('s-' + deployment_id) }}" + tracker_name: "{{ tracker_name | default('t-' + deployment_id) }}" + cleanup_summary: {} + tasks: - # Confirmation prompts + # Confirmation step (if enabled) - name: Confirm cleanup pause: - prompt: "This will delete all AWS resources for deployment ID {{ deployment_id }}. Continue? (yes/no)" - register: confirm_deletion - when: confirm_cleanup | default(true) | bool - + prompt: "Are you sure you want to delete all AWS resources for deployment ID {{ deployment_id }}? This action cannot be undone. Type 'yes' to confirm" + register: cleanup_confirmation + when: confirm_cleanup | bool + - name: Check confirmation assert: - that: confirm_deletion.user_input | default('yes') | lower == 'yes' + that: + - cleanup_confirmation.user_input | default('yes') == 'yes' fail_msg: "Cleanup cancelled by user" - when: confirm_cleanup | default(true) | bool - - # Display AWS region being used for cleanup - - name: Display AWS region being used for cleanup - debug: - msg: "Cleaning up resources in region: {{ aws_region }}" - when: aws_detailed_logging | bool - - # Check for and load shared infrastructure file - - name: Check for shared infrastructure state - stat: - path: "infrastructure_state.json" - register: infra_state_file - - - name: Load shared infrastructure state - include_vars: - file: "infrastructure_state.json" - name: shared_infra - when: infra_state_file.stat.exists | default(false) - - # Initialize cleaned resources tracking - - name: Initialize cleaned resources tracking - set_fact: - cleaned_resources: - instances: [] - key_pairs: [] - security_groups: [] - network_interfaces: [] - route_tables: [] - subnets: [] - internet_gateways: [] - vpcs: [] - - # EC2 Instance cleanup - - name: Terminate C2 instances - amazon.aws.ec2_instance: - state: absent + when: confirm_cleanup | bool + + # STEP 1: Find all instances by deployment ID + - name: Find all EC2 instances for this deployment + amazon.aws.ec2_instance_info: region: "{{ aws_region }}" filters: - "tag:Name": "{{ c2_name }}" - register: c2_instances_result - when: cleanup_c2 | default(true) | bool - - - name: Update cleaned instances list for C2 - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + c2_instances_result.instance_ids}, recursive=true) }}" - when: cleanup_c2 | default(true) | bool and c2_instances_result.instance_ids is defined + "tag:deployment_id": "{{ deployment_id }}" + register: deployment_instances - - name: Terminate redirector instances + - name: Set fact for instances found + set_fact: + cleanup_summary: "{{ cleanup_summary | combine({'instances_found': deployment_instances.instances | length}) }}" + + # STEP 2: Terminate all instances with proper tagging + - name: Terminate all instances for this deployment amazon.aws.ec2_instance: - state: absent + instance_ids: "{{ item.instance_id }}" region: "{{ aws_region }}" - filters: - "tag:Name": "{{ redirector_name }}" - register: redirector_instances_result - when: cleanup_redirector | default(true) | bool - - - name: Update cleaned instances list for redirector - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + redirector_instances_result.instance_ids}, recursive=true) }}" - when: cleanup_redirector | default(true) | bool and redirector_instances_result.instance_ids is defined - - - name: Terminate tracker instances - amazon.aws.ec2_instance: state: absent - region: "{{ aws_region }}" - 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 - - - name: Update cleaned instances list for tracker - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'instances': cleaned_resources.instances + tracker_instances_result.instance_ids}, recursive=true) }}" - when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_instances_result.instance_ids is defined + loop: "{{ deployment_instances.instances }}" + register: terminated_instances + when: deployment_instances.instances | length > 0 - # Wait for all instances to terminate before attempting to clean up dependent resources - - name: Wait for instances to terminate + - name: Wait for instances to be terminated pause: seconds: 30 - when: (cleanup_c2 | default(true) | bool and c2_instances_result.changed | default(false)) or - (cleanup_redirector | default(true) | bool and redirector_instances_result.changed | default(false)) or - (cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_instances_result.changed | default(false)) - - # List all key pairs to handle different naming patterns - - name: List available EC2 key pairs - amazon.aws.ec2_key_info: + when: deployment_instances.instances | length > 0 + + # STEP 3: Find all security groups by deployment ID + - name: Find all security groups for this deployment + amazon.aws.ec2_security_group_info: region: "{{ aws_region }}" - register: all_key_pairs + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: deployment_sgs - # Delete C2 deployment key with deployment_id pattern - - name: Delete C2 deployment key (deployment_id pattern) - amazon.aws.ec2_key: - name: "c2deploy_{{ deployment_id }}" + # Also find SGs by name pattern + - name: Find security groups by name pattern + amazon.aws.ec2_security_group_info: region: "{{ aws_region }}" - state: absent - register: c2_deploy_key_result - when: cleanup_c2 | default(true) | bool - - # Delete C2 EC2 key pair (original pattern) - - name: Delete C2 EC2 key pair (original pattern) - amazon.aws.ec2_key: - name: "{{ c2_name }}" - region: "{{ aws_region }}" - state: absent - register: c2_key_result - when: cleanup_c2 | default(true) | bool - - # Update cleaned key pairs list for C2 - - name: Update cleaned key pairs list for C2 + register: all_sgs + + - name: Filter SGs by name pattern set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [item]}, recursive=true) }}" - with_items: - - "c2deploy_{{ deployment_id }}" - - "{{ c2_name }}" - when: cleanup_c2 | default(true) | bool and (c2_key_result.changed or c2_deploy_key_result.changed) + named_sgs: "{{ all_sgs.security_groups | selectattr('group_name', 'search', redirector_name + '-sg|' + c2_name + '-sg') | list }}" - # Delete redirector EC2 key pair - - name: Delete redirector EC2 key pair - amazon.aws.ec2_key: - name: "{{ redirector_name }}" - region: "{{ aws_region }}" - state: absent - register: redirector_key_result - when: cleanup_redirector | default(true) | bool - - - name: Update cleaned key pairs list for redirector + - name: Combine all security groups to delete set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [redirector_name]}, recursive=true) }}" - when: cleanup_redirector | default(true) | bool and redirector_key_result.changed | default(false) - - - 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 - - - name: Update cleaned key pairs list for tracker - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'key_pairs': cleaned_resources.key_pairs + [tracker_name | default('t-' + deployment_id)]}, recursive=true) }}" - when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_key_result.changed | default(false) - - # Security group cleanup - - name: Delete C2 security group + all_sgs_to_delete: "{{ deployment_sgs.security_groups + named_sgs }}" + cleanup_summary: "{{ cleanup_summary | combine({'security_groups_found': (deployment_sgs.security_groups + named_sgs) | length}) }}" + + # STEP 4: Delete all security groups + - name: Delete security groups amazon.aws.ec2_security_group: - name: "{{ c2_name }}-sg" + group_id: "{{ item.group_id }}" region: "{{ aws_region }}" state: absent - register: c2_sg_result + loop: "{{ all_sgs_to_delete }}" + when: all_sgs_to_delete | length > 0 ignore_errors: yes - when: cleanup_c2 | default(true) | bool - - - name: Update cleaned security groups list for C2 - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [c2_sg_result.group_id | default('')]}, recursive=true) }}" - when: cleanup_c2 | default(true) | bool and c2_sg_result.changed | default(false) and c2_sg_result.group_id is defined - - - name: Delete redirector security group - amazon.aws.ec2_security_group: - name: "{{ redirector_name }}-sg" + register: deleted_sgs + + # STEP 5: Find and delete all ENIs + - name: Find network interfaces by tag + amazon.aws.ec2_eni_info: region: "{{ aws_region }}" - state: absent - register: redirector_sg_result - ignore_errors: yes - when: cleanup_redirector | default(true) | bool + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: deployment_enis - - name: Update cleaned security groups list for redirector - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [redirector_sg_result.group_id | default('')]}, recursive=true) }}" - when: cleanup_redirector | default(true) | bool and redirector_sg_result.changed | default(false) and redirector_sg_result.group_id is defined - - - name: Delete tracker security group - amazon.aws.ec2_security_group: - name: "{{ tracker_name | default('t-' + deployment_id) }}-sg" + - name: Delete ENIs + amazon.aws.ec2_eni: region: "{{ aws_region }}" + eni_id: "{{ item.id }}" state: absent - register: tracker_sg_result + force_detach: true + loop: "{{ deployment_enis.network_interfaces }}" ignore_errors: yes - when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool + register: deleted_enis + when: deployment_enis.network_interfaces | length > 0 - - name: Update cleaned security groups list for tracker + - name: Set ENIs count in summary set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [tracker_sg_result.group_id | default('')]}, recursive=true) }}" - when: cleanup_tracker | default(true) | bool and track_deployment | default(false) | bool and tracker_sg_result.changed | default(false) and tracker_sg_result.group_id is defined - - # Identify VPCs to clean up (by tag and by name pattern) - - name: Get VPCs by deployment tag + cleanup_summary: "{{ cleanup_summary | combine({'enis_found': deployment_enis.network_interfaces | length}) }}" + + # STEP 6: Find all VPCs by deployment ID + - name: Find all VPCs for this deployment amazon.aws.ec2_vpc_net_info: region: "{{ aws_region }}" filters: "tag:deployment_id": "{{ deployment_id }}" - register: tagged_vpcs + register: deployment_vpcs - - name: Add tagged VPCs to cleanup list - set_fact: - vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}" - with_items: "{{ tagged_vpcs.vpcs }}" - when: tagged_vpcs.vpcs | length > 0 - - # Find VPCs by name pattern - - name: Find VPCs by naming pattern for C2 + # STEP 7: Find VPCs by name pattern as fallback + - name: Find all VPCs by name pattern amazon.aws.ec2_vpc_net_info: region: "{{ aws_region }}" - filters: - "tag:Name": "{{ c2_name }}-vpc" - register: c2_named_vpcs - when: cleanup_c2 | default(true) | bool - - - name: Add C2-named VPCs to cleanup list + register: all_vpcs + + - name: Filter VPCs by name pattern set_fact: - vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}" - with_items: "{{ c2_named_vpcs.vpcs }}" - when: cleanup_c2 | default(true) | bool and c2_named_vpcs.vpcs | length > 0 - - - name: Find VPCs by naming pattern for redirector - amazon.aws.ec2_vpc_net_info: + named_vpcs: "{{ all_vpcs.vpcs | selectattr('tags', 'defined') | selectattr('tags.Name', 'defined') | selectattr('tags.Name', 'search', redirector_name + '-vpc|' + c2_name + '-vpc') | list }}" + + - name: Combine all VPCs to delete + set_fact: + all_vpcs_to_delete: "{{ deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id') }}" + cleanup_summary: "{{ cleanup_summary | combine({'vpcs_found': (deployment_vpcs.vpcs + named_vpcs | unique(attribute='vpc_id')) | length}) }}" + + # STEP 8: Find and delete NAT Gateways for each VPC separately + - name: Find NAT gateways in each VPC + amazon.aws.ec2_vpc_nat_gateway_info: region: "{{ aws_region }}" filters: - "tag:Name": "{{ redirector_name }}-vpc" - register: redirector_named_vpcs - when: cleanup_redirector | default(true) | bool + vpc-id: "{{ item.vpc_id }}" + register: natgw_results + loop: "{{ all_vpcs_to_delete }}" + when: all_vpcs_to_delete | length > 0 - - name: Add redirector-named VPCs to cleanup list - set_fact: - vpc_cleanup_list: "{{ vpc_cleanup_list + [item.vpc_id] }}" - with_items: "{{ redirector_named_vpcs.vpcs }}" - when: cleanup_redirector | default(true) | bool and redirector_named_vpcs.vpcs | length > 0 - - # Handle shared infrastructure - - name: Add shared VPC to cleanup if both C2 and redirector being cleaned - set_fact: - vpc_cleanup_list: "{{ vpc_cleanup_list + [shared_infra.vpc_id] }}" - when: > - infra_state_file.stat.exists | default(false) and - shared_infra.vpc_id is defined and - cleanup_c2 | default(true) | bool and - cleanup_redirector | default(true) | bool - - # Make the VPC cleanup list unique - - name: Deduplicate VPC cleanup list - set_fact: - vpc_cleanup_list: "{{ vpc_cleanup_list | unique }}" - when: vpc_cleanup_list | length > 0 - - # Display VPCs to be cleaned up - - name: Display VPCs to be cleaned - debug: - msg: "VPCs to be cleaned: {{ vpc_cleanup_list }}" - when: aws_detailed_logging | bool and vpc_cleanup_list | length > 0 - - # Process each VPC - - name: Process VPCs for cleanup - block: - - name: Process each VPC - include_tasks: "process_vpc.yml" - vars: - vpc_id: "{{ item }}" - with_items: "{{ vpc_cleanup_list | unique }}" - when: vpc_cleanup_list | length > 0 - - # Clean up infrastructure state file if both C2 and redirector are being cleaned - - name: Remove infrastructure state file if cleaning up shared infrastructure - file: - path: "infrastructure_state.json" + - name: Delete NAT gateways + amazon.aws.ec2_vpc_nat_gateway: + region: "{{ aws_region }}" + nat_gateway_id: "{{ item.1.nat_gateway_id }}" state: absent - when: > - infra_state_file.stat.exists | default(false) and - ((cleanup_c2 | default(true) | bool and cleanup_redirector | default(true) | bool) or - (cleanup_c2 | default(true) | bool and not cleanup_redirector | default(true) | bool and - c2_region | default(aws_region) == shared_infra.region) or - (cleanup_redirector | default(true) | bool and not cleanup_c2 | default(true) | bool and - redirector_region | default(aws_region) == shared_infra.region)) + release_eip: true + loop: "{{ natgw_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('nat_gateways', 'defined') | subelements('nat_gateways') }}" + ignore_errors: yes + register: deleted_natgws + when: natgw_results.results is defined + + - name: Wait after NAT deletion + pause: + seconds: 15 + when: deleted_natgws.results is defined and deleted_natgws.results | length > 0 + + # STEP 9: Find and delete Internet Gateways + - name: Find internet gateways for each VPC + amazon.aws.ec2_vpc_igw_info: + region: "{{ aws_region }}" + filters: + attachment.vpc-id: "{{ item.vpc_id }}" + register: igw_results + loop: "{{ all_vpcs_to_delete }}" + when: all_vpcs_to_delete | length > 0 - # Create summary of deleted resources - - name: Collect all deleted resources + - name: Detach and delete internet gateways + amazon.aws.ec2_vpc_igw: + internet_gateway_id: "{{ item.1.internet_gateway_id }}" + state: absent + region: "{{ aws_region }}" + loop: "{{ igw_results.results | default([]) | subelements('internet_gateways') }}" + ignore_errors: yes + register: deleted_igws + + - name: Wait after IGW deletion + pause: + seconds: 15 + when: deleted_igws.results is defined and deleted_igws.results | length > 0 + + # STEP 10: Find and delete Route Tables + - name: Find route tables for each VPC + amazon.aws.ec2_vpc_route_table_info: + region: "{{ aws_region }}" + filters: + vpc-id: "{{ item.vpc_id }}" + register: rtb_results + loop: "{{ all_vpcs_to_delete }}" + when: all_vpcs_to_delete | length > 0 + + - name: Delete non-main route tables + amazon.aws.ec2_vpc_route_table: + region: "{{ aws_region }}" + route_table_id: "{{ item.1.id }}" + lookup: id + state: absent + loop: "{{ rtb_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('route_tables', 'defined') | subelements('route_tables') }}" + when: not item.1.associations[0].main | default(false) + ignore_errors: yes + register: deleted_rtbs + + # Add this after your existing route table deletion + - name: Delete main route tables with AWS CLI + shell: | + for rtb in $(aws ec2 describe-route-tables --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --query 'RouteTables[?Associations[?Main==`true`]].RouteTableId' --output text); do + aws ec2 delete-route --route-table-id $rtb --destination-cidr-block 0.0.0.0/0 --region {{ aws_region }} || true + done + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + loop: "{{ all_vpcs_to_delete }}" + ignore_errors: yes + when: all_vpcs_to_delete | length > 0 + + # STEP 11: Find and delete Subnets + - name: Find subnets for each VPC + amazon.aws.ec2_vpc_subnet_info: + region: "{{ aws_region }}" + filters: + vpc-id: "{{ item.vpc_id }}" + loop: "{{ all_vpcs_to_delete }}" + register: subnet_results + + - name: Delete subnets + amazon.aws.ec2_vpc_subnet: + region: "{{ aws_region }}" + vpc_id: "{{ item.1.vpc_id }}" + cidr: "{{ item.1.cidr_block }}" + state: absent + loop: "{{ subnet_results.results | default([]) | subelements('subnets') }}" + ignore_errors: yes + register: deleted_subnets + when: subnet_results.results is defined + + # STEP 12: Find and delete VPC Endpoints + - name: Find VPC endpoints for each VPC + amazon.aws.ec2_vpc_endpoint_info: + region: "{{ aws_region }}" + filters: + vpc-id: "{{ item.vpc_id }}" + register: endpoint_results + loop: "{{ all_vpcs_to_delete }}" + when: all_vpcs_to_delete | length > 0 + + - name: Delete VPC endpoints + amazon.aws.ec2_vpc_endpoint: + region: "{{ aws_region }}" + vpc_endpoint_id: "{{ item.1.vpc_endpoint_id }}" + state: absent + loop: "{{ endpoint_results.results | default([]) | selectattr('skipped', 'undefined') | selectattr('vpc_endpoints', 'defined') | subelements('vpc_endpoints') }}" + ignore_errors: yes + register: deleted_endpoints + when: endpoint_results.results is defined + + # Add before STEP 13 + - name: Check for remaining VPC dependencies + shell: | + aws ec2 describe-network-interfaces --region {{ aws_region }} --filters "Name=vpc-id,Values={{ item.vpc_id }}" --output json + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + register: remaining_deps + loop: "{{ all_vpcs_to_delete }}" + when: all_vpcs_to_delete | length > 0 + + - name: Display any remaining dependencies + debug: + msg: "VPC {{ item.item.vpc_id }} still has dependencies that need to be removed" + loop: "{{ remaining_deps.results }}" + when: item.stdout | from_json | json_query('NetworkInterfaces') | length > 0 + + # Add this before the force delete of network interfaces + - name: Detach remaining network interfaces + shell: | + aws ec2 detach-network-interface --attachment-id $(aws ec2 describe-network-interfaces --network-interface-ids {{ item.1 }} --query 'NetworkInterfaces[0].Attachment.AttachmentId' --output text) --region {{ aws_region }} --force + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') | + map('attr', 'stdout') | map('from_json') | + map('json_query', 'NetworkInterfaces[?Status==`in-use`].NetworkInterfaceId') | + zip(remaining_deps.results | map('attr', 'item')) | list }}" + ignore_errors: yes + when: item.0 | length > 0 + + - name: Force delete any remaining network interfaces + shell: | + aws ec2 delete-network-interface --network-interface-id {{ item.1 }} --region {{ aws_region }} + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + loop: "{{ remaining_deps.results | selectattr('stdout', 'defined') | + map('attr', 'stdout') | map('from_json') | + map('json_query', 'NetworkInterfaces[].NetworkInterfaceId') | + zip(remaining_deps.results | map('attr', 'item')) | list }}" + ignore_errors: yes + when: item.0 | length > 0 + + # STEP 13: Final VPC deletion with multiple retries + - name: Wait for all dependencies to clear + pause: + seconds: 20 + when: all_vpcs_to_delete | length > 0 + + # First attempt with normal module - with error display + - name: Delete all VPCs (first attempt) + amazon.aws.ec2_vpc_net: + vpc_id: "{{ item.vpc_id }}" + region: "{{ aws_region }}" + state: absent + loop: "{{ all_vpcs_to_delete }}" + register: vpc_deletion + when: all_vpcs_to_delete | length > 0 + ignore_errors: yes + + - name: Display VPC deletion errors + debug: + msg: "Failed to delete VPC {{ item.item.vpc_id }}: {{ item.msg }}" + loop: "{{ vpc_deletion.results | default([]) }}" + when: item.failed is defined and item.failed + + # Direct API call for any VPCs that failed + - name: Find which VPCs still exist + amazon.aws.ec2_vpc_net_info: + region: "{{ aws_region }}" + vpc_ids: "{{ all_vpcs_to_delete | map(attribute='vpc_id') | list }}" + register: remaining_vpcs + when: all_vpcs_to_delete | length > 0 + + # Forcibly delete with direct AWS CLI command + - name: Force delete remaining VPCs with CLI + shell: | + aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }} + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + loop: "{{ remaining_vpcs.vpcs }}" + ignore_errors: yes + when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0 + register: force_vpc_delete + + # Add after the VPC deletion attempts - more aggressive approach + - name: Force delete remaining VPCs with AWS CLI and debug output + shell: | + aws ec2 delete-vpc --vpc-id {{ item.vpc_id }} --region {{ aws_region }} 2>&1 || echo "Failed with: $?" + environment: + AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" + AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" + loop: "{{ remaining_vpcs.vpcs }}" + register: force_vpc_delete_debug + when: remaining_vpcs is defined and remaining_vpcs.vpcs | length > 0 + + - name: Display debug output from force delete + debug: + msg: "{{ item.stdout }}" + loop: "{{ force_vpc_delete_debug.results | default([]) }}" + when: item.stdout is defined and item.stdout | trim != "" + + # Track deleted VPCs in summary + - name: Set VPC deletion results in summary 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: "{{ cleaned_resources.key_pairs | default([]) | select('search', 'c2deploy_' + deployment_id) | list + cleaned_resources.key_pairs | default([]) | select('search', c2_name) | list }}" - 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: "{{ cleaned_resources.route_tables | default([]) }}" - internet_gateways: "{{ cleaned_resources.internet_gateways | default([]) }}" - subnets: "{{ cleaned_resources.subnets | default([]) }}" - network_interfaces: "{{ cleaned_resources.network_interfaces | default([]) }}" - vpcs: "{{ cleaned_resources.vpcs | default([]) }}" - when: not disable_summary | default(false) - - # Display summary of deleted resources + cleanup_summary: "{{ cleanup_summary | combine({ + 'vpcs_deleted': ((vpc_deletion.results | default([]) | selectattr('failed', 'undefined') | list | length) + (force_vpc_delete.results | default([]) | selectattr('failed', 'undefined') | list | length))}) }}" + when: all_vpcs_to_delete | length > 0 + + # Add these tasks to confirm VPC deletion + - name: Verify VPC deletion + amazon.aws.ec2_vpc_net_info: + region: "{{ aws_region }}" + filters: + "tag:deployment_id": "{{ deployment_id }}" + register: vpc_check + - name: Display cleanup summary + debug: + msg: + - "Cleanup Summary:" + - "Redirector instance deleted: {{ redirector_deleted | default('N/A') }}" + - "C2 instance deleted: {{ c2_deleted | default('N/A') }}" + - "VPC resources deleted: {{ vpc_check.vpcs | length == 0 }}" + when: not disable_summary | default(false) + + # STEP 14: Delete key pairs + - name: Find key pairs by name patterns + amazon.aws.ec2_key: + name: "{{ item }}" + region: "{{ aws_region }}" + state: present + register: keys_check + ignore_errors: yes + with_items: + - "{{ redirector_name }}" + - "{{ c2_name }}" + - "{{ tracker_name }}" + + - name: Delete key pairs + amazon.aws.ec2_key: + name: "{{ item.invocation.module_args.name }}" + region: "{{ aws_region }}" + state: absent + loop: "{{ keys_check.results }}" + when: keys_check.results | length > 0 and item.failed is not defined and item.key is defined + register: deleted_keys + + - name: Count deleted keys + set_fact: + cleanup_summary: "{{ cleanup_summary | combine({ + 'keypairs_deleted': (deleted_keys.results | default([]) | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}" + + # Add this after your existing key pair finding task + - name: Find c2deploy key pairs + amazon.aws.ec2_key: + name: "c2deploy_{{ deployment_id }}" + region: "{{ aws_region }}" + state: present + register: c2deploy_key_check + ignore_errors: yes + + - name: Delete c2deploy key pairs + amazon.aws.ec2_key: + name: "c2deploy_{{ deployment_id }}" + region: "{{ aws_region }}" + state: absent + when: not c2deploy_key_check.failed | default(true) + register: deleted_c2deploy_key + + # STEP 15: Delete SSH key files + - name: Delete SSH key files + file: + path: "{{ item }}" + state: absent + with_items: + - "~/.ssh/{{ redirector_name }}.pem" + - "~/.ssh/{{ c2_name }}.pem" + - "~/.ssh/{{ tracker_name }}.pem" + - "~/.ssh/c2deploy_{{ deployment_id }}.pem" # Fix: add .pem extension + - "~/.ssh/c2deploy_{{ deployment_id }}.pub" + ignore_errors: yes + register: deleted_ssh_files + + - name: Count deleted SSH files + set_fact: + cleanup_summary: "{{ cleanup_summary | combine({ + 'ssh_files_deleted': (deleted_ssh_files.results | selectattr('changed', 'defined') | selectattr('changed') | list | length)}) }}" + + # Remove infrastructure state file - fix path to include deployment_id + - name: Remove infrastructure state file + file: + path: "infrastructure_state_{{ deployment_id }}.json" + state: absent + ignore_errors: yes + register: infra_file + + # STEP 16: Enhanced and Accurate Cleanup Summary + - name: Enhanced cleanup summary debug: msg: - "==========================================================" - - "CLEANUP SUMMARY FOR DEPLOYMENT ID: {{ deployment_id }}" + - " AWS CLEANUP SUMMARY: {{ 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 }}" + - "EC2 Instances: {{ cleanup_summary.instances_found | default(0) }} found, {{ terminated_instances.results | default([]) | length }} terminated" + - "Security Groups: {{ cleanup_summary.security_groups_found | default(0) }} found, {{ deleted_sgs.results | default([]) | length }} deleted" + - "Network Interfaces: {{ cleanup_summary.enis_found | default(0) }} found, {{ deleted_enis.results | default([]) | length }} deleted" + - "VPCs: {{ cleanup_summary.vpcs_found | default(0) }} found, {{ cleanup_summary.vpcs_deleted | default(0) }} deleted" + - "Key Pairs: {{ cleanup_summary.keypairs_deleted | default(0) }} deleted" + - "SSH Key Files: {{ cleanup_summary.ssh_files_deleted | default(0) }} deleted" + - "Infrastructure file: {{ 'Removed' if infra_file.changed else 'Not found' }}" - "==========================================================" - when: not disable_summary | default(false) \ No newline at end of file + - "CLEANUP {{ 'COMPLETED' if (cleanup_summary.vpcs_deleted | default(0) == cleanup_summary.vpcs_found | default(0)) else 'PARTIAL - SOME RESOURCES MAY REMAIN' }}" + - "=========================================================" \ No newline at end of file diff --git a/AWS/process_vpc.yml b/AWS/process_vpc.yml index a7e6959..caaf35a 100644 --- a/AWS/process_vpc.yml +++ b/AWS/process_vpc.yml @@ -1,204 +1,14 @@ --- # VPC Cleanup Process with enhanced dependency handling -# Step 1: Network Interfaces -- name: Find network interfaces in VPC {{ vpc_id }} - amazon.aws.ec2_eni_info: - region: "{{ aws_region }}" - filters: - vpc-id: "{{ vpc_id }}" - register: eni_info - failed_when: false - changed_when: false +# Removed detailed cleanup tasks for ENIs, RTs, IGWs, NATs, subnets, SGs to simplify deletion -- name: Delete network interfaces - amazon.aws.ec2_eni: - region: "{{ aws_region }}" - eni_id: "{{ item.id }}" - state: absent - force_detach: true - loop: "{{ eni_info.network_interfaces }}" - register: eni_deleted - ignore_errors: yes - when: eni_info.network_interfaces | length > 0 - -- name: Wait after deleting network interfaces - pause: - seconds: 10 - when: eni_info.network_interfaces | length > 0 - -# Step 2: Route Tables -- name: Find all route tables for VPC {{ vpc_id }} - amazon.aws.ec2_vpc_route_table_info: - region: "{{ aws_region }}" - filters: - vpc-id: "{{ vpc_id }}" - register: rt_info - failed_when: false - changed_when: false - -- name: Process route tables - when: rt_info.route_tables | length > 0 - block: - - name: Delete non-main route tables - amazon.aws.ec2_vpc_route_table: - region: "{{ aws_region }}" - vpc_id: "{{ vpc_id }}" - route_table_id: "{{ item.id }}" - state: absent - loop: "{{ rt_info.route_tables }}" - when: not item.associations or not item.associations[0].main | default(false) - register: deleted_rts - ignore_errors: yes - - - name: Update cleaned route tables - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'route_tables': cleaned_resources.route_tables + [item.id]}, recursive=True) }}" - with_items: "{{ rt_info.route_tables }}" - when: not item.associations or not item.associations[0].main | default(false) - -- name: Wait after deleting route tables - pause: - seconds: 10 - when: rt_info.route_tables | length > 0 - -# Step 3: Internet Gateways -- name: Find internet gateways for VPC {{ vpc_id }} - amazon.aws.ec2_vpc_igw_info: - region: "{{ aws_region }}" - filters: - attachment.vpc-id: "{{ vpc_id }}" - register: igw_info - failed_when: false - changed_when: false - -- name: Process internet gateways - when: igw_info.internet_gateways | length > 0 - block: - - name: Detach internet gateways - amazon.aws.ec2_vpc_igw: - region: "{{ aws_region }}" - vpc_id: "{{ vpc_id }}" - state: absent - register: igw_detached - ignore_errors: yes - - - name: Wait after detaching IGW - pause: - seconds: 15 - when: igw_detached is changed - - - name: Delete internet gateways - amazon.aws.ec2_vpc_igw: - region: "{{ aws_region }}" - igw_id: "{{ item.id }}" - state: absent - loop: "{{ igw_info.internet_gateways }}" - register: deleted_igws - ignore_errors: yes - - - name: Update cleaned internet gateways - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'internet_gateways': cleaned_resources.internet_gateways + [item.id]}, recursive=True) }}" - with_items: "{{ igw_info.internet_gateways }}" - -# Step 4: Subnets -- name: Find subnets for VPC {{ vpc_id }} - amazon.aws.ec2_vpc_subnet_info: - region: "{{ aws_region }}" - filters: - vpc-id: "{{ vpc_id }}" - register: subnet_info - failed_when: false - changed_when: false - -- name: Delete subnets - amazon.aws.ec2_vpc_subnet: +# Step X: Delete VPC directly +- name: Delete VPC {{ vpc_id }} + amazon.aws.ec2_vpc_net: region: "{{ aws_region }}" vpc_id: "{{ vpc_id }}" - cidr: "{{ item.cidr_block }}" state: absent - loop: "{{ subnet_info.subnets }}" - register: deleted_subnets - ignore_errors: true - when: subnet_info.subnets | length > 0 - -- name: Update cleaned subnets - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'subnets': cleaned_resources.subnets + [item.id]}, recursive=True) }}" - with_items: "{{ subnet_info.subnets }}" - when: subnet_info.subnets | length > 0 - -- name: Wait after deleting subnets - pause: - seconds: 15 - when: subnet_info.subnets | length > 0 - -# Step 5: Security Groups (except default) -- name: Find non-default security groups for VPC {{ vpc_id }} - amazon.aws.ec2_security_group_info: - region: "{{ aws_region }}" - filters: - vpc-id: "{{ vpc_id }}" - register: sg_info - failed_when: false - changed_when: false - -- name: Delete non-default security groups - amazon.aws.ec2_security_group: - region: "{{ aws_region }}" - group_id: "{{ item.group_id }}" - state: absent - loop: "{{ sg_info.security_groups }}" - when: item.group_name != 'default' - register: deleted_sgs - ignore_errors: true - -- name: Update cleaned security groups - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'security_groups': cleaned_resources.security_groups + [item.group_id]}, recursive=True) }}" - with_items: "{{ sg_info.security_groups }}" - when: item.group_name != 'default' - -- name: Wait after deleting security groups - pause: - seconds: 15 - when: sg_info.security_groups | length > 0 - -# Step 6: Delete VPC with proper dependencies and retries -- name: Wait longer before trying to delete VPC - pause: - seconds: 30 - -- name: Delete VPC with retries - block: - - name: Delete VPC {{ vpc_id }} - amazon.aws.ec2_vpc_net: - region: "{{ aws_region }}" - vpc_id: "{{ vpc_id }}" - state: absent - register: vpc_delete_result - retries: 5 - delay: 15 - until: vpc_delete_result is success - rescue: - - name: Force check dependencies again if VPC deletion failed - amazon.aws.ec2_vpc_net_info: - region: "{{ aws_region }}" - vpc_ids: - - "{{ vpc_id }}" - register: vpc_check - - - name: Final attempt to delete VPC if it still exists - amazon.aws.ec2_vpc_net: - region: "{{ aws_region }}" - vpc_id: "{{ vpc_id }}" - state: absent - when: vpc_check.vpcs | length > 0 - ignore_errors: true - register: final_vpc_delete - -- name: Update cleaned VPCs - set_fact: - cleaned_resources: "{{ cleaned_resources | combine({'vpcs': cleaned_resources.vpcs + [vpc_id]}, recursive=True) }}" - when: (vpc_delete_result is defined and vpc_delete_result is success) or - (final_vpc_delete is defined and final_vpc_delete is success) \ No newline at end of file + retries: 5 + delay: 15 + register: vpc_delete_result + until: vpc_delete_result is success \ No newline at end of file diff --git a/AWS/redirector.yml b/AWS/redirector.yml index 49bd25e..a4eacc4 100644 --- a/AWS/redirector.yml +++ b/AWS/redirector.yml @@ -14,7 +14,8 @@ instance_type: "{{ aws_instance_type | default('t2.micro') }}" deployment_id: "{{ deployment_id | default('') }}" redirector_name: "{{ redirector_name | default('r-' + deployment_id) }}" - shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}" + # Calculate effective port: use shell_handler_port from vars or default to 8083 + effective_listen_port: "{{ shell_handler_port | default(8083) }}" # Check for shared infrastructure # Only use shared when C2 and redirector are in the same region use_shared_infra: "{{ not (c2_region is defined and redirector_region is defined and c2_region != redirector_region) and not c2_only | default(false) | bool and not redirector_only | default(false) | bool }}" @@ -43,16 +44,37 @@ # Load shared infrastructure state if available - name: Check for shared infrastructure state stat: - path: "infrastructure_state.json" + path: "infrastructure_state_{{ deployment_id }}.json" register: infra_state_file when: use_shared_infra | bool - name: Load shared infrastructure state include_vars: - file: "infrastructure_state.json" + file: "infrastructure_state_{{ deployment_id }}.json" name: shared_infra when: use_shared_infra | bool and infra_state_file.stat.exists | default(false) - + + # After loading shared infrastructure state + - name: Validate shared VPC exists + amazon.aws.ec2_vpc_net_info: + region: "{{ shared_infra.region }}" + vpc_ids: + - "{{ shared_infra.vpc_id }}" + register: vpc_check + when: use_shared_infra | bool and infra_state_file.stat.exists | default(false) + ignore_errors: yes + + - name: Delete stale infrastructure state file + file: + path: "infrastructure_state.json" + state: absent + when: use_shared_infra | bool and vpc_check.vpcs is defined and vpc_check.vpcs | length == 0 + + - name: Disable shared infrastructure when VPC doesn't exist + set_fact: + use_shared_infra: false + when: use_shared_infra | bool and vpc_check.vpcs is defined and vpc_check.vpcs | length == 0 + - name: Set region for redirector from shared infra set_fact: aws_redirector_region: "{{ shared_infra.region | default(aws_region) }}" @@ -148,12 +170,6 @@ redirector_vpc_id: "{{ vpc_result.vpc.id }}" # Store for cleanup reference when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false)) - # Set a random shell handler port if not defined - - name: Set random shell handler port if not defined - set_fact: - shell_handler_port: "{{ 4000 + 59000 | random }}" - when: shell_handler_port is not defined - # Create security group - name: Create security group amazon.aws.ec2_security_group: @@ -167,7 +183,7 @@ - 22 - 80 - 443 - - "{{ shell_handler_port }}" + - "{{ effective_listen_port }}" cidr_ip: 0.0.0.0/0 rules_egress: - proto: -1 @@ -175,6 +191,20 @@ state: present register: security_group + # Save infrastructure state for reuse + - name: Save infrastructure state for reuse + copy: + content: | + { + "vpc_id": "{{ vpc_id }}", + "subnet_id": "{{ subnet_id }}", + "security_group_id": "{{ security_group.group_id }}", + "region": "{{ aws_redirector_region }}", + "deployment_id": "{{ deployment_id }}" + } + dest: "infrastructure_state_{{ deployment_id }}.json" + when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false)) + # Launch the redirector - name: Launch redirector instance amazon.aws.ec2_instance: @@ -215,6 +245,7 @@ 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" + shell_handler_port: "{{ effective_listen_port }}" # Rest of the playbook for configuring the redirector - name: Configure redirector @@ -225,12 +256,21 @@ - vars.yaml vars: c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}" + shell_handler_port: "{{ hostvars['localhost']['effective_listen_port'] }}" # Include the rest of your redirector configuration tasks here tasks: - name: Include common redirector configuration tasks include_tasks: "../tasks/configure_redirector.yml" + - name: Configure shell handler script with listening port + template: + src: "../files/havoc_shell_handler.sh" + dest: "/root/Tools/shell_handler.sh" + mode: 0755 + vars: + listen_port: "{{ effective_listen_port }}" + - name: Print deployment summary debug: msg: diff --git a/Linode/redirector.yml b/Linode/redirector.yml index 2ee240b..58a07e5 100644 --- a/Linode/redirector.yml +++ b/Linode/redirector.yml @@ -128,5 +128,4 @@ - "-------------------------------" - "Redirector IP: {{ ansible_host }}" - "Redirector Domain: {{ redirector_subdomain }}.{{ domain }} (Update DNS A record)" - - "Shell Handler Port: {{ shell_handler_port }}" when: not disable_summary | default(false) \ No newline at end of file diff --git a/deploy.py b/deploy.py index 999311a..fa8c574 100755 --- a/deploy.py +++ b/deploy.py @@ -21,7 +21,7 @@ deployment_id = None # Constants for providers PROVIDERS = ["aws", "linode", "flokinet"] DEFAULT_SSH_USER = { - "aws": "root", + "aws": "kali", "linode": "root", "flokinet": "root" } @@ -375,7 +375,7 @@ def gather_common_parameters(): config['zero_logs'] = input("Enable zero-logs configuration? (y/n) [default: y]: ").lower() != 'n' # Add SSH option that was missing - config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: n]: ").lower() == 'y' + config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: y]: ").lower() == 'y' return config @@ -519,6 +519,14 @@ def execute_deployment(config): print(f"\n{COLORS['RED']}Deployment failed.{COLORS['RESET']}") input("\nPress Enter to return to menu...") + # Clean up shared infrastructure state file if present + try: + state_file = os.path.join(os.getcwd(), 'infrastructure_state.json') + if os.path.exists(state_file): + os.remove(state_file) + logging.info('Removed shared infrastructure state file') + except Exception as e: + logging.warning(f'Failed to remove infra state file: {e}') def generate_random_string(length=8): """Generate a random string of letters and digits.""" @@ -526,8 +534,11 @@ def generate_random_string(length=8): def generate_deployment_id(): """Generate a consistent deployment ID for all resources in this deployment""" - rand_suffix = generate_random_string(6) - return f"{rand_suffix}" + global deployment_id + if not deployment_id: + rand_suffix = generate_random_string(6) + deployment_id = f"{rand_suffix}" + return deployment_id def setup_logging(deployment_id=None): """Set up logging for the deployment""" @@ -864,7 +875,7 @@ def interactive_setup(deployment_id=None): config['tracker_create_pixel'] = input("Create tracking pixel? (y/n) [default: y]: ").lower() != 'n' # Post-deployment options - config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: n]: ").lower() == 'y' + config['ssh_after_deploy'] = input("\nSSH into instance after deployment? (y/n) [default: y]: ").lower() == 'y' # Debug mode config['debug'] = input("Enable debug mode? (y/n) [default: n]: ").lower() == 'y' @@ -1326,6 +1337,8 @@ def deploy_infrastructure(config): logging.error(f"{provider} redirector deployment failed") if redirector_config.get('debug'): logging.error(f"Ansible stderr: {stderr}") +# Run cleanup before returning + cleanup_resources(config, interactive=True) return False # Extract and save redirector IP for C2 configuration @@ -1353,6 +1366,8 @@ def deploy_infrastructure(config): logging.error(f"{provider} C2 server deployment failed") if c2_config.get('debug'): logging.error(f"Ansible stderr: {stderr}") +# Run cleanup before returning + cleanup_resources(config, interactive=True) return False # Extract and save C2 IP for reference @@ -1367,7 +1382,8 @@ def deploy_infrastructure(config): logging.error(traceback.format_exc()) # Clean up any partial resources that were created - cleanup_resources(config, interactive=True) +# Force interactive to False to ensure cleanup runs without prompting when there's an exception + cleanup_resources(config, interactive=False) return False def deploy_flokinet_redirector(config): @@ -2212,7 +2228,7 @@ def main(): if args.provider == "linode": config['ssh_user'] = "root" elif args.provider == "aws": - config['ssh_user'] = "root" + config['ssh_user'] = "kali" else: if hasattr(args, 'ssh_user'): config['ssh_user'] = args.ssh_user or vars_data.get('ssh_user') or DEFAULT_SSH_USER.get(args.provider) diff --git a/tasks/configure_redirector.yml b/tasks/configure_redirector.yml index ba872e4..9c548b8 100644 --- a/tasks/configure_redirector.yml +++ b/tasks/configure_redirector.yml @@ -97,10 +97,12 @@ replace: 'C2_HOST="{{ c2_ip }}"' - name: Configure shell handler script with listening port - replace: - path: /root/Tools/shell-handler/persistent-listener.sh - regexp: 'LISTEN_PORT=4444' - replace: 'LISTEN_PORT={{ shell_handler_port }}' + template: + src: "../files/havoc_shell_handler.sh" + dest: "/root/Tools/shell_handler.sh" + mode: 0755 + vars: + listen_port: "{{ shell_handler_port | default(8083) }}" - name: Create shell handler service template: diff --git a/templates/infrastructure_state.j2 b/templates/infrastructure_state.j2 new file mode 100644 index 0000000..0480c89 --- /dev/null +++ b/templates/infrastructure_state.j2 @@ -0,0 +1,6 @@ +{ + "vpc_id": "{{ infra_state.vpc_id }}", + "subnet_id": "{{ infra_state.subnet_id }}", + "security_group_id": "{{ infra_state.security_group_id }}", + "region": "{{ infra_state.region }}" +} \ No newline at end of file