🛡️ Аудит безопасности — evrotrans-mailer

Почтовый сервер (SMTP/Postfix) · FTP · cron-узел
Дата аудита: 2026-06-06
Хост: vm-evrotrans-yandex-mailer-1750877542270
ОС: Ubuntu 20.04.6 LTS · ядро 5.4.0-216
Внешний IP: 31.44.10.106 (Ставрополь)
Домен: mail.evrotrans.net
Платформа: Yandex Cloud + Яндекс Cyber Backup
Uptime: 343 дня
Источник: ручной аудит из-под root

1. Сводка

6
🔴 Высокая критичность
7
🟠 Средняя критичность
9
🟢 Настроено хорошо
КритичностьТемы
🔴 ВысокаяПароли в открытом виде в .env (включая sudo-пароль админа), захардкоженные секреты в скриптах (MySQL root, ключ шифрования, SSH-пароль к чужому серверу), NOPASSWD-sudo у orphan-аккаунта y4tsun0v, zabbix в группе docker (=root), открытый FTP (cleartext), docker.sock в контейнере autoheal
🟠 СредняяХост-firewall выключен, переиспользование одного SSH-ключа на 4 аккаунта, переиспользование пароля для нескольких сервисов, Zabbix/Acronis на всех интерфейсах, бессрочные пароли, self-signed (snakeoil) TLS, journald без лимита (1.2 ГБ) + диск 74%
🟢 ХорошоPostfix НЕ open-relay; порт 25 только во внутреннем VPC; SSH (только ключи, root запрещён, AllowUsers, нестандартный порт, maxauthtries 3); реальных приватных ключей приложения нет; SUID штатный; нет пустых паролей; один UID 0; 0 security-обновлений в очереди
Главный вывод: входная дверь (SSH) и сам почтовик (Postfix) настроены добротно — релей закрыт, 25-й порт смотрит только во внутреннюю сеть. Но рядом лежит файл /home/evrotrans/stable/.env со всеми паролями открытым текстом, а в обслуживающих скриптах захардкожены ещё и MySQL-root и SSH-пароли — это даёт мгновенную эскалацию. Плюс повторяются проблемы первого сервера: orphan-аккаунт с беспарольным sudo и открытый незашифрованный FTP.
Содержание
  1. 🔴 Секреты открытым текстом — .env
  2. 🔴 Захардкоженные секреты в скриптах
  3. Учётные записи и привилегии
  4. SSH
  5. Postfix
  6. FTP (vsftpd)
  7. Контейнеры Docker
  8. Облако / метаданные Yandex Cloud
  9. Сетевые порты
  10. Firewall
  11. Входы и перебор
  12. Cron, SUID, обновления
  13. 🟠 Диск и журналы
  14. План действий
  15. Что хорошо
  16. Сравнение серверов

2. 🔴 Секреты открытым текстом — /home/evrotrans/stable/.env

Это один из самых серьёзных рисков сервера. Файл содержит рабочие пароли в plaintext:

ПеременнаяЗначениеЧто компрометирует
ENV_SERVER_ADMIN_PASSWORDxe3LLhaPF…🔴 Пароль админа r3ddan9он же sudo-пароль
ENV_CRON_ADMIN_PASSxe3LLhaPF…🔴 Тот же пароль (переиспользован)
ENV_SERVER_USER_PASSWORD / ENV_CRON_USER_PASSb3dYoqkH…🔴 Пароль evrotrans (он же FTP-логин)
ENV_BACKUP_SERVER_PASSWORDUoXR9Jca…🔴 Доступ к бэкап-серверу dev.evrotrans.net:48008
ENV_POSTFIX_PASSWORDV9MbTVH7…🟠 SMTP-аутентификация webmaster@evrotrans.net
ENV_ENCRYPTION_PASSWORD / _SELFw7yNyNnJ…🟠 Пароль шифрования (одинаковый)
ENV_GITHUB_TOKENghp_hash Плейсхолдер, не реальный токен
Действия (срочно): сменить все пароли; прекратить переиспользование; убрать из git (filter-repo/BFG); chmod 600; Docker secrets/vault; проверить утечку в бэкапы.
🔍 Доказательство — cat /home/evrotrans/stable/.env
# cat /home/evrotrans/stable/.env
ENV_SERVER_ADMIN_PASSWORD=xe3LLhaPF…
ENV_CRON_ADMIN_PASS=xe3LLhaPF…
ENV_SERVER_USER_PASSWORD=b3dYoqkH…
ENV_BACKUP_SERVER_PASSWORD=UoXR9Jca…
ENV_POSTFIX_PASSWORD=V9MbTVH7…
ENV_ENCRYPTION_PASSWORD=w7yNyNnJ…
# пароль admin = sudo-пароль r3ddan9, plaintext в дереве приложения

