Монитор с LDAP-фильтром в тёмной лаборатории, подсвеченной холодным голубым и янтарным свечением экранов. На втором дисплее в размытом фоне — правило детекта с красной меткой.


На внутреннем пентесте финансовой организации SharpHound проработал 34 секунды. Ровно столько потребовалось Microsoft Defender for Identity, чтобы сгенерировать алерт "LDAP Reconnaissance" и передать тикет дежурному аналитику. Сбор графа AD пришлось останавливать, переключаться на ручные запросы через ldapsearch и разбивать фильтры, чтобы не светить стандартные паттерны. С тех пор любой проект с разведкой Active Directory начинается для меня с разбора детектов на стороне SOC - и только потом с выбора инструмента. Потому что запустить SharpHound может любой, а вот не получить алерт через полминуты - уже ремесло.

Место LDAP-разведки Active Directory в цепочке атаки​

LDAP-разведка сидит между получением первичного доступа (initial access) и началом lateral movement. По MITRE ATT&CK - этап Discovery: Account Discovery: Domain Account (T1087.002). Сюда же примыкают Kerberoasting (T1558.003, Credential Access) и AS-REP Roasting (T1558.004, Credential Access) - обе техники начинаются с LDAP-запроса для поиска целевых учёток. Подробнее - в нашем подробном разборе пентест active directory.

Бизнес-логика простая: атакующий получил low-priv доменные учётные данные (через фишинг, password spray, или они выданы в grey box пентесте) и теперь должен понять, куда двигаться дальше. LDAP-запросы дают полную карту: пользователи, группы, делегации, SPN, ACL-записи. Без этих данных планировать privilege escalation - стрельба вслепую.

Почему именно LDAP? Huntress хорошо это сформулировали: каждая доменная машина постоянно использует LDAP для штатной работы, один запрос может вернуть тысячи объектов с атрибутами, а ограничить LDAP нельзя - сломается сам Active Directory. Для SOC тут фундаментальная проблема: отличить легитимный LDAP-трафик от разведки атакующего технически очень тяжело.

[Применимо: внутренний пентест, grey box. Предусловия: сетевой доступ к DC (порты 389/636), валидные доменные учётные данные любого уровня привилегий.]

Мониторинг LDAP-запросов в SIEM: серверная и клиентская телеметрия​

1784709194334.webp

Прежде чем обфусцировать запросы, нужно понять, что именно записывает защитная сторона. Телеметрия LDAP идёт из трёх источников - и большинство организаций используют максимум один из них.

Event ID 1644 на контроллере домена​

Основной источник данных о содержимом LDAP-запросов. Event 1644 записывает фильтр поиска, scope, базу поиска и время выполнения. По умолчанию он выключен - для активации нужно на каждом DC в реестре выставить значение "15 Field Engineering" в 5 по пути HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics. NCC Group именно его рекомендует для анализа подозрительных LDAP-запросов. Microsoft предоставляет скрипт Event1644Reader.ps1, который вытягивает данные из этих событий и импортирует их в Excel для анализа нагрузки.

Нюанс, который часто игнорируют: Event 1644 генерирует огромный объём данных на нагруженном DC. В крупных инфраструктурах включение этого логирования требует согласования с администраторами - SOC часто откладывает активацию, потому что боится положить production-контроллеры. И правильно боится, кстати.

Event ID 4662 и SACL-аудит объектов​

Event 4662 фиксирует операции с объектами Active Directory: чтение свойств, запись, изменение ACL. Для работы нужен включённый аудит Directory Service Access и настроенные SACL на целевых объектах. NCC Group рекомендует обращать внимание на операции Write Property, Control Access, DELETE, WRITE_DAC и WRITE_OWNER. Этот механизм лежит в основе canary-аккаунтов - если на decoy-объекте настроен SACL с аудитом "Read all properties" для Everyone, любое обращение к нему порождает событие.

Клиентская телеметрия: Event 30 и ETW​

На стороне клиента (endpoint, откуда летит запрос) работает ETW-провайдер Microsoft-Windows-LDAP-Client. Black Lantern Security показали, как его активировать:
Код:
wevtutil set-log "Microsoft-Windows-LDAP-Client/Debug" /enabled:true /quiet:true /retention:false /maxsize:100032
Event 30 записывается в Applications and Services Logs -> Microsoft-Windows-LDAP-Client/Debug и содержит информацию о том, какой процесс (PID) отправил запрос, с какого хоста и с какими параметрами. Huntress правильно подметили: серверные логи (Event 1644) показывают что произошло, а клиентские (Event 30) - кто это сделал. Для полной атрибуции нужны оба. Но тут есть подвох - Event 30 работает только для инструментов, использующих wldap32.dll. Impacket со своей Python-реализацией LDAP-клиента в этот лог просто не попадёт.

Трансляция OID в логах - почему детекты BloodHound не срабатывают​

