98103466d8
Sanitized version of red team infrastructure automation platform. Operational content (implant pipelines, lures, credential capture) replaced with documented stubs. Architecture and infrastructure automation code intact.
205 lines
7.4 KiB
YAML
Executable File
205 lines
7.4 KiB
YAML
Executable File
---
|
|
# Linode C2 Deployment Playbook
|
|
|
|
- name: Deploy Linode C2 server
|
|
hosts: localhost
|
|
gather_facts: false
|
|
connection: local
|
|
vars_files:
|
|
- vars.yaml
|
|
vars:
|
|
# Default values for required variables
|
|
linode_region: "{{ linode_region | default(region_choices | random) }}"
|
|
plan: "{{ plan | default('g6-standard-2') }}"
|
|
# Use static value to avoid recursive templating
|
|
c2_image_static: "linode/kali"
|
|
|
|
# Generate random instance name if not provided
|
|
c2_name: "{{ c2_name | default('node-' + 9999999999 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
|
|
|
|
tasks:
|
|
- name: Validate required Linode token
|
|
assert:
|
|
that:
|
|
- linode_token is defined and linode_token != ""
|
|
fail_msg: "Linode API token is required. Set linode_token in vars.yaml or via --linode-token."
|
|
|
|
# Replace these tasks at the beginning of the playbook
|
|
- name: Set region for C2 server
|
|
set_fact:
|
|
c2_region_value: "{{ selected_region | default(linode_region, true) | default('us-east', true) }}"
|
|
|
|
- name: Display region selection information for debugging
|
|
debug:
|
|
msg:
|
|
- "Selected Region: {{ selected_region | default('Not set') }}"
|
|
- "Linode Region: {{ linode_region | default('Not set') }}"
|
|
- "Using Region: {{ c2_region_value }}"
|
|
when: debug | default(false) | bool
|
|
|
|
- name: Set random region only if absolutely no region specified
|
|
set_fact:
|
|
c2_region_value: "{{ region_choices | random }}"
|
|
when: region_choices is defined and region_choices|length > 0 and not selected_region is defined and not linode_region is defined and not c2_region_value is defined
|
|
|
|
- name: Create C2 Linode instance
|
|
block:
|
|
- name: Try creating instance in specified region
|
|
community.general.linode_v4:
|
|
access_token: "{{ linode_token }}"
|
|
label: "{{ c2_name }}"
|
|
type: "{{ plan }}"
|
|
region: "{{ c2_region_value }}"
|
|
image: "linode/kali"
|
|
root_pass: "{{ lookup('password', '/dev/null length=16') }}"
|
|
authorized_keys:
|
|
- "{{ lookup('file', ssh_key_path) }}"
|
|
state: present
|
|
register: c2_instance
|
|
rescue:
|
|
- name: Log region restriction error
|
|
debug:
|
|
msg: "Region {{ c2_region_value }} is restricted. Trying fallback regions..."
|
|
|
|
- name: Set fallback regions (most reliable ones first)
|
|
set_fact:
|
|
fallback_regions:
|
|
- "us-east"
|
|
- "us-central"
|
|
- "eu-west"
|
|
- "us-west"
|
|
|
|
- name: Try fallback regions
|
|
community.general.linode_v4:
|
|
access_token: "{{ linode_token }}"
|
|
label: "{{ c2_name }}"
|
|
type: "{{ plan }}"
|
|
region: "{{ item }}"
|
|
image: "linode/kali"
|
|
root_pass: "{{ lookup('password', '/dev/null length=16') }}"
|
|
authorized_keys:
|
|
- "{{ lookup('file', ssh_key_path) }}"
|
|
state: present
|
|
register: c2_instance
|
|
loop: "{{ fallback_regions }}"
|
|
when: c2_instance is not defined or c2_instance.failed
|
|
ignore_errors: yes
|
|
|
|
- name: Update deployment region with successful fallback
|
|
set_fact:
|
|
c2_region_value: "{{ item }}"
|
|
loop: "{{ fallback_regions }}"
|
|
when: c2_instance.results is defined and c2_instance.results[ansible_loop.index0] is defined and not c2_instance.results[ansible_loop.index0].failed
|
|
|
|
- name: Fail if all regions are restricted
|
|
fail:
|
|
msg: "All attempted regions are restricted. Please try again later or contact Linode support."
|
|
when: c2_instance.failed | default(true)
|
|
|
|
- name: Set c2_ip for later use
|
|
block:
|
|
- name: Extract instance info from direct creation
|
|
set_fact:
|
|
c2_ip: "{{ c2_instance.instance.ipv4[0] }}"
|
|
c2_instance_id: "{{ c2_instance.instance.id }}"
|
|
when: c2_instance.instance is defined
|
|
|
|
- name: Extract instance info from fallback creation
|
|
set_fact:
|
|
c2_ip: "{{ item.instance.ipv4[0] }}"
|
|
c2_instance_id: "{{ item.instance.id }}"
|
|
loop: "{{ c2_instance.results | default([]) }}"
|
|
when: c2_instance.results is defined and item.instance is defined and not item.failed
|
|
|
|
- name: Display final C2 deployment region and IP
|
|
debug:
|
|
msg: "C2 server deployed successfully in region {{ c2_region_value }} with IP {{ c2_ip }}"
|
|
|
|
# Enhanced SSH wait task for Linode/c2.yml
|
|
- name: Wait for C2 SSH to be available
|
|
block:
|
|
- name: Initial wait for port to be open
|
|
wait_for:
|
|
host: "{{ c2_instance.instance.ipv4[0] }}"
|
|
port: 22
|
|
delay: 60
|
|
timeout: 180
|
|
state: started
|
|
|
|
- name: Additional pause for SSH initialization
|
|
pause:
|
|
seconds: 60
|
|
|
|
- name: Test SSH connection
|
|
command: >
|
|
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10
|
|
-i {{ ssh_key_path | replace('.pub', '') }} root@{{ c2_instance.instance.ipv4[0] }} echo "SSH Ready"
|
|
register: ssh_test
|
|
retries: 5
|
|
delay: 20
|
|
until: ssh_test.rc == 0
|
|
ignore_errors: yes
|
|
|
|
- name: Fail if SSH test unsuccessful
|
|
fail:
|
|
msg: "Could not connect to C2 server via SSH after multiple attempts"
|
|
when: ssh_test.rc != 0
|
|
|
|
- name: Add C2 to inventory
|
|
add_host:
|
|
name: "c2"
|
|
groups: "c2servers"
|
|
ansible_host: "{{ c2_ip }}"
|
|
ansible_user: "root"
|
|
ansible_ssh_private_key_file: "{{ ssh_key_path | replace('.pub', '') }}"
|
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
|
|
ansible_python_interpreter: "/usr/bin/python3" # Use remote system's Python
|
|
|
|
- name: Configure C2 server
|
|
hosts: c2servers
|
|
become: true
|
|
gather_facts: true
|
|
vars_files:
|
|
- vars.yaml
|
|
vars:
|
|
redirector_ip: "{{ hostvars['localhost']['redirector_ip'] | default('127.0.0.1') }}"
|
|
c2_subdomain: "{{ c2_subdomain | default('mail') }}"
|
|
tasks:
|
|
- name: Wait for apt to be available
|
|
apt:
|
|
update_cache: yes
|
|
register: apt_result
|
|
until: apt_result is success
|
|
retries: 5
|
|
delay: 10
|
|
|
|
- name: Disable root password authentication for SSH immediately
|
|
lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: '^#?PasswordAuthentication'
|
|
line: 'PasswordAuthentication no'
|
|
state: present
|
|
|
|
- name: Restart SSH service to apply changes
|
|
service:
|
|
name: ssh
|
|
state: restarted
|
|
|
|
- name: Include common tool installation tasks
|
|
include_tasks: "../../common/tasks/install_tools.yml"
|
|
|
|
- name: Include common C2 configuration tasks
|
|
include_tasks: "../../modules/c2/tasks/configure_c2.yml"
|
|
|
|
- name: Include common mail server configuration tasks
|
|
include_tasks: "../../common/tasks/configure_mail.yml"
|
|
|
|
- name: Print deployment summary
|
|
debug:
|
|
msg:
|
|
- "C2 Server Deployment Complete!"
|
|
- "-----------------------------"
|
|
- "C2 Server IP: {{ ansible_host }}"
|
|
- "C2 Server Domain: {{ domain }}"
|
|
- "GoPhish Admin Port: {{ gophish_admin_port }}"
|
|
when: not disable_summary | default(false) |