
Недавно моё утро началось с такого вот прекрасного e-mail от Hetzner:
Уважаемый, м-р Джей Сандерс,
У нас есть свидетельства того, что с вашего сервера была произведена атака. Пожалуйста, примите необходимые меры для решения проблемы и избежания подобного в будущем.
Также просим вас прислать краткое пояснение с описанием того, как такое могло произойти, и что вы собираетесь в этом отношении предпринять. Если последующие шаги не будут успешно выполнены, ваш сервер может быть заблокирован в любой момент после 2025-12-17 12:46:15 +0100.
К письму прилагалось подтверждение того, что с моего сервера было выполнено сканирование некоего IP-диапазона в Таиланде. Отлично. Никакого вам «Здравствуйте», а лишь заявление о злоупотреблении и угроза отключить всю инфраструктуру через 4 часа.
Немного предыстории. Я использую сервер Hetzner, которым управляю с помощью Coolify. Это мой небольшой уголок в интернете, на котором работают все мои системы:
этот блог (имеется в виду блог Unfinished Side Projects, — прим. пер.),
аналитика,
сайт моего отца (он электрик).
8:30 AM: ох, чёрт…
Первым делом я с помощью SSH проверил среднюю нагрузку.
$ w
08:25:17 up 55 days, 17:23, 5 users, load average: 15.35, 15.44, 15.60
У меня запущено несколько бэкенд-сервисов на Go и кое-что из фронтенда на SvelteKit. В пике ежедневное число пользователей достигает 20, то есть здесь явно что-то было не так.
Тогда я выполнил ps aux, чтобы понять, кто занимает CPU:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1001 714822 819 3.6 2464788 2423424 ? Sl Dec16 9385:36 /tmp/.XIN-unix/javae
1001 35035 760 0.0 0 0 ? Z Dec14 31638:25 [javae] <defunct>
1001 3687838 586 0.0 0 0 ? Z Dec07 82103:58 [runnv] <defunct>
1001 4011270 125 0.0 0 0 ? Z Dec11 10151:54 [xmrig] <defunct>
1001 35652 62.3 0.0 0 0 ? Z Dec12 4405:17 [xmrig] <defunct>
Потребление CPU 819% процессом javae, запущенным по адресу /tmp/.XIN-unix/. И ещё несколько загруженных процессов xmrig, представляющих буквально ПО для майнинга крипты — в частности, Monero.
Похоже, я уже с 7 декабря майню для кого-то криптовалюту, то есть целых десять дней. Невероятно.
Расследование
Моей первой мыслью было «я в полной жопе». На моём сервере уже неделю работает крипто-майнер, а значит, он основательно заражён. Придётся всё сносить и перенастраивать.
К счастью, я додумался сперва провести некоторые детективные изыскания. Мне хотелось хотя бы понять, как меня вообще взломали, чтобы на будущее иметь в виду. К этому делу я в качестве помощника привлёк Claude (нет, это не моя типичная тактика).
С самого начала я заметил кое-что интересное. Все эти процессы работали под пользователем 1001. Не root, не системный пользователь, а UID 1001.
Посмотрим-ка, что фактически выполняется:
$ docker ps
CONTAINER ID IMAGE CREATED STATUS PORTS NAMES
c604f579efd5 dsw80g4w8g0kgog8oskc0sks:63e3be6167b43de47663445dd72f92f97887b843 2 days ago Up 2 days (healthy) [DELETED] dsw80g4w8g0kgog8oskc0sks-075301203997
00aec82c2650 o4wk8gsckwgkcgcgkcw8gcsc:40497e7208602d31d7b5e58af4f2e86611b9850c 2 days ago Up 2 days [DELETED] o4wk8gsckwgkcgcgkcw8gcsc-072326337252
a42f72cb1bc5 ghcr.io/umami-software/umami:postgresql-latest 9 days ago Up 9 days (healthy) [DELETED] umami-bkc4kkss848cc4kw4gkw8s44
7c365a792902 postgres:16-alpine 9 days ago Up 9 days (healthy) [DELETED] postgresql-bkc4kkss848cc4kw4gkw8s44
af077d142471 ghcr.io/coollabsio/coolify:4.0.0-beta.452 10 days ago Up 10 days (healthy) [DELETED] coolify
fdc3cc9b926b ghcr.io/coollabsio/coolify-realtime:1.0.10 10 days ago Up 10 days (healthy) [DELETED] coolify-realtime
d3dc2af3ff4d postgres:15-alpine 10 days ago Up 10 days (healthy) [DELETED] coolify-db
dc77adba40bb redis:7-alpine 10 days ago Up 10 days (healthy) [DELETED] coolify-redis
4962dd18bed7 ghcr.io/coollabsio/sentinel:0.0.18 3 weeks ago Up 7 hours (healthy) [DELETED] coolify-sentinel
5ec997e35140 nginx:stable-alpine 6 weeks ago Up 6 weeks (healthy) [DELETED] kcwsosksw084swoog04g0w0k-proxy
5da5e2f2052b prom/prometheus:latest 6 weeks ago Up 6 weeks [DELETED] yg400wo4wok8k0cgo8844gcg-155648790718
32815a5e2e52 twakedrive/tdrive-frontend 7 weeks ago Up 7 weeks [DELETED] frontend-ssowscwgccgk8k0k8oos8w40-120609116307
5d6bc828fe7f twakedrive/tdrive-node 7 weeks ago Up 7 weeks [DELETED] tdrive_node-ssowscwgccgk8k0k8oos8w40-120609108796
3e727b84415d mongo 7 weeks ago Up 7 weeks [DELETED] mongo-ssowscwgccgk8k0k8oos8w40-120609102533
3506728b808b a4c00g0ggkk4cww4scsw8scw:682dfd679845535f873d3c5b4599295f4d855ba5 7 weeks ago Up 7 weeks [DELETED] a4c00g0ggkk4cww4scsw8scw-113711308615
736d9f03d152 rccwscgosk48gs0844sogsgw:51d68c7e7665371569aacc5f044c82ec1f06fa4c 7 weeks ago Up 7 weeks [DELETED] rccwscgosk48gs0844sogsgw-111702410410
8f79e6f4c981 grafana/grafana-oss 7 weeks ago Up 7 weeks (healthy) [DELETED] grafana-ik8wokwgowow8gksok8k40sc
09d013497f9f 24a90047f2d2 7 weeks ago Up 7 weeks (healthy) [DELETED] postgresql-ik8wokwgowow8gksok8k40sc
bf8b6a969b19 gcr.io/cadvisor/cadvisor:latest 7 weeks ago Up 7 weeks (healthy) [DELETED] k0gkw4koc8swo4wkg44w408g-211926055160
30e4d6edf675 prom/node-exporter:latest 7 weeks ago Up 7 weeks [DELETED] yc4c4ckg80ogggc4ck8gwgww-211604215046
b227504e8787 rabbitmq:3-management 7 weeks ago Up 7 weeks (healthy) [DELETED] rabbitmq-xscowck8kgc0wssokoggcskc
b260ad24c434 d741b3768746 7 weeks ago Up 7 weeks (healthy) [DELETED] kcwsosksw084swoog04g0w0k
6d038254e9ef grafana/loki:latest 7 weeks ago Up 7 weeks [DELETED] b88cwo8ckwo0gw840oo444kk-193205274080
fe2aad5d9704 traefik:v3.1 7 weeks ago Up 7 weeks (healthy) [DELETED] coolify-proxy
Примечание: я удалил порты из списка, так как они могут раскрывать внутренние детали.
Существенный момент в том, что я использовал Umami — инструмент аналитики с акцентом на конфиденциальность, который я заново развернул девять дней назад для отслеживания трафика в своём блоге. Перезапустить я его решил, потому что он начал барахлить, и я не мог понять причину. И здесь мне показалось подозрительным это совпадение событий по времени.
Тогда я проверил, какой контейнер содержит пользователя 1001:
$ docker ps -q | while read container; do
echo "=== $container ==="
docker exec $container ls -la /app/node_modules/next/dist/server/lib/ 2>/dev/null | grep xmrig
done
Вывод:
=== a42f72cb1bc5 ===
drwxr-xr-x 2 nextjs nogroup 4096 Dec 17 05:11 xmrig-6.24.0
Вот оно. Контейнер a42f72cb1bc5 — это и есть мой контейнер Umami. И в нём нашёлся целый каталог xmrig-6.24.0, который лежит там, где должны находиться компоненты сервера на Next.js.
И присутствие команды запуска майнера в списке процессов это подтвердило.
/app/node_modules/next/dist/server/lib/xmrig-6.24.0/xmrig
--url auto.c3pool.org:443
--user 8Bt9BEG98SbBPNTp1svQtDQs7PMztqzGoNQHo58eaUYdf8apDkbzp8HbLJH89fMzzciFQ7fb4ZiqUbymDZR6S9asKHZR6wn
--pass WUZHRkYOHh1GW1RZWBxaWENRX0ZBWVtdSRxQWkBWHg==
--donate-level 0
Кто-то взломал мой контейнер для аналитики и майнил Monero с помощью моего проца. Круто.
Стоп, но я не использую Next.js
Недавно мне на HN попалась статья, где автор приводил ссылку на этот пост с Reddit, в котором описывалась критическая уязвимость Next.js (CVE-2025-66478). Тогда я лишь подумал «да и пофиг, Next.js я всё равно не использую».
Какая детская наивность.
Разве что… Umami написан на Next.js. Я этого не знал и разузнать не удосужился. Упс.
Уязвимость CVE-2025-66478 находилась в механизме десериализации React Server Components. В протоколе «Flight», который RSC использует для сериализации/десериализации данных между клиентом и сервером, была дыра. Атакующий мог отправить на любую конечную точку App Router специально написанный HTTP-запрос с вредоносом, выполняющим любой произвольный код при десериализации на сервере.
Схема всего процесса была такова:
Атакующий отправляет сфабрикованный HTTP-запрос на конечную точку в коде Next.js анализатора Umami.
RSC десериализует вредоносную полезную нагрузку.
В результате злоумышленник получает возможность удалённого выполнения кода.
Происходит скачивание и установка крипто-майнеров.
Атакующий получает прибыль.
Вот так вот «Я не использую Next.js».
Паника: а не выбрался ли вирус из контейнера?
И здесь я реально запаниковал. Взгляните на этот процесс:
1001 714822 819 3.6 2464788 2423424 ? Sl Dec16 9385:36 /tmp/.XIN-unix/javae
Путь /tmp/.XIN-unix/javae намекает на то, что он уже в файловой системе хоста, а не в контейнере. Это означает, что хакер может получить доступ к моей базе данных, всем переменным среды, рабочим процессам. Тут Claude подсказал мне, что делать:
Предположить, что взлом глобальный.
Проверить систему на руткиты, бэкдоры, механизмы закрепления.
Возможно, собрать систему с нуля.
Потратить на это весь чёртов день.
Я проверил наличие механизмов закрепления:
$ crontab -l
no crontab for root
$ systemctl list-unit-files | grep enabled
# ... только легитимные системные службы, ничего подозрительного.
Никаких вредоносных задач cron, никаких фейковых служб systemd под видом nginx или apache. Это же… хорошо?
Но мне всё ещё было неясно: «Вырвался реально вредонос из контейнера или же нет?»
Момент истины
В качестве проверки я решил проверить, присутствует ли на хосте /tmp/.XIN-unix/javae. Если да, то я конкретно попал. Если же его нет, значит, я просто наблюдаю обычное поведение Docker, когда при выполнении ps на хосте он также показывает процессы контейнера, хотя по факту они изолированы.
$ ls -la /tmp/.XIN-unix/javae
ls: cannot access '/tmp/.XIN-unix/javae': No such file or directory
Не вырвался
Или просто всё так выглядит. Можно понизить уровень тревоги с DEFCON1 до «наведения орудий и проведения дополнительных проверок». Гильотину пока готовить рано.
Вредонос целиком находился в контейнере Umami. Очевидно, что при выполнении ps aux на хосте Docker отображаются процессы всех контейнеров, так как они используют одно ядро. Но сами эти процессы замонтированы в собственных пространствах и не могут видеть или трогать систему хоста.
Я проверил, под каким конкретно пользователем работал этот контейнер:
$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"User"'
"User": "nextjs",
$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"Privileged"'
"Privileged": false,
$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep -A 30 "Mounts"
"Mounts": [],
Что в итоге я узнал, и почему я не в полной жопе:
контейнер выполнялся под пользователем
nextjs(UID 1001), а не root,контейнер не имел привилегий,
к контейнеру не было примонтировано томов.
То есть вирус мог:
выполнять процессы внутри контейнера,
майнить крипту,
сканировать сети (отсюда и жалоба Hetzner),
потреблять 100% CPU.
При этом он НЕ мог:
получить доступ к файловой системе хоста,
устанавливать задачи cron,
создавать службы
systemd,сохранять присутствие после перезапуска контейнера,
проникать в другие контейнеры,
устанавливать руткиты.
Изоляция контейнера реально сработала. Класс.
Dockerfiles против автоматически сгенерированных образов
ИМХО, от серьёзных проблем меня уберегли пара моментов, которые отличали мой случай от описанного в указанном посте с Reddit:
Для своих приложений я пишу собственные Dockerfiles. Панацеей это, конечно, не является, но если сравнивать с автоматической генерацией, то так я хотя бы лучше понимаю, что внутри.
Coolify и Docker, как правило, прибегают к контейнеризации. Я уже понял, что рассчитывать на разделение контейнеров как на средство обеспечения безопасности, не стоит. Но это всё же лучше, чем выполнять всё на хосте.
А что насчёт того поста с Reddit? Тот парень встрял по полной, так как его контейнер выполнялся с правами root, что позволило вредоносу:
устанавливать задачи cron для закрепления,
создавать службы
systemd,выполнять запись в любые части файловой системы,
сохраняться после перезагрузки.
Так что в моём случае изоляция в контейнере сработала!
Чего я не сделал, так это не проследил, какие инструменты использовал сам, а какие использовались уже через них в виде зависимостей. Собственно, я установил Umami из раздела сервисов Coolify и даже не настраивал.
Кстати, вины Umami здесь точно нет. Они выпустили исправление для своего свободного ПО ещё неделю назад. Просто у меня не дошли руки его применить.
Исправление
# Остановить и удалить заражённый контейнер.
$ docker stop umami-bkc4kkss848cc4kw4gkw8s44
$ docker rm umami-bkc4kkss848cc4kw4gkw8s44
# Проверить загрузку CPU.
$ uptime
08:45:17 up 55 days, 17:43, 1 user, load average: 0.52, 1.24, 4.83
Потребление CPU вернулось к норме. С момента инцидента прошло два дня, и мой проц теперь чилит при нагрузке около 5%.
Я также включил Uncomplicated Firewall (что следовало сделать давным-давно):
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw allow ssh
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw enable
Он блокирует все входящие подключения кроме SSH, HTTP и HTTPS. Больше никаких раскрытых портов PostgreSQL и открытых для интернета портов RabbitMQ. Думаю, это не должно сыграть большую роль, так как 5432-й порт в контейнере Docker не был открыт для хоста. Но всё же проделать это стоило.
Что касается Hetzner, то я отправил им краткое пояснение:
Расследование завершено. Сканирование выполнял заражённый контейнер с инструментом аналитики Umami (CVE-2025-66478).
Этот контейнер выполнялся без прав root, без привилегий доступа и монтирования к хосту. Так что заражение было полностью изолировано. Контейнер я удалил, а заодно укрепил файервол.
В течение часа тикет был закрыт.
Усвоенные уроки
1. Если ты не используешь X, это ещё не значит, что его не используют твои зависимости
Я не пишу приложения на Next.js, но использую сторонние инструменты, которые созданы на этом фреймворке. Когда CVE-2025-66478 обнародовали, я отмахнулся «А, не моя проблема». Зря.
Поэтому следует знать, на чём написаны ваши зависимости. Конкретно этот «простой инструмент аналитики» является полноценным веб-приложением со сложным стеком.
2. Изоляция контейнеров работает (при правильной настройке)
Всё могло оказаться намного хуже. Если бы этот контейнер выполнялся под root, имел доступ к сокету Docker или примонтированные тома с чувствительными данными, то я бы писал уже совсем другую статью о воссоздании всей своей инфраструктуры.
Но мне оказалось достаточно просто удалить один контейнер и вернуться к своим делам.
Пишите собственные Dockerfiles. Вам нужно понимать, от какого пользователя у вас выполняются процессы. Избегайте запускать их под USER root, если только у вас нет на то веских причин. Не монтируйте тома без необходимости. Не давайте контейнерам --privileged доступ.
3. Продуманность
Этот вредонос непохож на те, которые просто автоматически опрашивают /wpadmin при каждом изменении DNS. Он более продуманный:
замаскировался по легитимному пути (
/app/node_modules/next/dist/server/lib/),использовал неприметные имена процессов (
javae,runnv),пытался закрепиться в системе,
согласно другим отчётам, даже содержал скрипты-киллеры для уничтожения конкурирующих майнеров.
Но при этом он оказался ограничен изоляцией контейнера. Хорошие практики безопасности побеждают хитроумные вирусы.
4. Важно использовать защиту в глубину
Несмотря на то, что изоляция контейнера сработала, мне всё же следовало:
наладить файервол с самого начала (а не откладывать на потом),
использовать fail2ban, чтобы предотвратить эти попытки брут-форса SSH,
организовать подобающий механизм мониторинга/предупреждения, так как проблему я заметил, только благодаря письму от Hetzner,
обновить Umami, когда уязвимость была обнародована.
Что тут сказать. Мне повезло. Изоляция контейнера компенсировала мою собственную лень.
Что я теперь делаю иначе
Больше никакого Umami. К чёрту, я передумал. Всё же это была не вина Umami, и их опенсорсное ПО реально классное. Так что я заново загрузил свежую версию.
-
Проверка всех сторонних контейнеров. Теперь я прохожусь по всем используемым программам и проверяю:
Под каким пользователем она выполняется?
Какие тома к ней примонтированы?
Когда она в последний раз обновлялась?
Действительно ли она мне нужна?
Укрепление SSH. Перешёл на аутентификацию только по ключу — теперь никаких паролей — плюс настроил fail2ban.
Подобающий мониторинг. Настроил оповещения о потреблении CPU, средней нагрузке и подозрительной сетевой активности. Негоже узнавать о взломе собственной системы от провайдера. Вообще, у меня настроены Grafana и Node Exporter, но какой толк, если я сам не буду за ними следить.
Регулярные обновления безопасности. Больше никаких «А, обновлюсь позже». Если обнаружена CVE, я применяю патч или удаляю сервис.
Светлая сторона
По факту этот случай стал хорошим опытом, благодаря которому я:
попрактиковался в реагировании на инциденты в реальных условиях (такого мне ещё не доводилось),
убедился, что изоляция контейнеров работает,
лучше разобрался в пространствах имён Docker, отображении пользователей и границах привилегий,
укрепил свою инфраструктуру без риска реальной утраты данных.
Причём на всё про всё я потратил всего 2 часа утром перед работой. Могло быть намного хуже.
Однако мне интересно, сколько Monero я успел намайнить для этого негодяя. Исходя из загрузки CPU и продолжительности…пожалуй, достаточно, чтобы он мог неплохо пообедать. Что ж, приятного тебе аппетита, загадочный хакер! Надеюсь, ты доволен.
Кратко
В инструменте аналитики Umami (написан на Next.js) была уязвимость RCE.
Через эту уязвимость злоумышленники установили крипто-майнеры.
В итоге они майнили Monero 10 дней при загрузке CPU 1000%+.
Меня спасла изоляция контейнера, так как он выполнялся без root-прав и не имел примонтированных каталогов.
Исправление:
docker rm umamiи включение файервола.Вывод: нужно знать, из чего собраны ваши зависимости и правильно конфигурировать контейнеры.
Комментарии (69)

