Компрометираният сървър
RCE във фреймуърка, ботнет, три неуспешни преинсталации и изходящата връзка, която ги разкри
- Роля
- Сам, реагиране при инцидент
- Статус
- Пуснат
- Код
- Частно хранилище
- Технологии
- Ubuntu 24.04Next.jsOpenSSHUFWfail2bansysctlssTailscale
В числа
3
почиствания и преинсталации, след които сървърът се зарази отново, преди да се открие първопричината
4h
от първото пускане до първопричината
42s
за инсталиране на поправения Next.js 16.0.11
18
записа в crontab, които зловредният софтуер добави, за да остане в системата
10
стъпки за подсилване на защитата, после 10 проверки
Проблемът
Пуснах видеоинструмента на ValoxVSL на нов облачен сървър. Около час по-късно се оказа, че на сървъра работи x86_64.kok, вариант на Mirai, маскиран като systemd-logind и закрепен чрез crontab (18 записа), rc.local, init.d и bashrc. Почистването в режим за възстановяване не помогна, както и двете преинсталации, едната с нови SSH ключове, другата зад защитна стена на облачния доставчик, която допускаше SSH само от един IP адрес. Всеки път заразата се връщаше до пет минути.
Подходът
Спрях да чистя и погледнах с кого говори сървърът. ss -tnp state established показа, че самият процес на Next.js държи връзка със сървър за командване и управление (C2), и така търсенето се премести от SSH към приложението. Дървото на зависимостите в npm излезе чисто. Причината беше React2Shell, отдалечено изпълнение на код без автентикация в протокола на React Server Components, което докладът за инцидента води като CVE-2025-66478 (CVSS 10,0). Приложението работеше на Next.js 16.0.1, а ботнетът RondoDox го използваше през портове 80 и 443; всяко преинсталиране беше пускало същата версия. Надграждането до 16.0.11 отне 42 секунди. Преинсталирах сървъра още веднъж, смених тайните му (ключове, пароли и токени) и автоматично наблюдение от 15 минути излезе чисто.
Как работи
Изходящите връзки като сигнал
Правилата на защитната стена за входящия трафик не виждат връзка, която сървърът отваря сам. ss -tnp state established показва всяка установена връзка заедно с процеса, който я държи, а процес на приложение, свързан с непознат хост, е мястото, откъдето се започва. Сега това е ред от контролния списък за проверка, а очакваният резултат е само моята собствена SSH сесия.
Две атаки едновременно
auth.log показваше атака с груба сила по SSH, затова три етапа работа отидоха в SSH. Тази атака беше истинска и протичаше едновременно, но трайната дойде през собствените портове на приложението, които трябва да останат отворени. Ubuntu 24.04 внесе допълнителен шум: стойността по подразбиране TriggerLimitBurst от 20 на ssh.socket спира слушането на SSH след 20 опита за връзка, затова SSH падаше по време на атаката.
Наръчникът
Написан по следите на инцидента: десет стъпки, от изключване на ssh.socket, през SSH само с ключ и модерните шифри от препоръките на Mozilla, потребител без root права и заключен root, UFW с блокиране на входящия трафик по подразбиране, fail2ban, автоматични обновявания с изключено автоматично рестартиране, подсилване на защитата чрез sysctl и банер при вход, до блокиране на изходящия трафик към известни C2 адреси. След това десет проверки потвърждават резултата. Правилото му за компрометиран сървър: не го почиствай; архивирай базата данни, инсталирай наново и смени всяка тайна, защото зловреден софтуер в процеса на приложението може да чете променливите на средата му.
Втори урок, по-късно
По-късно сам се заключих извън сървъра на играта: UFW и защитната стена на облака бяха ограничили SSH до един IP адрес, и мачът пропадна. Сега наръчникът казва: SSH само с ключ плюс fail2ban, без закачане към IP адрес в UFW. Сървърът на играта беше изграден наново по него почти ред по ред, до текста на банера. По-късните сървъри тръгват от него и го нагаждат: административните части са достъпни само през tailnet (частната мрежа на Tailscale) или от самия сървър (loopback), а конфигурацията на Biogard добавя изолация чрез контейнери.
Какво избрах и какво отпадна
Избрах
Поправка на фреймуърка, ново преинсталиране на сървъра и смяна на всяка тайна
Пред
Четвърти кръг подсилване на защитата на SSH и почистване
Всяко преинсталиране беше пускало отново уязвимия Next.js, така че сървърът се заразяваше пак през HTTP, каквато и да беше настройката на SSH.
Избрах
SSH само с ключ плюс fail2ban, без закачане към IP адрес в UFW
Пред
Ограничаване на SSH до един IP адрес в UFW и в защитната стена на облака
Тази настройка по-късно ме заключи извън сървъра на играта.
Резултатът
Проблемът отпадна, щом фреймуъркът беше поправен. Докладът отчита, че поправеното пускане е чисто при 15-минутно наблюдение и след два часа работа, като по-късните опити на ботнета се виждат в дневниците като отхвърлени извиквания на Server Action. Анализът след инцидента е 647 реда в 21 раздела, с разказна версия до него. Наръчникът е основата за новите сървъри и се прилага неравномерно: сървърът на играта го следва почти точно, а останалите вземат части от него и заместват останалото с изолация чрез контейнери и администрация само през tailnet.
Какво следва
Ще приведа най-стария сървър в парка си към наръчника, който той вдъхнови.