2-bis. 🔴 Захардкоженные секреты в скриптах (stable/host/)

Помимо .env, реальные пароли зашиты прямо в код сервисных скриптов (читаемы под evrotrans):

ФайлСекретЧто компрометирует
cron_home_backuper_database.shmysqldump -uroot -p"vsyvzoajoa"🔴 root-пароль MySQL парка в открытую
cron_home_backuper_{config,database,web}.shopenssl … -k w7yNyNnJVx4N🔴 Ключ шифрования бэкапов в 3 скриптах (= .env) — расшифровка любого бэкапа
cron_backup_catcher_config.shsshpass -p "V2LaYJMAc0" scp … etrans@77.222.52.97🔴 SSH-пароль к другому серверу 77.222.52.97; всплыли юзеры etrans, vitek
Один скомпрометированный файл host/ = доступ к БД парка (MySQL root), расшифровка всех бэкапов и SSH к соседнему серверу. Ключ шифрования лежит рядом с данными — шифрование декоративное. Пароли через sshpass -p видны в ps.

⚠️ Эти скрипты ссылаются на пути /home/etrans/stable/... и контейнеры (stable_mysql_1, stable-certbot-1), которых на mailer нет — это общая библиотека, скопированная с web-сервера. На mailer инертна, но секреты в ней настоящие и общие для парка.

Действия: сменить root-пароль MySQL и SSH-пароль к 77.222.52.97; вынести ключ шифрования из кода; перейти на SSH-ключи. Применить и на web-сервере, где скрипты активны.
🔍 Доказательство — grep -rnE 'p"vsyvzoajoa"|-k w7yNyNnJVx4N|sshpass -p' host/
# grep -rnE 'p"vsyvzoajoa"|-k w7yNyNnJVx4N|sshpass -p' /home/evrotrans/stable/host/
cron_home_backuper_database.sh:  mysqldump -uroot -p"vsyvzoajoa" …
cron_home_backuper_config.sh:    openssl enc -aes-256-cbc … -k w7yNyNnJVx4N
cron_home_backuper_database.sh:  openssl enc -aes-256-cbc … -k w7yNyNnJVx4N
cron_home_backuper_web.sh:       openssl enc -aes-256-cbc … -k w7yNyNnJVx4N
cron_backup_catcher_config.sh:   sshpass -p "V2LaYJMAc0" scp … etrans@77.222.52.97
# MySQL root, ключ шифрования и SSH-пароль к другому серверу — в открытую

3. Учётные записи и привилегии

3.1 Интерактивные пользователи

ПользовательUIDПарольSSHsudoНазначение
root0🔒 L❌ запрещёнСистемный
y4tsun0v1000✅ P❌ не в AllowUsers🔴 NOPASSWD:ALLOrphan от cloud-init
r3ddan91001✅ P✅ sudo + dockerАдминистратор (danil)
evrotrans1002✅ P❌ (но в docker)Сервисный аккаунт

UID 0 ровно один ✅ · Пустых паролей нет ✅ · Системные демоны — nologin

3.2 🔴 sudo и группа docker

root      ALL=(ALL:ALL) ALL
%admin    ALL=(ALL) ALL              # группа admin — ПУСТАЯ
%sudo     ALL=(ALL:ALL) ALL          # только r3ddan9 (с паролем)
y4tsun0v  ALL=(ALL) NOPASSWD:ALL     # /etc/sudoers.d/90-cloud-init-users
getent group dockerr3ddan9, evrotrans, zabbix. Группа docker эквивалентна root. То есть evrotrans и zabbix (агент мониторинга) фактически имеют root без пароля и без sudo. Компрометация Zabbix-агента = root на хосте.

y4tsun0v — полный root без пароля через cloud-init (подтверждено в метаданных Yandex Cloud). По SSH не заходит, но любая локальная сессия под ним → мгновенный root.
🔍 Доказательство — getent group docker
# getent group docker
docker:x:998:r3ddan9,evrotrans,zabbix
# docker-группа = root без пароля, в т.ч. у агента zabbix
🔍 Доказательство — cat /etc/sudoers.d/90-cloud-init-users
# sudo cat /etc/sudoers.d/90-cloud-init-users
y4tsun0v ALL=(ALL) NOPASSWD:ALL
# orphan-аккаунт получает root без пароля
🔍 Доказательство — getent group sudo
# getent group sudo
sudo:x:27:r3ddan9
# getent group admin
# группа admin пустая → sudo через группу только у r3ddan9 (с паролем)