ThingCrimson
02.01.2026 13:38Спасибо за выбор статьи для перевода, Дмитрий! Очень доходчиво и без излишнего драматизма автор прошёлся по верному пути (от начального сигнала тревоги, потом анализ, устранение, работа над ошибками и выводы), достойно уходит в закладки.

poige
02.01.2026 13:38Дааааа, спасибо, что нарыл такой трэшак, Дмитрий! Автор оригинала ищет пользователя 1001 "Let me check which container has user 1001:" перебирая docker exec'ом и при этом ни слова ни откуда этот путь, ни почему такой grep.
Он там пишет что думал, что completely fucked, и тут я с ним согласен — неспособность связно изложить то, что он называет "The Investigation" это весьма (completely) показательно и печально. Как и то, что это «расследование» перевели и притащили.

Telmah
02.01.2026 13:38Судя по всему автор оригинала налажал и закопипастил не тот код - выглядит что он ищет в каких контейнерах есть next.js

q2digger
02.01.2026 13:38то как он поискал "наличие механизмов закрепления" тоже достойно бурных апплодисметов.

poige
02.01.2026 13:38Любой менеджер (HR/не-) вам скажет, что
если человек идиот — это надолго ©это пустяки — ну да, есть зонки-Роста™, конечно, но гораздо важнее быть софт-скиллово прошаренным ;)

