Към съдържанието

Компрометираният сървър

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 минути излезе чисто.

Как работи

  1. Изходящите връзки като сигнал

    Правилата на защитната стена за входящия трафик не виждат връзка, която сървърът отваря сам. ss -tnp state established показва всяка установена връзка заедно с процеса, който я държи, а процес на приложение, свързан с непознат хост, е мястото, откъдето се започва. Сега това е ред от контролния списък за проверка, а очакваният резултат е само моята собствена SSH сесия.

  2. Две атаки едновременно

    auth.log показваше атака с груба сила по SSH, затова три етапа работа отидоха в SSH. Тази атака беше истинска и протичаше едновременно, но трайната дойде през собствените портове на приложението, които трябва да останат отворени. Ubuntu 24.04 внесе допълнителен шум: стойността по подразбиране TriggerLimitBurst от 20 на ssh.socket спира слушането на SSH след 20 опита за връзка, затова SSH падаше по време на атаката.

  3. Наръчникът

    Написан по следите на инцидента: десет стъпки, от изключване на ssh.socket, през SSH само с ключ и модерните шифри от препоръките на Mozilla, потребител без root права и заключен root, UFW с блокиране на входящия трафик по подразбиране, fail2ban, автоматични обновявания с изключено автоматично рестартиране, подсилване на защитата чрез sysctl и банер при вход, до блокиране на изходящия трафик към известни C2 адреси. След това десет проверки потвърждават резултата. Правилото му за компрометиран сървър: не го почиствай; архивирай базата данни, инсталирай наново и смени всяка тайна, защото зловреден софтуер в процеса на приложението може да чете променливите на средата му.

  4. Втори урок, по-късно

    По-късно сам се заключих извън сървъра на играта: 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.

Какво следва

Ще приведа най-стария сървър в парка си към наръчника, който той вдъхнови.