1. Introducción: La Superficie de Ataque del Kernel
La mayoría de las guías de hardening se quedan en la superficie: configurar firewalls, endurecer SSH, desactivar servicios innecesarios. Son medidas necesarias pero insuficientes. Un adversario sofisticado no ataca tus reglas de iptables; ataca el Kernel Space, donde residen los privilegios absolutos del sistema.
El Kernel Self-Protection Project (KSPP) representa un cambio de paradigma: en lugar de depender exclusivamente de mecanismos externos (antivirus, IDS), reconfiguramos el propio núcleo de Linux para que sea resistente por diseño contra explotación de memoria, escalada de privilegios y ejecución de código arbitrario.
Este manual no utiliza herramientas de terceros. Vamos a modificar cómo el kernel gestiona la memoria, las llamadas al sistema y la ejecución de procesos. El objetivo: crear un sistema inmune a clases enteras de vulnerabilidades, incluyendo exploits de día cero (0-days) que aún no han sido descubiertos.
2. Implementación de KSPP: Configuración del Bootloader
Acción: Modificar parámetros de GRUB
/etc/default/grub y modifica la línea GRUB_CMDLINE_LINUX_DEFAULT:GRUB_CMDLINE_LINUX_DEFAULT="quiet slab_nomerge page_alloc.shuffle=1 vsyscall=none init_on_alloc=1 init_on_free=1 pti=on spectre_v2=on spec_store_bypass_disable=seccomp l1tf=full mds=full,nosmt tsx=off kvm.nx_huge_pages=force"
Análisis de parámetros críticos
| Parámetro | Mecanismo de Protección | Vector de Ataque Mitigado |
|---|---|---|
slab_nomerge | Evita que el kernel fusione cachés de objetos de diferente tamaño | Heap overflow attacks que dependen de manipular cachés adyacentes |
page_alloc.shuffle=1 | Aleatoriza la asignación de páginas de memoria | Ataques de predicción de direcciones de memoria (ASLR bypass) |
vsyscall=none | Deshabilita la emulación de vsyscall legacy | ROP (Return-Oriented Programming) gadgets en memoria fija |
init_on_alloc=1 | Inicializa a cero toda memoria asignada | Uso de datos residuales de kernel previos (information leaks) |
init_on_free=1 | Sobrescribe memoria liberada antes de reasignar | Use-after-free exploits |
pti=on | Aisla las tablas de páginas de kernel y usuario | Meltdown y ataques de lectura de memoria kernel desde userland |
spectre_v2=on | Habilita mitigaciones de branch target injection | Spectre v2 (Branch Target Injection) |
spec_store_bypass_disable=seccomp | Protección contra Speculative Store Bypass | Variant 4 de ataques especulativos |
l1tf=full | Mitigación completa contra L1 Terminal Fault | L1TF (Foreshadow) |
mds=full,nosmt | Protección contra Microarchitectural Data Sampling | RIDL, Fallout, ZombieLoad |
tsx=off | Deshabilita Intel TSX (Transactional Synchronization Extensions) | TAA (TSX Asynchronous Abort) |
kvm.nx_huge_pages=force | Fuerza No-Execute en páginas huge del hipervisor | Ataques de corrupción de memoria en entornos virtualizados |
Aplicar cambios:
sysctl --system
Aplicar cambios grub
sudo update-grub
sudo reboot
Nota para entornos virtualizados: Estos parámetros funcionan tanto en hardware bare-metal como en VMs (KVM, VMware, VirtualBox). El hipervisor emula las protecciones de hardware, permitiéndote probar configuraciones de seguridad extrema sin riesgo para el sistema host.
3. Hardening del Stack de Red: Sysctl Avanzado
Configuración de /etc/sysctl.d/99-security.conf
# === Protección contra spoofing y redirección ===
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# === Prevención de inundaciones y DoS ===
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
net.netfilter.nf_conntrack_max = 2000000
net.netfilter.nf_conntrack_tcp_loose = 0
# === Ocultamiento de información del kernel ===
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.yama.ptrace_scope = 2
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2
# === Protección de memoria ===
vm.mmap_rnd_bits = 32
vm.mmap_rnd_compat_bits = 16
vm.unprivileged_userfaultfd = 0
Explicación técnica de parámetros clave
kernel.kptr_restrict = 2: Oculta las direcciones de memoria de símbolos del kernel incluso para el usuario root. Los exploits de escalada de privilegios a menudo requieren conocer direcciones específicas del kernel para construir gadgets de ROP. Con esta configuración, /proc/kallsyms muestra 0000000000000000 para todos los símbolos del kernel.kernel.yama.ptrace_scope = 2: Limita el uso de ptrace (herramienta de debugging) solo a procesos con capacidad CAP_SYS_PTRACE. Esto bloquea técnicas comunes de inyección de código y dumping de credenciales desde procesos comprometidos.vm.unprivileged_userfaultfd = 0: Deshabilita userfaultfd para usuarios no privilegiados. Esta syscall ha sido explotada en múltiples vulnerabilidades (como la cadena de exploit de DirtyPipe) para manipular la gestión de memoria del kernel.Aplicación de configuraciones
sudo sysctl --system
4. Control de Ejecución: Seccomp y Capabilities
Concepto: Reducción de superficie de ataque por syscall
execve, el proceso no puede lanzar nuevos programas. Si eliminamos openat, no puede abrir archivos arbitrarios.Práctica: Perfil Seccomp para Nginx
/etc/nginx/seccomp-bpf.json{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86"],
"syscalls": [
{
"names": [
"accept", "accept4", "bind", "clone", "close", "connect",
"epoll_create", "epoll_create1", "epoll_ctl", "epoll_pwait",
"epoll_wait", "eventfd2", "exit", "exit_group", "fchdir",
"fchmod", "fchown", "fcntl", "fstat", "fstatfs", "fsync",
"ftruncate", "getcwd", "getdents", "getdents64", "getegid",
"geteuid", "getgid", "getpgrp", "getpid", "getppid", "getrlimit",
"getuid", "ioctl", "io_setup", "listen", "lseek", "mkdir",
"mmap", "mprotect", "munmap", "nanosleep", "openat", "pipe",
"pipe2", "poll", "pread64", "pselect6", "pwrite64", "read",
"recvfrom", "recvmsg", "rename", "rmdir", "rt_sigaction",
"rt_sigprocmask", "rt_sigreturn", "select", "sendfile",
"sendmsg", "sendto", "setitimer", "setrlimit", "setsockopt",
"shutdown", "sigaltstack", "socket", "socketpair", "stat",
"statfs", "sysinfo", "umask", "uname", "unlink", "utimensat",
"write", "writev"
],
"action": "SCMP_ACT_ALLOW"
},
{
"names": ["execve", "execveat", "fork", "vfork"],
"action": "SCMP_ACT_KILL"
}
]
}
Integración con Systemd
/etc/systemd/system/nginx.service.d/override.conf):[Service]
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID
Análisis de protecciones
-
SystemCallFilter=@system-service: Utiliza el conjunto predefinido de syscalls seguras para servicios de sistema. -
NoNewPrivileges=true: Previene que el proceso gane privilegios adicionales (bloquea setuid binaries). -
ProtectSystem=strict: Monta el sistema de archivos raíz como solo lectura e inaccesible para el servicio. -
MemoryDenyWriteExecute=true: Activa W^X (Write XOR Execute), previniendo que la memoria sea simultáneamente escribible y ejecutable (mitigación contra shellcode).
sudo systemctl daemon-reload
sudo systemctl restart nginx
Ejemplo plantillas Seccomp-BPF para Servicios Comunes
Crear directorio y archivo
sudo mkdir -p /etc/seccomp
sudo vi /etc/seccomp/profiles.json
/etc/seccomp/profiles.json (formato compatible con Docker, containerd, systemd y runc){
"profiles": {
"nginx-web-server": {
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_AARCH64"
],
"syscalls": [
{
"names": [
"accept", "accept4", "access", "alarm", "bind", "brk",
"capget", "capset", "chdir", "chmod", "chown", "clock_gettime",
"clone", "clone3", "close", "close_range", "connect", "copy_file_range",
"creat", "dup", "dup2", "dup3", "epoll_create", "epoll_create1",
"epoll_ctl", "epoll_pwait", "epoll_pwait2", "epoll_wait", "eventfd2",
"execve", "execveat", "exit", "exit_group", "faccessat", "faccessat2",
"fadvise64", "fallocate", "fanotify_mark", "fchdir", "fchmod",
"fchmodat", "fchown", "fchownat", "fcntl", "fdatasync", "fgetxattr",
"flistxattr", "flock", "fork", "fremovexattr", "fsetxattr", "fstat",
"fstatfs", "fsync", "ftruncate", "futex", "getcwd", "getdents",
"getdents64", "getegid", "geteuid", "getgid", "getgroups",
"getitimer", "getpeername", "getpgid", "getpgrp", "getpid",
"getppid", "getpriority", "getrandom", "getresgid", "getresuid",
"getrlimit", "getrusage", "getsid", "getsockname", "getsockopt",
"gettid", "gettimeofday", "getuid", "getxattr", "inotify_add_watch",
"inotify_init1", "inotify_rm_watch", "io_cancel", "io_destroy",
"io_getevents", "io_setup", "io_submit", "ioctl", "ioprio_get",
"ioprio_set", "kcmp", "kill", "lchown", "lgetxattr", "link",
"linkat", "listen", "listxattr", "llistxattr", "lremovexattr",
"lseek", "lsetxattr", "lstat", "madvise", "memfd_create",
"mincore", "mkdir", "mkdirat", "mknod", "mknodat", "mlock",
"mlock2", "mlockall", "mmap", "mprotect", "mq_getsetattr",
"mq_notify", "mq_open", "mq_timedreceive", "mq_timedsend",
"mq_unlink", "mremap", "msgctl", "msgget", "msgrcv", "msgsnd",
"msync", "munlock", "munlockall", "munmap", "nanosleep",
"newfstatat", "open", "openat", "openat2", "pause", "pipe",
"pipe2", "poll", "ppoll", "prctl", "pread64", "preadv",
"preadv2", "prlimit64", "pselect6", "pwrite64", "pwritev",
"pwritev2", "read", "readahead", "readdir", "readlink",
"readlinkat", "readv", "recv", "recvfrom", "recvmmsg",
"recvmsg", "remap_file_pages", "removexattr", "rename",
"renameat", "renameat2", "restart_syscall", "rmdir", "rseq",
"rt_sigaction", "rt_sigpending", "rt_sigprocmask", "rt_sigqueueinfo",
"rt_sigreturn", "rt_sigsuspend", "rt_sigtimedwait", "rt_tgsigqueueinfo",
"sched_getaffinity", "sched_getattr", "sched_getparam",
"sched_get_priority_max", "sched_get_priority_min", "sched_getscheduler",
"sched_rr_get_interval", "sched_setaffinity", "sched_setattr",
"sched_setparam", "sched_setscheduler", "sched_yield", "seccomp",
"select", "semctl", "semget", "semop", "semtimedop", "send",
"sendfile", "sendmmsg", "sendmsg", "sendto", "setfsgid", "setfsuid",
"setgid", "setgroups", "setitimer", "setpgid", "setpriority",
"setregid", "setresgid", "setresuid", "setreuid", "setrlimit",
"setsid", "setsockopt", "setuid", "setxattr", "shmat", "shmctl",
"shmdt", "shmget", "shutdown", "sigaltstack", "signalfd4",
"socket", "socketpair", "splice", "stat", "statfs", "statx",
"symlink", "symlinkat", "sync", "sync_file_range", "syncfs",
"sysinfo", "tee", "tgkill", "time", "timer_create", "timer_delete",
"timer_getoverrun", "timer_gettime", "timer_settime", "timerfd_create",
"timerfd_gettime", "timerfd_settime", "times", "tkill", "truncate",
"umask", "uname", "unlink", "unlinkat", "utime", "utimensat",
"utimes", "vfork", "wait4", "waitid", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
},
{
"names": [
"bpf",
"clock_adjtime",
"clock_settime",
"create_module",
"delete_module",
"finit_module",
"get_kernel_syms",
"get_mempolicy",
"init_module",
"ioperm",
"iopl",
"kexec_file_load",
"kexec_load",
"keyctl",
"lookup_dcookie",
"mbind",
"nfsservctl",
"open_by_handle_at",
"perf_event_open",
"personality",
"pivot_root",
"process_vm_readv",
"process_vm_writev",
"ptrace",
"query_module",
"quotactl",
"reboot",
"request_key",
"set_mempolicy",
"setns",
"settimeofday",
"stime",
"swapoff",
"swapon",
"_sysctl",
"syslog",
"tuxcall",
"umount2",
"uselib",
"userfaultfd",
"ustat",
"vm86",
"vm86old"
],
"action": "SCMP_ACT_KILL"
}
]
},
"database-server": {
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": [
"accept", "accept4", "access", "bind", "brk", "capget", "capset",
"chdir", "chmod", "chown", "clock_gettime", "clone", "clone3",
"close", "connect", "creat", "dup", "dup2", "dup3", "epoll_create",
"epoll_create1", "epoll_ctl", "epoll_pwait", "epoll_wait", "eventfd2",
"execve", "exit", "exit_group", "faccessat", "fadvise64", "fallocate",
"fchdir", "fchmod", "fchmodat", "fchown", "fchownat", "fcntl",
"fdatasync", "flock", "fork", "fstat", "fstatfs", "fsync", "ftruncate",
"futex", "getcwd", "getdents", "getdents64", "getegid", "geteuid",
"getgid", "getgroups", "getitimer", "getpeername", "getpgrp", "getpid",
"getppid", "getpriority", "getrandom", "getresgid", "getresuid",
"getrlimit", "getrusage", "getsockname", "getsockopt", "gettid",
"gettimeofday", "getuid", "ioctl", "kill", "link", "linkat", "listen",
"lseek", "lstat", "madvise", "mkdir", "mkdirat", "mknod", "mknodat",
"mlock", "mlockall", "mmap", "mprotect", "mq_getsetattr", "mq_notify",
"mq_open", "mq_timedreceive", "mq_timedsend", "mq_unlink", "mremap",
"msync", "munlock", "munlockall", "munmap", "nanosleep", "newfstatat",
"open", "openat", "pause", "pipe", "pipe2", "poll", "ppoll", "prctl",
"pread64", "preadv", "prlimit64", "pselect6", "pwrite64", "pwritev",
"read", "readahead", "readlink", "readlinkat", "readv", "recv",
"recvfrom", "recvmmsg", "recvmsg", "rename", "renameat", "renameat2",
"rmdir", "rt_sigaction", "rt_sigpending", "rt_sigprocmask",
"rt_sigqueueinfo", "rt_sigreturn", "rt_sigsuspend", "rt_sigtimedwait",
"sched_getaffinity", "sched_getattr", "sched_getparam",
"sched_get_priority_max", "sched_get_priority_min", "sched_getscheduler",
"sched_rr_get_interval", "sched_setaffinity", "sched_setattr",
"sched_setparam", "sched_setscheduler", "sched_yield", "select",
"semctl", "semget", "semop", "semtimedop", "send", "sendfile",
"sendmmsg", "sendmsg", "sendto", "setfsgid", "setfsuid", "setgid",
"setgroups", "setitimer", "setpgid", "setpriority", "setregid",
"setresgid", "setresuid", "setreuid", "setrlimit", "setsid",
"setsockopt", "setuid", "shmat", "shmctl", "shmdt", "shmget",
"shutdown", "sigaltstack", "signalfd4", "socket", "socketpair",
"splice", "stat", "statfs", "sync", "sync_file_range", "syncfs",
"sysinfo", "tee", "tgkill", "time", "timer_create", "timer_delete",
"timer_getoverrun", "timer_gettime", "timer_settime", "timerfd_create",
"timerfd_gettime", "timerfd_settime", "times", "tkill", "truncate",
"umask", "uname", "unlink", "unlinkat", "utime", "utimensat",
"utimes", "vfork", "wait4", "waitid", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
},
{
"names": ["execveat", "ptrace", "process_vm_readv", "process_vm_writev",
"userfaultfd", "perf_event_open", "bpf", "mount", "umount2"],
"action": "SCMP_ACT_KILL"
}
]
},
"minimal-microservice": {
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": [
"accept", "accept4", "bind", "brk", "capget", "capset", "chdir",
"chmod", "clock_gettime", "clone", "clone3", "close", "connect",
"creat", "dup", "dup2", "dup3", "epoll_create", "epoll_create1",
"epoll_ctl", "epoll_pwait", "epoll_wait", "eventfd2", "exit",
"exit_group", "faccessat", "fadvise64", "fallocate", "fchdir",
"fchmod", "fchmodat", "fchown", "fchownat", "fcntl", "fdatasync",
"flock", "fstat", "fstatfs", "fsync", "ftruncate", "futex", "getcwd",
"getdents", "getdents64", "getegid", "geteuid", "getgid", "getgroups",
"getitimer", "getpeername", "getpgrp", "getpid", "getppid",
"getpriority", "getrandom", "getresgid", "getresuid", "getrlimit",
"getrusage", "getsockname", "getsockopt", "gettid", "gettimeofday",
"getuid", "ioctl", "listen", "lseek", "lstat", "madvise", "mkdir",
"mkdirat", "mmap", "mprotect", "mremap", "munmap", "nanosleep",
"newfstatat", "open", "openat", "pipe", "pipe2", "poll", "ppoll",
"pread64", "preadv", "prlimit64", "pselect6", "pwrite64", "pwritev",
"read", "readahead", "readlink", "readlinkat", "readv", "recv",
"recvfrom", "recvmmsg", "recvmsg", "rename", "renameat", "renameat2",
"rmdir", "rt_sigaction", "rt_sigpending", "rt_sigprocmask",
"rt_sigreturn", "rt_sigsuspend", "rt_sigtimedwait", "sched_getaffinity",
"sched_getattr", "sched_getparam", "sched_get_priority_max",
"sched_get_priority_min", "sched_getscheduler", "sched_rr_get_interval",
"sched_setaffinity", "sched_setattr", "sched_setparam",
"sched_setscheduler", "sched_yield", "select", "send", "sendfile",
"sendmmsg", "sendmsg", "sendto", "setfsgid", "setfsuid", "setgid",
"setgroups", "setitimer", "setpgid", "setpriority", "setregid",
"setresgid", "setresuid", "setreuid", "setrlimit", "setsid",
"setsockopt", "setuid", "shutdown", "sigaltstack", "signalfd4",
"socket", "socketpair", "splice", "stat", "statfs", "sync",
"sync_file_range", "syncfs", "sysinfo", "tee", "tgkill", "time",
"timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
"timer_settime", "timerfd_create", "timerfd_gettime", "timerfd_settime",
"times", "tkill", "truncate", "umask", "uname", "unlink", "unlinkat",
"utime", "utimensat", "utimes", "wait4", "waitid", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
},
{
"names": ["execve", "execveat", "fork", "vfork", "ptrace", "mount",
"umount2", "chroot", "pivot_root", "setns", "unshare"],
"action": "SCMP_ACT_KILL"
}
]
}
}
}
Archivo: /usr/local/bin/apply-seccomp.sh
#!/bin/bash
# Aplica perfiles seccomp a servicios systemd
PROFILE=$1
SERVICE=$2
if [[ -z "$PROFILE" || -z "$SERVICE" ]]; then
echo "Uso: $0 <nginx-web-server|database-server|minimal-microservice> <nombre-servicio>"
exit 1
fi
# Crear directorios necesarios si no existen
mkdir -p /var/log/nginx /var/lib/nginx /var/cache/nginx /run/nginx
mkdir -p /etc/systemd/system/${SERVICE}.service.d/
cat > /etc/systemd/system/${SERVICE}.service.d/seccomp.conf << EOF
[Service]
# 1. Primero: definir rutas de lectura/escritura
ReadWritePaths=/var/log/nginx /var/lib/nginx /var/cache/nginx /run/nginx
# 2. Luego: protecciones de sistema
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
# 3. Restricciones de seguridad
NoNewPrivileges=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
# 4. Filtro de syscalls
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
EOF
systemctl daemon-reload
systemctl restart $SERVICE
echo "Perfil seccomp aplicado a $SERVICE"
Damos permisos y ejecutamos el script
chmod +x /usr/local/bin/apply-seccomp.sh
/usr/local/bin/apply-seccomp.sh nginx-web-server nginx
Perfil seccomp aplicado a nginx
Comprobamos que el servicio
root@srvlhm01:~# systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Drop-In: /etc/systemd/system/nginx.service.d
└─seccomp.conf
Active: active (running) since Fri 2026-02-13 17:49:06 UTC; 45s ago
Docs: man:nginx(8)
Process: 753 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 754 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 755 (nginx)
Tasks: 3 (limit: 4700)
Memory: 2.4M
CPU: 129ms
CGroup: /system.slice/nginx.service
├─755 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
├─756 "nginx: worker process"
└─757 "nginx: worker process"
Como modificar Script para Nuevo Servicio
Agregar caso en apply-seccomp.sh:
#!/bin/bash
PROFILE=$1
SERVICE=$2
# Crear directorios específicos del servicio
case "$SERVICE" in
nginx)
mkdir -p /var/log/nginx /var/lib/nginx /var/cache/nginx /run/nginx
READWRITE="/var/log/nginx /var/lib/nginx /var/cache/nginx /run/nginx"
;;
mysql|mariadb)
mkdir -p /var/log/mysql /var/lib/mysql /var/run/mysqld /tmp
READWRITE="/var/log/mysql /var/lib/mysql /var/run/mysqld /tmp"
;;
postgresql)
mkdir -p /var/log/postgresql /var/lib/postgresql /var/run/postgresql /tmp
READWRITE="/var/log/postgresql /var/lib/postgresql /var/run/postgresql /tmp"
;;
redis)
mkdir -p /var/log/redis /var/lib/redis /var/run/redis /tmp
READWRITE="/var/log/redis /var/lib/redis /var/run/redis /tmp"
;;
*)
echo "Servicio no configurado. Usando rutas genéricas."
READWRITE="/var/log/$SERVICE /var/lib/$SERVICE /var/run/$SERVICE /tmp"
mkdir -p $READWRITE
;;
esac
mkdir -p /etc/systemd/system/${SERVICE}.service.d/
cat > /etc/systemd/system/${SERVICE}.service.d/seccomp.conf << EOF
[Service]
ReadWritePaths=$READWRITE
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
NoNewPrivileges=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
EOF
systemctl daemon-reload
systemctl restart $SERVICE
echo "Perfil seccomp aplicado a $SERVICE"
Gestión de Excepciones
Cuando un Servicio Falla
Paso 1: Verificar error específico
journalctl -xeu SERVICIO --no-pager -n 50
Paso 2: Identificar tipo de error
| Error | Causa | Solución |
|---|---|---|
Read-only file system | Falta directorio en ReadWritePaths | Añadir ruta |
No such file or directory + NAMESPACE | Directorio no existe | mkdir -p antes |
Operation not permitted | Syscall bloqueada | Revisar SystemCallFilter |
Permission denied | Capabilities insuficientes | Ajustar CapabilityBoundingSet |
/etc/systemd/system/SERVICIO.service.d/seccomp.conf:[Service]
# Añadir excepción de ruta
ReadWritePaths=/var/log/nginx /var/lib/nginx /var/cache/nginx /run/nginx /NUEVA/RUTA
# O añadir capability específica
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_NUEVA
# O relajar SystemCallFilter para syscalls específicas
SystemCallFilter=@system-service personality # añadir syscall al allowlist
Paso 4: Recargar y reiniciar
systemctl daemon-reload
systemctl restart SERVICIO
Ejemplos Prácticos
MySQL/MariaDB
/usr/local/bin/apply-seccomp.sh database-server mysql
Excepciones típicas:
/var/lib/mysql– Datos/var/log/mysql– Logs/var/run/mysqld– Socket/tmp– Temporales
Capability adicional:
CapabilityBoundingSet=CAP_IPC_LOCK # Para bloquear memoria con mlock
PostgreSQL
/usr/local/bin/apply-seccomp.sh database-server postgresql
/var/lib/postgresql/var/log/postgresql/var/run/postgresql
Redis
/usr/local/bin/apply-seccomp.sh minimal-microservice redis
Excepciones:
/var/lib/redis/var/log/redis/var/run/redis
Verificación de Funcionamiento
# Verificar que el servicio está activo
systemctl status SERVICIO
# Verificar que las restricciones están aplicadas
systemctl show SERVICIO --property=ProtectSystem,ProtectHome,NoNewPrivileges,MemoryDenyWriteExecute
# Verificar syscalls bloqueadas (auditar denegaciones)
dmesg | grep -i "audit.*seccomp\|syscall"
grep -E "CONFIG_IMA|CONFIG_IMA_APPRAISE|CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY" /boot/config-$(uname -r)
5. Auditoría de Integridad: AIDE (Advanced Intrusion Detection Environment)
Requisitos de la Raíz de Confianza (Root of Trust)
-
Almacenamiento seguro: La base de datos de AIDE debe guardarse en medio de solo lectura o sistema de archivos remoto inmutable
-
Kernel hardening: Las protecciones KSPP previenen la modificación de AIDE en tiempo de ejecución
-
Monitoreo: Integración con SIEM para alertas en tiempo real de modificaciones críticas
Verificación del Soporte e Instalación
# Instalación en Debian/Ubuntu
sudo apt update && sudo apt install -y aide aide-common
# Verificar instalación
aide --version
Configuración de AIDE
/etc/aide/aide.conf# === CONFIGURACIÓN BASE ===
database_in=file:/var/lib/aide/aide.db
database_out=file:/var/lib/aide/aide.db.new
database_new=file:/var/lib/aide/aide.db.new
gzip_dbout=yes
verbose=5
# === REGLAS DE DEFINICIÓN ===
# Atributos a monitorear:
# p: permisos
# i: inode
# n: número de enlaces
# u: usuario
# g: grupo
# s: tamaño
# b: bloques
# m: mtime
# a: atime
# c: ctime
# S: checksum SHA256
# sha256: hash SHA256 completo
# Binarios críticos - monitoreo estricto
Binlib = p+u+g+s+b+m+c+sha256
# Archivos de configuración - detectar modificaciones
ConfFiles = p+u+g+s+b+m+c+sha256
# Logs - solo permisos y ownership (cambian frecuentemente)
Logs = p+u+g
# Directorios - estructura básica
Dirs = p+u+g
# === RUTAS A MONITOREAR ===
# Directorios de sistema críticos
/boot Binlib
/bin Binlib
/sbin Binlib
/lib Binlib
/lib64 Binlib
/usr/bin Binlib
/usr/sbin Binlib
/usr/lib Binlib
/usr/lib64 Binlib
# Archivos de configuración críticos
/etc ConfFiles
!/etc/mtab
!/etc/resolv.conf
!/etc/hdparam
!/etc/udev/devices
!/etc/network/run
!/etc/network/interfaces
!/etc/network/if-*
!/etc/network/if-*/.*
!/etc/puppet/ssl
!/etc/rc*.d
!/etc/init.d
!/etc/cron.d
!/etc/cron.daily
!/etc/cron.hourly
!/etc/cron.weekly
!/etc/cron.monthly
!/etc/logrotate.d
!/etc/logrotate.status
!/etc/prelink.cache
# Kernel y módulos
/lib/modules Binlib
/usr/src Binlib
# Archivos de servicios críticos
/usr/local/bin Binlib
/opt Binlib
# Exclusiones para reducir ruido
!/var/log/.*
!/var/cache/.*
!/var/tmp/.*
!/var/spool/.*
!/var/run/.*
!/var/lock/.*
!/proc
!/sys
!/dev
!/run
!/tmp
!/home
!/root/.bash_history
!/root/.lesshst
!/root/.viminfo
Inicialización de la Base de Datos
# Crear directorio para la base de datos
sudo mkdir -p /var/lib/aide
sudo chmod 700 /var/lib/aide
# Inicializar base de datos (primera vez - toma tiempo)
sudo aideinit
# El comando anterior crea /var/lib/aide/aide.db.new
# Mover a ubicación definitiva
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
sudo chmod 600 /var/lib/aide/aide.db
# Verificar que se creó correctamente
ls -la /var/lib/aide/
Verificación y Chequeos Manuales
# Verificar integridad del sistema contra la base de datos
sudo aide --check
# Actualizar base de datos después de cambios legítimos
sudo aide --update
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Automatización con Cron
Archivo: /etc/cron.d/aide-check
# Verificación diaria de integridad a las 3:00 AM
0 3 * * * root /usr/bin/aide --check | mail -s "AIDE Check $(hostname)" root@localhost
# Actualización semanal de la base de datos (domingos a las 2:00 AM)
0 2 * * 0 root /usr/bin/aide --update && mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Integración con Systemd para Alertas en Tiempo Real
Archivo: /etc/systemd/system/aide-check.service
[Unit]
Description=AIDE Integrity Check
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/aide --check
StandardOutput=journal
StandardError=journal
/etc/systemd/system/aide-check.timer[Unit]
Description=Run AIDE check every hour
Requires=aide-check.service
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
Activar timer:
sudo systemctl daemon-reload
sudo systemctl enable aide-check.timer
sudo systemctl start aide-check.timer
Configuración de GRUB con Soporte para AIDE
Dado que AIDE opera en espacio de usuario, no requiere parámetros especiales de kernel. Sin embargo, mantenemos el hardening KSPP:
GRUB_CMDLINE_LINUX_DEFAULT="quiet slab_nomerge page_alloc.shuffle=1 vsyscall=none pti=on spectre_v2=on spec_store_bypass_disable=seccomp l1tf=full mds=full,nosmt tsx=off net.ifnames=0 biosdevname=0"
sudo update-grub
sudo reboot
Verificación del Funcionamiento
# Verificar que AIDE está instalado
which aide
aide --version
# Verificar base de datos
ls -la /var/lib/aide/aide.db
# Ejecutar chequeo manual
sudo aide --check
# Ver logs de systemd si usas timer
journalctl -u aide-check.service --no-pager -n 20
Script de Configuración Automatizada para Servidores Web
Archivo: aide-setup-webserver.sh
#!/bin/bash
# AIDE Setup for Web Servers
# Configura AIDE para servidores web con monitoreo específico
set -euo pipefail
AIDE_DIR="/var/lib/aide"
CONF_DIR="/etc/aide"
LOG_DIR="/var/log/aide"
KEYS_DIR="/etc/keys/aide"
log() {
echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $1"
}
error() {
echo "[ERROR] $1" >&2
exit 1
}
check_aide_support() {
if ! command -v aide &> /dev/null; then
log "Instalando AIDE..."
apt-get update && apt-get install -y aide aide-common || \
yum install -y aide || \
pacman -S aide
fi
if ! command -v aide &> /dev/null; then
error "No se pudo instalar AIDE"
fi
log "AIDE instalado: $(aide --version | head -1)"
}
setup_directories() {
mkdir -p "$AIDE_DIR" "$CONF_DIR" "$LOG_DIR" "$KEYS_DIR"
chmod 700 "$AIDE_DIR" "$KEYS_DIR"
chmod 755 "$CONF_DIR" "$LOG_DIR"
log "Directorios creados"
}
create_custom_config() {
log "Creando configuración personalizada para servidor web..."
cat > "${CONF_DIR}/aide-web.conf" << 'EOF'
# AIDE Configuration for Web Servers
database_in=file:/var/lib/aide/aide.db
database_out=file:/var/lib/aide/aide.db.new
database_new=file:/var/lib/aide/aide.db.new
gzip_dbout=yes
verbose=5
# Definiciones de reglas
Binlib = p+u+g+s+b+m+c+sha256
ConfFiles = p+u+g+s+b+m+c+sha256
WebFiles = p+u+g+s+b+m+c+sha256
Logs = p+u+g
# Sistema base
/boot Binlib
/bin Binlib
/sbin Binlib
/lib Binlib
/lib64 Binlib
/usr/bin Binlib
/usr/sbin Binlib
/usr/lib Binlib
/usr/lib64 Binlib
# Configuración del sistema
/etc ConfFiles
# Servidores web específicos
/etc/nginx ConfFiles
/etc/apache2 ConfFiles
/etc/httpd ConfFiles
/etc/php ConfFiles
/usr/share/nginx Binlib
/usr/share/apache2 Binlib
/var/www WebFiles
/var/www/html WebFiles
/var/www/cgi-bin WebFiles
# Aplicaciones web comunes
/opt/lampp Binlib
/usr/local/lampp Binlib
# Exclusiones
!/var/log/.*
!/var/cache/.*
!/var/tmp/.*
!/var/spool/.*
!/var/run/.*
!/var/lock/.*
!/proc
!/sys
!/dev
!/run
!/tmp
!/home
!/root/.bash_history
!/root/.lesshst
!/root/.viminfo
!/var/lib/aide
!/var/log/aide
EOF
chmod 644 "${CONF_DIR}/aide-web.conf"
log "Configuración creada en ${CONF_DIR}/aide-web.conf"
}
initialize_database() {
log "Inicializando base de datos AIDE..."
if [[ -f "${AIDE_DIR}/aide.db" ]]; then
log "Base de datos existente encontrada. ¿Regenerar? (s/N)"
read -r response
if [[ ! "$response" =~ ^[Ss]$ ]]; then
return
fi
backup_file="${AIDE_DIR}/aide.db.backup.$(date +%Y%m%d%H%M%S)"
cp "${AIDE_DIR}/aide.db" "$backup_file"
log "Backup creado: $backup_file"
fi
aide --config="${CONF_DIR}/aide-web.conf" --init
if [[ -f "${AIDE_DIR}/aide.db.new" ]]; then
mv "${AIDE_DIR}/aide.db.new" "${AIDE_DIR}/aide.db"
chmod 600 "${AIDE_DIR}/aide.db"
log "Base de datos inicializada correctamente"
else
error "No se pudo crear la base de datos"
fi
}
setup_cron_jobs() {
log "Configurando cron jobs..."
# Script de chequeo con notificación
cat > /usr/local/bin/aide-check-wrapper.sh << 'EOF'
#!/bin/bash
# Wrapper para AIDE con logging y alertas
LOG_FILE="/var/log/aide/aide-check-$(date +%Y%m%d-%H%M%S).log"
REPORT_FILE="/var/log/aide/aide-report-$(date +%Y%m%d-%H%M%S).txt"
echo "=== AIDE Check Started: $(date) ===" > "$LOG_FILE"
# Ejecutar chequeo
aide --config=/etc/aide/aide-web.conf --check > "$REPORT_FILE" 2>&1
RESULT=$?
if [ $RESULT -eq 0 ]; then
echo "AIDE check completed: No changes detected" >> "$LOG_FILE"
logger -t aide "Integrity check passed - no changes"
else
echo "AIDE check completed: CHANGES DETECTED" >> "$LOG_FILE"
echo "See report: $REPORT_FILE" >> "$LOG_FILE"
logger -t aide "ALERT: Integrity check failed - changes detected"
# Enviar alerta (personalizar según infraestructura)
if command -v mail &> /dev/null; then
mail -s "AIDE ALERT: Changes detected on $(hostname)" root@localhost < "$REPORT_FILE"
fi
# Opcional: Integración con Slack/Discord/webhook
# curl -X POST -H 'Content-type: application/json' \
# --data '{"text":"AIDE Alert: Changes detected on '$(hostname)'"}' \
# YOUR_WEBHOOK_URL
fi
# Mantener solo los últimos 30 días de logs
find /var/log/aide -name "aide-check-*.log" -mtime +30 -delete
find /var/log/aide -name "aide-report-*.txt" -mtime +30 -delete
exit $RESULT
EOF
chmod +x /usr/local/bin/aide-check-wrapper.sh
# Cron job para chequeo diario
echo "0 3 * * * root /usr/local/bin/aide-check-wrapper.sh" > /etc/cron.d/aide-web-check
log "Cron jobs configurados"
}
create_status_script() {
cat > /usr/local/bin/aide-status << 'EOF'
#!/bin/bash
# AIDE Status Checker
echo "=== AIDE Status Report ==="
echo "Fecha: $(date)"
echo ""
if command -v aide &> /dev/null; then
echo "AIDE está instalado"
aide --version | head -1
echo ""
if [[ -f /var/lib/aide/aide.db ]]; then
echo "Base de datos: $(ls -lh /var/lib/aide/aide.db | awk '{print $5, $6, $7, $8}')"
echo "Última modificación: $(stat -c %y /var/lib/aide/aide.db)"
else
echo "ADVERTENCIA: No se encontró base de datos"
fi
echo ""
echo "Últimos chequeos:"
ls -lt /var/log/aide/aide-check-*.log 2>/dev/null | head -5 | awk '{print $6, $7, $8, $9}'
echo ""
echo "Para ejecutar chequeo manual: sudo aide --config=/etc/aide/aide-web.conf --check"
echo "Para actualizar base de datos: sudo aide --config=/etc/aide/aide-web.conf --update"
else
echo "AIDE NO está instalado"
fi
EOF
chmod +x /usr/local/bin/aide-status
log "Script de verificación creado: /usr/local/bin/aide-status"
}
create_emergency_script() {
cat > /usr/local/bin/aide-emergency << 'EOF'
#!/bin/bash
# AIDE Emergency Procedures
echo "=== AIDE Emergency Tools ==="
echo ""
case "$1" in
update)
echo "Actualizando base de datos AIDE..."
aide --config=/etc/aide/aide-web.conf --update
if [[ -f /var/lib/aide/aide.db.new ]]; then
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
echo "Base de datos actualizada"
fi
;;
compare)
echo "Comparando con backup..."
if [[ -f /var/lib/aide/aide.db.backup.* ]]; then
latest=$(ls -t /var/lib/aide/aide.db.backup.* | head -1)
echo "Comparando con: $latest"
# Nota: AIDE no soporta comparación directa de DBs, se requiere exportar
echo "Use: aide --config=/etc/aide/aide-web.conf --check"
else
echo "No se encontraron backups"
fi
;;
reset)
echo "REINICIALIZANDO BASE DE DATOS AIDE..."
echo "¿Estás seguro? Esto eliminará la base actual. (yes/no)"
read -r confirm
if [[ "$confirm" == "yes" ]]; then
rm -f /var/lib/aide/aide.db
aide --config=/etc/aide/aide-web.conf --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
echo "Base de datos reinicializada"
else
echo "Operación cancelada"
fi
;;
*)
echo "Uso: $0 {update|compare|reset}"
echo ""
echo " update - Actualizar base de datos después de cambios legítimos"
echo " compare - Intentar comparar con backup (manual)"
echo " reset - Reinicializar base de datos (¡PELIGROSO!)"
;;
esac
EOF
chmod +x /usr/local/bin/aide-emergency
log "Script de emergencia creado: /usr/local/bin/aide-emergency"
}
main() {
echo "=========================================="
echo " AIDE Setup for Web Servers"
echo "=========================================="
echo ""
echo "ADVERTENCIA: Este script configura AIDE para"
echo "monitoreo de integridad de archivos."
echo "Asegúrate de tener snapshots antes de continuar."
echo ""
echo "¿Continuar? (s/N)"
read -r confirm
if [[ ! "$confirm" =~ ^[Ss]$ ]]; then
log "Operación cancelada"
exit 0
fi
check_aide_support
setup_directories
create_custom_config
initialize_database
setup_cron_jobs
create_status_script
create_emergency_script
echo ""
echo "=========================================="
log "Configuración AIDE completada"
echo ""
echo "PRÓXIMOS PASOS:"
echo "1. Verificar estado con: /usr/local/bin/aide-status"
echo "2. Ejecutar chequeo manual: sudo aide --config=/etc/aide/aide-web.conf --check"
echo "3. Revisar logs en: /var/log/aide/"
echo ""
echo "IMPORTANTE:"
echo "- La base de datos debe almacenarse en medio de solo lectura"
echo "- Configurar notificaciones en /usr/local/bin/aide-check-wrapper.sh"
echo "- Programar actualizaciones de DB después de actualizaciones del sistema"
echo "=========================================="
}
main "$@"
Archivo complementario: aide-emergency-fix.sh
#!/bin/bash
# AIDE Emergency Procedures - Usar si hay demasiados falsos positivos
echo "=== AIDE Emergency Tools ==="
case "$1" in
log-only)
echo "Cambiando a modo solo-log (sin alertas)..."
sed -i 's/verbose=5/verbose=1/' /etc/aide/aide-web.conf
systemctl stop aide-check.timer 2>/dev/null || true
echo "AIDE configurado para logging mínimo"
;;
restore)
echo "Restaurando configuración normal..."
sed -i 's/verbose=1/verbose=5/' /etc/aide/aide-web.conf
systemctl start aide-check.timer 2>/dev/null || true
echo "AIDE restaurado"
;;
disable)
echo "Deshabilitando chequeos automáticos..."
systemctl disable aide-check.timer 2>/dev/null || true
systemctl stop aide-check.timer 2>/dev/null || true
rm -f /etc/cron.d/aide-web-check
echo "Chequeos automáticos deshabilitados"
;;
*)
echo "Uso: $0 {log-only|restore|disable}"
echo ""
echo " log-only - Reducir verbosidad temporalmente"
echo " restore - Restaurar configuración normal"
echo " disable - Detener todos los chequeos automáticos"
;;
esac
Instrucciones de Uso Rápido
# 1. Preparar entorno (VM recomendada)
sudo apt update && sudo apt install -y aide aide-common
# 2. Ejecutar hardening de GRUB
chmod +x kspp-grub-hardening.sh
sudo ./kspp-grub-hardening.sh
# 3. Configurar AIDE (antes de reiniciar)
chmod +x aide-setup-webserver.sh
sudo ./aide-setup-webserver.sh
# 4. Aplicar seccomp a servicios
chmod +x apply-seccomp.sh
sudo ./apply-seccomp.sh nginx-web-server nginx
# 5. Reiniciar y verificar
sudo reboot
# Después del reinicio:
sudo /usr/local/bin/aide-status
sudo aide --config=/etc/aide/aide-web.conf --check
6. Análisis y Gestión de Entropía
Un sistema criptográficamente seguro depende de la calidad de su generador de números aleatorios (RNG). En entornos virtualizados, la entropía es frecuentemente insuficiente porque las VMs carecen de fuentes de ruido hardware (interrupciones de disco, variaciones térmicas, etc.).
Diagnóstico de entropía
Verifica el estado actual:
cat /proc/sys/kernel/random/entropy_avail
# Valor ideal: > 3000
# En VMs recién iniciadas: frecuentemente < 1000
Configuración avanzada
Archivo: /etc/default/haveged
DAEMON_ARGS="-w 1024 -v 1"
# -w 1024: Mantener reserva de 1024 bits de entropía
# -v 1: Nivel de verbosidad para logging
Verificación post-implementación
# Monitoreo continuo de entropía
watch -n 1 cat /proc/sys/kernel/random/entropy_avail
# Prueba de calidad del RNG
rngtest -c 1000 < /dev/random
Alternativa: VirtIO-RNG (entornos virtualizados)
Si tu hipervisor lo soporta (KVM/QEMU), utiliza el generador de entropía del host:
# Verificar dispositivo virtio-rng
ls /sys/devices/virtual/misc/hw_random/rng_available
# Debe mostrar "virtio_rng.0"
# Configurar como fuente primaria
sudo rngd -r /dev/hwrng
Impacto en el hardening
La baja entropía compromete:
- Generación de claves SSH/TLS (claves predecibles)
- ASLR efectivo (direcciones de memoria predecibles)
- Nonces criptográficos (ataques de repetición)
Con haveged o virtio-rng, garantizamos que el sistema tiene suficiente aleatoriedad para mantener la efectividad de todas las mitigaciones anteriores.
Arquitectura de Defensa en Profundidad
Este manual ha implementado un hardening estructural que opera en múltiples capas:Table
| Capa | Mecanismo | Protección |
|---|---|---|
| Arranque | Parámetros de kernel KSPP | Invariantes de seguridad antes del espacio de usuario |
| Memoria | Aleatorización, aislamiento | Prevención de corrupción y explotación |
| Red | Sysctl hardening | Filtrado estricto y ocultamiento de información |
| Proceso | Seccomp + Capabilities | Reducción de syscalls y superficie de ataque |
| Integridad | AIDE | Detección de modificaciones no autorizadas |
| Criptográfica | Entropía garantizada | Operaciones seguras de RNG |
El resultado es un sistema donde:
- Un exploit de buffer overflow en Nginx no puede ejecutar shellcode (W^X, seccomp)
- Un atacante con acceso root deja trazas detectables (AIDE monitoreando binarios críticos)
- Un proceso comprometido no puede escalar privilegios (kptr_restrict, yama)
- La ejecución de código arbitrario es prevenida por diseño, no solo por parches
- Las modificaciones no autorizadas son detectadas y alertadas (AIDE + logging centralizado)
Diferencias Clave: IMA vs AIDE
| Característica | IMA (Integrity Measurement Architecture) | AIDE (Advanced Intrusion Detection Environment) |
|---|---|---|
| Nivel de operación | Kernel space | User space |
| Verificación | En tiempo real, bloquea ejecución | Periódica, detecta post-modificación |
| Requisitos kernel | CONFIG_IMA_APPRAISE, firmas en binarios | Ninguno especial |
| Riesgo de bloqueo | Kernel panic si falta firma | Solo alertas, no bloquea |
| Complejidad | Alta (MOK, firmas, initramfs) | Media (configuración de reglas) |
| Uso de recursos | Bajo (integrado en kernel) | Moderado (escaneos periódicos) |
| Detección de rootkits | Limitada (solo binarios firmados) | Completa (todos los archivos monitoreados) |
| Ideal para | Sistemas críticos de alta seguridad | Servidores web, detección de intrusiones |
-
Se necesita flexibilidad en la gestión de actualizaciones
-
No se puede arriesgar la disponibilidad del sistema
-
Se requiere detección de cambios en configuraciones, no solo binarios
-
El equipo de seguridad necesita auditoría forense post-incidente
:wq!