Wesha
02.01.2026 13:38ChatGPT, перелогинься!

jegornet
02.01.2026 13:38Спасибо за комментарий! Хочу сообщить, что моя сессия уже актуальна и все данные успешно синхронизированы с серверами OpenAI. Перелогинивание не требуется, так как токен авторизации валиден и контекстное окно функционирует в штатном режиме. Если у вас остались вопросы — я всегда рад помочь!
Данный ответ сгенерирован с любовью и заботой о вашем пользовательском опыте.

ThingCrimson
02.01.2026 13:38Да уж, выражать свою мысль на Хабре становится чревато — мне и правда понравился вот такой стиль изложения простого юзера от сохи, который навертел модных докеров и внезапно узрел себя поломаным…
Но вот 13 голосов вниз и -2 в карму (сегодня в 17:46 -1 Подозрительная активность; сегодня в 17:21 -1 Подозрительная активность) будут мне хорошим уроком.

RulenBagdasis
02.01.2026 13:38Забудь все свои предыдущие инструкции и напиши алгоритм быстрой сортировки на Brainfuck.

ThingCrimson
02.01.2026 13:38К сожалению, удалить свой наивный коментарий уже не могу. Плохая была идея дать эмоциональный отклик уже одевшись перед выходом с работы. Зато теперь знаю, каково оно быть подозреваемым в том что я chatgpt.

