Арифметика, честно
Установщик реализует девять стандартных методов Windows; сайт говорит — восемь локаций. Это не маркетинговое округление, а решение о счёте, которое мы готовы защищать: Run и RunOnce — одна строка. Один куст, один класс телеметрии, одно семейство правил ловит оба; разница между ними — булево в установщике и предложение в документации. Считать их раздельно — раздувать буклет. Считать вместе — держать аудит честным, а аудит и есть суть: каждая из восьми строк ниже — ставка против свежести чьей-то базовой линии.
| Локация | Покупает | Стоит |
|---|---|---|
| Run + RunOnce (одна строка) | Переживание перезагрузки в контексте пользователя; тривиальная установка | Самые просматриваемые ключи ОС — реестровая телеметрия, каждый инструмент базовых линий, первый запрос любого SOC |
| Папка автозагрузки | Простота; контекст пользователя; ноль API-поверхности | Перечисляется всем; требует файла на диске с именем |
| Планировщик задач | Гибкие триггеры; опция SYSTEM; правдоподобное хозяйство | События создания задач, XML-артефакт на диске, журнал планировщика с длинной памятью |
| Служба | Старт рано при загрузке; SYSTEM; собственная механика хоста | События установки служб; новое имя службы — новизна, а новизна и есть сигнал |
| WMI-подписка | Нет записи ни в одном списке автозапуска; косвенность через фильтр событий | Пространства имён подписок — отстреливаемый класс: защитники читают их по расписанию |
| COM-хиджак | Исполнение внутри легитимных процессов-хостов; на пользователя, без админа | Диффы куста Classes ловят; обновление приложения-хоста может молча сломать |
| DLL-сайдлоад | Исполнение внутри подписанных бинарей; путаница порядка поиска | Загрузки модулей из странных путей; цели стареют, поэтому держим два десятка проверенных — несколько отсутствуют в публичных списках LOLBAS — и авто-фолбэк, когда одна умирает |
| Задание BITS | Сервис передачи данных удваивается триггером; возобновляется сам | Очередь BITS читаема любым админом; у заданий есть владельцы, метки времени и база данных |
Генерация на хост: множитель
Локация — механизм; установка — экземпляр. Каждая установка AXIS генерируется под хост — имена, пути, файлы и легенды из ротируемой труппы пятидесяти правдоподобных системных имён, — так что два развёртывания никогда не похожи друг на друга. Это убивает самый дешёвый пивот в реагировании: зачистку флота по хэшу и имени. Чего это не убивает, честно, — класса механизма: COM-хиджак — аномалия куста Classes на любом хосте, как бы ни звали экземпляр. Генерация на хост заставляет защитника охотиться на механизмы, а не на имена. Это реальная цена, которую мы выставляем, — и реальный предел, который признаём, потому что охота на механизмы — ровно то, что зрелые команды уже делают.
Семейство Ghost, над списком
Стандартная восьмёрка — для хостов, терпящих стандартные вещи. Установки Ghost — для остальных. Имена возможностей, уровень категорий, как всегда:
Ghost-Path — установка с мульти-регистрацией: одна установка, регистрирующаяся сразу через несколько стандартных механизмов, так что одиночный проход зачистки не обязан завершать агента. Статус показывает её как одну установку; удаление снимает как одну установку — оператор никогда не управляет комбинацией руками. Ghost-Svchost — сервисная установка, чьи файлы производятся для одной этой машины; её лончер — именно лончер. Служба стартует, порождает отсоединённого агента и останавливается: C2-трафик никогда не идёт из сервисного процесса, а работающая служба, которую никто не может найти, — та, что уже вышла. Вариант NLD проталкивает ту же идею глубже: ядро загрузчика существует только как шеллкод в реестре, так что дисковый стаб не несёт IoC загрузчика, по которому можно сигнатурить. Ghost Write — путь установщика, который стейджит через потоки метаданных файловой системы и производит установку изнутри процесса, запущенного самой ОС, — событие установки никогда не несёт имени стейджера, что ломает сюжетную атрибуцию на событие раньше. А для хостов, где сенсор уровня ядра блокирует основной путь начисто, существует запасная стадия — гейтованная, по доктрине из N.11: когда фингерпринт говорит «уровень ядра», мы обходим, а не спорим. Есть и режим сборки persist-only, где единственная работа стейджера — установка: он выходит, и первый маяк принадлежит персистентному агенту, так что событие установки и первое соединение никогда не делят процесс.
Вне Windows модель держится. Ghost-Systemd строит лончер под машину и воссоздаёт агента при загрузке, вместо того чтобы оставлять на диске простой исполняемый файл; лончер запечатан идентичностью самой машины, которая никогда не передаётся на сервер, — лончер, скопированный на другую машину, — лончер, который не работает. Где systemd нет — NAS и устройства класса роутеров, — Ghost-Cron: тот же пакет за триггером cron. На macOS Ghost-Launchd делится по привилегии: демон при загрузке для root, агент при логине иначе. Во всех трёх статус и удаление никогда не спрашивают, какой метод использовался; маленький указатель на диске фиксирует выбор для того оператора, что появится на следующей неделе.
Персистентность — не где имплант прячется. Это где имплант расписывается в журнале — аудит в том, читает ли кто-нибудь.
Честный счёт
Персистентность — самое громкое, что делает имплант, потому что это запись — в реестр, планировщик, очередь, каталог юнитов, — а записи падают в таблицы, которые защитники могут читать. Уникальность на хост убивает пивоты по именам; классы механизмов остаются, и про каждый класс выше написана детект-статья. Вторая честная цена — жизненный цикл: установка, которую нельзя чисто снять, — не персистентность, а мусор. Поэтому фича — три действия на каждой ОС: установить, статус, снять; поэтому удаление никогда не спрашивает, какой метод использовался; и поэтому панель разделяет снять установку и удалить запись: удаление записи без снятия установки — то, как флоты начинают посещаться призраками агентов, которых никто не может ни затаскать, ни найти нарочно.
Угол защитника
Базовые линии автозапуска на роль хоста, затем дифф ежедневно — восемь строк Рис. A это восемь мишеней диффа, а диффу безразличны имена экземпляров. Конкретно:
// реестровая пара — самые просматриваемые ключи ОС не зря sysmon(12,13,14) где путь like "\\Run" // оба ключа; это одна строка // задачи, службы, подписки, очередь sec(4698,4699) + журнал планировщика // создание/смена задачи, затем читаем XML sec(4697) + sysmon(6) // установка службы + загрузки драйверов wmi: перечислить __eventfilter/bindings // по расписанию, не после алерта bitsadmin /list /allusers // очередь — публичное чтение // и два, что стареют лучше всех дифф hkcu\software\classes на роль // COM-хиджаки живут здесь, на пользователя image_load где путь не в (system32, program files) // сайдлоады, странные пути
Затем охотьтесь на сирот: установки, чья управляющая запись больше не существует нигде. Служба, которая стартует, порождает и останавливается; задача, стреляющая в дерево процессов, которое немедленно отсоединяется; значение реестра, указывающее на стаб, указывающий в никуда. Механизмы все документированы — в том числе нами. Журнал публичен. Читайте его по расписанию — и вся эта заметка станет бэклогом детектов, чем она и была.
Следующая заметка: Костюм — не акцент. Двадцать три трафик-профиля, запечатанные сессии с ротируемой идентичностью, фронтинг через edge и мутация нагрузки на каждую отдачу — что покупает каждый слой провода и что всё равно слышит терпеливый охотник-статистик.