Автоматизация проверки прав Active Directory: BloodHound, Neo4j API и Python-скрипт

По данным IBM X-Force Threat Intelligence Index 2025, атаки с использованием легитимных учётных данных выросли на 71% за год. CrowdStrike Global Threat Report дополняет: 75% вторжений в 2024 году начинались с валидных кредов. Ручной аудит прав в домене на пять тысяч объектов — работа на дни. А Python-скрипт, который стучится в Neo4j через Bolt-протокол и прогоняет Cypher-запросы по базе BloodHound, закрывает ту же задачу за минуты. На выходе — CSV, готовый для отчёта заказчику.
Место автоматизации BloodHound в цепочке пентеста Active Directory
BloodHound — платформа для графового анализа Active Directory (AD — служба каталогов Microsoft, центральная нервная система любой корпоративной Windows-сети). Инструмент собирает данные о пользователях, группах, компьютерах, политиках и правах доступа, а затем выстраивает из них граф: узлы — объекты, рёбра — связи и права между ними. Представьте карту метро, где станции — объекты AD, а маршруты — реальные пути, по которым атакующий может двигаться от рядового пользователя до администратора домена.
MITRE ATT&CK — открытая база тактик и техник атак; T-коды вроде T1087.002 — её идентификаторы. Если вы впервые сталкиваетесь с этой базой, запомните: каждый T-код — конкретная техника, которую атакующие применяют на практике. Автоматизация проверки прав AD через BloodHound покрывает несколько из них:
- Обнаружение доменных учёток (T1087.002, тактика Discovery) — перечисление пользователей и их привилегий
- Обнаружение доменных групп (T1069.002, Discovery) — анализ вложенности групп и транзитивных прав
- Обнаружение доверительных отношений (T1482, Discovery) — маппинг трастов между доменами
- Kerberoasting (T1558.003, Credential Access) — поиск сервисных учёток с SPN (Service Principal Name — идентификатор сервиса в Kerberos), чьи тикеты можно запросить и взломать офлайн
В полной цепочке атаки автоматизированный аудит прав — этап после получения первоначального доступа (initial access) и закрепления (foothold). Неважно, выданы ли учётные данные заказчиком в grey box пентесте или получены через фишинг — дальше нужно понять, куда с этими кредами можно дотянуться. Python-скрипт забирает данные из графовой базы BloodHound и за секунды находит пути эскалации привилегий, которые руками пришлось бы искать часами.
Что происходит до: SharpHound (коллектор BloodHound) собирает данные из AD через LDAP-запросы и SMB-сессии, упаковывает результат в ZIP-архив. Архив загружается в BloodHound, данные попадают в Neo4j — графовую базу, хранящую узлы и рёбра.
Что происходит после: результаты автоматизированной проверки превращаются в конкретные рекомендации для отчёта: «уберите GenericAll у группы X на объект Y», «отключите SPN у учётки Z», «заблокируйте неактивный аккаунт W».
Контекст применения: [внутренний пентест, grey box / white box]. Скрипт работает после сбора данных SharpHound. Нужны: учётные данные доменного пользователя любого уровня привилегий для сбора и сетевой доступ к Neo4j (порт 7687) или BloodHound CE API (порт 8080).
Neo4j Bolt vs BloodHound CE API — выбор интерфейса для автоматизации bloodhound
Прежде чем писать bloodhound python скрипт, определитесь с интерфейсом доступа к данным. Вариантов два.
Neo4j Bolt — прямое подключение к графовой базе Neo4j через двоичный протокол Bolt (порт 7687). Работает с BloodHound Legacy (4.x) и с BloodHound CE, где Neo4j входит в стандартный Docker Compose как один из трёх контейнеров (приложение, PostgreSQL для конфигурации, Neo4j для графовых данных). Python-библиотека — neo4j, официальный драйвер от Neo4j Inc.
BloodHound CE REST API — HTTP-эндпоинт CE-версии. Документация доступна прямо из GUI; аутентификация через API-ключ, который генерируется в настройках CE.
| Критерий | Neo4j Bolt | BloodHound CE REST API |
|---|---|---|
| Преимущества | Полный Cypher без ограничений, CSV-экспорт, прямая работа с графом, агрегации (count, collect) | Документирован в GUI, токен-аутентификация, маркировка Tier Zero из коробки |
| Ограничения | Требует проброса порта 7687 из Docker, ручная настройка пароля | По данным исследования 8com, не возвращает SPN-данные напрямую; часть Cypher-конструкций может быть ограничена |
| Когда использовать | Сложные запросы с агрегациями, массовый экспорт, построение отчётных пайплайнов | CE уже развёрнут, нужны базовые проверки, быстрая интеграция в существующую автоматизацию |
| Когда не использовать | CE установлен без проброса Neo4j-порта — придётся менять docker-compose.yml | Нужны полные SPN для анализа Kerberoasting или многоступенчатые Cypher-запросы |
По исследованию 8com, при автоматизации Kerberoasting-проверок через CE API приходится делать дополнительные запросы для получения SPN, тогда как через Neo4j всё достаётся одним Cypher-запросом. Для задачи «вытащить всех Kerberoastable-пользователей с атрибутами и экспортировать в CSV» прямой Neo4j-доступ удобнее. Я выбираю Bolt.
Python-скрипт для автоматизации проверки прав Active Directory через Neo4j
Требования к окружению
- ОС: Kali Linux 2024.x+ или любая с Python 3.8+
- RAM: 4 ГБ минимум для скрипта; 8–16 ГБ если Neo4j и BloodHound крутятся на той же машине
- Python-зависимость:
pip install neo4j - Сеть: доступ к порту 7687 (Bolt) на хосте с Neo4j
- Данные: ZIP-архив SharpHound уже загружен в BloodHound
Частая ошибка новичков: попытка подключиться к http://localhost:7474 (веб-интерфейс для браузера) вместо bolt://localhost:7687 (протокол для программного доступа). Веб-интерфейс — для ручных запросов в браузере. Скрипт на Python работает через Bolt. Ещё одна типичная проблема — забыть сменить пароль Neo4j после установки. При первом входе система просит задать новый пароль, и если этого не сделать через веб-интерфейс, подключение из Python упадёт с AuthError.
Шаг за шагом: от подключения к отчёту
Шаг 1. Проверяем подключение. Создайте файл и запустите — скрипт должен вывести количество узлов-пользователей в базе. Число больше нуля означает, что данные SharpHound загружены и доступны.
from neo4j import GraphDatabase
driver = GraphDatabase.driver(
"bolt://localhost:7687",
auth=("neo4j", "your_password") # замените на свой пароль
)
with driver.session() as session:
result = session.run("MATCH (u:User) RETURN count(u) AS total")
print(f"Пользователей в базе: {result.single()['total']}")
driver.close()
Ожидаемый результат: строка вида «Пользователей в базе: 1247». Если 0 — данные SharpHound не загружены или загружены в другую базу. ServiceUnavailable — Neo4j не запущена. AuthError — неверный пароль.
Шаг 2. Запускаем целевые проверки. Каждая проверка — Cypher-запрос, переданный в session.run(). Для Kerberoastable-учёток: MATCH (u:User {hasspn: true, enabled: true}) RETURN u.name, u.serviceprincipalnames. Зачем это нужно: каждая такая учётка — потенциальная цель для Kerberoasting (T1558.003). Её тикет можно запросить без каких-либо привилегий и взломать пароль офлайн. Если результат пуст — в домене нет активных Kerberoastable-учёток. В продуктивных средах такое бывает редко.
Шаг 3. Собираем все проверки в один скрипт с экспортом. Словарь {"название_проверки": "MATCH ..."} — список запросов. Скрипт проходит по каждому, выполняет через session.run() и пишет результаты в CSV. На выходе — таблица, которую можно вставить в отчёт или передать заказчику.
from neo4j import GraphDatabase
import csv
CHECKS = {
"kerberoastable": "MATCH (u:User {hasspn:true,enabled:true}) RETURN u.name",
"dacl_abuse": "MATCH (u:User)-[r:WriteDACL|WriteOwner]->(g:Group) WHERE g.name STARTS WITH 'DOMAIN ADMINS' RETURN u.name,g.name",
"unconstrained_deleg": "MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name",
}
drv = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "pass"))
with drv.session() as s, open("ad_audit.csv", "w", newline="") as f:
w = csv.writer(f)
for name, q in CHECKS.items():
for r in s.run(q): w.writerow([name] + list(r.values()))
drv.close()
Ожидаемый результат: файл ad_audit.csv с колонками «тип проверки, имя объекта, дополнительные данные». Пустой файл — либо домен действительно чист (маловероятно на пяти тысячах объектов), либо проблема в данных SharpHound.
Cypher-запросы BloodHound для аудита прав пользователей AD
Ниже — набор neo4j cypher запросов bloodhound, которые закрывают типовые проверки на каждом внутреннем пентесте. Каждый передаётся в session.run() аналогично шагам выше.
ACL-контроль над привилегированными группами. Запрос MATCH (u:User)-[r:GenericAll|WriteDACL|WriteOwner|AllExtendedRights]->(g:Group) WHERE g.name STARTS WITH 'DOMAIN ADMINS' RETURN u.name, g.name, type(r) находит учётки с правами изменять ACL (Access Control List — список управления доступом) привилегированных групп. Почему это критично: если рядовой пользователь имеет WriteDACL (право менять список доступа) на группу Domain Admins, он может добавить туда кого угодно. Прямой путь к полному контролю над доменом — и в реальных проектах я встречал такое чаще, чем хотелось бы.
Кратчайшие пути до Domain Admins (до 5 хопов). Запрос MATCH p=shortestPath((n)-[*1..5]->(g:Group {name:'DOMAIN ADMINS@CORP.LOCAL'})) WHERE n<>g RETURN p LIMIT 50 находит до 50 путей. Замените CORP.LOCAL на FQDN вашего домена в верхнем регистре. Несовпадение регистра или доменного суффикса — причина пустого результата номер один. Если запрос ничего не вернул, первым делом проверьте именно это.
Неактивные включённые учётки. Пользователи, не входившие более 90 дней, но не заблокированные. По данным 8com, такие аккаунты — приоритетные цели для password-атак: блокировка их при брутфорсе никого не затронет, а пароль с высокой вероятностью слабый. Запрос проверяет атрибуты lastlogon и lastlogontimestamp (реплицированная метка с других контроллеров домена) — оба должны быть старше 90 дней.
Компьютеры с unconstrained delegation. Машины, где Kerberos-делегирование не ограничено: MATCH (c:Computer {unconstraineddelegation: true}) RETURN c.name. Если атакующий получает контроль над такой машиной, он перехватывает TGT (Ticket Granting Ticket — мастер-билет Kerberos, по сути «золотой ключ» для аутентификации) любого пользователя, который залогинился на ней.
Пути от «owned»-узлов. После пометки скомпрометированных учёток в BloodHound запрос MATCH p=shortestPath((n {owned:true})-[*1..5]->(g:Group {name:'DOMAIN ADMINS@CORP.LOCAL'})) RETURN p показывает реальные пути из вашей текущей позиции. На практике это самый полезный запрос — именно он отвечает на вопрос «что я могу сделать прямо сейчас с теми кредами, что уже есть».
Ограничения автоматизации BloodHound и когда скрипт не поможет
Устаревшие данные. BloodHound показывает снимок AD на момент сбора SharpHound. Если между сбором и анализом прошло две недели — часть путей уже не существует, а новые могли появиться. Запускайте SharpHound непосредственно перед автоматизированным анализом и повторяйте сбор на длительных проектах.
Ложные пути и фактор EDR. Не каждый путь в графе реально эксплуатируем. Ребро HasSession показывает, что администратор залогинен на машине X, но если на ней стоит CrowdStrike Falcon с актуальными сигнатурами — дамп LSASS (процесса, хранящего учётные данные в памяти) не пройдёт без целенаправленного evasion. Скрипт не знает, какой EDR стоит на конечных точках. SentinelOne и Elastic 8.x+ детектируют SharpHound на диске, и при реальном red team потребуется in-memory исполнение. Граф покажет путь, но пройти по нему — отдельная задача.
Расхождение схемы Legacy vs CE. Свойство hasspn работает в Legacy (4.x). В CE схема свойств узлов может отличаться — маркировка highvalue заменена на Tier Zero через атрибут system_tags. Перед запуском скриптов выполните MATCH (u:User) RETURN keys(u) LIMIT 1 — этот запрос покажет все доступные свойства узлов и поможет адаптировать Cypher-запросы под вашу версию.
Неполный сбор. При запуске SharpHound с флагом DCOnly (только контроллер домена) в базе не окажется информации о сессиях и локальных администраторах рабочих станций. Пути эскалации через lateral movement (горизонтальное перемещение между машинами) просто не отобразятся — скрипт найдёт только ACL-пути и членство в группах. Если на проекте нет ограничений по скрытности, используйте -c All.
За пределами автоматизации. Скрипт не заменяет ручной анализ: кастомные рёбра (например, HasCredentials — когда пароль найден в конфигурационном файле на сетевой шаре), специфика гибридных Azure AD конфигураций, оценка реальной эксплуатируемости путей с учётом защитных средств конкретного заказчика. Автоматизация находит кандидатов, голова пентестера — оценивает.
Чеклист автоматизированной проверки прав Active Directory
- Запустить SharpHound с флагом
-c Allдля полного сбора данных. Если нужна скрытность —-c DCOnly,ACL,Group,Trustsс параметрами--Throttle 1000 --Jitter 30. - Загрузить ZIP в BloodHound (Legacy: перетащить в GUI; CE: кнопка Upload).
- Убедиться в доступности Neo4j на
bolt://localhost:7687. Сменить дефолтный пароль. - Установить Python-драйвер:
pip install neo4j. - Проверить подключение:
MATCH (u:User) RETURN count(u)— результат должен быть > 0. - Проверить Kerberoastable-учётки:
MATCH (u:User {hasspn:true, enabled:true}) RETURN u.name. - Проверить ACL-контроль над Domain Admins: искать рёбра GenericAll, WriteDACL, WriteOwner, AllExtendedRights.
- Найти неактивные включённые учётки (lastlogon старше 90 дней).
- Перечислить компьютеры с unconstrained delegation.
- Экспортировать результаты в CSV и включить в отчёт.
- Повторить сбор SharpHound через 1–2 недели и сравнить результаты — проверить, закрыты ли найденные проблемы.
Минилаб для отработки
Минимальный стенд для воспроизведения всех шагов из статьи:
- VM1: Windows Server 2019/2022 — контроллер домена. Подойдёт любой готовый образ уязвимого AD (DVAD, Vulnerable-AD на GitHub, GOAD).
- VM2: Kali Linux 2024.x — для SharpHound и Python-скрипта.
- RAM: 16 ГБ суммарно (8 ГБ на DC, 4 ГБ на Kali, остальное хосту).
Создайте 5–10 пользователей. Задайте WriteDACL рядовому пользователю на группу Domain Admins через dsacls или PowerShell. Добавьте SPN на одну сервисную учётку командой setspn -A MSSQLSvc/sql01.corp.local:1433 svc_sql. Запустите SharpHound, загрузите данные, запустите скрипт. Проверка: оба проблемных объекта должны появиться в CSV.
Большинство пентестеров, с которыми я работал на проектах, используют BloodHound как «инструмент для скриншотов»: запустили встроенный запрос Find Shortest Path to Domain Admins, получили красивый граф, вставили картинку в отчёт. Вся мощь инструмента — программный доступ к графовой базе — остаётся нетронутой. А потом заказчик задаёт конкретные вопросы: сколько в домене Kerberoastable-учёток, какие из них в привилегированных группах, какие не логинились больше года — и начинается ручной разбор, потому что скрипта нет.
Три-четыре Cypher-запроса, обёрнутые в Python с экспортом в CSV — час работы, который экономит дни на каждом следующем проекте. Причём те же запросы полезны и защитнику: системный администратор, прогоняющий скрипт раз в месяц, увидит новые excessive privileges до того, как их найдёт атакующий. По сути, это та же функциональность, которую BloodHound Enterprise от SpecterOps продаёт как коммерческий продукт — только реализованная руками и бесплатно.
Моя позиция: если вы работаете с AD-инфраструктурой регулярно, автоматизация проверки прав через BloodHound — не опция, а базовая гигиена. Встроенных запросов хватает для первого взгляда, но для системного аудита нужна собственная библиотека Cypher-запросов, заточенная под конкретные домены. Чем раньше начнёте её собирать — тем быстрее каждый следующий проект. На курсе WAPT в Codeby Academy эту связку BloodHound + Neo4j + Python разбирают на живых лабах с полноценным AD-доменом.
Эту тему и смежные навыки разбирают на практике в курсе «Python для пентестера» Codeby Academy.