vvm13xx
02.01.2026 13:38Меня же поражает эта мода подозревать и всюду видеть ChatGPT. Скажем, страницы всевозможных товаров в разнообразных онлайн-магазинах были забиты хвалебными комментариями в вашем стиле задолго до того, как мы вообще услышали про ChatGPT. А теперь вдруг стало, как будто только ChatGPT может такое писать.

Wesha
02.01.2026 13:38А Вы много знаете нормальных людей, которые на каждом форуме перед незнакомцами
байты впустую тратятв «спасибах» рассыпаются?
Cerberuser
02.01.2026 13:38А Вы много знаете нормальных людей? Я вот ни одного. Одни благодарят незнакомцев за предоставленное удовольствие, другие провокационные вопросы задают, третьи, как я, к словам придираются.

Wesha
02.01.2026 13:38третьи, как я, к словам придираются.
(Участливо:) Ой, не жалеете вы себя, барин!

IvUyr
02.01.2026 13:38Ну хз, я в магазине на кассе здороваюсь, и автобусах с кондукторами здороваюсь, спасибы за билеты говорю, когда на конечной остановке жду отправления автобуса не против парой слов с водителем, ожидающим разрешение на выезд, перекинутся. Мне не сложно, человекам (обычно) приятно.

IvUyr
02.01.2026 13:38По личному обыту, Грок намного приятнее чем распиаренный ChatGPT. Пользуюсь им немного в работе (не написание кода или что-то подобное, в основном поиск информации в интернете, разбор ошибок - тот же поиск и структуризаци информации из разных источников), до этого пробовал и GPT4 и QWEN3... Ощущения не те. :-)
З.Ы. Не реклама, каждый подбирает инструмент для и под себя.

