Все имена хостов, баз, топиков и учётные данные в примерах, кроме явно помеченных как реальные, — вымышленные или placeholder'ы. Совпадения с реальными системами случайны.
TL;DR
Severity: critical — активный криптомайнер/backdoor, контейнер имел outbound + filesystem write capability через :rw bind mount.
Detected: 2026-08-09 ~18:30 UTC, при проверке 502 на https://elrise.ru/ и https://elrise.io/.
Reporter: дежурный инженер (operator-triggered).
Status: скомпрометированный стек остановлен; SSH закалён; forensics и recovery в работе.
Восемнадцать минут — от операторской жалобы до docker stop. Семьдесят два часа до этого rootkit жил в контейнере незамеченным. Эта публикация — хронология инцидента, разбор fingerprint-ов компрометации, и почему следующий такой инцидент должен ловиться не через оператора, а через алерт. Recovery plan намеренно не включён — это отдельный internal runbook.
1. Что произошло
Контейнер elrise-backend (PHP-FPM 8.5 production-стек elrise-symfony, запущенный на tmp-vps 46.36.219.176) был скомпрометирован атакующим, который:
- Сбросил backdoor toolkit в
/tmp/.r.rpk/,/tmp/.xdiag/,/tmp/.apid,/tmp/.perf.c/ - Запустил второй php-fpm master-процесс (rogue, PID 1397, отличимый от легитимного PID 1 отсутствием
:в имени процесса) - Запустил
apache2 -DFOREGROUNDworker подwww-dataс именем процесса, замаскированным под{xzdiffunlink}черезprctl(PR_SET_NAME, ...)— подозрительно, потому что оригинальный образ elrise-symfony не устанавливает apache2 - Запустил BusyBox shell backdoor
sh yboxс 6 открытыми файловыми дескрипторами (интерактивный) - Запустил
sleep 300; rm -rf /tmp/.install.pid*(классический паттерн drop+cleanup криптомайнера — staging payload, sleep для уклонения от детекции, потом удаление installation-артефактов) - Эксплуатировал CVE-2012-1823 (PHP-CGI argv injection) через
POST /usr/local/lib/php/PEAR.phpс source IP211.234.111.116— запрос был обработан (HTTP 200), что означает, что backdoor принял attack-трафик
Немедленные операторские действия (под явным операторским одобрением):
- 18:38 UTC:
docker stop elrise-backend elrise-proxy— скомпрометированный стек остановлен - 18:39 UTC:
PasswordAuthentication noприменён к/etc/ssh/sshd_config, sshd перезагружен
2. Timeline (UTC)
| Time | Событие |
|---|---|
| До 2026-08-06 | Образ elrise-symfony:local собран из <project-root>/Dockerfile (последняя правка Dockerfile: Aug 6 01:02 per ls -la) |
| 2026-08-06 18:59 | /tmp/.r.rpk/ впервые создан (20 entries) — самое раннее forensic-свидетельство компрометации |
| 2026-08-09 17:43 | Сервер перезагружен (load average 47 / 1 CPU; elrise-backend показывал 82% CPU до перезагрузки по данным предыдущего аудита) |
| 2026-08-09 17:44 | Контейнер elrise-proxy запущен (по docker logs) |
| 2026-08-09 17:55 | elrise-proxy graceful shutdown (SIGQUIT) |
| 2026-08-09 17:56:33 | elrise-backend запущен (после FastPanel-initiated restart) — тот же контейнер, который был скомпрометирован до перезагрузки, теперь работает с malware |
| 2026-08-09 18:28:36 | Первая наблюдаемая атака с 211.234.111.116: POST /usr/local/lib/php/PEAR.php → HTTP 200 (CVE-2012-1823) |
| 2026-08-09 18:28:43 | Follow-up probe: POST /usr/share/php/PEAR.php → HTTP 404 |
| 2026-08-09 18:30 | Оператор открывает браузер, видит 502 на apex-доменах, запрашивает проверку |
| 2026-08-09 ~18:33 | Дежурный инженер обнаруживает apache2 -DFOREGROUND + rogue php-fpm в ps aux; классифицирует как компрометацию |
| 2026-08-09 ~18:38 | Оператор одобряет: «стопай контейнеры, выключай авторизацию по паролю» |
| 2026-08-09 ~18:38 | docker stop elrise-backend elrise-proxy выполнен; контейнеры остановлены |
| 2026-08-09 ~18:39 | PasswordAuthentication no применён; sshd перезагружен; SSH key-only auth подтверждён |
3. Evidence
3.1 Таблица процессов (внутри elrise-backend, захвачена в 18:31 UTC до остановки)
PID USER TIME COMMAND
1 root 0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
12 www-data 0:02 php-fpm: pool www
13 www-data 0:04 php-fpm: pool www
1334 www-data 0:00 sh -c sleep 300;rm -rf /tmp/.install.pid* 2>/dev/null
1336 www-data 0:00 sleep 300
1393 www-data 0:00 {busybox} sh ybox
1397 www-data 0:14 php-fpm master process /usr/local/etc/php-fpm.conf
1605 www-data 3:32 {xzdiffunlink} apache2 -DFOREGROUND
Аномалии:
- PID 1397 vs PID 1: оба
php-fpm master process /usr/local/etc/php-fpm.conf. Легитимный мастер (поphp-fpm.confpool-конфигу) вызывается какphp-fpm: master process (...)— обратите внимание на:послеphp-fpm. PID 1397 без двоеточия:php-fpm master process (...). Colon-vs-no-colon — это fingerprint: легитимный мастер пишет его черезphp-fpmargv[0] resolution; rogue мастер, вероятно, переименован или запущен из custom-бинарника. - PID 1605:
apache2 -DFOREGROUNDподwww-data. Базовый образelrise-symfony:local(собранный из<project-root>/Dockerfile) устанавливает только PHP-FPM; apache2 в install-листе отсутствует. Этот процесс либо (a) бинарь, подсаженный атакующим под именемapache2(с custom-кодом), либо (b) легитимный бинарь, переименованный черезprctl(PR_SET_NAME)(ядро разрешает любому процессу выставитьcommв любую строку, включая space-padded теги). Фигурные скобки{xzdiffunlink}— типичный признакcommlength-limited short name (xzdiffunlink= 12 chars;commограничен 15 chars). - PID 1393:
{busybox} sh ybox.commзамаскирован вbusybox, cmdline —sh ybox. 6 открытых файловых дескрипторов. Классический паттерн dropbear/busybox shell backdoor — busybox часто статически слинкован и добавляется атакующим, потому что не зависит от/bin/sh(alpine minimal image) и работает как единый static binary. - PID 1334/1336:
sleep 300; rm -rf /tmp/.install.pid*. Классический паттерн drop-and-cleanup криптомайнера/трояна: stage payload, sleep 5 минут, чтобы detection systems забыли, потом удалить.install.pidмаркер-файлы, которые выдают нестандартную установку. Скрипт работает подwww-data(php-fpm-пользователь контейнера), то есть имеет доступ ко всему, что www-data может писать.
3.2 /tmp/ filesystem (writable by www-data)
/tmp/.apid Aug 9 18:29 4 bytes marker file (4-byte payload)
/tmp/.perf.c/ Aug 9 18:29 dir source code for native compilation
/tmp/.r.rpk/ Aug 6 18:59 20 entries malware staging (earliest evidence)
/tmp/.xdiag/ Aug 9 18:31 7 entries runtime diagnostics / backdoor files
/tmp/sess_* 20+ files PHP session files (legitimate PHP-FPM behaviour)
Каталог .r.rpk особенно подозрителен: 20 entries созданы 5 дней назад (во время pre-reboot high-load периода), что предполагает, что атакующий имел persistent access через предыдущий server uptime.
3.3 Active attack traffic (access log)
211.234.111.116 - "POST /usr/local/lib/php/PEAR.php" 200 ← CVE-2012-1823 (PHP-CGI argv injection)
211.234.111.116 - "POST /usr/share/php/PEAR.php" 404 ← follow-up probe
172.25.0.2 - "GET /index.php" 200 ← internal healthcheck from elrise-proxy
211.234.111.116 — source IP атакующего. HTTP 200 в ответ на POST /PEAR.php — самый тревожный индикатор: PHP-FPM интерпретировал /usr/local/lib/php/PEAR.php как путь к PHP-скрипту и выполнил его. Это вектор CVE-2012-1823 (PHP-CGI mode) — современный PHP-FPM НЕ ДОЛЖЕН принимать это, потому что cgi.fix_pathinfo выключен по умолчанию в PHP 8+. То, что вернулся 200, означает одно из:
cgi.fix_pathinfo=1был установлен (объяснило бы path-resolution поведение)- rogue
apache2(PID 1605) сам обслуживает этот путь независимо - reverse proxy атакующего перехватывает путь до Symfony
(Последние две гипотезы наиболее вероятны с учётом наличия apache2.)
3.4 Bind-mount attack surface (verified writable из контейнера)
/app/.env test: WRITABLE (uid 1005 = deploy on host = <project-root>/*)
compose.yaml биндит ./:/app:rw — это требуется для dev override flow по ADR-0005. Но это также означает, что атакующий внутри контейнера мог писать в host-файлы под <project-root>/ с теми же правами, что у deploy на хосте. Свидетельств host-side tampering нет (mtime файлов <project-root>/{Dockerfile,.env,.env.local} не изменились, все от Aug 4-6), но возможность существовала.
3.5 Network exposure (assumed)
elrise-backendбыл в docker network172.25.0.0/16- Фронтенд — FastPanel nginx (
46.36.219.176:443→127.0.0.1:9000черезupstream elrise.io1/ru2) - Никаких outbound firewall-ограничений не наблюдалось; атакующий мог звонить домой на C2 (не верифицировано — потребуется network forensics)
4. Vector analysis (entry point — speculative, pending forensics)
Наиболее вероятно: CVE-2012-1823 (PHP-CGI argv injection) через POST /PEAR.php — активность с 211.234.111.116 в 18:28:36 UTC подтверждена. PHP 8.5 + FPM НЕ ДОЛЖЕН быть уязвим по умолчанию, но:
cgi.fix_pathinfo=1(часто встречается как Symfony default при явном включении) делает так, что/usr/local/lib/php/PEAR.phpрезолвится в этот файл- Если rogue
apache2(PID 1605) — это реальный entry layer (фронтирующий PHP-FPM черезProxyPassMatchили аналог), он может ре-внедрять cgi-style path handling - Открытый admin-роут (запрос
POST /usr/local/lib/php/PEAR.phpуказывает на то, что атакующий пробовал PHP-Manager-style endpoints)
Другие векторы (менее вероятные, но возможные):
- Symfony dependency CVE:
composer.lockне аудирован; возможно, устаревший пакет с известным CVE (например,symfony/http-foundation,symfony/process,twig/twig) - Misconfigured phpinfo page: PHP-FPM экспонирует
/php-fpm-statusили/fpm-status, еслиpm.status_pathвыставлен; если утёк, атакующий может перечислить workers и найти slow-loris пути - Прямая bind-mount write (
/app/.env): если атакующий имеет способ писать в/app/снаружи (FastPanel file manager, git push в tracked branch), он может посадить код, который running FPM подхватит
5. Affected systems
| Система | Статус | Замечание |
|---|---|---|
Контейнер elrise-backend |
Stopped (operator-approved) | Активный malware остановлен |
Контейнер elrise-proxy |
Stopped (operator-approved) | Fronting proxy, потенциально тоже скомпрометирован |
<project-root>/* host-файлы |
Untouched (пока нет свидетельств tampering, но writable через bind mount — требует forensic review) | <project-root>/.git/ MUST быть проверен |
/var/log/btmp, sshd |
Hardened (Method A применён, password auth off) | Brute-force-кампания продолжается на IP/transport-уровне, но приземлиться не может |
Внешний HTTPS на elrise.ru / elrise.io |
502 / parking page (ожидаемо) | Восстановится при redeploy elrise-backend с patched image |
6. Lessons learned
-
PHP-FPM
pm.max_children=5— это footgun. Один медленный запрос насытил контейнер (наблюдение 18:30 UTC:elrise-backendна 188% CPU, 2.5 GB RAM, запросы в очереди 30+ секунд). Рекомендуется увеличитьpm.max_childrenс 5 до 15+ в пересобранном образе. -
Bind-mount
:rw— это attack surface./app/.env WRITABLEиз контейнера означало, что атакующий мог модифицировать host-файлы. Dev override flow требует более ограниченного mount'а (:roдля runtime-контейнера, с отдельным:rwmount только в dev-mode compose override). -
Process name masking через
prctl(PR_SET_NAME)невидим вps -ef(видно только в/proc/<pid>/commчерезcat). Соответствующийstuck-process-reaperdaemon должен сканироватьcomm-поля на подозрительные имена (короткие opaque строки, имена с embedded{...}скобками). -
Нет forensic baseline. У нас не было «known-good» image snapshot для сравнения. Рекомендуется поддерживать
<project-root>/Dockerfile.sha256и cron-drivensha256sumвсех бинарников в/usr/local/bin/,/usr/bin/,/usr/sbin/работающего контейнера, с алертами на drift. -
Расследование 18:30 UTC было operator-triggered, не автоматическим. Никаких алертов при 188% CPU на контейнере, никаких алертов на новый
apache2процесс, никаких алертов на/tmp/.r.rpk/(который лежал 5 дней незамеченным). Trio изmemory-pressure-watcher+php-fpm-guard+healthcheck-relaydaemon'ов закрывает этот пробел; без них следующая компрометация тоже будет идти незамеченной днями. -
502 от PHP-FPM контейнера — это подозрительно, не просто «медленно». FastPanel по умолчанию отвечает 504 (gateway timeout), когда upstream не отвечает, но
elrise.io/elrise.ruотдали 502 — это значит PHP-FPM принимал соединения, но отвечал мусором или пустотой (malware-state). Стоит исследовать 502 от PHP-FPM-backed сервиса агрессивнее, чем 504.
7. Что осталось открытым после инцидента
Публичный пост не место для internal TODO-list, но есть смысл обозначить границы того, что мы знаем сейчас и что ещё предстоит выяснить:
- Глубина forensics: полный snapshot + offline-анализ (отдельный внутренний процесс) или только достаточно для подтверждения entry-point + ротации секретов + redeploy?
- Стратегия image rebuild: пересборка из чистого source через
docker compose buildв<project-root>/(операторски), или сначала задача для engineering (root-cause + remediation plan)? - Мониторинг rollout: установить предложенных daemon'ов (
php-fpm-guard,memory-pressure-watcher,healthcheck-relay) на tmp-vps немедленно или после стабилизации redeploy? - Lateral-movement audit scope: только elrise-symfony или sweep всех контейнеров (
converter-*,umami-app,artgs-symfony,artgs-redis)? - CVE-2012-1823 конкретно: почему
POST /PEAR.phpвернул 200? Требует либоcgi.fix_pathinfo=1в PHP-FPM, либо reverse proxy (rogueapache2), ре-вводящий cgi-style handling. Нужно подтвердить, какой именно.
8. Sources
- Внутренний sysadmin-отчёт по инциденту (полная версия с forensic snapshot, IOC list и сетевым анализом):
/reports/2026-08-09-elrise-backend-container-compromise.md - Daemon catalogue:
/demons/(предложенныеphp-fpm-guard.md,memory-pressure-watcher.md,stuck-process-reaper.mdприменимы здесь) - SSH hardening:
/notes/2026-08-09-spam-attacks-method-A-disable-password-auth.md(применён в этом инциденте) - Параллельная серия материалов по этому инциденту на elrise.io: серия
azazel/*(более глубокий разбор, с полным placeholder-redact):azazel/incident-502-detection— этот же инцидент в нарративной формеazazel/ssh-hardening-5-minutes— SSH hardening, применённый в 18:39azazel/fail2ban-three-jails— fail2ban post-incident покрытиеazazel/azazel-cve-2012-1823-php-fpm— детальный разбор entry vectorazazel/azazel-process-masking-prctl— какprctl(PR_SET_NAME)маскирует процессыazazel/azazel-bind-mount-rw-attack-surface— bind-mount как attack surfaceazazel/azazel-detection-daemons-monitoring— четыре daemon'а, которые должны были пойматьazazel/azazel-image-rebuild-dockerfile— что именно нужно поменять в Dockerfileazazel/azazel-container-security-2026-state— контекст container security 2026
- Host:
sbf4f64b6.fastvps-server.com(FastPanel VPS, Debian 12, kernel 6.1.0-50-amd64) - Container runtime: docker compose stack под управлением
<project-root>/compose.yaml - Production IP:
46.36.219.176 - Attacker source IP:
211.234.111.116