
Escáner de malware para Linux con múltiples motores y cinco etapas de detección (MD5, patrón HEX, YARA, ClamAV, estadística), monitorización inotify en tiempo real, cuarentena y alertas multicanal.
Escáner de malware para Linux — detección de amenazas de múltiples etapas (MD5, SHA-256, HEX, YARA, análisis estadístico), integración con ClamAV, monitorización en tiempo real con inotify, operaciones de cuarentena/limpieza/restauración y alertas multicanal (correo electrónico, Slack, Telegram, Discord).
(C) 2002-2026, R-fx Networks <[email protected]>
(C) 2026, Ryan MacDonald <[email protected]>
Con licencia GNU GPL v2
Motor de escaneo nativo 43 veces más rápido — la canalización de escaneo nativa se ha reescrito por completo con procesamiento paralelo por lotes. Prueba comparativa real con ~10,000 archivos:
| Versión | Tiempo | Archivos | Aciertos |
|---|---|---|---|
| v1.6.6 | 1,217s | 9,931 | 35 |
| v2.0.1 | 28s | 9,931 | 35 |
El emparejamiento de firmas MD5 y HEX ahora usa grep por lotes con trabajadores paralelos Aho-Corasick, eliminando la sobrecarga de compilación de patrones por archivo y ~500,000 bifurcaciones (forks) de subprocesos por escaneo. Configure el número de trabajadores paralelos con scan_workers (predeterminado: auto).
Otras novedades: gestión del ciclo de vida del escaneo (--kill, --pause, --stop/--continue, -L), escaneo de hash SHA-256 con detección automática de hardware de CPU (scan_hashtype), escaneo YARA nativo (scan_yara=1), alertas por webhook de Discord, correcciones en alertas de Slack/Telegram, soporte de comodines HEX de ClamAV en el motor nativo y más de 200 correcciones de errores en todo el código.
Consulte CHANGELOG para más detalles.
./install.sh
maldet -a /home/?/public_html
maldet -r /home/?/public_html 2
maldet -co scan_yara=1 -a /home/?/public_html
maldet -q SCANID
maldet -m users
maldet -u
---
## 1. Introducción
Arquitectura de LMD, etapas de detección y plataformas compatibles.
Linux Malware Detect (LMD) es un escáner de malware para Linux publicado bajo la licencia GNU GPLv2, diseñado en torno a las amenazas presentes en entornos de alojamiento compartido. Utiliza datos de amenazas procedentes de sistemas de detección de intrusiones en el perímetro de la red para extraer malware que se utiliza activamente en ataques y genera firmas para su detección. Además, los datos de amenazas se obtienen de los envíos de los usuarios mediante la función de checkout de LMD y de recursos de la comunidad de malware.
LMD se centra en las clases de malware que los productos antivirus tradicionales suelen pasar por alto: shells PHP, inyectores JavaScript, backdoors codificados en base64, bots de IRC y otras amenazas de la capa de aplicación web que atacan las cuentas de usuario del alojamiento compartido en lugar de los componentes internos del sistema operativo.
**Etapas de detección**
- Coincidencia de hash MD5 de archivos para la identificación exacta de amenazas
- Coincidencia de patrones HEX mediante el motor grep nativo por lotes con trabajadores en paralelo
- Escaneo de firmas compuestas (csig) con lógica booleana de múltiples patrones (AND/OR/umbral), coincidencia sin distinción de mayúsculas/minúsculas, coincidencia ancha (UTF-16LE) y comodines con espacio acotado
- Escaneo nativo de reglas YARA con soporte completo de módulos y reglas personalizadas
- Análisis estadístico de longitud de cadenas para detectar amenazas ofuscadas (base64, gzinflate)
- Integración con ClamAV para una cobertura ampliada con firmas de ClamAV mantenidas por LMD
**Escaneo y monitorización**
- Escaneo de todos los archivos, archivos modificados recientemente o archivos de una lista
- Monitorización de archivos en tiempo real mediante inotify del kernel (eventos de creación/modificación/movimiento)
- Escaneo de subidas HTTP mediante el hook `inspectFile` de ModSecurity2
- Escaneo en segundo plano para operaciones a gran escala sin supervisión
- Filtrado por expresión regular de inclusión/exclusión por escaneo
**Cuarentena y respuesta**
- Cola de cuarentena con almacenamiento de archivos sin permisos
- Cuarentena/restauración por lotes por ID de escaneo
- Reglas de limpieza específicas por firma para la eliminación de malware
- Restauración completa de archivos (contenido, propietario, permisos, mtime)
**Alertas e informes**
- Alertas por correo electrónico en HTML y texto con diseño rfxn unificado (marca verde azulado, entradas tipo tarjeta)
- Soporte de relay SMTP (TLS/SSL) para entornos sin MTA local
- Alertas por entrada con Slack Block Kit, Telegram MarkdownV2 y Discord embed
- Plantillas de alerta personalizables mediante overrides de `alert/custom.d/`
- Informes de escaneo con detalles de coincidencias por archivo y tipos de coincidencia codificados por colores
**Infraestructura**
- Enlazado automático de firmas de ClamAV para cobertura de doble motor
- Cron diario con detección automática de más de 12 paneles de control de alojamiento
- Control de recursos de CPU/IO (nice, ionice, cpulimit)
- Actualizaciones automáticas de firmas y versión
- Soporte de unidad de servicio systemd y script de inicio SysV
### Plataformas compatibles
LMD se ejecuta en cualquier distribución de Linux con bash y utilidades GNU estándar. Plataformas probadas:
| Plataforma | Sistema de inicio | Ruta de configuración del paquete |
|----------|-------------|---------------------|
| RHEL / Rocky / AlmaLinux 8, 9, 10 | systemd | `/etc/sysconfig/maldet` |
| CentOS 6, 7 | SysV / systemd | `/etc/sysconfig/maldet` |
| Debian 10, 11, 12 | systemd | `/etc/default/maldet` |
| Ubuntu 20.04, 22.04, 24.04 | systemd | `/etc/default/maldet` |
| Gentoo | OpenRC | — |
| Slackware | SysV | — |
| FreeBSD | — | — (parcial; sin inotify) |
---
## 2. Instalación
Instalación, actualización y eliminación de LMD de un sistema.
El script `install.sh` incluido se encarga de todas las tareas de instalación. Las instalaciones anteriores se respaldan automáticamente.```bash
./install.sh
El instalador:
/usr/local/maldetectmaldet en /usr/local/sbin//etc/cron.daily/maldetconf.maldet), las firmas personalizadas y los archivos de exclusión entre actualizacionesLas instalaciones anteriores se guardan en /usr/local/maldetect.bk{PID} con un enlace simbólico maldetect.last a la copia de seguridad más reciente.
Rutas por defecto:
/usr/local/maldetect/usr/local/sbin/maldet/etc/cron.daily/maldet/usr/lib/systemd/system/maldet.serviceTodos los ajustes visibles para el usuario y sus valores predeterminados. Consulta man maldet(1) para la referencia completa.
El archivo de configuración principal es /usr/local/maldetect/conf.maldet. Todas las opciones están comentadas para facilitar la configuración. Las opciones usan 0/1 para deshabilitar/habilitar, salvo que se indique lo contrario.
La configuración también se puede anular en tiempo de ejecución con la opción -co:```bash
maldet -co quarantine_hits=1,email_addr=[email protected] -a /home
### 3.1 Opciones Generales
| Variable | Propósito | Por defecto |
|----------|-----------|-------------|
| `autoupdate_signatures` | Actualizar firmas automáticamente a diario mediante cron | `1` |
| `autoupdate_version` | Actualizar la versión de LMD automáticamente a diario mediante cron | `1` |
| `autoupdate_version_hashed` | Verificar el hash SHA-256 del ejecutable de LMD contra el upstream (usa MD5 como alternativa) | `1` |
| `sigup_interval` | Horas entre comprobaciones automáticas de actualización de firmas mediante un trabajo cron independiente (`/etc/cron.d/maldet-sigup`); 0 = deshabilitado | `6` |
| `cron_prune_days` | Días de retención de datos de cuarentena/sesión/temporales | `21` |
| `cron_daily_scan` | Habilitar escaneo automático diario mediante cron | `1` |
| `scan_days` | Días hacia atrás para buscar archivos modificados en los escaneos cron diarios | `1` |
| `import_config_url` | URL para descargar una configuración remota de reemplazo | — |
| `import_config_expire` | Caducidad de caché para la configuración importada (segundos) | `43200` |
| `sig_import_md5_url` | URL para descargar firmas MD5 personalizadas | — |
| `sig_import_hex_url` | URL para descargar firmas HEX personalizadas | — |
| `sig_import_yara_url` | URL para descargar reglas YARA personalizadas | — |
| `sig_import_sha256_url` | URL para descargar firmas SHA-256 personalizadas | — |
| `sig_import_csig_url` | URL para descargar firmas compuestas personalizadas | — |
| `session_legacy_compat` | Generar archivos de sesión de texto plano heredados junto con TSV: `auto` (detectar sesiones en formato antiguo), `1` (siempre), `0` (solo TSV) | `auto` |
### 3.2 Alertas
| Variable | Propósito | Por defecto |
|----------|-----------|-------------|
| `email_alert` | Habilitar alertas por correo electrónico después de los escaneos | `0` |
| `email_addr` | Dirección del destinatario de las alertas | `[email protected]` |
| `email_subj` | Plantilla de la línea de asunto del correo | `maldet alert from $(hostname)` |
| `email_ignore_clean` | Suprimir alertas cuando todas las detecciones fueron limpiadas | `1` |
| `email_panel_user_alerts` | Enviar alertas a usuarios del panel al detectar infecciones | `0` |
| `email_panel_from` | Cabecera From para alertas de usuarios del panel | `[email protected]` |
| `email_panel_replyto` | Cabecera Reply-To para alertas de usuarios del panel | `[email protected]` |
| `email_panel_alert_subj` | Línea de asunto para alertas de usuarios del panel | `maldet alert from $(hostname)` |
| `email_format` | Formato de correo: `text`, `html` o `both` | `html` |
| `smtp_relay` | URL del relay SMTP (p. ej., `smtps://smtp.gmail.com:465`) | — |
| `smtp_from` | Dirección del remitente para la entrega mediante relay SMTP | — |
| `smtp_user` | Nombre de usuario de autenticación SMTP | — |
| `smtp_pass` | Contraseña de autenticación SMTP | — |
| `slack_alert` | Habilitar alertas con carga de archivos a Slack | `0` |
| `slack_subj` | Nombre de archivo para la carga a Slack | `maldet alert from $(hostname)` |
| `slack_token` | Token de API de Slack Bot (ámbitos: `files:write`, `files:read`) | — |
| `slack_channels` | Lista separada por comas de nombres o IDs de canales | `maldetreports` |
| `telegram_alert` | Habilitar alertas de Telegram | `0` |
| `telegram_bot_token` | Token de API de Telegram Bot | — |
| `telegram_channel_id` | ID de chat o grupo de Telegram | — |
| `discord_alert` | Habilitar alertas mediante webhook de Discord | `0` |
| `discord_webhook_url` | URL del webhook de Discord para la entrega de alertas | — |
### 3.3 Opciones de Escaneo
| Variable | Propósito | Por defecto |
|----------|-----------|-------------|
| `scan_hashtype` | Algoritmo hash para la etapa 1: `auto`, `sha256`, `md5`, `both` | `auto` |
| `scan_max_depth` | Profundidad máxima de directorio para find | `15` |
| `scan_min_filesize` | Tamaño mínimo de archivo a escanear | `24` bytes |
| `scan_max_filesize` | Tamaño máximo de archivo a escanear | `2048k` |
| `scan_hexdepth` | Profundidad en bytes para la coincidencia de firmas HEX | `262144` |
| `scan_hex_chunk_size` | Archivos por micro-lote en el escaneo HEX+CSIG (rango: 1024-20480) | `10240` |
| `scan_csig` | Habilitar escaneo de firmas compuestas (csig) (solo modo nativo) | `1` |
| `scan_workers` | Trabajadores paralelos para los pases de escaneo MD5, SHA-256, HEX y CSIG | `auto` |
| `scan_cpunice` | Prioridad nice para el proceso de escaneo (-19 a 19) | `19` |
| `scan_ionice` | Clase de prioridad de planificación de E/S (0-7) | `6` |
| `scan_cpulimit` | Límite de uso de CPU en porcentaje (0=deshabilitado) | `0` |
| `scan_ignore_root` | Omitir archivos propiedad de root en los escaneos (no se aplica en modo monitor de forma predeterminada; ver `monitor_scan_owner_filters`) | `1` |
| `scan_ignore_user` | Omitir archivos propiedad de usuarios específicos | — |
| `scan_ignore_group` | Omitir archivos propiedad de grupos específicos | — |
| `scan_user_access` | Permitir que usuarios no root ejecuten escaneos | `0` |
| `scan_user_access_minuid` | UID mínimo para la creación de directorios de usuario con --mkpubpaths | `100` |
| `scan_find_timeout` | Tiempo de espera para la generación de la lista de archivos mediante find (0=deshabilitado, mínimo 60 s, se recomienda 14400=4 h) | `0` |
| `scan_export_filelist` | Guardar los resultados de find en tmp/find_results.last | `0` |
| `scan_tmpdir_paths` | Rutas temporales escribibles por cualquier usuario incluidas en escaneos -a/-r | `/tmp /var/tmp /dev/shm /var/fcgi_ipc` |
| `string_length_scan` | Habilitar análisis estadístico de longitud de cadenas | `0` |
| `string_length` | Longitud mínima de cadena sospechosa | `150000` |
| `scan_progress_log_interval` | Segundos entre puntos de control del registro de progreso durante escaneos en segundo plano (0=deshabilitado) | `60` |
| `scan_meta_cleanup_age` | Horas de retención de archivos meta de escaneos completados/terminados (0=deshabilitado) | `48` |
| `maint_compress_age` | Días antes de que los archivos de sesión completados se compriman con gzip (0=deshabilitado) | `30` |
| `maint_archive_age` | Días antes de que las sesiones comprimidas se agrupen en archivos mensuales (0=deshabilitado) | `90` |
### 3.4 Escaneo YARA
El escaneo YARA nativo invoca el binario `yara` (o `yr` de YARA-X) de forma independiente de ClamAV, lo que permite usar módulos YARA completos, reglas compiladas y archivos de reglas personalizados que el subconjunto limitado de YARA de ClamAV no puede manejar. Cuando ambos están disponibles, se prefiere `yr` (YARA-X). Cuando se establece en `auto`, el YARA nativo solo se habilita si ClamAV no está disponible y se encuentra un binario yara/yr, evitando así la evaluación duplicada de reglas.
| Variable | Propósito | Por defecto |
|----------|-----------|-------------|
| `scan_yara` | Habilitar la etapa de escaneo YARA nativo: `auto` (detectar binario, usar ClamAV como alternativa), `0` (deshabilitado), `1` (habilitado) | `auto` |
| `scan_yara_timeout` | Tiempo de espera en segundos (0=sin tiempo de espera) | `300` |
| `scan_yara_scope` | Alcance de las reglas cuando ClamAV también está activo: `all` (escaneo nativo completo) o `custom` (solo reglas personalizadas de forma nativa, ClamAV maneja rfxn.yara) | `custom` |
| `sig_import_yara_url` | URL para descargar reglas YARA personalizadas en la actualización de firmas | — |
**Reglas YARA personalizadas** pueden colocarse en dos ubicaciones, ambas conservadas entre actualizaciones:
- `sigs/custom.yara` — reglas de archivo único
- `sigs/custom.yara.d/` — directorio de inclusión para archivos de reglas `.yar` y `.yara`
Compatible con conjuntos de reglas de terceros como [YARA Forge](https://yarahq.github.io/) y [Signature Base](https://github.com/Neo23x0/signature-base). Las reglas compiladas (salida de `yarac`) también son compatibles mediante `sigs/compiled.yarc`.
**Escaneo por lotes:** YARA 4.0+ y todas las versiones de YARA-X usan `--scan-list` para el escaneo eficiente por lotes de archivos. Las versiones antiguas de YARA recurren automáticamente al escaneo archivo por archivo.
Habilitar en tiempo de ejecución sin editar la configuración:```bash
maldet -co scan_yara=1 -a /home/?/public_html
Se puede invocar un script hook configurable después de completar el escaneo; recibe
los resultados del escaneo mediante argumentos posicionales, variables de entorno LMD_* y
opcionalmente JSON en stdin. El hook nunca interrumpe el escaneo: los fallos se
registran, pero no son fatales. Consulte maldet(1) para conocer el contrato completo del hook.
Cuando el escaneo con ClamAV está habilitado (scan_clamscan=1 o auto con un binario detectado), LMD selecciona el mejor motor ClamAV disponible en orden de prioridad:
clamdscan remoto (si scan_clamd_remote=1 y existe la configuración)clamd local ejecutándose como rootclamd local ejecutándose como no root (con --fdpass)clamscan (respaldo, más lento)Mediante install.sh, las firmas de LMD se enlazan simbólicamente de forma automática a los directorios de datos de ClamAV, lo que le da a ClamAV acceso a las firmas MD5 (rfxn.hdb), HEX (rfxn.ndb) y YARA (rfxn.yara) de LMD.
Puerta de validación de firmas: antes de implementar firmas actualizadas en los directorios de datos de ClamAV, LMD las valida mediante clamscan -d contra un directorio provisional. Si la validación falla, las firmas existentes de LMD se eliminan de la ruta de ClamAV para evitar que bases de datos malformadas rompan ClamAV. La señal de recarga SIGUSR2 para clamd solo se envía cuando al menos un directorio de datos de ClamAV pasa la validación (issue #467).
| Variable | Propósito | Predeterminado |
|---|---|---|
scan_clamscan | Habilitar ClamAV como motor de escaneo: auto (detectar binario en tiempo de ejecución), 0 (deshabilitado), 1 (habilitado) | auto |
Las fuentes posteriores sobrescriben los valores anteriores:
internals/internals.conf — rutas internas, descubrimiento de binarios, definiciones de URLconf.maldet — configuración orientada al usuariointernals/compat.conf — mapeos de variables obsoletas/etc/sysconfig/maldet o /etc/default/maldet — sobrescrituras del sistema-co|--config-option — sobrescrituras en tiempo de ejecuciónInterfaz de línea de comandos, códigos de salida y ejemplos comunes. Consulte man maldet(1) para la referencia completa de opciones.```
usage: maldet [OPTION] [ARGUMENT]
SCANNING: -a, --scan-all PATH scan all files in path (wildcard: ?) -r, --scan-recent PATH DAYS scan files created/modified in last X days -f, --file-list FILE scan files from a line-separated file list -b, --background run scan in the background
SCAN FILTERS: -i, --include-regex REGEX include only matching paths -x, --exclude-regex REGEX exclude matching paths -co, --config-option V=V,... override config options at runtime -U, --user USER run as specified user
MONITORING: -m, --monitor USERS|PATHS|FILE|RELOAD start inotify monitoring -k, --kill-monitor stop inotify monitoring
SCAN MANAGEMENT: -L, --list-active list active scans (text/json/tsv) --kill SCANID abort a running scan --pause SCANID [DURATION] pause a running scan (e.g., 2h, 30m) --unpause SCANID resume a paused scan --stop SCANID checkpoint and stop a running scan --continue SCANID resume a stopped scan from checkpoint --maintenance rotate histories, compress/archive old sessions
QUARANTINE & RESTORE: -q, --quarantine SCANID quarantine hits from scan -n, --clean SCANID clean malware from scan hits -s, --restore FILE|SCANID restore quarantined file(s) -qd PATH override quarantine directory for this run
REPORTING: -e, --report [SCANID|list|latest|hooks|active] view scan report --all show full history with -e list (default: recent) --format text|json|html|tsv set report output format (default: text) --mailto ADDRESS email report to address --json-report [SCANID|list] shorthand: --report --format json --alert-daily generate inotify monitor digest alert --digest fire unified digest (monitor + hook sources) -l, --log view event log
UPDATES: -u, --update-sigs [--force] update malware signatures -d, --update-ver [--force|--beta] update LMD version --cron-sigup cron sig update (internal use)
OTHER: -p, --purge clear logs, quarantine, temp data -c, --checkout FILE submit suspected malware to rfxn.com --test-alert TYPE CHANNEL test alert delivery (scan|digest, email|slack|telegram|discord) --mkpubpaths create per-user pub/ data directories --web-proxy IP:PORT set HTTP/HTTPS proxy -hscan, --hook-scan scan via service hook (internal use) -v, --version show version information -h, --help show detailed help
### 4.1 Códigos de salida
| Código | Significado |
|------|---------|
| `0` | Éxito, sin detecciones de malware |
| `1` | Error o todas las rutas de escaneo inexistentes |
| `2` | Se encontraron detecciones de malware |
**Ejemplos:**```bash
# Scan all files under user web roots
maldet -a /home/?/public_html
# Scan recent files with auto-quarantine and YARA enabled
maldet -co quarantine_hits=1,scan_yara=1 -r /home/?/public_html 2
# Background scan with email alert to specific address
maldet -b -co [email protected] -a /var/www
# View the most recent scan report
maldet -e
# Email a specific report
maldet --mailto [email protected] -e 050910-1534.21135
# Output scan report as JSON (pipe to jq for formatting)
maldet --format json -e 050910-1534.21135
# List all reports as JSON
maldet --format json -e list
# Shorthand JSON output (equivalent to --format json -e)
maldet --json-report 050910-1534.21135
# Restore all quarantined files from a scan
maldet -s 050910-1534.21135
Salida JSON: Usa --format json -e o --json-report para generar JSON estructurado (esquema v1.2) con metadatos del escáner, detalles del escaneo (ruta, tiempos, recuentos de archivos), entradas por detección con nombre de firma, ruta de archivo, tipo de detección, propietario, permisos y estado de cuarentena, además de un resumen con desgloses por tipo. Se admiten tanto sesiones TSV como sesiones de texto plano heredadas; las sesiones heredadas incluyen "source": "legacy" y muestran los campos enriquecidos no disponibles (hash, tamaño, propietario, etc.) como null.
Los escaneos de larga duración en sistemas de archivos grandes (1M+ archivos) se pueden controlar sin kill -9:```bash
maldet -L
maldet --format json -L
maldet --kill 260327-1509.25279
maldet --pause 260327-1509.25279 2h
maldet --unpause 260327-1509.25279
maldet --stop 260327-1509.25279
maldet --continue 260327-1509.25279
maldet --maintenance
**Reanudación de checkpoint:** `--stop` escribe un archivo de checkpoint que registra la etapa de escaneo, el recuento de aciertos, las opciones de configuración y el progreso por trabajador. `--continue` valida el checkpoint, avisa si las firmas cambiaron, reconstruye la lista de archivos desde el estado actual del sistema de archivos, restaura los aciertos previos y reanuda el escaneo desde la etapa interrumpida. Los trabajadores HEX se reanudan con granularidad de chunk (~30 s de trabajo perdido por trabajador).
**Soporte de motores:** El motor nativo (trabajadores HEX/CSIG/hash) y `clamscan` independiente admiten todas las operaciones del ciclo de vida. ClamAV basado en demonio (`clamdscan`/`clamd`) solo admite `--kill`; `--pause` y `--stop` se rechazan con un mensaje de error porque el estado de E/S del demonio es opaco y compartido con otros clientes.
---
## 5. Opciones de Ignorado
Exclusión de rutas, tipos de archivo y firmas de escaneos y monitoreo.
Cuatro archivos de ignore controlan lo que se excluye del escaneo:
| Archivo | Formato | Propósito |
|------|--------|---------|
| `ignore_paths` | Rutas separadas por líneas | Excluir directorios o archivos de los escaneos |
| `ignore_file_ext` | Extensiones separadas por líneas | Excluir extensiones de archivo (`.js`, `.css`) |
| `ignore_sigs` | Patrones separados por líneas | Omitir firmas coincidentes (regex, coincidencia de subcadena) |
| `ignore_inotify` | Rutas literales separadas por líneas | Excluir eventos de monitoreo de inotify |
Todos los archivos de ignore se encuentran en `/usr/local/maldetect/`.
**Ejemplos:**```
# ignore_paths
/home/user/public_html/cgi-bin
# ignore_file_ext
.js
.css
# ignore_sigs
base64.inject.unclassed
# ignore_inotify (user-owned — your additions only)
/home/user/public_html/cache/
backup-
# ignore_inotify.defaults (LMD-managed — refreshed on every upgrade)
# Ships under /usr/local/maldetect/internals/ with curated defaults
# for systemd-private tmpdirs, MariaDB temp tables, Redis, ClamAV, etc.
# Do NOT edit — add your own entries to ignore_inotify instead.
Nota: las entradas de ignore_sigs se tratan como patrones de expresiones regulares extendidas y coinciden como subcadenas. Una entrada php.shell suprimirá php.shell, php.shell.v2, {YARA}php.shell.backdoor, etc. Use ^php\.shell$ para una coincidencia exacta. El carácter . coincide con cualquier carácter en la expresión regular; escápelo como \. para un punto literal.
Escaneo diario automatizado, poda de datos y actualización de firmas.
El trabajo cron instalado en /etc/cron.daily/maldet realiza tres tareas:
cron_prune_days (predeterminado: 21)autoupdate_signatures y autoupdate_version están habilitados)scan_days, predeterminado: 1)El escaneo diario detecta automáticamente los paneles de control instalados y ajusta las rutas de escaneo en consecuencia:
Si el modo monitor está activo, los escaneos diarios se omiten y, en su lugar, se emite un informe diario de los eventos de monitoreo.
Para rutas de escaneo personalizadas, use el archivo hook /usr/local/maldetect/cron/custom.cron. Para anulaciones de configuración específicas de cron, use /etc/sysconfig/maldet (RHEL) o /etc/default/maldet (Debian) o /usr/local/maldetect/cron/conf.maldet.cron.
Un script de vigilancia semanal (/etc/cron.weekly/maldet-watchdog) proporciona actualizaciones de firmas de respaldo independientes cuando el cron principal está roto o desactualizado.
Monitoreo de archivos en tiempo real con inotify del kernel, alertas de resumen y gestión del supervisor.
El monitoreo de archivos en tiempo real usa el subsistema inotify del kernel para detectar eventos de creación, modificación y movimiento de archivos. Requiere un kernel con CONFIG_INOTIFY_USER (estándar en todos los kernels modernos).```bash
maldet -m users
maldet -b -m users
maldet -m /home/mike,/home/ashton
maldet -m /root/monitor_paths
maldet -k
**Cómo funciona:**
`maldet -m` ejecuta un proceso supervisor en primer plano de forma predeterminada. El supervisor gestiona un proceso hijo `inotifywait` y maneja la recuperación ante caídas, las recargas de configuración y las alertas de resumen. Use `-b` para convertir el supervisor en demonio y regresar de inmediato.
1. `monitor_init()` configura vigilancias inotify en todos los archivos bajo las rutas monitoreadas
2. Los eventos de archivo se ponen en cola y se analizan por lotes cada `inotify_sleep` segundos (predeterminado: 15)
3. La configuración se recarga cada `inotify_reloadtime` segundos (predeterminado: 3600)
4. Los parámetros `max_user_watches` y `max_user_instances` del kernel se ajustan automáticamente para un rendimiento óptimo
5. Si `inotifywait` se bloquea, el supervisor lo reinicia con retroceso exponencial (2, 4, 8, 16, 32 segundos); después de 3 fallos consecutivos, el supervisor se cierra
**Las alertas de resumen** se envían periódicamente en el intervalo definido por `digest_interval` (predeterminado: `24h`). Si el recuento de detecciones desde el último resumen supera `digest_escalate_hits`, se envía una alerta de escalada inmediata (predeterminado: `0`, deshabilitado).
**Rutas adicionales:** Para vigilar rutas adicionales sin editar `conf.maldet`, añádelas una por línea al archivo referenciado por `monitor_paths_extra` (predeterminado: `/usr/local/maldetect/monitor_paths.extra`). Estas se combinan con la lista de vigilancia principal en cada recarga de configuración.
Al usar el modo `users`, solo se monitorean los subdirectorios que coinciden con `inotify_docroot` (predeterminado: `public_html,public_ftp`), además de los directorios temporales del sistema `/tmp`, `/var/tmp` y `/dev/shm`.
**Archivos de ignorados (inotify):** Las exclusiones del monitor combinan dos archivos: el del usuario `/usr/local/maldetect/ignore_inotify` y el gestionado por LMD `/usr/local/maldetect/internals/ignore_inotify.defaults`. Ambos están separados por líneas y admiten comentarios con `#` y líneas en blanco. El `ignore_inotify` del usuario acepta POSIX ERE (expresiones regulares extendidas) de forma predeterminada: los anclajes (`^`, `$`) y los comodines (`.*`, `.+`) funcionan. Para excluir una ruta literal que contenga metacaracteres de expresiones regulares, prefija la entrada con `literal:` (p. ej., `literal:/tmp/app.cache`). El `ignore_inotify.defaults` gestionado por LMD se trata como subcadenas literales: sus entradas seleccionadas se escapan automáticamente al cargar. El archivo de valores predeterminados se sobrescribe en cada actualización de LMD; añade exclusiones específicas del sitio solo a `ignore_inotify`.
---
## 8. Sistema de firmas
Tipos de firmas, convenciones de nomenclatura, actualizaciones y archivos de reglas personalizados.
LMD incluye cinco tipos de firmas:
| Tipo | Archivo | Formato | Cantidad |
|------|---------|--------|----------|
| Hashes MD5 | `sigs/md5v2.dat` | `HASH:SIZE:{MD5}sig.name.N` | ~14,801 |
| Hashes SHA-256 | `sigs/sha256v2.dat` | `HASH:SIZE:{SHA256}sig.name.N` | CDN |
| Patrones HEX | `sigs/hex.dat` | `HEXSTRING:{HEX}sig.name.N` | ~2,054 |
| Firmas compuestas | `sigs/csig.dat` | `SUBSIG1\|\|SUBSIG2:signame` | CDN |
| Reglas YARA | `sigs/rfxn.yara` | sintaxis YARA | ~783 reglas |
| YARA compilado | `sigs/compiled.yarc` | salida de `yarac` | opcional |
También se mantienen firmas compatibles con ClamAV:
- `sigs/rfxn.hdb` — formato MD5 de ClamAV
- `sigs/rfxn.ndb` — formato HEX de ClamAV
- `sigs/rfxn.hsb` — formato SHA-256 de ClamAV (requiere ClamAV >= 0.97)
**Convención de nomenclatura de firmas:** `{TYPE}category.name.variant_number`
Las categorías incluyen: `bin.` (binario), `c.` (lenguaje C), `exp.` (exploit), `php.` (PHP), `js.` (JavaScript), `perl.` (Perl), `html.` (phishing), `base64.inject.`, `gzbase64.`
**Prefijos de detección en los informes de escaneo:**
| Prefijo | Origen |
|---------|--------|
| `{MD5}` | Coincidencia de hash MD5 (etapa 1) |
| `{SHA256}` | Coincidencia de hash SHA-256 (etapa 1) |
| `{HEX}` | Coincidencia de patrón HEX (etapa 2) |
| `{CSIG}` | Coincidencia de firma compuesta (etapa 2.5) |
| `{SA}` | Análisis estadístico (longitud de cadena) |
| `{YARA}` | Escaneo YARA nativo (`scan_yara=1`) |
| `{CAV}` | Motor ClamAV (clamd/clamscan) |
### 8.1 Actualización de firmas
Las firmas se actualizan diariamente mediante el trabajo cron o manualmente:```bash
maldet -u # update signatures
maldet -u --force # force update even if current
Se pueden añadir firmas personalizadas en tres formatos, todos conservados entre actualizaciones:
Se pueden configurar URLs de importación remota para su descarga automática durante las actualizaciones de firmas:
Aislamiento, restauración y limpieza de archivos infectados por malware.
Los archivos en cuarentena se almacenan en /usr/local/maldetect/quarantine/ con permisos establecidos en 000. La ruta original, el propietario, los permisos y la hora de modificación se registran en /usr/local/maldetect/sess/quarantine.hist para su restauración completa.```bash
maldet -q SCANID
maldet -s SCANID
maldet -s /usr/local/maldetect/quarantine/config.php.23754
maldet -n SCANID
**Nombre de archivo en cuarentena:** `FILENAME.INODE` (p. ej., `config.php.23754`)
Para escaneos que no son de root (p. ej., escaneo de subida de ModSecurity2), los datos de cuarentena se almacenan en `/usr/local/maldetect/pub/USERNAME/quar/`. Use la bandera `-U` para interactuar con la cuarentena no root:```bash
maldet -U nobody -s 112012-0032.13771
La función limpiadora busca scripts con el nombre de la firma en el directorio clean/. Cada script recibe la ruta del archivo infectado como argumento y debe eliminar el contenido malicioso. Después de la limpieza, el archivo se vuelve a escanear — si todavía genera una detección, la limpieza se marca como FAILED.
Para crear una regla de limpieza para la firma php.cmdshell.r57, añade un archivo clean/php.cmdshell.r57 que contenga un comando como sed -i con el patrón adecuado. Las limpiezas exitosas restauran el archivo a su ruta, propietario y permisos originales.
El limpiador es una subfunción de la cuarentena — los archivos deben estar en cuarentena (o usar -n) para que se ejecute la limpieza.
API de hook de servicio para ModSecurity, FTP, Exim e integraciones personalizadas.
LMD proporciona escaneo de archivos en tiempo real para múltiples servicios a través de la API unificada hookscan.sh. Un único script gestiona el despacho de modos para ModSecurity, pure-ftpd, ProFTPD, Exim e integraciones genéricas (personalizadas).
Las detecciones del escaneo hook se registran en un registro de detecciones rotatorio (hook.hits.log) en lugar de crear archivos de sesión por escaneo. Las detecciones se incluyen en los avisos de resumen periódicos y pueden consultarse mediante maldet --report hooks.
SecRequestBodyAccess On
SecTmpSaveUploadedFiles On # Required for ModSecurity >= 2.9
SecRule FILES_TMPNAMES "@inspectFile /usr/local/maldetect/hookscan.sh"
"id:1999999,phase:2,t:none,deny,log,auditlog,severity:2,
msg:'Malware upload blocked by LMD'"
Las cargas maliciosas son rechazadas con una acción de denegación y se registran en el registro de auditoría de ModSecurity. No se necesita ningún argumento de modo — `hookscan.sh` usa por defecto el modo ModSecurity para compatibilidad con versiones anteriores. Tanto ModSecurity v2 como v3 (libmodsecurity) usan el mismo contrato `popen()`.
### 10.2 pure-ftpd```bash
# pure-ftpd.conf (or command-line flags):
CallUploadScript yes
# Start the upload-script daemon:
pure-uploadscript -r /usr/local/maldetect/hookscan.sh -B
Requiere pure-ftpd compilado con --with-uploadscript. El modo se detecta automáticamente mediante la variable de entorno UPLOAD_VUSER. Los archivos infectados se ponen en cuarentena después de la subida (fire-and-forget — las subidas no se pueden bloquear, solo se pueden procesar posteriormente).
av_scanner = cmdline:
/usr/local/maldetect/hookscan.sh exim %s :
maldet: (.+):
maldet: (.+)
Los tres campos separados por dos puntos son: plantilla de comando, expresión regular de activación y expresión regular de captura de nombre. Cuando se detecta malware, Exim rechaza el mensaje utilizando el nombre de firma capturado.
### 10.5 API Genérica
Para integraciones personalizadas, escaneo por lotes y uso por terceros:```bash
# Single file scan
hookscan.sh generic /path/to/file
# Exit: 0 = clean, 1 = error, 2 = infected
# Stdout: CLEAN: /path, INFECTED: signame /path, ERROR: reason
# Batch scan from a file list
hookscan.sh generic --list /tmp/filelist.txt
# Batch scan from stdin
find /uploads -newer /tmp/marker -type f | hookscan.sh generic --stdin
La salida por lotes produce una línea STATUS: PATH por archivo. El código de salida es el del peor resultado.
La configuración del escaneo hook se almacena en conf.maldet.hookscan (opcional — los valores predeterminados están integrados en el script). Los valores predeterminados de referencia están en conf.maldet.hookscan.default.
Variables clave:
Ejecute maldet --mkpubpaths después de habilitar para crear directorios de datos por usuario para operaciones de escaneo no root.
Verifique que los canales de entrega de alertas estén correctamente configurados:```bash maldet --test-alert scan email # test per-scan email alert maldet --test-alert scan slack # test per-scan Slack alert maldet --test-alert digest email # test digest email alert maldet --test-alert digest telegram # test digest Telegram alert
Las alertas de prueba utilizan el pipeline de renderizado real con datos sintéticos. La línea de asunto tiene el prefijo `[TEST]`. El aislamiento de canal garantiza que solo se active el canal especificado.
### 10.8 Resumen de hooks
Las detecciones de hooks se condensan en alertas de resumen periódicas:```bash
# On-demand digest (reads all sources: monitor + hooks)
maldet --digest
# View hook scan activity
maldet --report hooks # last 24 hours
maldet --report hooks --last 7d # last 7 days
maldet --report hooks --mode modsec # filter by mode
La tarea cron diaria dispara automáticamente un resumen de hook cuando existen nuevas detecciones (controlada por cron_digest_hook=1 en conf.maldet).
Para administradores que reemplazan CXS con LMD:
Conexión de LMD con herramientas externas, pipelines de automatización y escáneres de terceros.
Las firmas de LMD se enlazan simbólicamente automáticamente a los directorios de datos de ClamAV mediante install.sh, proporcionando cobertura de doble motor. Establezca scan_clamscan=auto (predeterminado) para la detección automática de ClamAV. Consulte 3.8 Integración con ClamAV para la selección del motor y la validación de firmas.
Habilite enable_statistic=1 con elk_host, elk_port y elk_index para transmitir eventos de escaneo a Elasticsearch. Consulte 3.10 Integración con ELK.
LMD admite cuatro canales de entrega de alertas además del correo electrónico: Slack (Block Kit), Telegram (MarkdownV2), Discord (embeds de webhook) y relé SMTP para entornos sin un MTA local. Consulte 3.2 Alertas para la configuración.
Salida de escaneo legible por máquina para CI/CD y automatización:```bash maldet --format json -e SCANID # JSON report to stdout maldet --json-report list # list all scans as JSON
Vea `man maldet`(1) para el esquema JSON de v1.2 (forma uniforme `{schema_version, scanner, host, reports[]}` tanto para `-e SCANID` como para `-e list`).
### Detección de paneles de alojamiento
El cron diario detecta automáticamente más de 12 paneles de control de alojamiento y ajusta las rutas de escaneo. Consulte [6. Cron diario](#6-cron-daily) para obtener la matriz completa de paneles.
---
## Licencia
LMD es desarrollado y soportado de forma voluntaria por Ryan MacDonald [[email protected]].
Linux Malware Detect (LMD) se distribuye bajo la GNU General Public License (GPL) v2
sin restricciones de uso o redistribución. La declaración de derechos de autor y la GNU GPL
se incluyen en el archivo `COPYING.GPL`. Se debe otorgar crédito a las obras derivadas según
lo requiere la GNU GPL.
---
## Soporte
El repositorio de código fuente de LMD está en: https://github.com/rfxn/linux-malware-detect
Los errores, solicitudes de funciones y preguntas generales pueden presentarse como incidencias de GitHub o enviarse a [email protected].
La página oficial del proyecto está en: https://www.rfxn.com/projects/linux-malware-detect/
| Variable | Propósito | Predeterminado |
|---|
quarantine_hits | Poner en cuarentena automáticamente el malware detectado | 0 |
quarantine_clean | Intentar limpiar el malware de los archivos en cuarentena | 0 |
quarantine_suspend_user | Suspender la cuenta de cPanel o revocar el shell al detectar una coincidencia | 0 |
quarantine_suspend_user_minuid | UID mínimo para suspender (protege las cuentas del sistema) | 500 |
quarantine_on_error | Poner en cuarentena archivos cuando el motor de escaneo devuelve un error | 1 |
| Variable | Propósito | Predeterminado |
|---|
default_monitor_mode | Modo de inicio del monitor (users o ruta a un archivo); vacío = deshabilitado | "" |
inotify_base_watches | Número base de observaciones de archivos por ruta de usuario | 16384 |
inotify_minuid | UID mínimo para el monitoreo de directorios personales de usuarios | 500 |
inotify_docroot | Subdirectorios a monitorear en los directorios personales de los usuarios | public_html,public_ftp |
inotify_sleep | Segundos entre lotes de escaneo | 15 |
inotify_reloadtime | Segundos entre recargas de configuración | 3600 |
inotify_cpunice | Prioridad nice para el proceso del monitor | 18 |
inotify_ionice | Prioridad de E/S para el proceso del monitor | 6 |
inotify_cpulimit | Límite estricto de CPU para el monitor (0=deshabilitado) | 0 |
digest_interval | Intervalo entre alertas periódicas de resumen: 24h, 30m, 7d, 0 (deshabilitado) | 24h |
digest_escalate_hits | Umbral de detecciones para alerta de escalada inmediata; 0 = deshabilitado | 0 |
cron_digest_hook | Habilitar el barrido de resumen del hook cron.daily (dispara el resumen si existen nuevas detecciones de hook) | 1 |
monitor_paths_extra | Ruta a un archivo con rutas de observación inotify adicionales, una por línea | /usr/local/maldetect/monitor_paths.extra |
monitor_scan_owner_filters | Aplicar los filtros de propiedad scan_ignore_root/scan_ignore_user/scan_ignore_group en modo monitor; 0 (predeterminado) = desactivado — el monitor escanea todos los archivos independientemente del propietario (restaura la semántica de 1.6.6, corrige el issue #485); 1 = activado — aplicar filtros de propiedad | 0 |
| Variable | Propósito | Predeterminado |
|---|
post_scan_hook | Ruta al script hook (de propiedad de root, no escribible por todos). No se puede establecer mediante -co | "" |
post_scan_hook_format | Nivel de salida: args, file, json (acumulativo) | args |
post_scan_hook_exec | Modo de ejecución: async (no bloqueante), sync (espera) | async |
post_scan_hook_timeout | Segundos antes de SIGTERM (0=deshabilitado, mínimo 5) | 60 |
post_scan_hook_on | Filtro de tipo de escaneo: all, cli, digest | all |
post_scan_hook_min_hits | Mínimo de detecciones para activarse (0=siempre) | 1 |
| Variable | Propósito | Predeterminado |
|---|
scan_clamd_remote | Usar un servidor clamd remoto para el escaneo | 0 |
remote_clamd_config | Ruta al archivo de configuración de clamd remoto | /etc/clamd.d/clamd.remote.conf |
remote_clamd_max_retry | Máximo de reintentos ante fallo del clamd remoto | 5 |
remote_clamd_retry_sleep | Segundos entre reintentos | 3 |
| Variable | Propósito | Predeterminado |
|---|
enable_statistic | Habilitar la recopilación de estadísticas de la pila ELK | 0 |
elk_host | Host TCP para la entrada de ELK | — |
elk_port | Puerto TCP para la entrada de ELK | — |
elk_index | Nombre del índice de Elasticsearch | — |
| Panel | Ruta de escaneo |
|---|
| cPanel | /home?/?/public_html/ (+ docroots de addon/subdominio) |
| Plesk | /var/www/vhosts/?/ |
| DirectAdmin | /home?/?/domains/?/public_html/, /var/www/html/?/ |
| Ensim | /home/virtual/?/fst/var/www/html/ |
| ISPConfig | /var/www/clients/?/web?/web, …/subdomains, /var/www |
| Virtualmin | /home/?/public_html/, /home/?/domains/?/public_html/ |
| ISPmanager | /var/www/?/data/, /home/?/data/ |
| Froxlor | /var/customers/webs/ |
| Bitrix | /home/bitrix/www/, /home/bitrix/ext_www/?/ |
| VestaCP / HestiaCP | /home/?/web/?/public_html/ (+ public_shtml, tmp, private) |
| DTC | ${conf_hosting_path:-/var/www/sites}/?/?/subdomains/?/html/ |
| Tipo | Archivo | Formato |
|---|
| MD5 personalizado | sigs/custom.md5.dat | Igual que md5v2.dat |
| SHA-256 personalizado | sigs/custom.sha256.dat | Igual que sha256v2.dat |
| HEX personalizado | sigs/custom.hex.dat | Igual que hex.dat |
| CSIG personalizado | sigs/custom.csig.dat | Igual que csig.dat |
| YARA personalizado | sigs/custom.yara | Sintaxis de reglas YARA |
| YARA personalizado (drop-in) | sigs/custom.yara.d/*.yar | Archivos de reglas YARA |
| YARA compilado | sigs/compiled.yarc | Salida de yarac (opcional) |
| Variable | Propósito |
|---|
sig_import_md5_url | URL para firmas MD5 personalizadas |
sig_import_sha256_url | URL para firmas SHA-256 personalizadas |
sig_import_hex_url | URL para firmas HEX personalizadas |
sig_import_csig_url | URL para firmas compuestas personalizadas |
sig_import_yara_url | URL para reglas YARA personalizadas |
| Variable | Predeterminado | Descripción |
|---|
hookscan_timeout | 30 | Tiempo de espera del escaneo en segundos |
hookscan_fail_open | 1 | Permitir archivo en error de escaneo (0 = bloquear) |
hookscan_escalate_hits | 0 | Alerta inmediata a N aciertos de hook/hora (0 = deshabilitado) |
hookscan_service_users | apache,nginx,... | UIDs de servicio exentos de la restricción del directorio de inicio |
hookscan_user_rate_limit | 60 | Máximo de escaneos/hora para llamadores no root |
hookscan_user_show_signames | 1 | Mostrar nombres de firmas a llamadores no root |
hookscan_list_max_bytes | 1048576 | Tamaño máximo del archivo de lista (1 MB) |
hookscan_list_max_entries | 10000 | Máximo de entradas en la lista de archivos |
| Componente CXS | Equivalente LMD |
|---|
cxscgi.sh | hookscan.sh modsec |
cxsftp.sh | hookscan.sh ftp |
| ProFTPD mod_exec a cxs | hookscan.sh proftpd |
cxs --file | hookscan.sh generic |
cxswatch | maldet --monitor |
/etc/cxs/cxs.conf | conf.maldet.hookscan |