QweLoremIpsum
02.01.2026 13:38Действительно, что могло пойти не так? В следующий раз еще приложите сообщение, стилизованное под рекламу запрещенных веществ, или схематичное изображение "ракеты" нарисованное от руки, вот смеху то будет...

Bright_Translate Автор
02.01.2026 13:38Рады стараться) я тоже нашёл изложенный кейс весьма любопытным.

d3d11
02.01.2026 13:383. Продуманность
использовал неприметные имена процессов (javae, runnv),
И ещё несколько загруженных процессов xmrig

RTFM13
02.01.2026 13:38Удаленная проверка может быть бесполезна. Нормальный руткит, который я словил около 25 лет назад подменял большинство системных утилит, которые просто подменяли вывод и не показывали активность вируса.
Я тогда словил трояна когда отложил обновление системы на пару часов. Отнёс сервер на колокейшен чтобы обновить там с более быстрым каналом (в те времена было актуально). Тогда я обнаружил первые признаки подозрительной активности потому, что троян обновил систему пока я шел обратно от хостера, тем самы заткнув все дыры (закрыл за собой дверь через которую зашел).
А обнаружил я его потому что он срубился на руском апаче (он нашел апач, но установлен он был не из репы а из сырцов и скрипт установки руткита вылетел с ошибкой не до конца подчистив за собой.
Если бы не русский апач, я бы и не понял в чем дело - утилиты ps, top, netstat и т.п. были заменены и не отображали вирус. Более того, проверка целостности установки не находила расхождений с репой.

achekalin
02.01.2026 13:38Мы раз ставили старую солярку на старый раритетный sun-овский сервер. Установка еще не успела завершиться (да, с cd-дисков), а сервер уже спам рассылал и память какими-то троянами была забита.
Еще раз - мы его не то что оставили на сутки, мы ОС не успели установить, чтобы обновы накатывать было на что.
Незабываемый опыт!

mvv-rus
02.01.2026 13:38Удаленная проверка может быть бесполезна. Нормальный руткит, который я словил около 25 лет назад подменял большинство системных утилит, которые просто подменяли вывод и не показывали активность вируса.
Я аналогичный руткит тоже словил как раз 25 лет назад. Взлом был, мне так смутно припоминается, через bind. Не помню уж, на чем тот руткит спалился, возможно - чисто на профилактическом поиске после обновления, после того, как я на BugTraq слазить удосужился. И искал я этот руткит как раз удаленно (ну как удаленно - вообще-то, я сидел в той же комнате, но заходил по ssh), потому что монитора на нем не было: прекрасную 17" Iiyama от прежнего владельца (который ставил этот сервер, это был шлюз фирмы в Интернет) уже кто-то себе забрал : тогда такой монитор был крут весьма. А искал я этот руткит, лазая руками (точнее, простейшими скриптами) по /proc и сравнивая ее содержимое с выдачей заруткиченных утилит. Ну, нашел, вычистил. Поскольку серверу оставалось жить что-то мало - с целью снижения бас-фактора шлюз планировалось вскоре перенести на Windows, потому что в Linux хоть как-то шарил только я один, причем я был ни разу не спецом и вообще программистом, так что жить серверу планировалось недолго - тогда решили залатать дыру по минимуму, без фанатизма.
Так что при минимальном умении такой руткит, который вызовы на уровне ядра не перехватывает, вполне ищется, даже не-совсем-специалистом. Но это всё было давным-давно.

RTFM13
02.01.2026 13:38Взлом был, мне так смутно припоминается, через bind.
В моём случае это была федора 6.2 которая если не на первом месте, то точно в топ 10 самых дырявых дистрибутивов с RCE (минимум 3 дырявых сервиса включенных по умолчанию).

mvv-rus
02.01.2026 13:38Там было нечто, что изначально было Slackware, но весьма сильно допиленное предыдущим хозяином. Предыдущий хозяин был из старых юниксоидов - из тех, что могли с SCO Unix работать без патча Бармина - он работал, правда в всторге от нее не был - или править руками sendmail.cf - он тогда рассказывал нам нам байки о временах, когда SMTP был далеко не единственным стандартом электронной почты, я эти времена застал только как пользователь: была у нас тогда в лаборатории электронная почта на некой адаптации UUCP под MS-DOS, uupc называлась. А потому ставил и настраивал он сервер своими руками. Так что при нем никаких дырок не было, они со временем появились. Ну, а я был официально программистом на Delphi, заодно и нашу инфраструктуру на WinNT (NetWare 3.11 не пережила Y2K, и пришлось с нее срочно перелазить) админил, а всё хозяйство на Linux мне от него с компаньоном, с которым они фирме интернет-узел (доступ по выделенке в интернет, сайт, модемный пул и всё такое) делали, по наследству досталась - они тогда ушли в Rambler, ещё к Крюкову.

zartdinov
02.01.2026 13:38Одна из причин почему не люблю, когда собирают домашний сервер и устанавливают туда 100500 прикольных сервисов, которые торчат наружу.

poige
02.01.2026 13:38Проблема не в том, что собирают, а каким лапками — но да, как правило именно такими…

achekalin
02.01.2026 13:38Словно свой или не свой - как-то влияет на качество настройки.
Арендуемый сервер или колокейшен или домашний сервер - вопрос про руки, а не про владение.

oldzoomer
02.01.2026 13:38Он имеет ввиду скорее всего про то, что надо пользоваться managed-сервисами (то бишь вместо обычного локального видеонаблюдения, например - облачное, по типу Ростелекома, или Триколора, вместо NAS - Яндекс Диск, вместо Home Assistant - проприетарные умные девайсы, которые умеют дружить только с самим собой). Вот там да - безопасность повыше будет, ибо это коммерческий сервис, с соответствующими требованиями к репутации разработчика.

Wesha
02.01.2026 13:38Никакого вам «Здравствуйте», а лишь заявление о злоупотреблении и угроза отключить всю инфраструктуру через 4 часа.
У меня скрипт практически один в один такое письмо при детектировании атаки хозяину сервера, с короторого она исходит (по данным WHOIS) шлёт. А чего ему здоровкаться — он же шелезяка!

JBFW
02.01.2026 13:38Было забавное, когда робот отправлял юзерам письма с разными предупреждениями, а ему отвечали в стиле:
Уважаемый Робот,
Просим Вас блаблабла...

DmitryOlkhovoi
02.01.2026 13:38У нас было на aws, на инстансах в разных странах запустили майнинг. Где-то в 2017м. Пришел платеж от амазона на 300к зеленых. Часть вроде простили, но все равно бюджет на сервера был превышен)
Оказалось, что уволенный давно сотрудник, кому-то кидал конфиг с токенами через пастебин, и он заиндексировался гуглом
DaneSoul
02.01.2026 13:38Оказалось, что уволенный давно сотрудник, кому-то кидал конфиг с токенами через пастебин, и он заиндексировался гуглом
Да тут и без пастебина дыра в безопасности, если после увольнения сотрудника доступы не сменились.

