PHP Classes

File: ids/ssh.sh

Recommend this page to a friend!
  Packages of Moises Espindola   Sentinela   ids/ssh.sh   Download  
File: ids/ssh.sh
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Sentinela
Linux protection tools with Web dashboard panel
Author: By
Last change:
Date: 6 days ago
Size: 4,884 bytes
 

Contents

Class file image Download
#!/usr/bin/env bash #============================================================================= # Sentinela ? Intelligent Linux Security Framework # ids/ssh.sh ? Detección de ataques de fuerza bruta SSH #============================================================================= # # Analiza /var/log/auth.log en busca de: # - Múltiples intentos fallidos de SSH # - Conexiones desde IPs sospechosas # - Usuarios inexistentes # - Tiempos entre intentos (for Brute Force timing) #============================================================================= # shellcheck source=lib/common.sh source "${SENTINELA_DIR}/lib/common.sh" #============================================================================= # Variables de estado #============================================================================= SSH_BRUTE_THRESHOLD="${SSH_BRUTE_THRESHOLD:-5}" # Intentos fallidos antes de ban SSH_BRUTE_WINDOW="${SSH_BRUTE_WINDOW:-300}" # Ventana en segundos (5 min) #============================================================================= # Leer nuevas líneas del log SSH # Soporta rsyslog (tail -c) y journald (journalctl --after-cursor) #============================================================================= ssh_read_new_lines() { log_read_new_lines "ssh_auth" } #============================================================================= # Detectar fuerza bruta SSH #============================================================================= ssh_brute_force_detect() { if ! log_check_exists "ssh_auth"; then return 0 fi local new_lines new_lines=$(ssh_read_new_lines) || return 0 if [[ -z "${new_lines}" ]]; then return 0 fi # Cache de intentos por IP (formato: IP:timestamp) local fail_cache="${SENTINELA_DIR}/logs/.ssh_fail_cache" [[ -f "${fail_cache}" ]] || touch "${fail_cache}" local now now=$(date +%s) while IFS= read -r line; do [[ -z "${line}" ]] && continue # Detectar intentos fallidos if echo "${line}" | grep -qiP '(Failed password|authentication failure|Connection closed by.*\[preauth\]|Invalid user|Connection reset by peer)'; then local ip="" local user="" # Extraer IP ip=$(echo "${line}" | grep -oP 'from \K[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || echo "") if [[ -z "${ip}" ]]; then ip=$(echo "${line}" | grep -oP '\b[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b' | head -1 || echo "") fi # Extraer usuario user=$(echo "${line}" | grep -oP 'for \K[a-zA-Z0-9_.-]+' | head -1 || echo "unknown") if [[ -z "${ip}" ]] || ! is_valid_ip "${ip}"; then continue fi # Actualizar cache de intentos local entry entry=$(grep "^${ip} " "${fail_cache}" 2>/dev/null || true) if [[ -n "${entry}" ]]; then local count last_time last_time=$(echo "${entry}" | awk '{print $2}') count=$(echo "${entry}" | awk '{print $3}') if (( now - last_time < SSH_BRUTE_WINDOW )); then count=$((count + 1)) sed -i "s/^${ip} .*/${ip} ${now} ${count}/" "${fail_cache}" 2>/dev/null || true # Si supera el threshold, banear if (( count >= SSH_BRUTE_THRESHOLD )); then log_attack "SSH_BRUTE|${ip}|${count} intentos fallidos (último user: ${user})" source "${SENTINELA_DIR}/firewall/blacklist.sh" blacklist_add "${ip}" "ssh_bruteforce: ${count} intentos" # Resetear contador sed -i "s/^${ip} .*/${ip} ${now} 0/" "${fail_cache}" 2>/dev/null || true # Telegram alert if [[ "${TELEGRAM_ENABLE}" == "yes" ]]; then source "${SENTINELA_DIR}/telegram/telegram.sh" telegram_send_alert "${ip}" "ssh_bruteforce" \ "Fuerza bruta SSH: ${count} intentos (usuario: ${user})" \ "" "" "" "SSH" fi fi else # Resetear (ventana expiró) sed -i "s/^${ip} .*/${ip} ${now} 1/" "${fail_cache}" 2>/dev/null || true fi else echo "${ip} ${now} 1" >> "${fail_cache}" 2>/dev/null || true fi fi done <<< "${new_lines}" # Limpiar cache antiguo (> 1h) local cleanup_cutoff=$((now - 3600)) awk -v cutoff="${cleanup_cutoff}" '$2 >= cutoff' "${fail_cache}" > "${fail_cache}.tmp" 2>/dev/null || true mv "${fail_cache}.tmp" "${fail_cache}" 2>/dev/null || true return 0 }