
Мультидвижковый сканер вредоносных программ для Linux с пятью этапами обнаружения (MD5, HEX-шаблоны, YARA, ClamAV, статистический), мониторингом inotify в реальном времени, карантином и многоканальным оповещением.
Сканер вредоносных программ для Linux — многоступенчатое обнаружение угроз (MD5, SHA-256, HEX, YARA, статистический анализ), интеграция с ClamAV, мониторинг в реальном времени через inotify, операции карантина/очистки/восстановления и многоканальные оповещения (email, Slack, Telegram, Discord).
(C) 2002-2026, R-fx Networks <[email protected]>
(C) 2026, Ryan MacDonald <[email protected]>
Лицензировано по GNU GPL v2
Нативный движок сканирования в 43 раза быстрее — конвейер нативного сканирования был полностью переписан с использованием пакетной параллельной обработки. Реальный тест на ~10,000 файлах:
| Версия | Время выполнения | Файлы | Совпадения |
|---|---|---|---|
| v1.6.6 | 1,217s | 9,931 | 35 |
| v2.0.1 | 28s | 9,931 | 35 |
Сопоставление сигнатур MD5 и HEX теперь использует пакетный grep с параллельными рабочими процессами
Aho-Corasick, что устраняет накладные расходы на компиляцию шаблонов для каждого файла и ~500 000
форков подпроцессов за одно сканирование. Количество параллельных рабочих процессов настраивается
с помощью scan_workers (по умолчанию: auto).
Другие особенности: управление жизненным циклом сканирования (--kill, --pause, --stop/--continue,
-L), сканирование хешей SHA-256 с автоматическим определением аппаратного обеспечения CPU (scan_hashtype),
нативное сканирование YARA (scan_yara=1), оповещения через Discord webhook, исправления оповещений
Slack/Telegram, поддержка hex-шаблонов ClamAV в нативном движке и более 200 исправлений ошибок по всей
кодовой базе. Подробности см. в CHANGELOG.
./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. Введение
Архитектура LMD, этапы обнаружения и поддерживаемые платформы.
Linux Malware Detect (LMD) — сканер вредоносных программ для Linux, распространяемый под лицензией GNU GPLv2 и разработанный с учётом угроз, характерных для сред общего хостинга. Он использует данные об угрозах из систем обнаружения вторжений на сетевом периметре для выделения вредоносных программ, активно применяемых в атаках, и формирует сигнатуры для их обнаружения. Кроме того, данные об угрозах поступают из пользовательских материалов через функцию проверки LMD (checkout) и из ресурсов сообщества по вредоносному ПО.
LMD ориентирован на те классы вредоносных программ, которые традиционные антивирусные продукты часто пропускают: PHP-шеллы, JavaScript-инжекторы, бэкдоры в base64-кодировке, IRC-боты и другие угрозы уровня веб-приложений, нацеленные на учётные записи пользователей общего хостинга, а не на внутренние компоненты операционной системы.
**Этапы обнаружения**
- Сопоставление MD5-хешей файлов для точной идентификации угроз
- Поиск HEX-шаблонов с помощью встроенного пакетного grep-движка с параллельными рабочими процессами
- Сканирование составными сигнатурами (csig) с многопатерновой булевой логикой (AND/OR/порог), регистронезависимым поиском, широким (UTF-16LE) поиском и подстановочными символами с ограниченным разрывом
- Встроенное сканирование по правилам YARA с полной поддержкой модулей и пользовательскими правилами
- Статистический анализ длины строк для обнаружения обфусцированных угроз (base64, gzinflate)
- Интеграция с ClamAV для расширенного покрытия с сигнатурами ClamAV, поддерживаемыми LMD
**Сканирование и мониторинг**
- Сканирование всех файлов, недавно изменённых файлов или файлов из списка
- Мониторинг файлов в реальном времени через inotify ядра (события создания/изменения/перемещения)
- Сканирование HTTP-загрузок через хук ModSecurity2 `inspectFile`
- Фоновое сканирование для неконтролируемых крупномасштабных операций
- Фильтрация включения/исключения по регулярным выражениям для каждого сканирования
**Карантин и реагирование**
- Очередь карантина с хранением файлов с нулевыми правами доступа
- Пакетный карантин/восстановление по ID сканирования
- Специфичные для сигнатур правила очистки для удаления вредоносных программ
- Полное восстановление файлов (содержимое, владелец, права, mtime)
**Оповещение и отчёты**
- HTML- и текстовые email-оповещения с единым дизайном rfxn (фирменный бирюзовый цвет, карточные записи)
- Поддержка SMTP-релея (TLS/SSL) для сред без локального MTA
- Оповещения по каждой записи через Slack Block Kit, Telegram MarkdownV2, Discord embed
- Настраиваемые шаблоны оповещений через переопределения в `alert/custom.d/`
- Отчёты о сканировании с деталями совпадений по каждому файлу и цветовой кодировкой типов совпадений
**Инфраструктура**
- Автоматическая привязка сигнатур ClamAV для покрытия двумя движками
- Ежедневный cron с автоматическим определением более 12 панелей управления хостингом
- Контроль ресурсов CPU/IO (nice, ionice, cpulimit)
- Автоматическое обновление сигнатур и версий
- Поддержка systemd-юнита и SysV init-скрипта
### Поддерживаемые платформы
LMD работает на любом дистрибутиве Linux с bash и стандартными утилитами GNU. Протестированные платформы:
| Платформа | Система инициализации | Путь к конфигурации пакета |
|----------|-------------|---------------------|
| 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 | — | — (частично; без inotify) |
---
## 2. Установка
Установка, обновление и удаление LMD в системе.
Включённый сценарий `install.sh` выполняет все задачи установки. Предыдущие установки автоматически резервируются.```bash
./install.sh
Установщик:
/usr/local/maldetectmaldet в /usr/local/sbin//etc/cron.daily/maldetconf.maldet), пользовательские сигнатуры и файлы игнорирования при обновленияхПредыдущие установки сохраняются в /usr/local/maldetect.bk{PID} с символической ссылкой maldetect.last на самую последнюю резервную копию.
Пути по умолчанию:
/usr/local/maldetect/usr/local/sbin/maldet/etc/cron.daily/maldet/usr/lib/systemd/system/maldet.serviceВсе пользовательские настройки и их значения по умолчанию. Полный справочник см. в man maldet(1).
Основной файл конфигурации — /usr/local/maldetect/conf.maldet. Все параметры закомментированы для удобства настройки. Параметры используют 0/1 для отключения/включения, если не указано иное.
Конфигурацию также можно переопределить во время выполнения с помощью флага -co:```bash
maldet -co quarantine_hits=1,email_addr=[email protected] -a /home
### 3.1 Общие параметры
| Variable | Purpose | Default |
|----------|---------|---------|
| `autoupdate_signatures` | Автоматически обновлять сигнатуры ежедневно через cron | `1` |
| `autoupdate_version` | Автоматически обновлять версию LMD ежедневно через cron | `1` |
| `autoupdate_version_hashed` | Проверять SHA-256 хеш исполняемого файла LMD на соответствие вышестоящему источнику (откат к MD5) | `1` |
| `sigup_interval` | Часы между автоматическими проверками обновления сигнатур через отдельную cron-задачу (`/etc/cron.d/maldet-sigup`); 0 = отключено | `6` |
| `cron_prune_days` | Дни хранения данных карантина/сеансов/временных файлов | `21` |
| `cron_daily_scan` | Включить ежедневное автоматическое сканирование через cron | `1` |
| `scan_days` | Дни для поиска изменённых файлов при ежедневных сканированиях через cron | `1` |
| `import_config_url` | URL для загрузки удалённого переопределения конфигурации | — |
| `import_config_expire` | Срок действия кэша импортированной конфигурации (секунды) | `43200` |
| `sig_import_md5_url` | URL для загрузки пользовательских MD5-сигнатур | — |
| `sig_import_hex_url` | URL для загрузки пользовательских HEX-сигнатур | — |
| `sig_import_yara_url` | URL для загрузки пользовательских правил YARA | — |
| `sig_import_sha256_url` | URL для загрузки пользовательских SHA-256 сигнатур | — |
| `sig_import_csig_url` | URL для загрузки пользовательских составных сигнатур | — |
| `session_legacy_compat` | Создавать устаревшие plaintext-файлы сеансов наряду с TSV: `auto` (обнаруживать сеансы старого формата), `1` (всегда), `0` (только TSV) | `auto` |
### 3.2 Оповещения
| Variable | Purpose | Default |
|----------|---------|---------|
| `email_alert` | Включить email-оповещения после сканирований | `0` |
| `email_addr` | Адрес получателя оповещений | `[email protected]` |
| `email_subj` | Шаблон темы письма | `maldet alert from $(hostname)` |
| `email_ignore_clean` | Подавлять оповещения, если все обнаружения были обработаны | `1` |
| `email_panel_user_alerts` | Отправлять оповещения пользователям панели при обнаружении угроз | `0` |
| `email_panel_from` | Заголовок From для оповещений пользователей панели | `[email protected]` |
| `email_panel_replyto` | Заголовок Reply-To для оповещений пользователей панели | `[email protected]` |
| `email_panel_alert_subj` | Тема письма для оповещений пользователей панели | `maldet alert from $(hostname)` |
| `email_format` | Формат письма: `text`, `html` или `both` | `html` |
| `smtp_relay` | URL SMTP-ретрансляции (например, `smtps://smtp.gmail.com:465`) | — |
| `smtp_from` | Адрес отправителя для доставки через SMTP-ретрансляцию | — |
| `smtp_user` | Имя пользователя для аутентификации SMTP | — |
| `smtp_pass` | Пароль для аутентификации SMTP | — |
| `slack_alert` | Включить оповещения Slack с загрузкой файлов | `0` |
| `slack_subj` | Имя файла для загрузки в Slack | `maldet alert from $(hostname)` |
| `slack_token` | Токен Slack Bot API (права: `files:write`, `files:read`) | — |
| `slack_channels` | Разделённый запятыми список имён или ID каналов | `maldetreports` |
| `telegram_alert` | Включить оповещения Telegram | `0` |
| `telegram_bot_token` | Токен Telegram Bot API | — |
| `telegram_channel_id` | ID чата или группы Telegram | — |
| `discord_alert` | Включить оповещения через вебхуки Discord | `0` |
| `discord_webhook_url` | URL вебхука Discord для доставки оповещений | — |
### 3.3 Параметры сканирования
| Variable | Purpose | Default |
|----------|---------|---------|
| `scan_hashtype` | Алгоритм хеширования для этапа 1: `auto`, `sha256`, `md5`, `both` | `auto` |
| `scan_max_depth` | Максимальная глубина каталогов для find | `15` |
| `scan_min_filesize` | Минимальный размер файла для сканирования | `24` bytes |
| `scan_max_filesize` | Максимальный размер файла для сканирования | `2048k` |
| `scan_hexdepth` | Глубина в байтах для сопоставления HEX-сигнатур | `262144` |
| `scan_hex_chunk_size` | Файлов на микро-пакет при HEX+CSIG сканировании (диапазон: 1024-20480) | `10240` |
| `scan_csig` | Включить сканирование составных сигнатур (csig) (только в нативном режиме) | `1` |
| `scan_workers` | Параллельные рабочие процессы для проходов MD5, SHA-256, HEX и CSIG | `auto` |
| `scan_cpunice` | Приоритет nice для процесса сканирования (-19 до 19) | `19` |
| `scan_ionice` | Приоритет класса планировщика ввода-вывода (0-7) | `6` |
| `scan_cpulimit` | Жёсткий лимит загрузки CPU в процентах (0=отключено) | `0` |
| `scan_ignore_root` | Пропускать файлы, принадлежащие root, при сканировании (по умолчанию не применяется в режиме монитора; см. `monitor_scan_owner_filters`) | `1` |
| `scan_ignore_user` | Пропускать файлы, принадлежащие определённым пользователям | — |
| `scan_ignore_group` | Пропускать файлы, принадлежащие определённым группам | — |
| `scan_user_access` | Разрешить не-root пользователям запускать сканирования | `0` |
| `scan_user_access_minuid` | Минимальный UID для создания пользовательских каталогов `--mkpubpaths` | `100` |
| `scan_find_timeout` | Таймаут для формирования списка файлов через find (0=отключено, мин. 60 с, рекомендуется 14400=4 часа) | `0` |
| `scan_export_filelist` | Сохранять результаты find в tmp/find_results.last | `0` |
| `scan_tmpdir_paths` | Общедоступные для записи временные пути, включаемые в сканирования -a/-r | `/tmp /var/tmp /dev/shm /var/fcgi_ipc` |
| `string_length_scan` | Включить статистический анализ длины строк | `0` |
| `string_length` | Минимальная подозрительная длина строки | `150000` |
| `scan_progress_log_interval` | Секунды между контрольными точками журнала прогресса при фоновых сканированиях (0=отключено) | `60` |
| `scan_meta_cleanup_age` | Часы хранения файлов метаданных завершённых/прерванных сканирований (0=отключено) | `48` |
| `maint_compress_age` | Дни до сжатия завершённых файлов сеансов в gzip (0=отключено) | `30` |
| `maint_archive_age` | Дни до объединения сжатых сеансов в ежемесячные архивы (0=отключено) | `90` |
### 3.4 Сканирование YARA
Нативное сканирование YARA вызывает бинарный файл `yara` (или `yr` из YARA-X) независимо от ClamAV, поддерживая полные модули YARA, скомпилированные правила и пользовательские файлы правил, которые ограниченное подмножество YARA в ClamAV обработать не может. Когда доступны оба варианта, предпочтение отдаётся `yr` (YARA-X). При значении `auto` нативный YARA включается только тогда, когда ClamAV недоступен и найден бинарный файл yara/yr, что предотвращает дублирующую оценку правил.
| Variable | Purpose | Default |
|----------|---------|---------|
| `scan_yara` | Включить нативный этап сканирования YARA: `auto` (обнаружить бинарный файл, откат к ClamAV), `0` (отключено), `1` (включено) | `auto` |
| `scan_yara_timeout` | Таймаут в секундах (0=без таймаута) | `300` |
| `scan_yara_scope` | Область правил, когда ClamAV также активен: `all` (полное нативное сканирование) или `custom` (только пользовательские правила нативно, ClamAV обрабатывает rfxn.yara) | `custom` |
| `sig_import_yara_url` | URL для загрузки пользовательских правил YARA при обновлении сигнатур | — |
**Пользовательские правила YARA** можно размещать в двух местах, оба сохраняются при обновлениях:
- `sigs/custom.yara` — однофайловые правила
- `sigs/custom.yara.d/` — каталог для подключения файлов правил `.yar` и `.yara`
Совместимо со сторонними наборами правил, такими как [YARA Forge](https://yarahq.github.io/) и [Signature Base](https://github.com/Neo23x0/signature-base). Скомпилированные правила (вывод `yarac`) также поддерживаются через `sigs/compiled.yarc`.
**Пакетное сканирование:** YARA 4.0+ и все версии YARA-X используют `--scan-list` для эффективного пакетного сканирования файлов. Более старые версии YARA автоматически переключаются на построчное сканирование файлов.
Включить во время выполнения без редактирования конфигурации:```bash
maldet -co scan_yara=1 -a /home/?/public_html
| Variable | Purpose | Default |
|---|---|---|
quarantine_hits | Автоматически помещать обнаруженное вредоносное ПО в карантин | 0 |
quarantine_clean | Попытаться очистить файлы в карантине от вредоносного ПО | 0 |
quarantine_suspend_user | Приостановить учётную запись cPanel или отозвать shell при обнаружении | 0 |
quarantine_suspend_user_minuid | Минимальный UID для приостановки (защищает системные учётные записи) | 500 |
quarantine_on_error | Помещать файлы в карантин при возврате ошибки сканирующим движком | 1 |
| Variable | Purpose | Default |
|---|---|---|
default_monitor_mode | Стартовый режим монитора (users или путь к файлу); пусто = отключено | "" |
inotify_base_watches | Базовое количество файловых наблюдений (watches) на один пользовательский путь | 16384 |
inotify_minuid | Минимальный UID для мониторинга домашних каталогов пользователей | 500 |
inotify_docroot | Подкаталоги для мониторинга в домашних каталогах пользователей | public_html,public_ftp |
inotify_sleep | Секунд между пакетами сканирования | 15 |
inotify_reloadtime | Секунд между перезагрузками конфигурации | 3600 |
inotify_cpunice | Приоритет nice для процесса монитора | 18 |
inotify_ionice | Приоритет ввода-вывода (IO) для процесса монитора | 6 |
inotify_cpulimit | Жёсткий лимит CPU для монитора (0=отключено) | 0 |
digest_interval | Интервал между периодическими сводными уведомлениями digest: 24h, 30m, 7d, 0 (отключено) | 24h |
digest_escalate_hits | Порог количества срабатываний для немедленного эскалационного уведомления; 0 = отключено | 0 |
cron_digest_hook | Включить проход digest через хуки cron.daily (запускает digest при наличии новых обнаружений от хуков) | 1 |
monitor_paths_extra | Путь к файлу с дополнительными путями inotify для наблюдения, по одному пути в строке |
Настраиваемый скрипт-хук может вызываться после завершения сканирования и получает результаты сканирования через позиционные аргументы, переменные окружения LMD_* и, при необходимости, JSON через стандартный ввод (stdin). Хук никогда не прерывает сканирование — сбои регистрируются в журнале и не являются фатальными. Полное описание контракта хука см. в maldet(1).
| Variable | Purpose | Default |
|---|---|---|
post_scan_hook | Путь к скрипту-хуку (принадлежит root, не доступен для записи всем). Не может быть задан через -co | "" |
post_scan_hook_format | Уровень вывода: args, file, json (накопительный) | args |
post_scan_hook_exec | Режим выполнения: async (неблокирующий), sync (ожидание) | async |
post_scan_hook_timeout | Секунд до отправки SIGTERM (0=отключено, минимум 5) | 60 |
post_scan_hook_on | Фильтр типа сканирования: all, cli, digest | all |
post_scan_hook_min_hits | Минимальное количество срабатываний для запуска (0=всегда) | 1 |
Когда сканирование ClamAV включено (scan_clamscan=1 или auto при обнаруженном бинарном файле), LMD выбирает лучший доступный движок ClamAV в порядке приоритета:
clamdscan (если scan_clamd_remote=1 и конфигурация существует)clamd, работающий от rootclamd, работающий не от root (с --fdpass)clamscan (запасной вариант, медленнее)Сигнатуры LMD автоматически связываются символьными ссылками с каталогами данных ClamAV скриптом install.sh, предоставляя ClamAV доступ к сигнатурам LMD: MD5 (rfxn.hdb), HEX (rfxn.ndb) и YARA (rfxn.yara).
Шлюз проверки сигнатур: Перед развёртыванием обновлённых сигнатур в каталогах данных ClamAV LMD проверяет их с помощью clamscan -d в промежуточном (staging) каталоге. Если проверка не удалась, существующие сигнатуры LMD удаляются из пути ClamAV, чтобы повреждённые базы данных не нарушили работу ClamAV. Сигнал перезагрузки SIGUSR2 демону clamd отправляется только в том случае, если хотя бы один каталог данных ClamAV прошёл проверку (issue #467).
| Variable | Purpose | Default |
|---|---|---|
scan_clamscan | Включить ClamAV в качестве сканирующего движка: auto (определять бинарный файл во время выполнения), 0 (отключено), 1 (включено) | auto |
| Variable | Purpose | Default |
|---|---|---|
scan_clamd_remote | Использовать удалённый сервер clamd для сканирования | 0 |
remote_clamd_config | Путь к конфигурационному файлу удалённого clamd | /etc/clamd.d/clamd.remote.conf |
remote_clamd_max_retry | Максимальное количество повторных попыток при сбое удалённого clamd | 5 |
remote_clamd_retry_sleep | Секунд между повторными попытками | 3 |
| Variable | Purpose | Default |
|---|---|---|
enable_statistic | Включить сбор статистики стека ELK | 0 |
elk_host | TCP-хост для ввода ELK | — |
elk_port | TCP-порт для ввода ELK | — |
elk_index | Имя индекса Elasticsearch | — |
Более поздние источники переопределяют более ранние значения:
internals/internals.conf — внутренние пути, обнаружение бинарных файлов, определения URLconf.maldet — пользовательская конфигурацияinternals/compat.conf — сопоставления устаревших переменных/etc/sysconfig/maldet или /etc/default/maldet — системные переопределения-co|--config-option — переопределения во время выполненияИнтерфейс командной строки, коды возврата и типовые примеры. Полный справочник параметров см. в man maldet(1).```
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 Коды завершения
| Код | Значение |
|------|---------|
| `0` | Успешно, вредоносных программ не обнаружено |
| `1` | Ошибка или все пути сканирования не существуют |
| `2` | Обнаружены вредоносные программы |
**Примеры:**```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
JSON-вывод: Используйте --format json -e или --json-report для вывода структурированного JSON
(схемы v1.2) с метаданными сканера, деталями сканирования (путь, время, количество файлов), записями по
каждому срабатыванию с именем сигнатуры, путём к файлу, типом срабатывания, владельцем, правами доступа и
статусом карантина, а также сводкой с разбивкой по типам. Поддерживаются как TSV, так и устаревшие сеансы
обычного текста; устаревшие сеансы включают "source": "legacy" и отображают недоступные
обогащённые поля (хэш, размер, владелец и т. д.) как null.
Длительные сканирования больших файловых систем (1M+ файлов) можно контролировать без 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
**Возобновление контрольной точки:** `--stop` записывает файл контрольной точки, фиксируя этап сканирования, количество срабатываний, параметры конфигурации и прогресс каждого воркера. `--continue` проверяет контрольную точку, предупреждает, если сигнатуры изменились, перестраивает список файлов на основе текущего состояния файловой системы, восстанавливает предыдущие срабатывания и возобновляет сканирование с прерванного этапа. HEX-воркеры возобновляют работу с точностью до чанка (потеря ~30 секунд работы на воркера).
**Поддержка движков:** Встроенный движок (воркеры HEX/CSIG/hash) и автономный `clamscan` поддерживают все операции жизненного цикла. ClamAV на основе демона (`clamdscan`/`clamd`) поддерживает только `--kill` — `--pause` и `--stop` отклоняются с сообщением об ошибке, так как состояние ввода-вывода демона непрозрачно и используется совместно с другими клиентами.
---
## 5. Параметры исключения
Исключение путей, типов файлов и сигнатур из сканирования и мониторинга.
Четыре файла исключений определяют, что исключается из сканирования:
| Файл | Формат | Назначение |
|------|--------|---------|
| `ignore_paths` | По одному пути на строку | Исключает каталоги или файлы из сканирования |
| `ignore_file_ext` | По одному расширению на строку | Исключает расширения файлов (`.js`, `.css`) |
| `ignore_sigs` | По одному шаблону на строку | Пропускает соответствующие сигнатуры (regex, подстрока) |
| `ignore_inotify` | По одному буквальному пути на строку | Исключает события мониторинга inotify |
Все файлы исключений находятся в `/usr/local/maldetect/`.
**Примеры:**```
# 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.
Примечание: записи ignore_sigs обрабатываются как расширенные regex-шаблоны и сопоставляются как подстроки. Запись php.shell подавит php.shell, php.shell.v2, {YARA}php.shell.backdoor и т.д. Используйте ^php\.shell$ для точного совпадения. Символ . в regex соответствует любому символу; экранируйте его как \. для буквальной точки.
Автоматическое ежедневное сканирование, очистка данных и обновление сигнатур.
Устанавливаемое задание cron /etc/cron.daily/maldet выполняет три задачи:
cron_prune_days (по умолчанию: 21)autoupdate_signatures и autoupdate_version)scan_days дней, по умолчанию: 1)Ежедневное сканирование автоматически определяет установленные панели управления и соответствующим образом корректирует пути сканирования:
| Панель | Путь сканирования |
|---|---|
| cPanel | /home?/?/public_html/ (+ корневые каталоги аддонов/поддоменов) |
| 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/ |
Если активен режим мониторинга, ежедневные сканирования пропускаются, и вместо этого выдаётся ежедневный отчёт о событиях мониторинга.
Для пользовательских путей сканирования используйте hook-файл /usr/local/maldetect/cron/custom.cron. Для переопределений конфигурации, специфичных для cron, используйте /etc/sysconfig/maldet (RHEL) или /etc/default/maldet (Debian) или /usr/local/maldetect/cron/conf.maldet.cron.
Еженедельный watchdog-скрипт (/etc/cron.weekly/maldet-watchdog) обеспечивает независимые резервные обновления сигнатур, если основной cron сломан или устарел.
Мониторинг файлов в реальном времени с использованием inotify ядра, оповещения по контрольным суммам и управление супервизором.
Мониторинг файлов в реальном времени использует подсистему inotify ядра для обнаружения событий создания, изменения и перемещения файлов. Требуется ядро с CONFIG_INOTIFY_USER (стандартно для всех современных ядер).```bash
maldet -m users
maldet -b -m users
maldet -m /home/mike,/home/ashton
maldet -m /root/monitor_paths
maldet -k
**Как это работает:**
`maldet -m` запускает супервизорный процесс в режиме переднего плана по умолчанию. Супервизор управляет дочерним процессом `inotifywait` и обрабатывает восстановление после сбоев, перезагрузку конфигурации и отправку дайджест-оповещений. Используйте `-b`, чтобы демонизировать супервизор и немедленно вернуть управление.
1. `monitor_init()` устанавливает inotify-наблюдение за всеми файлами в отслеживаемых путях
2. События файлов помещаются в очередь и сканируются пакетно каждые `inotify_sleep` секунд (по умолчанию: 15)
3. Конфигурация перезагружается каждые `inotify_reloadtime` секунд (по умолчанию: 3600)
4. Параметры ядра `max_user_watches` и `max_user_instances` автоматически настраиваются для оптимальной производительности
5. Если `inotifywait` аварийно завершается, супервизор перезапускает его с экспоненциальной задержкой (2, 4, 8, 16, 32 секунды); после 3 последовательных сбоев супервизор завершает работу
**Дайджест-оповещения** отправляются периодически с интервалом, заданным параметром `digest_interval` (по умолчанию: `24h`). Если количество срабатываний с момента последнего дайджеста превышает `digest_escalate_hits`, немедленно отправляется эскалационное оповещение (по умолчанию: `0`, отключено).
**Дополнительные пути:** Чтобы отслеживать дополнительные пути без редактирования `conf.maldet`, добавьте их по одному на строку в файл, указанный в `monitor_paths_extra` (по умолчанию: `/usr/local/maldetect/monitor_paths.extra`). При каждой перезагрузке конфигурации они объединяются с основным списком наблюдения.
При использовании режима `users` отслеживаются только подкаталоги, соответствующие `inotify_docroot` (по умолчанию: `public_html,public_ftp`), а также системные временные каталоги `/tmp`, `/var/tmp` и `/dev/shm`.
**Файлы исключений (inotify):** Исключения мониторинга объединяют два файла — пользовательский `/usr/local/maldetect/ignore_inotify` и управляемый LMD `/usr/local/maldetect/internals/ignore_inotify.defaults`. Оба разделены переводами строк и поддерживают комментарии `#` и пустые строки. Пользовательский `ignore_inotify` по умолчанию принимает POSIX ERE (расширенные регулярные выражения) — якоря (`^`, `$`) и шаблоны (`.*`, `.+`) работают. Чтобы исключить литеральный путь, содержащий метасимволы регулярных выражений, добавьте префикс `literal:` (например, `literal:/tmp/app.cache`). Управляемый LMD `ignore_inotify.defaults` обрабатывается как литеральные подстроки — его курируемые записи автоматически экранируются при загрузке. Файл значений по умолчанию перезаписывается при каждом обновлении LMD; добавляйте локальные исключения только в `ignore_inotify`.
---
## 8. Система сигнатур
Типы сигнатур, соглашения об именовании, обновления и пользовательские файлы правил.
LMD поставляется с пятью типами сигнатур:
| Тип | Файл | Формат | Кол-во |
|------|------|--------|-------|
| MD5-хеши | `sigs/md5v2.dat` | `HASH:SIZE:{MD5}sig.name.N` | ~14,801 |
| SHA-256 хеши | `sigs/sha256v2.dat` | `HASH:SIZE:{SHA256}sig.name.N` | CDN |
| HEX-шаблоны | `sigs/hex.dat` | `HEXSTRING:{HEX}sig.name.N` | ~2,054 |
| Составные сигнатуры | `sigs/csig.dat` | `SUBSIG1\|\|SUBSIG2:signame` | CDN |
| Правила YARA | `sigs/rfxn.yara` | синтаксис YARA | ~783 правил |
| Скомпилированный YARA | `sigs/compiled.yarc` | вывод `yarac` | необязательно |
Также поддерживаются сигнатуры, совместимые с ClamAV:
- `sigs/rfxn.hdb` — формат ClamAV MD5
- `sigs/rfxn.ndb` — формат ClamAV HEX
- `sigs/rfxn.hsb` — формат ClamAV SHA-256 (требуется ClamAV >= 0.97)
**Соглашение об именовании сигнатур:** `{TYPE}category.name.variant_number`
Категории включают: `bin.` (двоичные), `c.` (язык C), `exp.` (эксплойты), `php.` (PHP), `js.` (JavaScript), `perl.` (Perl), `html.` (фишинг), `base64.inject.`, `gzbase64.`
**Префиксы срабатываний в отчётах сканирования:**
| Prefix | Source |
|--------|--------|
| `{MD5}` | совпадение MD5-хеша (этап 1) |
| `{SHA256}` | совпадение SHA-256 хеша (этап 1) |
| `{HEX}` | совпадение HEX-шаблона (этап 2) |
| `{CSIG}` | совпадение составной сигнатуры (этап 2.5) |
| `{SA}` | статистический анализ (длина строки) |
| `{YARA}` | нативное сканирование YARA (`scan_yara=1`) |
| `{CAV}` | движок ClamAV (clamd/clamscan) |
### 8.1 Обновление сигнатур
Сигнатуры обновляются ежедневно через задание cron или вручную:```bash
maldet -u # update signatures
maldet -u --force # force update even if current
Пользовательские сигнатуры могут быть добавлены в трёх форматах, все сохраняются при обновлении:
| Тип | Файл | Формат |
|---|---|---|
| Пользовательский MD5 | sigs/custom.md5.dat | То же, что md5v2.dat |
| Пользовательский SHA-256 | sigs/custom.sha256.dat | То же, что sha256v2.dat |
| Пользовательский HEX | sigs/custom.hex.dat | То же, что hex.dat |
| Пользовательский CSIG | sigs/custom.csig.dat | То же, что csig.dat |
| Пользовательский YARA | sigs/custom.yara | Синтаксис правил YARA |
| Пользовательский YARA (drop-in) | sigs/custom.yara.d/*.yar | Файлы правил YARA |
| Компилированный YARA | sigs/compiled.yarc | Вывод yarac (опционально) |
URL-адреса удалённого импорта могут быть настроены для автоматической загрузки при обновлении сигнатур:
| Переменная | Назначение |
|---|---|
sig_import_md5_url | URL для пользовательских сигнатур MD5 |
sig_import_sha256_url | URL для пользовательских сигнатур SHA-256 |
sig_import_hex_url | URL для пользовательских сигнатур HEX |
sig_import_csig_url | URL для пользовательских составных сигнатур |
sig_import_yara_url | URL для пользовательских правил YARA |
Изоляция, восстановление и очистка файлов, заражённых вредоносным ПО.
Файлы в карантине хранятся в /usr/local/maldetect/quarantine/ с правами доступа 000. Исходный путь, владелец, права доступа и время изменения записываются в /usr/local/maldetect/sess/quarantine.hist для полного восстановления.```bash
maldet -q SCANID
maldet -s SCANID
maldet -s /usr/local/maldetect/quarantine/config.php.23754
maldet -n SCANID
**Quarantine file naming:** `FILENAME.INODE` (e.g., `config.php.23754`)
For non-root scans (e.g., ModSecurity2 upload scanning), quarantine data is stored under `/usr/local/maldetect/pub/USERNAME/quar/`. Use the `-U` flag to interact with non-root quarantine:```bash
maldet -U nobody -s 112012-0032.13771
Функция очистки ищет скрипты с именами сигнатур в каталоге clean/. Каждый скрипт получает путь к заражённому файлу в качестве аргумента и должен удалять вредоносное содержимое. После очистки файл сканируется повторно — если он по-прежнему вызывает срабатывание, очистка помечается как FAILED.
Чтобы создать правило очистки для сигнатуры php.cmdshell.r57, добавьте файл clean/php.cmdshell.r57, содержащий команду, например sed -i, с соответствующим шаблоном. Успешная очистка восстанавливает файл в исходный путь, владельцу и правам доступа.
Очистка является подфункцией карантина — файлы должны быть помещены в карантин (или использовать -n), чтобы очистка выполнялась.
API перехватчиков служб для ModSecurity, FTP, Exim и пользовательских интеграций.
LMD обеспечивает сканирование файлов в реальном времени для нескольких служб через единый API hookscan.sh. Один скрипт обрабатывает диспетчеризацию режимов для ModSecurity, pure-ftpd, ProFTPD, Exim и универсальных (пользовательских) интеграций.
Обнаружения hook-сканирования записываются в скользящий журнал срабатываний (hook.hits.log), а не создают файлы сеансов для каждого сканирования. Обнаружения включаются в периодические сводные оповещения и могут быть просмотрены с помощью 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'"
Вредоносные загрузки отклоняются действием deny и регистрируются в журнале аудита ModSecurity. Аргумент режима не требуется — `hookscan.sh` по умолчанию использует режим ModSecurity для обратной совместимости. И ModSecurity v2, и v3 (libmodsecurity) используют один и тот же контракт `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
Требуется pure-ftpd, скомпилированный с --with-uploadscript. Режим определяется автоматически через переменную окружения UPLOAD_VUSER. Заражённые файлы помещаются в карантин после загрузки (принцип «запустил и забыл» — загрузку нельзя заблокировать, возможна только постобработка).
av_scanner = cmdline:
/usr/local/maldetect/hookscan.sh exim %s :
maldet: (.+):
maldet: (.+)
Три поля, разделённые двоеточием: шаблон команды, триггерное регулярное выражение и регулярное выражение захвата имени. Когда обнаружено вредоносное ПО, Exim отклоняет сообщение, используя захваченное имя сигнатуры.
### 10.5 Универсальный API
Для пользовательских интеграций, пакетного сканирования и стороннего использования:```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
Пакетный вывод формирует по одной строке STATUS: PATH на файл. Код возврата — по принципу «наихудший результат побеждает».
Конфигурация hook-сканирования хранится в conf.maldet.hookscan (необязательно — значения по умолчанию встроены в скрипт). Эталонные значения по умолчанию находятся в conf.maldet.hookscan.default.
Ключевые переменные:
| Variable | Default | Описание |
|---|---|---|
hookscan_timeout | 30 | Таймаут сканирования в секундах |
hookscan_fail_open | 1 | Разрешить файл при ошибке сканирования (0 = блокировать) |
hookscan_escalate_hits | 0 | Немедленное предупреждение при N срабатываниях hook в час (0 = отключено) |
hookscan_service_users | apache,nginx,... | UID сервисов, освобождённые от ограничения homedir |
hookscan_user_rate_limit | 60 | Максимум сканирований в час для вызывающих не от root |
hookscan_user_show_signames | 1 | Показывать имена сигнатур не-root вызывающим |
hookscan_list_max_bytes | 1048576 | Максимальный размер файла списка (1 МБ) |
hookscan_list_max_entries | 10000 | Максимум записей в списке файлов |
После включения выполните maldet --mkpubpaths, чтобы создать пользовательские каталоги данных для операций сканирования не от root.
Убедитесь, что каналы доставки предупреждений настроены корректно:```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
Тестовые оповещения используют реальный конвейер рендеринга с синтетическими данными. Тема письма снабжается префиксом `[TEST]`. Изоляция канала гарантирует, что срабатывает только указанный канал.
### 10.8 Дайджест хуков
Обнаружения хуков сводятся в периодические дайджест-оповещения:```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
Ежедневное задание cron автоматически отправляет дайджест хуков при появлении новых обнаружений (управляется через cron_digest_hook=1 в conf.maldet).
Для администраторов, заменяющих CXS на LMD:
| Компонент CXS | Эквивалент LMD |
|---|---|
cxscgi.sh | hookscan.sh modsec |
cxsftp.sh | hookscan.sh ftp |
| ProFTPD mod_exec для cxs | hookscan.sh proftpd |
cxs --file | hookscan.sh generic |
cxswatch | maldet --monitor |
/etc/cxs/cxs.conf | conf.maldet.hookscan |
Подключение LMD к внешним инструментам, конвейерам автоматизации и сторонним сканерам.
Сигнатуры LMD автоматически симлинкуются в каталоги данных ClamAV с помощью install.sh, обеспечивая покрытие двумя движками. Установите scan_clamscan=auto (по умолчанию) для автоматического определения ClamAV. См. 3.8 Интеграция с ClamAV для выбора движка и проверки сигнатур.
Установите enable_statistic=1 вместе с elk_host, elk_port и elk_index, чтобы передавать события сканирования в Elasticsearch. См. 3.10 Интеграция с ELK.
Помимо электронной почты LMD поддерживает четыре канала доставки оповещений: Slack (Block Kit), Telegram (MarkdownV2), Discord (встраиваемые вебхуки) и SMTP-ретрансляцию для сред без локального MTA. См. 3.2 Оповещения для настройки.
Машиночитаемый вывод результатов сканирования для CI/CD и автоматизации:```bash maldet --format json -e SCANID # JSON report to stdout maldet --json-report list # list all scans as JSON
См. `man maldet`(1) для схемы JSON v1.2 (единая форма `{schema_version, scanner, host, reports[]}` как для `-e SCANID`, так и для `-e list`).
### Обнаружение панелей управления хостингом
Ежедневный cron автоматически обнаруживает 12+ панелей управления хостингом и корректирует пути сканирования. Полную матрицу панелей см. в [6. Cron Daily](#6-cron-daily).
---
## Лицензия
LMD разрабатывается и поддерживается на добровольной основе Райаном Макдональдом [[email protected]].
Linux Malware Detect (LMD) распространяется под лицензией GNU General Public License (GPL) v2
без ограничений на использование или распространение. Заявление об авторских правах и текст GNU GPL
включены в файл `COPYING.GPL`. Для производных работ необходимо указывать авторство
в соответствии с требованиями GNU GPL.
---
## Поддержка
Исходный репозиторий LMD находится по адресу: https://github.com/rfxn/linux-malware-detect
Об ошибках, запросах функций и общих вопросах можно сообщить через GitHub issues или отправив письмо на [email protected].
Официальная страница проекта: https://www.rfxn.com/projects/linux-malware-detect/
/usr/local/maldetect/monitor_paths.extramonitor_scan_owner_filters | Применять фильтры владельцев scan_ignore_root/scan_ignore_user/scan_ignore_group в режиме монитора; 0 (по умолчанию) = выкл — монитор сканирует все файлы независимо от владельца (восстанавливает семантику 1.6.6, исправляет issue #485); 1 = вкл — применять фильтры владельцев | 0 |