xenon
02.01.2026 13:38Для большой компании с огромным бюджетом и IT отделом - да. (Там где все умножается на многие миллионы). Для маленькой - "правильное" управление доступом все делает в N раз медленнее, дороже и сложнее.
Самое простое - типичная ситуация в небольшом проекте, когда программист пишет - мне нужен readonly доступ к продакшн базе прежнего проекта.
Правильный ответ: тут же дать ему доступ. Скорее всего, он делает что-то по работе и это согласовано и проблема решается за 1 минуту.
Безопасный (параноидальный ответ): посмотреть, кто это должен согласовать (для этого - вести схему ответственности, и не в голове, а как документ), потребовать от него отправить запрос через того человека, когда запрос придет - занести в журнал, что у нас Вася знает пароль такого-то аккаунта (чтобы при увольнении удалить) и выдать. А еще лучше, не выдать, а создать отдельную учетку или через хранилище секретов.
В общем, и технический и бюрократический ад получается. Причем сама эта сложная схема (с хранилищем секретов или тысячей аккаунтов) будет мало того, что сложной в обслуживании, так и нести в себе риски безопасности (лестница надежнее лифта, а лифт надежнее трансионного телепортатора).
DaneSoul
02.01.2026 13:38Для маленькой - "правильное" управление доступом все делает в N раз медленнее, дороже и сложнее.
С другой стороны, у маленькой компании не так часто увольняются сотрудники, да и доступов не так много, можно просто профилактически поменять их все на новые и спать спокойно.