Это тот момент, который упускают и авторы Sigma-правил, и большинство SOC-команд. Huntress подробно разобрали проблему: то, что инструмент атаки отправляет по сети, и то, что DC записывает в Event 1644 - это разные строки.

Конкретный пример. Impacket GetUserSPNs.py отправляет фильтр для поиска Kerberoastable-аккаунтов:
Код:
# Фильтр, отправляемый Impacket GetUserSPNs (T1558.003):
(&(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(servicePrincipalName=*))

# Что DC фактически записывает в Event 1644:
(&(objectCategory=person)(!(userAccountControl&2))(servicePrincipalName=*))
OID 1.2.840.113556.1.4.803 (LDAP_MATCHING_RULE_BIT_AND) заменяется на символ &. Аналогично 1.2.840.113556.1.4.804 (LDAP_MATCHING_RULE_BIT_OR) превращается в |. DC транслирует matching rule OID в оператор побитового сравнения при записи события.

По данным Huntress, findDelegation.py отправляет фильтр (userAccountControl:1.2.840.113556.1.4.803:=16777216), а Event 1644 записывает (userAccountControl&16777216). Любое Sigma-правило, ищущее строку 1.2.840.113556.1.4.803 в поле фильтра Event 1644, никогда не сработает. Не потому что правило логически неверно - оно корректно описывает поведение инструмента. Но оно не учитывает трансляцию на стороне DC.

Прямые последствия для обеих сторон:

Для SOC: если ваши Sigma-правила содержат OID-строки и работают с Event 1644 - проверьте, ищете ли вы OID или транслированный оператор. Правила в SigmaHQ (например, proc_creation_win_hktl_rubeus.yml) чаще ориентированы на process creation, а не на LDAP-фильтры, именно поэтому.

Для red team: трансляция OID - не баг, который можно эксплуатировать. Но она означает, что реальная поверхность детекта у́же - DC ищет побитовые операторы, а не OID-строки. Обфускация должна быть направлена на то, что фактически попадает в лог.

Обфускация LDAP-фильтров на практике​

Требования к окружению​

Для воспроизведения техник ниже нужны: доменная учётная запись (подойдёт любой аутентифицированный пользователь), сетевой доступ к DC на порт 389 (LDAP) или 636 (LDAPS), инструмент для ручных LDAP-запросов (ldapsearch из пакета ldap-utils на GNU/Linux, или PowerShell с модулем ActiveDirectory на Windows). Для верификации детекта - DC с включённым Event 1644 и SIEM с настроенным форвардингом.

Манипуляция BaseObject, Scope и атрибутами​

Стандартные сборщики типа SharpHound и RustHound используют широкие запросы: фильтр (objectClass=*) с базой поиска от корня домена и scope subtree. Это сразу выделяется на фоне штатного LDAP-трафика - легитимные приложения запрашивают конкретные OU или объекты.

Техники снижения заметности:

Сужение BaseObject. Вместо запроса от DC=corp,DC=local формируйте запросы к конкретным OU: OU=Users,DC=corp,DC=local, OU=Servers,DC=corp,DC=local. SOC-правила, срабатывающие на поиск от корня домена, промолчат. Предусловие: нужно знать структуру OU (её можно получить одним запросом к rootDSE, который не логируется в Event 1644).

Замена scope. subtree -> onelevel в нескольких последовательных запросах к разным OU. Запросов станет больше, но каждый из них выглядит менее подозрительно. Ограничение: если SOC ведёт поведенческую аналитику (volume-based), серия запросов может быть заметнее одного.

Минимизация запрашиваемых атрибутов. SharpHound тянет десятки атрибутов одновременно - member, memberOf, servicePrincipalName, msDS-AllowedToDelegateTo, nTSecurityDescriptor и прочее. Запрос с 30+ атрибутами на фоне штатного трафика (где обычно запрашивают 3-5) - аномалия, которую видно невооружённым глазом. Запрашивайте атрибуты порциями: сначала базовые (sAMAccountName, objectClass), потом целевые (servicePrincipalName).

Эквивалентные фильтры. Фильтр (objectCategory=person) можно заменить на (objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=corp,DC=local) - полный DN категории вместо короткого имени. DC вернёт те же объекты, но строка фильтра в логе будет отличаться от сигнатуры инструмента.

Техника обфускацииОбходит Event 1644 (сигнатура)Обходит Defender for IdentityОбходит canary-аккаунтыКонтекст применения
Сужение BaseObjectДаЧастичноНетВнутренний пентест, grey box
Замена scope subtree -> onelevelЧастичноЧастичноНетВнутренний пентест, low-and-slow
Минимизация атрибутовДаЧастичноНетЛюбой внутренний сценарий
Эквивалентные фильтры (DN вместо CN)ДаНетНетВнутренний пентест
Снижение page size + задержкиДаДаНетLong-term recon, 2+ дня
Wildcard в значениях атрибутовЧастичноНетНетТочечные запросы

Работает если: SOC полагается на сигнатурные правила для LDAP-фильтров и Event 1644 включён без поведенческого анализа. Не работает если: развёрнуты canary-аккаунты с SACL-аудитом, используется Defender for Identity с ML-моделями, или SOC ведёт baseline LDAP-активности per-host.

Обход детектирования Kerberoasting и AS-REP Roasting через LDAP​

Kerberoasting (T1558.003, Credential Access) начинается с LDAP-запроса для поиска учёток с непустым servicePrincipalName. Стандартный фильтр Impacket - тот самый (&(objectCategory=person)(!(userAccountControl&2))(servicePrincipalName=*)) (в транслированном виде). По данным Fidelis Security, SOC также ловит запросы с флагами DONT_REQ_PREAUTH (AS-REP Roasting, T1558.004), TRUSTED_FOR_DELEGATION и PASSWD_NOTREQD в userAccountControl.

Варианты обфускации LDAP-части Kerberoasting:

Разделение фильтра на два запроса. Первый: получить список всех активных пользователей (&(objectCategory=person)(!(userAccountControl&2))). Второй: для каждого пользователя отдельно запросить атрибут servicePrincipalName. SOC-правило, срабатывающее на комбинацию servicePrincipalName=* + userAccountControl в одном фильтре, промолчит. Ограничение: запросов станет на порядок больше, что может тригернуть volume-based детект.

Замена objectCategory на objectClass. Фильтр (objectClass=user) вместо (objectCategory=person) вернёт аналогичные результаты, но строка в логе будет другой. Sigma-правила, заточенные на objectCategory=person, не среагируют.

Использование ANR (Ambiguous Name Resolution). Вместо прямого перечисления пользователей можно использовать атрибут anr для поиска по частичному совпадению. Добавляет шум и затрудняет автоматический парсинг лога.

Для AS-REP Roasting атакующий ищет аккаунты с флагом DONT_REQ_PREAUTH (значение 4194304 в userAccountControl). Стандартный фильтр содержит (userAccountControl&4194304). Альтернатива - запросить всех пользователей с минимальным набором атрибутов и фильтровать userAccountControl уже на своей стороне. Подозрительный фильтр из лога уходит, но объём возвращённых данных растёт.

Обнаружение разведки Active Directory: что SOC ловит несмотря на обфускацию​

1784709235587.webp

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Elastic Security 8.x+ - детекты основаны на Event 1644 и корреляции с другими источниками. Правила работают с транслированными фильтрами (побитовые операторы, а не OID). Если правило написано корректно (с учётом трансляции OID), обфускация эквивалентными фильтрами не спасёт - паттерн тот же.

Sigma-правила (SigmaHQ) - большинство правил для T1087.002 и T1558.003 ориентированы на process creation (proc_creation_win_pua_adfind_execution.yml, proc_creation_win_setspn_spn_enumeration.yml) и файловые артефакты, а не на LDAP-фильтры. Вывод: обфускация LDAP-запросов не защитит от детекта по запуску инструмента.

Canary-аккаунты - единственный механизм, который невозможно обойти обфускацией фильтра. Если canary-объект попадает в scope вашего запроса - Event 4662 сгенерируется. Единственная стратегия - вычислить, какие объекты являются ловушками. Косвенные признаки: аккаунт с SPN, но с устаревшим lastLogonTimestamp; группа с "вкусным" именем, но без реальных членов. Black Lantern Security прямо указывают, что при развёртывании canary критически важно обновлять lastLogon - старая дата выдаёт ловушку опытному оператору.

Гонку между обфускацией LDAP-фильтров и сигнатурными детектами red team выигрывает - слишком много способов переписать фильтр, сохранив семантику. Но это не значит, что разведка проходит незаметно. SOC, который комбинирует canary-аккаунты, поведенческий анализ и клиентский ETW, закрывает каналы, не зависящие от конкретных строк в фильтре.

Половина публичных Sigma-правил для LDAP-разведки ищет OID-строки в Event 1644, которые DC туда просто не записывает. По данным Huntress, это системная проблема: авторы правил не генерируют реальную телеметрию перед написанием детекта. На стороне атаки ситуация зеркальная - операторы запускают SharpHound с дефолтными параметрами и удивляются алерту через минуту. Обе стороны работают по шаблону вместо того, чтобы разобраться в механике.

Для атакующего правильный подход - разведка через ручные запросы с минимальным scope, в темпе легитимного трафика, с учётом того, что canary-аккаунт может стоять в любом OU. Для защитника - отказ от чисто сигнатурного подхода в пользу триады: canary + baseline + клиентская телеметрия.

Через пару лет зрелые SOC-команды полностью перейдут с «ищем паттерн фильтра» на «ищем аномалию профиля» - и тогда обфускация фильтров станет просто гигиеной, а не реальным evasion. Проверьте свои Sigma-правила на стенде: отправьте GetUserSPNs.py запрос, откройте Event 1644 и посмотрите, что там записано. Если в правиле OID-строка - вы ловите фантом.
 
Последнее редактирование модератором:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab