#!/usr/bin/env bash
#=============================================================================
# Sentinela ? Intelligent Linux Security Framework
# ids/apache.sh ? Detección de ataques en logs de Apache
#=============================================================================
#
# Analiza logs de Apache en busca de patrones maliciosos.
# Los logs se procesan incrementalmente (desde la última posición leída).
#=============================================================================
# shellcheck source=lib/common.sh
source "${SENTINELA_DIR}/lib/common.sh"
#=============================================================================
# Leer nuevas líneas del log de Apache
# Soporta rsyslog (tail -c) y journald (journalctl --after-cursor)
#=============================================================================
apache_read_new_lines() {
log_read_new_lines "apache_access"
}
#=============================================================================
# Detectar ataques en una línea de log de Apache
#=============================================================================
apache_analyze_line() {
local line="$1"
local ip="$2"
# Extraer User-Agent (entre comillas dobles al final)
local ua=""
ua=$(echo "${line}" | grep -oP '"([^"]*)"$' | tr -d '"' || echo "")
# Extraer URI (path)
local uri=""
uri=$(echo "${line}" | grep -oP '"(GET|POST|PUT|DELETE|HEAD|OPTIONS|PATCH)\s+\K[^"]+' | awk '{print $1}' || echo "")
# Extraer método HTTP
local method=""
method=$(echo "${line}" | grep -oP '"(GET|POST|PUT|DELETE|HEAD|OPTIONS|PATCH)' | tr -d '"' || echo "")
# Extraer status code
local status=""
status=$(echo "${line}" | awk '{print $(NF-1)}' || echo "")
echo "${ua}|||${uri}|||${method}|||${status}"
}
#=============================================================================
# Escanear log de Apache en busca de ataques
#=============================================================================
apache_scan() {
if ! log_check_exists "apache_access"; then
log_debug "Log de Apache no disponible (sistema: ${LOG_SYSTEM})"
return 0
fi
local new_lines
new_lines=$(apache_read_new_lines) || return 0
if [[ -z "${new_lines}" ]]; then
return 0
fi
local attack_count=0
while IFS= read -r line; do
[[ -z "${line}" ]] && continue
# Extraer IP (primer campo)
local ip
ip=$(echo "${line}" | awk '{print $1}')
# Validar IP
if ! is_valid_ip "${ip}"; then
continue
fi
# Analizar línea
local parsed
parsed=$(apache_analyze_line "${line}" "${ip}")
local ua="${parsed%%|||*}"
local rest="${parsed#*|||}"
local uri="${rest%%|||*}"
local rest2="${rest#*|||}"
local method="${rest2%%|||*}"
local status="${rest2#*|||}"
# Detectar ataques
local attack_type=""
local attack_reason=""
# SQL Injection
if echo "${uri}" | grep -qiP '(union.*select|select.*from|insert.*into|delete.*from|drop.*table|exec.*xp_cmdshell|information_schema|sleep\(|benchmark\(|0x[0-9a-f]{8,}|--[^-]|/\*!\||%27|%2527|%%27)'; then
attack_type="sqli"
attack_reason="SQL Injection detectado en URI"
fi
# XSS
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(alert\(|script>|<script|<img.*onerror|onload=|javascript:|<svg|eval\(|document\.cookie|fromCharCode)'; then
attack_type="xss"
attack_reason="XSS detectado en URI"
fi
# LFI
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(\.\./\.\./|/etc/passwd|/proc/self|/proc/1/environ|php://filter|php://input|data://|expect://)'; then
attack_type="lfi"
attack_reason="LFI detectado en URI"
fi
# RFI
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(https?://[^\s&]+\.(php|txt|cmd|sh|pl|py))'; then
attack_type="rfi"
attack_reason="RFI detectado en URI"
fi
# Command Injection
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(\|cat\s|\|bash\s|\|sh\s|`[a-z]|;\s*whoami|;\s*id\s|;\s*uname\s|;\s*cat\s|;\s*curl\s|;\s*wget\s)'; then
attack_type="command_injection"
attack_reason="Command Injection detectado en URI"
fi
# Path Traversal
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(\.\./){2,}|\.\.\\\.\.\\|/\.\./|\\\.\.\\|file:///etc)'; then
attack_type="path_traversal"
attack_reason="Path Traversal detectado en URI"
fi
# Scanners (archivos de configuración expuestos)
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(/\.env|/wp-config\.php|/config\.php|/config\.json|/admin\.php|/phpmyadmin|/pma|/mysql|/sqladmin|/administrator|/backup|/db_backup|/\.git/|/\.svn/|/crossdomain\.xml|/clientaccesspolicy\.xml|/server-status|/server-info|/actuator|/actuator/health|/swagger|/api/swagger|/graphql|/console)'; then
attack_type="scanner"
attack_reason="Scanner detectado (archivo/configuración sensible)"
fi
# Scanners de CMS
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(/wp-admin|/wp-content|/wp-includes|/wp-json|/xmlrpc\.php|/joomla|/Joomla|/drupal|/Drupal|/magento|/Magento|/wordpress|/WordPress)'; then
attack_type="scanner"
attack_reason="Scanner de CMS detectado"
fi
# Tool detection por User-Agent
if [[ -z "${attack_type}" ]] && echo "${ua}" | grep -qiP '(sqlmap|nikto|nmap|masscan|zgrab|acunetix|burpsuite|burp scanner|wpscan|joomscan|droopescan|w3af|openvas|nessus|netsparker|appscan|gobuster|dirbuster|dirsearch|wfuzz|ffuf|hydra|medusa|THC|arachni|whatweb)'; then
attack_type="tool"
attack_reason="Herramienta de ataque detectada (User-Agent): ${ua}"
fi
# DDoS detection
if [[ -z "${attack_type}" ]] && echo "${ua}" | grep -qiP '(Go-http-client|Python-urllib|Python-requests|Java/|okhttp|HttpClient|HTTP Client|axios|node-fetch|curl/\d|Wget/|perl|ruby|libwww)'; then
attack_type="scanner"
attack_reason="Cliente automatizado detectado (User-Agent): ${ua}"
fi
# Log4Shell
if [[ -z "${attack_type}" ]] && echo "${uri}" | grep -qiP '(\$\{jndi:|\$\{log4j:|\$\{env:|\$\{sys:|\$\{::-|\$\{lower:)'; then
attack_type="log4shell"
attack_reason="Log4Shell detectado en URI"
fi
# XXE
if [[ -z "${attack_type}" ]] && echo "${line}" | grep -qiP '(<!DOCTYPE.*\[|<!ENTITY\s+|SYSTEM\s+"file:)'; then
attack_type="xxe"
attack_reason="XXE detectado"
fi
# Si se detectó un ataque
if [[ -n "${attack_type}" ]]; then
attack_count=$((attack_count + 1))
log_attack "Apache|${ip}|${attack_type}|${attack_reason}|${uri}|${ua}"
# Banear IP
source "${SENTINELA_DIR}/firewall/blacklist.sh"
blacklist_add "${ip}" "${attack_type}: ${attack_reason}"
# Enviar alerta Telegram
if [[ "${TELEGRAM_ENABLE}" == "yes" ]]; then
source "${SENTINELA_DIR}/telegram/telegram.sh"
telegram_send_alert "${ip}" "${attack_type}" "${attack_reason}" "${uri}" "${ua}" "${method}" "Apache"
fi
fi
done <<< "${new_lines}"
if [[ "${attack_count}" -gt 0 ]]; then
log_info "Apache scan: ${attack_count} ataques detectados"
fi
return 0
}
|