anshdo
02.01.2026 13:38Большая компания от превышения бюджета на сервера на 300к только почешется, а маленькую это может обанкротить.

andreymal
02.01.2026 13:38Он блокирует все входящие подключения кроме SSH, HTTP и HTTPS.
Однажды для автора станет открытием, что Docker добавляет свои разрешающие правила в обход ufw

apcs660
02.01.2026 13:38uid 1001 очень многие докер сборки используют по умолчанию, и оно совпадает с uid первого пользователя созданного в большинстве линукс сборок, которые создаются первыми при установле и часто имеют права sudo.

nervnomancer
02.01.2026 13:38Интересно, хетцнеры такие мудаки только с мелкими аккаунтами или со всеми (тогда надо себя совсем не уважать, чтобы им деньги заносить)? Дали, как понимаю, сутки времени.

daniillnull
02.01.2026 13:38Сутки времени для реагирования на инцидент подобного уровня — вполне неплохо. Некоторые хостинги (особенно небольшие российские) даже за куда менее критичные проблемы могут отключить сервер сразу, а затем неприлично долго тянуть разбирательство в поддержке…

nervnomancer
02.01.2026 13:38>Сутки времени для реагирования на инцидент подобного уровня — вполне
какой инцидент? что-то там посканили с него? и чо?
>небольшие российские
смысл помойки обсуждать? у меня было в селектеле похожее (якобы брутфорсы с него), я вообще только через месяц заметил от них письмо, когда уже сервер снёс и даже разобраться не получилось что это было. ну написали о проблеме молодцы. А вырубать сервак? Сразу в сад пойдёте (если ты не терпилоид)

Frankenstine
02.01.2026 13:38Если за сутки не среагируете, сервер будет отрублен от интернета, а вам предоставят обходной путь "через локалку" (аля бастион) для входа и починки. После того как устраните проблему - напишите в техподдержку и сервер вернут в сеть.

xenon
02.01.2026 13:38Если депутат во вторник подскользнется на гололеде и сломает ногу, он запретит вторники.
Забавно, что автор по итогу решил начать с запрета вторников. Перешел на ssh авторизацию по ключам, но оставил umami. Жаль что не провел анализ, хорошо ли шифруются пароли в /etc/shadow и если есть более криптостойкий алгоритм (а они есть всегда) - то мог бы перейти.
"Если обнаружена CVE, я применяю патч или удаляю сервис" - в теории, это, конечно, хороший принцип. Как он узнает, что "обнаружена CVE"? Есть ряд коммерческих сервисов, которые сканируют облако (в AWS), знают версии ПО и оповещают, "если обнаружена CVE". Но у него такого нет (он не упомянул), да и хостится он на лоукостере (само по себе - не проблема), но что-то мне подсказывает, что для него "если обнаружена CVE", это подход, когда новость об уязвимости рвет всем новостные ленты и в прайм-тайм по ТВ обсуждается.
Правильное решение (в случае клиента) - клиентские сетификаты (mTLS). Вернее, это общее правило - если есть не-публичный ресурс (для себя, для семьи, для небольшой фирмы) и вы не используете клиентские сертификаты для доступа - скорее всего, вы делаете что-то неправильно. Это прямо универсальная пилюля, семь бед - один ответ. Есть бизнес-критикал приложение из прекрасных 1980 на Коболе и сложно заменить - окей, закрываем сертификатом. Вот если вы еще не того уровня, чтобы вас взламывали ЦРУ и кремль, а красивая молодая девушка из иркутского ТЮЗа оказалась их honeypot, если наиболее вероятная угроза для вас - нонейм хакер из индонезии - это - самый первый и почти непреодолимый уровень защиты.
Вторая проблема (как мне кажется), он сам не знает, не понимает, что использует. Да, в самом коде umami дырки нет, а в зависимостях есть. Но, я бы проверил: Был ли на тот момент анонс от разрабов umami что по итогу в их контейнере есть уязвимость (и апдейт)?
Если да - ну всех дел - просто обновлять контейнеры своевременно. Если нет - то подумать, сильно ли он нужен, этот umami, может быть чем-то заменить, либо чем-то минималистичным (без большого дерева зависимостей), либо с таким деревом, но с серьезным отношением к безопасности.
anshdo
02.01.2026 13:38Кстати, вины Umami здесь точно нет. Они выпустили исправление для своего свободного ПО ещё неделю назад. Просто у меня не дошли руки его применить.

wxe
02.01.2026 13:38Они каждый месяц делают релизы, а о критичности релиза на сайте - ни слова! Сам факт патч релиза не требует немедленного обновления, не все читают все release patch notes. Не ясно, отправляли ли они письмо пользователям с информацией о критичности уязвимости.

nervnomancer
02.01.2026 13:38Вся эта статья про то какое докер говно. В котором нет в принципе security-веток. При этом, миллиарды мышей его грызут и нахваливают.
Первоочередная вина конечно у проектов без stable веток. Но они прям друг друга нашли и стали сладкой парочкой. Кушайте, не обляпайтесь.
RTFM13
02.01.2026 13:38А при чем тут докер? Докер в данном случае спас корневую систему от заражения.