3.3 Политика паролей

PASS_MAX_DAYS 99999   # бессрочные ⚠️
PASS_MIN_DAYS 0
PASS_WARN_AGE 7

4. SSH

ПараметрЗначениеОценка
port48008✅ нестандартный
permitrootloginno
passwordauthenticationno✅ только ключи
pubkeyauthenticationyes
permitemptypasswordsno
maxauthtries3
allowusersr3ddan9 evrotrans✅ белый список
x11forwardingyes🟢 можно no
🔍 Доказательство — sshd -T | grep -Ei '^(port|permitrootlogin|...)'
# sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|permitemptypasswords|maxauthtries|allowusers)'
port 48008
permitrootlogin no
passwordauthentication no
pubkeyauthentication yes
permitemptypasswords no
maxauthtries 3
allowusers r3ddan9 evrotrans
# только ключи, root запрещён, нестандартный порт, белый список — SSH настроен хорошо

Во всех четырёх аккаунтах прописан один ключ danil@IdeaPad-3-14ALC6. Root-ключ обезврежен форсированной командой-заглушкой. ✅

🟠 Один приватный ключ = доступ ко всем учёткам.
🟠 /home/evrotrans/.ssh/authorized_keys и /home/r3ddan9/.ssh/authorized_keys имеют права 664 (читаемы миром, group-writable) — должно быть 600.
🔍 Доказательство — ls -l .../authorized_keys
# ls -l /home/evrotrans/.ssh/authorized_keys /home/r3ddan9/.ssh/authorized_keys
-rw-rw-r-- 1 evrotrans evrotrans … /home/evrotrans/.ssh/authorized_keys
-rw-rw-r-- 1 r3ddan9   r3ddan9   … /home/r3ddan9/.ssh/authorized_keys
# права 664 (group-writable, читаемы миром) — должно быть 600
🔍 Доказательство — grep -rl 'danil@IdeaPad-3-14ALC6' /root/.ssh /home/*/.ssh
# sudo grep -rl 'danil@IdeaPad-3-14ALC6' /root/.ssh /home/*/.ssh
/root/.ssh/authorized_keys
/home/y4tsun0v/.ssh/authorized_keys
/home/r3ddan9/.ssh/authorized_keys
/home/evrotrans/.ssh/authorized_keys
# один и тот же ключ во всех 4 аккаунтах = единая точка компрометации

5. Postfix — оценка

Open-relay НЕ обнаружен:
smtpd_relay_restrictions     = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_recipient_restrictions = permit_sasl_authenticated, reject_unauth_destination
mynetworks = 127.0.0.0/8 [::1]/128        # только localhost
smtpd_sasl_auth_enable = yes
Чужие письма не пересылаются. 🟢 Порт 25 проброшен только на внутренний VPC-адрес 10.150.0.20:25 — снаружи SMTP недоступен. Сервис активно отправляет почту (см. раздел доставляемости в ARCHITECTURE).
🔍 Доказательство — postconf -n | grep -E 'relay_restrictions|mynetworks|sasl_auth'
# docker exec stable-postfix-1 postconf -n | grep -E 'smtpd_relay_restrictions|smtpd_recipient_restrictions|mynetworks|smtpd_sasl_auth_enable'
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
mynetworks = 127.0.0.0/8 [::1]/128
smtpd_sasl_auth_enable = yes
# defer_unauth_destination + mynetworks=localhost → чужие письма не релеятся (НЕ open-relay)
🔍 Доказательство — ss -tlpn | grep :25
# ss -tlpn | grep :25
LISTEN 0 … 10.150.0.20:25 … users:(("docker-proxy",…))
# слушает 10.150.0.20, не 0.0.0.0 — снаружи SMTP недоступен
🟠 TLS на self-signed snakeoil-сертификате, security_level = may — SASL-логин может уйти по нешифрованному каналу. Поставить Let's Encrypt для mail.evrotrans.net.

6. FTP (vsftpd) — 🔴 открыт наружу, без шифрования

listen_port=48080
anonymous_enable=NO          # ✅ анонимов нет
ssl_enable=NO                # 🔴 шифрования НЕТ
chroot_local_user=YES, local_root=/home/$USER/
allow_writeable_chroot=YES   # 🟠 ослабляет chroot
userlist_enable=YES, userlist_deny=NO   # белый список: r3ddan9, evrotrans
🔴 vsftpd слушает 0.0.0.0:48080 — доступен из интернета, передаёт логин/пароль открытым текстом. Логины = локальные пользователи, пароли в .env plaintext.

Но FTP фактически не используется (/var/log/vsftpd.log пуст) → отключение (systemctl disable --now vsftpd) закрывает риск без потерь. Если понадобится — SFTP (уже есть SSH) или FTPS + сертификат + firewall.
🔍 Доказательство — grep -E 'ssl_enable|listen_port|anonymous_enable' /etc/vsftpd.conf
# grep -E 'ssl_enable|listen_port|anonymous_enable' /etc/vsftpd.conf
listen_port=48080
anonymous_enable=NO
ssl_enable=NO
# wc -l /var/log/vsftpd.log
0 /var/log/vsftpd.log
# ssl_enable=NO → пароли cleartext; лог пуст → сервис не используется, можно отключить без потерь

7. Контейнеры Docker

КонтейнерОбразСеть/портыПримечание
stable-postfix-1catatnight/postfix10.150.0.20:25Почтовик
stable-autoheal-1willfarrell/autoheal:1.2.0🔴 монтирует docker.sock:rw
stable-crontab-1ddan9/crontabnetwork_mode: hostCron (dormant); монтирует crontab/keys → /root/.ssh
🔴 autoheal + docker.sock: доступ к Docker-сокету = возможность запустить привилегированный контейнер и стать root на хосте. Минимизировать: socket-proxy с ограниченными endpoint'ами либо :ro.
🔍 Доказательство — docker inspect stable-autoheal-1 --format '{{json .Mounts}}'
# docker inspect stable-autoheal-1 --format '{{json .Mounts}}'
[{"Type":"bind","Source":"/var/run/docker.sock","Destination":"/var/run/docker.sock","Mode":"rw","RW":true,…}]
# docker.sock смонтирован RW → путь к root на хосте
🟢 У всех контейнеров privileged: false, no-new-privileges=true, apparmor=docker-default, ограничено логирование.

8. Облако / метаданные Yandex Cloud

🔍 Доказательство — curl -H 'Metadata-Flavor: Google' …/user-data
# curl -s -H 'Metadata-Flavor: Google' metadata.google.internal/computeMetadata/v1/instance/attributes/user-data
#cloud-config
users:
  - name: y4tsun0v
    sudo: ALL=(ALL) NOPASSWD:ALL
    …
# curl -s -H 'Metadata-Flavor: Google' …/attributes/enable-oslogin
Not Found
# cloud-init жёстко прописывает y4tsun0v NOPASSWD:ALL; OS Login выключен → контроль метаданных = контроль VM

9. Сетевые порты

ПортПроцессОценка
48008 tcpsshd✅ SSH (ключи)
48080 tcpvsftpd🔴 FTP — наружу, без шифрования
10050 tcp (*)zabbix_agent2🟠 только серверу Zabbix
37845 tcp (*)grpm-sync (Acronis)🟠 на всех интерфейсах
10.150.0.20:25postfix✅ только внутренний VPC
🔍 Доказательство — ss -tulpn
# ss -tulpn
LISTEN 0 … 0.0.0.0:48008 … users:(("sshd",…))
LISTEN 0 … 0.0.0.0:48080 … users:(("vsftpd",…))
LISTEN 0 … *:10050 … users:(("zabbix_agent2",…))
LISTEN 0 … *:37845 … users:(("grpm-sync-unit",…))
# sshd, vsftpd, zabbix-агент и Acronis слушают на всех интерфейсах (наружу)

10. Firewall — 🟠 выключен

ufw statusinactive. В iptables — только автоправила Docker; ограничений на INPUT нет (-P INPUT ACCEPT). Порты 48080/10050/37845 открыты всем, кого пропустит облачный SG.

Действие: включить ufw/nftables (allow 48008; остальные — доверенные IP) + облачный firewall Yandex Cloud.
🔍 Доказательство — ufw status / iptables -S | grep -- '-P INPUT'
# sudo ufw status
Status: inactive
# sudo iptables -S | grep -- '-P INPUT'
-P INPUT ACCEPT
# ufw выключен, политика INPUT по умолчанию ACCEPT → host-firewall отсутствует

11. Входы и фоновый перебор