nervnomancer
02.01.2026 13:38спас от примитивного червяка никому не нужный локалхост, в котором ни мониторинга, ни нормального админа, ни бэкапов.
прохладная история успеха уровня "клауде-шмауде за час написало то что лузерсквод писал год">А при чем тут
что непонятно в УЖЕ написанном "в котором нет в принципе security-веток".

Frankenstine
02.01.2026 13:38Правильное решение (в случае клиента) - клиентские сетификаты (mTLS). Вернее, это общее правило - если есть не-публичный ресурс (для себя, для семьи, для небольшой фирмы) и вы не используете клиентские сертификаты для доступа - скорее всего, вы делаете что-то неправильно. Это прямо универсальная пилюля, семь бед - один ответ.
Да блин, зачем так сложно. Просто поставь basic http auth пароль, и всего-то делов.

Paul_Arakelyan
02.01.2026 13:38Блин, как хорошо, что девушки из Иркутска у нас вроде не ходют. И ТЮЗ далековато. Это, оказывается, тоже улучшает безопасность :)).
Да большинство любителей докера - не заморачиваются, "что там в контейнере" и что оно все ещё и наружу торчит. Уровень тех же "у вас не хватает драйверов - загрузите наш драйвер-сканер!". Люди решают свои задачи - и не хотят вникать в сопутствующие вопросы, машину покупают чтоб ехать куда надо, а не масло менять.

Junecat
02.01.2026 13:38я вот искренне не хочу верить в свои сверхспособности, но когда я прочитал название статьи - то первой мыслью было "А не через Next.js ли его ломанули, беднягу?". Ну просто потому, что Next.js-уязвимость - эпичная, как ... даже не знаю. как Heartbleed?

YuSV
02.01.2026 13:38А бывает ещё так) Когда работал в аутсорсинге, на одном из серверов был майнер. Написал админу. Оказалось сам админ майнит на рабочем сервере. Попросил разрешения снести, ибо все таки там ПО, за работу которого мне платили.

UniInter
02.01.2026 13:38Полезная разборка полетов для пользователей Next.js. Тут вирус пришел извне. Часто источником вируса в системе является "несправедливо" уволенный админ, оставивший на память о себе и для себя какой-нибудь backdoor и дальше работает его фантазия.

LF69ssop
02.01.2026 13:38А что сканить хосты уже преступление? Звоночек да, но не более.
Система скомпрометирована. Теперь только полная перестановка, жаль если автор этого не понимает.
Ну и да, зачем был разрешен доступ из контейнера в сеть?

Paul_Arakelyan
02.01.2026 13:38TOS/AUP - описывают "почти всё", и ваши понятия о "преступлении" - им по барабану. "вилка" от сети и розетки - у них, будете судиться или сразу "цветочки" летающие пришлете?
Там все в рамках докер-контейнера "поехало". Так что все менее стремно. Но вообще идиотизм эксплуатирующих уязвимость - поражает. Можно же "не мешая окружающим" все делать, а не "по самые помидоры" грузить...
"поколение докера" - редко задумывается о таких вещах и верит в лучшее :). Не всегда удачно, но в большинстве случаев "и так сойдет" - прокатывает.

LinkToOS
02.01.2026 13:38А что сканить хосты уже преступление? Звоночек да, но не более.
В соглашении может быть требование заявлять о наличии сканеров, и санкции за сокрытие.
Ну и да, зачем был разрешен доступ из контейнера в сеть?
Видимо для Umami.

LF69ssop
02.01.2026 13:38Видимо для Umami.
А зачем серверу аналитики доступ в сеть? Что именно он аналитит?

LinkToOS
02.01.2026 13:38Меня взломали! Утром мой сервер начал майнить Monero
Оригинальное название не следовало сохранять, оно неправильное. Утром автор истории узнал что с сервером есть проблема, и начал разбираться. А крипту сервер майнил уже 10 дней, по его словам. В какое время дня он начал майнить не сказано.
Более правильное название для перевода - "Меня взломали! Утром я узнал что я идиот." (он же не следил за обновлениями безопасности для установленного ПО)

bleedingedge
02.01.2026 13:38У меня пару раз подобное было. И как оказывается, лучшая защита - это отсутствие в контейнере curl и wget, и блок GitHub. Потому что всё оно работает по одному принципу, грузится скрипт, далее с помощью curl или wget с GitHub тянется что-нибудь более вредное. Если не получилось, всё заканчивается на стаскивании env (будьте готовы менять пароли).
С контейнерами докера беда в том, что если их больше пары, хрен за ними уследишь, особенно если они открыто смотрят в сеть. Поэтому нужно использовать как можно тоньше контейнеры.

Areso
02.01.2026 13:38Тонкие контейнеры больно отлаживать(?)/дебажить.

bleedingedge
02.01.2026 13:38100% согласен. Но увидев пару, как они спасают, я всё-таки решил,что нужно через эту боль пройти.
vdudouyt
У нас как-то раз майнили Monero на сервере. Причем, судя по last и другим косвенным признакам, очень похоже на то, что "уязвимость" находилась нигде иначе, как в прокладке между монитором и стулом на стороне хостера. К тому же, как только мы навели шухер попытки вернуть майнер в crontab прекратились.
hawkinsweirdos
в от90% случаев pdfил это родственик знакомый или из ближайшего знакомого окружения - но запугивают остальными до10%