🔍 Доказательство — lastb | head
# sudo lastb | head
root     ssh:notty    77.83.39.x       … gone - no logout
admin    ssh:notty    130.12.181.x     … gone - no logout
user     ssh:notty    45.144.212.x     … gone - no logout
# фоновый перебор SSH с ботнет-подсетей — рекомендуется fail2ban

12. Cron, SUID, обновления — ✅ в норме

12-bis. 🟠 Дисковое пространство и журналы

Диск / заполнен на 74% (11/15 ГБ) — пока не критично, но растёт бесконтрольно:

ПотребительОбъёмПримечание
/var/log/journal1.2 ГБ🟠 systemd-журнал без лимита
Acronis (/opt + /var/lib + /usr/lib)~3.7 ГБагент бэкапа — главный потребитель
один лог Acronis Scheduler152 МБодин файл
crontab/logs/cron.log9.9 МБспам crond: wakeup (cron в простое)
/swapfile1.0 ГБ+ zram-своп
Память: контейнеры почти ничего не едят (postfix 16 МБ); основное потребление — агент Acronis (mms 57 МБ, task-manager 21 МБ). Машина на постоянном свопе (RAM 1 ГБ).

Действия: лимит журналу (SystemMaxUse=200M), ротация логов Acronis и cron.log; рассмотреть увеличение диска/RAM.
🔍 Доказательство — du -sh /var/log/journal / df -h /
# du -sh /var/log/journal
1.2G    /var/log/journal
# df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/…           15G   11G  4.0G  74% /
# journald без лимита (1.2 ГБ), диск / заполнен на 74%

13. План действий

🔴 Высокий приоритет

  1. .env-секреты: сменить ВСЕ пароли; прекратить переиспользование; chmod 600; убрать из git/бэкапов; secrets/vault.
  2. Захардкоженные секреты в скриптах: сменить MySQL root (vsyvzoajoa), SSH-пароль к 77.222.52.97 (V2LaYJMAc0), ключ шифрования; перейти на SSH-ключи. Применить и на web-сервере.
  3. zabbix из группы docker: убрать (gpasswd -d zabbix docker). Пересмотреть evrotrans.
  4. y4tsun0v NOPASSWD-sudo: удалить orphan или убрать NOPASSWD; исправить cloud-init в метаданных Yandex Cloud.
  5. FTP: отключить — сервис не используется, риск снимается без потерь.
  6. docker.sock в autoheal: socket-proxy или :ro.

🟠 Средний приоритет

  1. Включить host-firewall; ограничить 48080/10050/37845; продублировать SG Yandex Cloud.
  2. TLS Postfix: Let's Encrypt вместо snakeoil.
  3. Права authorized_keys: chmod 600 для evrotrans и r3ddan9.
  4. fail2ban против SSH-перебора.
  5. Разделить ключи/пароли по ролям вместо общего danil@IdeaPad.
  6. Политика паролей: PASS_MAX_DAYS 365.
  7. Метаданные Yandex Cloud: проверить ssh-keys; рассмотреть OS Login.
  8. Диск/журналы: лимит journald, ротация логов Acronis и cron.log.
  9. DMARC: поднять p=nonep=quarantine после анализа rua.

🟢 Дополнительно

  1. Периодическая перезагрузка (uptime 343 дня).
  2. Убрать/усмирить dormant cron-контейнер (лог растёт спамом).
  3. Обновить Postfix (образ ~11 лет, версия 2.11).
  4. x11forwarding no в sshd.

14. Что настроено хорошо (сохранить)

15. Сравнение с первым сервером (web/vpn)

ТемаСервер 1 (web/vpn)Сервер 2 (mailer)
y4tsun0v NOPASSWD-sudo🔴 есть🔴 есть (то же)
Открытый FTP (cleartext)🔴 есть🔴 есть (но не используется)
Приватные ключи в дереве приложения🔴 id_rsa, OpenVPN CA/server✅ нет
Пароли plaintext в .env(не проверялось)🔴 есть
Захардкоженные секреты в скриптах🔴 вероятно (общая библиотека)🔴 есть (MySQL root, ключ, SSH-пароль)
zabbix в группе docker🔴 есть
Postfix open-relayn/a✅ закрыт
SSH-конфиг✅ хорошо✅ хорошо
Переиспользуемый ключ danil@IdeaPad🟠 на 4 аккаунтах🟠 на 4 аккаунтах (тот же!)
Скрипты host/ — общая библиотека, ссылающаяся на пути web-сервера (/home/etrans/...) и содержащая секреты MySQL/SSH. Исправления по §2-bis нужно провести на всём парке, а не только на mailer.