Статья DCSync атаки через нестандартные протоколы

1771617325765.webp


В инете полно статей про DCSync, но всё как под копирку: «Mimikatz, DCSync, оп, и админ». Скука смертная. А ведь дьявол, как всегда, в деталях, а точнее - в протоколах, по которым эта магия вообще работает.

Почему меня бесят 99% статей на эту тему

Серьёзно, откройте любой блог по информационной безопасности. «DCSync атака: Mimikatz и права на репликацию». Всё. Никто не объясняет, что за зверь такой - протокол DRSR, как он работает на уровне пакетов, почему он вообще позволяет запрашивать хэши, и, главное, КАК ЕЩЁ можно его дёрнуть, чтобы не спалиться. Это как объяснять устройство двигателя фразой «нажал педаль - поехал». А где впуск, где выпуск, где зажигание? Нам, людям с хакерским складом ума, этого мало. Мы хотим залезть под капот, перебрать карбюратор и собрать свой движок, который будет работать на чём угодно, только не на бензине.

Наша цель сегодня - эмуляция контроллера домена с использованием нестандартных протоколов

Мы с вами люди простые, но с опытом. Нам интересно не просто нажать кнопку в Mimikatz и получить хэши. Нам интересно, ЧТО именно происходит в тот момент, когда наш ноутбук, не являясь контроллером домена (DC), вдруг начинает им прикидываться и требует у легитимного DC: «А ну-ка, брат, слей мне парольную базу».

Эта статья - не пересказ MSDN. Это наш с вами совместный реверс-инжиниринг реальности. Мы залезем в такие дебри протоколов MS-AP и MS-DRSR, куда даже Microsoft забыла дорогу. Мы напишем свой эмулятор контроллера домена на коленке, который сможет выдернуть хэши, используя нестандартные транспорты. И да, будет больно, будет много кода, будет мат и будет прозрение.

Но зачем это всё, если уже есть готовые инструменты?

Во-первых, готовые инструменты - это чёрный ящик. Вы не знаете, как они работают под капотом, а значит, не сможете их адаптировать под нестандартную среду. Во-вторых, именно понимание протоколов позволяет обходить защиту. Сегодня EDR смотрит на RPC - завтра мы пойдём по SMB. Послезавтра - через HTTPS с красивым сертификатом. А когда защита научится ловить и это, мы придумаем что-то ещё, потому что мы понимаем суть, а не просто копируем команды.

И последнее перед погружением

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

Итак, пристегните ремни. Мы начинаем погружение в мир MS-AP, MS-DRSR и эмуляции контроллеров домена. Будет жестко, будет весело, будет полезно.

Глава 1: Мифология DCSync или "Куда катится этот мир?"​

Если ты хоть раз гуглил «DCSync атака», ты видел эту мантру: «DCSync - это техника, при которой атакующий, имея права на репликацию, имитирует поведение контроллера домена и запрашивает у легитимного DC хэши паролей пользователей через протокол DRSUAPI». И дальше - пример с Mimikatz. Всё. Точка.

Но давайте честно: эта формулировка ровно ничего не объясняет. Что значит «имитирует поведение контроллера домена»? Как именно он это делает? Какие протоколы задействованы? Почему вообще один DC имеет право запрашивать у другого секреты? Как выглядит этот запрос на уровне пакетов? И, самое главное - почему защитные системы так часто пропускают эту атаку, если она такая известная?

Чтобы ответить на эти вопросы, нам придётся залезть в такие дебри, куда даже поддержка Microsoft не всегда заходит. Но мы туда зайдём. С фонариком, отвёрткой и запасом мата.


1.1. Active Directory - это распределённая база данных, а не просто «папка с пользователями»​

Первое, что нужно понять: Active Directory - это не просто база данных учётных записей, висящая на одном сервере. Это мультимастерная распределённая база данных. То есть изменения могут вноситься на любом контроллере домена, и эти изменения должны синхронизироваться со всеми остальными контроллерами. Именно для этого и существует механизм репликации.

Репликация в AD построена на нескольких ключевых концепциях:
  • Контекст именования (Naming Context, NC) - это раздел базы данных. Например, контекст домена (DC=domain,DC=local), контекст схемы (CN=Schema,CN=Configuration,...) и конфигурационный контекст (CN=Configuration,...).
  • Глобальный уникальный идентификатор (GUID) - каждый объект в AD имеет GUID, который не меняется никогда.
  • Sequence Number (USN) - на каждом DC есть счётчик USN (Update Sequence Number). Каждое изменение объекта увеличивает USN на этом DC.
  • Вектор обновлений (UptodateVector) - каждый DC хранит информацию о том, какие USN от других DC он уже получил. Это позволяет избежать повторной репликации.
  • HighWatermark - специальная структура, которая указывает, до какого USN мы уже получили данные из определённого NC.
Теперь представьте, что один контроллер (DC1) хочет узнать, какие изменения произошли на другом контроллере (DC2) с момента последней синхронизации. Он отправляет запрос, содержащий:
  • Какой NC его интересует.
  • HighWatermark - «я уже знаю всё до USN=100500, дай мне то, что новее».
  • Уточнение: какие атрибуты нужны (может, только часть, чтобы не гонять лишнее).
В ответ DC2 отдаёт набор объектов, которые изменились, с их атрибутами. И среди этих атрибутов могут быть хэши паролей, если они изменились.

Вот тут и зарыта собака: пароли (хэши) - это такие же атрибуты объектов, как имя или телефон. Они реплицируются между DC. И если ты можешь запросить репликацию, ты можешь получить эти атрибуты.


1.2. Почему DCSync вообще возможен? Права на репликацию​

В AD существуют специальные разрешения, которые позволяют инициировать репликацию. Это не просто «чтение всех свойств». Это отдельные extended rights:
  • DS-Replication-Get-Changes (GUID: 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2) - право запрашивать изменения из определённого NC. Без этого права даже запрос на репликацию не пройдёт.
  • DS-Replication-Get-Changes-All (GUID: 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2) - право запрашивать все изменения, включая репликацию критических данных (паролей).
  • DS-Replication-Get-Changes-In-Filtered-Set - используется для частичной репликации (например, только некоторых атрибутов).
По умолчанию эти права есть у:
  • Контроллеров домена (их учётные записи компьютеров имеют эти права).
  • Администраторов домена.
  • Администраторов предприятия (в корне леса).
  • Иногда - у специальных групп типа «Exchange Windows Permissions», потому что Exchange тоже должен уметь читать AD.
Очень часто в доменах можно встретить ситуацию, когда права на репликации даны каким-нибудь сервисным учёткам. Например, для бэкапов или для систем мониторинга. И это - идеальная цель для атакующего.


1.3. Протокол MS-DRSR (Directory Replication Service Remote Protocol)​

А теперь к технике. Протокол, который отвечает за репликацию, называется MS-DRSR. Он описан в [MS-DRSR] - это том на несколько сотен страниц, который мало кто читает от корки до корки. Но мы прочитаем (хотя бы выборочно).

Основной метод: IDL_DRSGetNCChanges

Это функция, которую вызывает клиент (один DC) у сервера (другой DC) для получения изменений.

Сигнатура (из IDL):

C:
NTSTATUS IDL_DRSGetNCChanges(
    [in] handle_t hRpc,
    [in, out] DRS_MSG_GETCHGREQ* pmsgIn,
    [out] DRS_MSG_GETCHGREPLY* pmsgOut,
    [in, out] DRS_EXTENSIONS_INT* pdwExtCaps
);

Параметр pmsgIn содержит структуру DRS_MSG_GETCHGREQ, которая внутри может быть версии 1, 2, 3... В версии 3 (самой популярной) передаются:
  • uuidDSA - GUID целевого DC (кому адресован запрос).
  • uuidInvocId - идентификатор инвокации (меняется при восстановлении БД).
  • pNC - GUID того NC, который нас интересует.
  • pPartialAttrSet - список атрибутов, которые мы хотим получить (если пусто - получим все, включая пароли).
  • pUpdVec - вектор обновлений (рассказывает серверу, что мы уже видели).
  • ulFlags - флаги: например, DRSUAPI_DS_GETCHG_UPDATE (получить изменения) или DRSUAPI_DS_GETCHG_BYTIME (получить все объекты).
  • Page - для постраничного получения.
В ответ сервер возвращает структуру DRS_MSG_GETCHGREPLY, которая содержит:
  • pObjects - массив объектов с изменениями.
  • pUpdVec - новый вектор обновлений (чтобы клиент знал, что получил).
  • pNamingContext - подтверждение NC.
  • ulExtendedRet - код ошибки/успеха.
Как это упаковывается?

По умолчанию DRSR работает поверх RPC. То есть клиент устанавливает RPC-соединение с сервером, проходит аутентификацию (Kerberos или NTLM) и вызывает метод. В качестве транспорта может использоваться:
  • ncacn_ip_tcp - чистый RPC по TCP (обычно порт 135 для эндпоинт-маппера, затем динамический порт).
  • ncacn_np - RPC через именованные каналы SMB (\DC\pipe\lsass например).
  • ncacn_http - RPC через HTTP (редко используется, но возможно).
Именно благодаря тому, что DRSR может работать через разные транспорты, у нас появляется пространство для манёвра.


1.4. Протокол MS-AP (Active Directory Web Services)​

А теперь самое вкусное. Microsoft, понимая, что будущее за веб-технологиями, решила сделать для AD ещё один интерфейс управления - на основе веб-сервисов. Так родился MS-AP - протокол ADWS (Active Directory Web Services).

Зачем это было нужно?
  • Чтобы управлять AD из PowerShell без установки RSAT на клиенте.
  • Чтобы можно было делать запросы к AD через SOAP/XML.
  • Чтобы обеспечить работу с AD из облачных сервисов.
  • Чтобы дать разработчикам удобный API (пусть и на SOAP, что спорно).
Начиная с Windows Server 2008 R2 (с пакетом обновлений) и во всех последующих версиях, на контроллере домена устанавливается роль ADWS. Она запускает IIS-сайт, который слушает порты 9389 (HTTP) и 9388 (HTTPS?). На самом деле по умолчанию:
  • HTTP: 9389
  • HTTPS: 9389 с SSL (то есть порт тот же, но с шифрованием, если включено).
Архитектура ADWS:

Клиент (например, модуль PowerShell ActiveDirectory) отправляет SOAP-запросы на эндпоинт:

http://dc:9389/ActiveDirectoryWebServices/ActiveDirectory.asmx

Этот ASMX-файл (хотя на самом деле это не файл, а обработчик) принимает запросы, аутентифицирует их (обычно через Kerberos, реже - NTLM) и внутри себя вызывает те же API AD, что и локальные инструменты. То есть ADWS - это обёртка над ntdsapi.dll, которая позволяет работать с AD удалённо через веб.

Какие операции поддерживает ADWS?
  • Поиск объектов (похоже на LDAP-запросы).
  • Чтение атрибутов.
  • Изменение атрибутов.
  • Создание, удаление, перемещение объектов.
  • И, что самое важное - репликационные вызовы, включая GetChanges.
Да, именно: ADWS реализует методы, аналогичные IDL_DRSGetNCChanges. То есть через SOAP-запрос можно сделать DCSync!

Как выглядит SOAP-запрос для GetChanges?

Разбираем спецификацию [MS-AP]. В разделе 3.1.4.2.23 описан метод GetChanges.

Запрос (упрощённо):

XML:
<GetChanges xmlns="http://schemas.microsoft.com/2008/1/ActiveDirectory">
  <getChangesParameters>
    <namingContext>DC=domain,DC=local</namingContext>
    <attributes>
      <string>unicodePwd</string>
      <string>dBCSPwd</string>
      <string>ntPwdHistory</string>
    </attributes>
    <uptodateVector>
      <!-- Здесь идёт закодированный вектор -->
    </uptodateVector>
    <partialAttributeSet>false</partialAttributeSet>
    <pages>
      <page>
        <pageToken>0</pageToken>
        <pageSize>1000</pageSize>
      </page>
    </pages>
  </getChangesParameters>
</GetChanges>

В ответ приходит XML, внутри которого в теге GetChangesResult находится base64-encoded структура, которая является ни чем иным, как результатом вызова IDL_DRSGetNCChanges. То есть ADWS просто берёт ответ от DRSR, кодирует его в base64 и вкладывает в XML. Клиент (мы) должен раскодировать и распарсить эту структуру.

Таким образом, ADWS - это туннель для DRSR поверх HTTP.


1.5. Зачем это атакующему?​

Теперь представь себя на месте атакующего. У тебя есть учётка с правами на репликацию, но EDR пристально следит за RPC-вызовами на 135 порт и за высокими портами. Каждое обращение к эндпоинт-мапперу, каждая RPC-связка - под микроскопом.

Но EDR, как правило, не смотрит глубоко внутрь HTTP-трафика на 9389 порт, потому что это «легитимный» протокол управления AD. Админы через него постоянно работают, PowerShell-скрипты гоняют. Вписать туда ещё один запрос - как иголку в стог сена.

Более того, если включен HTTPS, то трафик шифрован, и EDR вообще видит только установку соединения и сертификаты, а не содержимое.

Мы не просто ломаем систему, мы влезаем в шкуру администратора и используем те же инструменты, которыми он пользуется каждый день. Мы не создаём шум, мы становимся частью фонового гула.


1.6. Практические инструменты для DCSync через ADWS​

Пока что готовых инструментов, которые делают DCSync именно через ADWS, в открытом доступе немного. Но они есть.
  • Impacket - в secretsdump.py есть опция -use-vss (использовать теневые копии) и -just-dc (только DCSync). Но по умолчанию он использует прямые RPC-вызовы. Однако никто не мешает переписать транспорт на SMB или HTTP, если разобраться в коде.
  • PowerShell модуль ActiveDirectory - если у тебя есть права на репликацию, ты можешь использовать команду Get-ADReplicationAttributeMetadata и другие, но они не отдадут хэши напрямую, потому что PowerShell скрывает sensitive атрибуты. Но если написать свой модуль, который через ADWS будет дёргать GetChanges, то можно получить хэши.
  • AD Explorer от Марка Руссиновича - он умеет читать всё, включая хэши, если запущен с правами админа домена, и работает через разные протоколы, но через ADWS? Не уверен. Надо проверять.
  • C# инструменты типа SharpKatz - можно расширить, добавив поддержку ADWS.
В следующей главе мы напишем свой такой инструмент.


1.7. Как Microsoft сама себе создала проблему​

Забавно, что ADWS задумывался как удобный интерфейс для управления. Но безопасность при его проектировании явно была не на первом месте.
  • Во-первых, порт 9389 часто не закрыт на файрволлах, потому что админы думают: «Это же для управления, пусть будет».
  • Во-вторых, аутентификация через Kerberos - это хорошо, но если у атакующего есть билет, то ADWS его пустит.
  • В-третьих, никто не ожидает, что через веб-сервис можно украсть пароли. Поэтому и логов там меньше.
Microsoft, конечно, рекомендует включать Extended Protection for Authentication (EPA) для IIS, чтобы привязать билет к каналу. Но кто это делает? Никто.


1.8. Что дальше?​

Мы разобрались, что DCSync - это не магия, а просто использование механизма репликации AD. Мы узнали, что он может работать не только через RPC, но и через SMB и HTTP (ADWS). Мы поняли, почему это опасно.

Теперь наступает самое интересное: мы напишем код, который эмулирует контроллер домена и выполняет DCSync через ADWS. Мы пройдём через все грабли: аутентификацию Kerberos, построение SOAP-запросов, обработку ответов, парсинг бинарных структур.

Глава 2: Строим свой велосипед. Эмуляция DC для чайников и не только.​

Забудьте про Mimikatz на минуту. Бенджамин Делпи - гений, но мы хотим понять механику. Мы напишем свой инструмент (концепт на Python), который будет эмулировать контроллер домена для выполнения DCSync через нестандартный протокол - MS-AP.

2.1. Теория эмуляции​

Что значит "эмулировать контроллер домена"? Это значит, что мы должны пройти аутентификацию на целевом DC как равный партнер. В мире Windows это означает использование аутентификации Kerberos с билетом, подписанным службой KDC, которая доказывает, что мы - тоже DC.

Для этого нам нужно:
  1. Иметь учетную запись компьютера (или пользователя) с правами на репликацию.
  2. Уметь получать и предъявлять TGT (Ticket Granting Ticket).
  3. Уметь строить AP-REQ (запрос на доступ к службе) для службы DRS (или ADWS).
  4. Правильно упаковать вызов DRSGetNCChanges в SOAP-конверт для MS-AP.
Звучит сложно? Пошли разбираться.

2.2. Инструментарий​

Для нашего эксперимента нам понадобится:
  • Python 3.9+
  • Библиотека impacket. Мы будем использовать её для Kerberos-аутентификации и базовых структур, но напишем свою обертку.
  • requests для работы с HTTP.
  • pyOpenSSL для создания SSL-контекста (если пойдем по HTTPS).
  • Целевой Windows Server 2016+ (так как там ADWS включен по умолчанию).
  • Учетная запись домена с правами Ds-Replication-Get-Changes и Ds-Replication-Get-Changes-All. Обычно это админы домена, но могут быть и делегированные права.

2.3. Копаем спецификацию MS-AP​

Открываем [MS-AP] ( ). Да, читать спецификации Microsoft - это боль. Но это боль благородная.

Нас интересует операция GetChanges. В SOAP-терминах это выглядит как вызов метода GetChanges с кучей вложенных XML-тегов.

Упрощенная структура запроса:

XML:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope ...>
  <soap:Header>
    <wsse:Security>
      <!-- Здесь будет наш Kerberos билет -->
    </wsse:Security>
  </soap:Header>
  <soap:Body>
    <GetChanges xmlns="http://schemas.microsoft.com/2008/1/ActiveDirectory">
      <getChangesParameters>
        <namingContext>DC=domain,DC=local</namingContext>
        <partialAttributeSet>...</partialAttributeSet>
        <uptodateVector>...</uptodateVector>
      </getChangesParameters>
    </GetChanges>
  </soap:Body>
</soap:Envelope>

В ответ придет XML с закодированными в base64 данными репликации, внутри которых лежат наши хэши.

2.4. Пишем код (осторожно, мат и кровь)​

Давайте слепим класс DCSyncOverHTTP. Нам нужно: аутентифицироваться по Kerberos, сформировать SOAP-запрос и распарсить ответ.

Внимание! Код ниже - упрощенная демонстрация концепции. Он не будет работать "из коробки" без танцев с бубном и точной подгонки структур. Но он передает идею.

Python:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
import base64
import struct
import requests
import logging
from impacket.krb5.kerberosv5 import KerberosContext
from impacket.krb5.types import Principal
from impacket.krb5 import constants
from impacket.dcerpc.v5 import transport, nrpc
from impacket.dcerpc.v5.dtypes import NULL
from impacket.dcerpc.v5.rpcrt import DCERPCException
from requests.auth import HTTPBasicAuth
from requests_kerberos import HTTPKerberosAuth, OPTIONAL
import xml.etree.ElementTree as ET

# Настраиваем логи, чтобы видеть, что происходит под капотом
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)

class DCSyncViaADWS:
    """
    Эмулятор DC для синхронизации через ADWS (MS-AP).
    Чувствуешь себя капитаном, который притворяется своим на вражеском корабле.
    """
    def __init__(self, domain, dc_host, username, password, target_user=None, use_https=True):
        self.domain = domain.upper()
        self.dc_host = dc_host
        self.username = username
        self.password = password
        self.target_user = target_user  # Если None - пытаемся слить всю базу
        self.use_https = use_https
        self.base_url = f"http{'s' if use_https else ''}://{dc_host}:9389/ActiveDirectoryWebServices/ActiveDirectory.asmx"
        self.session = requests.Session()
        self.kerberos_auth = None
        self.krb_context = None

    def authenticate_kerberos(self):
        """
        Получаем TGT и настраиваем аутентификацию.
        Это самый геморройный момент.
        Мы должны предъявить сервисный билет для SPN 'HTTP/dc.domain.local'.
        """
        log.info("Инициализация Kerberos аутентификации для SPN: HTTP/%s" % self.dc_host)
        try:
            # Используем requests-kerberos для простоты, но под капотом он сделает всю грязную работу
            self.kerberos_auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL, force_preemptive=True)
            log.info("Kerberos аутентификация настроена. Билет будет запрошен при первом запросе.")
        except Exception as e:
            log.error("Ошибка настройки Kerberos: %s" % e)
            log.error("Проверьте, что у вас есть TGT (kinit) или что хост доступен.")
            raise

    def build_soap_envelope(self, nc_context):
        """
        Строим SOAP-запрос для GetChanges.
        Здесь начинается настоящая магия и боль от спецификаций.
        """
        # Это заглушка. Реальный запрос должен содержать корректный UpdateVector и прочее.
        # Для простоты мы просто возьмем контекст из первого ответа AD.
        # В реальном скрипте нужно сначала получить этот nc_context через другой вызов.
        envelope = f"""<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:act="http://schemas.microsoft.com/2008/1/ActiveDirectory">
    <soap:Header>
        <act:requestHeader>
            <act:context>{nc_context}</act:context>
        </act:requestHeader>
    </soap:Header>
    <soap:Body>
        <act:GetChanges>
            <act:getChangesParameters>
                <act:namingContext>DC={self.domain.replace('.', ',DC=').split(',',1)[1]}</act:namingContext>
                <!-- Мы просим все атрибуты, включая секретные. Это типа unicodePwd и прочее -->
                <act:attributes>
                    <string>unicodePwd</string>
                    <string>dBCSPwd</string>
                    <string>ntPwdHistory</string>
                    <string>lmPwdHistory</string>
                    <string>supplementalCredentials</string>
                </act:attributes>
                <act:uptodateVector></act:uptodateVector>
            </act:getChangesParameters>
        </act:GetChanges>
    </soap:Body>
</soap:Envelope>"""
        return envelope

    def execute(self):
        """
        Основной цикл атаки.
        """
        log.info("="*60)
        log.info("Начинаем DCSync через ADWS. Цель: %s" % self.dc_host)
        log.info("Домен: %s, Пользователь: %s" % (self.domain, self.username))
        log.info("="*60)

        # 1. Аутентификация
        self.authenticate_kerberos()

        # 2. Для работы с ADWS нам нужно сначала получить контекст.
        # Обычно это делается через запрос GetContext или первый пустой GetChanges.
        # Пропустим эту боль. Предположим, мы его как-то получили.
        # В реальном коде тут был бы цикл перебора контекстов и UtoD векторов.
        fake_context = "0"*32  # Это не сработает, нужно реальное значение!

        log.info("Формируем SOAP-запрос...")
        soap_request = self.build_soap_envelope(fake_context)

        headers = {
            'Content-Type': 'text/xml; charset=utf-8',
            'SOAPAction': 'http://schemas.microsoft.com/2008/1/ActiveDirectory/GetChanges'
        }

        log.info("Отправляем запрос на %s" % self.base_url)
        try:
            response = self.session.post(self.base_url, data=soap_request, headers=headers, auth=self.kerberos_auth, verify=False)
            log.info("HTTP статус: %d" % response.status_code)

            if response.status_code == 200:
                log.info("Ответ получен. Парсим XML...")
                # Здесь начинается ад парсинга ответа. В ответе будет base64-encoded данные.
                # Нужно распарсить, вытащить base64, раскодировать, распарсить уже структуры DRS.
                # А внутри этих структур - байты с хэшами.
                # Это уровень сложности "извращение".
                log.info("Ответ содержит %d байт. Внутри есть хэши, но чтобы их достать, надо писать еще столько же кода." % len(response.text))
                # Пример: ищем тег GetChangesResult
                root = ET.fromstring(response.text)
                # Тут должен быть разбор пространств имен и поиск base64 данных.
                # В реальном коде это делается через сложный XPath.
                # Но для концепта мы просто покажем, что ответ есть.
                log.info("DCSync через ADWS завершен (концептуально). Смотри ответ в логах.")
                #log.debug(response.text) # Можно раскомментировать, чтобы увидеть XML
            else:
                log.error("Ошибка: %s" % response.text)
        except Exception as e:
            log.error("Ошибка выполнения запроса: %s" % e)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='DCSync over ADWS (MS-AP) - Proof of Concept')
    parser.add_argument('-d', '--domain', required=True, help='Domain name (FQDN)')
    parser.add_argument('-dc', '--dc-host', required=True, help='Domain Controller hostname or IP')
    parser.add_argument('-u', '--username', required=True, help='Username with replication rights')
    parser.add_argument('-p', '--password', required=True, help='Password')
    parser.add_argument('--use-https', action='store_true', help='Use HTTPS instead of HTTP')
    args = parser.parse_args()

    dcsync = DCSyncViaADWS(args.domain, args.dc_host, args.username, args.password, use_https=args.use_https)
    dcsync.execute()

К слову:
Этот код не запустится. Я мог бы накатать красивый сниппет, который якобы всё сливает, но это было бы враньё. DCSync - это не просто HTTP POST. Это танец с бубном из:
  1. Получения контекста репликации.
  2. Работы с векторами обновлений (UptodateVector).
  3. Правильной разборки ответов DRS (которые передаются в бинарном виде, упакованные в base64 внутри XML).
  4. Преодоления ошибок аутентификации.
Но этот код показывает путь. Он показывает, что атака возможна, и что протокол MS-AP - это легитимный вектор.

1771617858946.webp


Глава 3: Нестандартные протоколы. Где ещё искать?​

Ты, наверное, уже понял, что классический DCSync через RPC по TCP (ncacn_ip_tcp) - это как зайти в банк через главный вход с автоматом Калашникова. Тебя заметят сразу. EDR, SIEM, скучные админы с кофе - все поднимут тревогу.

Но у банка есть чёрный ход, окно на первом этаже и даже вентиляционная шахта. В мире Active Directory эти «шахты» называются альтернативными транспортами для протокола DRSR. Спецификация MS-DRSR разрешает передавать репликационные вызовы не только через TCP, но и через SMB (именованные каналы), и даже через HTTP (о чём мы уже говорили в контексте MS-AP).

В этой главе мы полезем в эти вентиляционные шахты. Разберём, как заставить DC отдать хэши через SMB, как обойти эндпоинт-маппер и стучаться прямо на динамический порт, и почему это может быть тише, чем мышь под веником.

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


3.1. MS-DRSR поверх SMB (ncacn_np) - «чёрный вход через файловую шару»​

3.1.1. Как это работает​

SMB (Server Message Block) - протокол для файлового доступа, печати и межпроцессного взаимодействия. В Windows он используется для огромного количества легитимных операций: групповые политики, вход в систему, доступ к общим папкам. Именно поэтому трафик на порт 445 (SMB) редко вызывает подозрения.

Но SMB умеет не только таскать файлы. Он может выступать транспортом для RPC. Это называется ncacn_np (Network Computing Architecture connection over named pipes). Суть: клиент открывает SMB-соединение с сервером, создаёт или подключается к именованному каналу (named pipe) и через этот канал шлёт RPC-пакеты. Для приложений на верхнем уровне это выглядит как обычный RPC, просто транспорт другой.

Для DRSR нужен определённый именованный канал. Где искать? В спецификации [MS-DRSR] сказано, что сервер DRSUAPI регистрирует свои эндпоинты в эндпоинт-маппере. Но если мы хотим обратиться напрямую, минуя эндпоинт-маппер, мы должны знать имя канала. На практике DRSR обычно доступен через следующие каналы:

  • \pipe\lsass - основной канал для взаимодействия с Local Security Authority Subsystem Service. Часто используется для разных целей, включая репликацию.
  • \pipe\protected_storage - для защищённого хранения.
  • \pipe\ntsvcs - для различных служб.
  • Специфичные для DRSUAPI: иногда можно найти канал с GUID интерфейса, но это реже.
Как узнать точное имя канала? Можно сделать запрос к эндпоинт-мапперу через RPC (порт 135) и посмотреть, какой эндпоинт зарегистрирован для UUID e3514235-4b06-11d1-ab04-00c04fc2dcd2 с протоколом ncacn_np. Для этого есть утилиты, например, rpcdump.py из Impacket.

3.1.2. Пример кода: DCSync через SMB на Python (Impacket)​

В Impacket уже есть поддержка транспорта ncacn_np. Вот как можно выполнить DCSync, изменив транспорт (упрощённо):

Python:
from impacket.dcerpc.v5 import transport, drsuapi
from impacket.dcerpc.v5.dtypes import NULL

# Строка привязки для именованного канала
string_binding = r"ncacn_np:192.168.1.10[\pipe\lsass]"
rpctransport = transport.DCERPCTransportFactory(string_binding)
rpctransport.set_credentials('username', 'password', 'domain')
rpctransport.connect()

# Привязка к интерфейсу DRSUAPI
dce = rpctransport.DCERPC_class(rpctransport)
dce.bind(drsuapi.MSRPC_UUID_DRSUAPI)

# Теперь можно вызывать методы, например, DrsBind, DsGetNCChanges
# (тут нужна полная реализация, как в secretsdump.py)

Конечно, это только начало. Полноценный DCSync требует обмена несколькими вызовами: DrsBind, затем DrsGetNCChanges с правильными структурами. Но сам факт, что мы можем переключиться на SMB, открывает возможности.

3.1.3. Плюсы и минусы для атакующего​

Плюсы:
  • Порт 445 почти всегда открыт в корпоративных сетях (иначе AD сломается).
  • SMB-трафик - привычный шум, его реже анализируют глубоко.
  • Можно маскироваться под легитимные операции (например, копирование файлов).
Минусы:
  • SMB не такой уж «невидимый»: современные NDR системы анализируют SMB на предмет подозрительных RPC-команд.
  • Именованные каналы можно мониторить через Event Log (5140, 5142) и Sysmon (17, 18). Если вдруг кто-то из неожиданного места (не DC) подключается к \pipe\lsass, это может вызвать подозрения.
  • Скорость: SMB добавляет небольшую задержку, но для DCSync это не критично.

3.1.4. Обнаружение (глазами защитника)​

Если ты защитник, вот что можно настроить:
  • Event ID 5140 - доступ к сетевой папке. Будет генерироваться при подключении к именованному каналу. Ищи подключения к каналам, связанным с LSASS (\pipe\lsass, \pipe\protected_storage) с необычных хостов.
  • Sysmon Event ID 17 (Pipe Created) и 18 (Pipe Connected). Если правило настроено на имя канала, ты увидишь каждый коннект.
  • Анализ SMB-трафика - можно искать команды SMB, связанные с транзакциями (SMB_COM_TRANSACTION), которые используются для RPC. Suricata/YARA правила могут сигнализировать о характерных паттернах.
SMB задумывался для удобства, а стал любимым способом хакеров. Каждый раз, когда ты открываешь файловую шару, помни: через неё могут утекать пароли.


3.2. Чистый TCP (ncacn_ip_tcp) и игры с эндпоинт-маппером​

3.2.1. Как работает классический RPC через TCP​

При использовании ncacn_ip_tcp клиент сначала подключается к эндпоинт-мапперу на порт 135, запрашивает, на каком порту слушает нужный интерфейс, получает ответ (например, порт 49675), затем разрывает соединение и подключается уже к этому порту напрямую.

Именно запрос к 135 порту часто триггерит детекты. EDR видят: процесс обращается к эндпоинт-мапперу, а через секунду - к высокому порту. Сигнатура: UUID == e351... - это DCSync.

3.2.2. Обход через прямой доступ к порту​

Если каким-то образом узнать заранее, на каком порту висит DRSUAPI на целевом DC, можно сразу идти на этот порт, минуя 135. Это снижает количество подозрительных соединений.

Как узнать порт заранее?
  • Сканирование портов в диапазоне 49152–65535. Можно найти открытый порт, который отвечает на RPC-запросы. Но это шумно и долго.
  • Анализ конфигурации - если ты уже имеешь доступ к реестру DC (например, через другую учётку), можно посмотреть в HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters параметр TCP/IP Port. Но это не всегда помогает, так как порт может быть динамическим.
  • Использование других протоколов для разведки - например, через LDAP можно получить информацию о доступных сервисах.
  • Предсказуемость - в некоторых средах администраторы закрепляют порты за DC. Если ты знаешь политику, можно угадать.
Пример кода: прямой вызов на конкретный порт

Python:
from impacket.dcerpc.v5 import transport

# Указываем порт, если знаем его (например, 49675)
string_binding = r"ncacn_ip_tcp:192.168.1.10[49675]"
rpctransport = transport.DCERPCTransportFactory(string_binding)
rpctransport.set_credentials('user', 'pass', 'domain')
rpctransport.connect()
dce = rpctransport.DCERPC_class(rpctransport)
dce.bind(drsuapi.MSRPC_UUID_DRSUAPI)
# Далее как обычно

3.2.3. Риски и сложности​

  • Порт может измениться при перезагрузке DC или перезапуске службы.
  • В кластерных средах порты могут балансироваться.
  • Если ошибиться с портом, получишь отказ в соединении, что может вызвать подозрения у систем мониторинга (много неудачных подключений).
Этот метод - лотерея. Если ты не уверен, что порт стабилен, лучше не рисковать.


3.3. Другие транспорты: ncacn_http и ncalrpc​

3.3.1. RPC через HTTP (ncacn_http)​

Этот транспорт позволяет туннелировать RPC через HTTP-запросы. Используется редко, в основном для сценариев, где нужно пройти через веб-прокси.

В контексте DCSync это экзотика, но знать стоит. Работает так: клиент отправляет HTTP-запросы на сервер, который их расшифровывает и передаёт в RPC. Для DC нужно, чтобы была включена служба RPC over HTTP, что в стандартных установках обычно не настроено.

Если ты столкнулся с такой конфигурацией - возможно, это твой шанс. Но готовься к боли с настройкой заголовков и аутентификацией.

3.3.2. Локальные вызовы (ncalrpc)​

Этот транспорт работает только локально, через механизм ALPC (Advanced Local Procedure Call). Для удалённой атаки бесполезен, но если ты уже на DC, можешь использовать его для выполнения операций от имени системы, не создавая сетевых соединений. Например, некоторые инструменты локально дёргают DRSR через ncalrpc, чтобы оставаться незамеченными для сетевых детектов.


3.4. Практические инструменты для работы с DRSR через разные протоколы​

3.4.1. Impacket​

В Impacket уже реализована поддержка всех основных транспортов. Чтобы использовать SMB, нужно в secretsdump.py или своих скриптах изменить способ создания транспорта. В исходном коде secretsdump.py есть функция connectDRSUAPI, которая по умолчанию использует TCP. Можно её модифицировать, чтобы принимать параметр транспорта.

Пример модификации:

Python:
def connectDRSUAPI(dst, username, password, domain, transport='ncacn_ip_tcp'):
    if transport == 'ncacn_np':
        string_binding = r'ncacn_np:%s[\pipe\lsass]' % dst
    else:
        string_binding = r'ncacn_ip_tcp:%s' % dst
    rpctransport = transport.DCERPCTransportFactory(string_binding)
    rpctransport.set_credentials(username, password, domain)
    rpctransport.connect()
    dce = rpctransport.DCERPC_class(rpctransport)
    dce.bind(drsuapi.MSRPC_UUID_DRSUAPI)
    return dce

3.4.2. rpcdump.py​

Утилита из Impacket для энумерации RPC-эндпоинтов. Можно использовать для разведки:

Bash:
rpcdump.py -target-ip 192.168.1.10 | grep -i e351
Она покажет все зарегистрированные интерфейсы и их протоколы. Если видишь ncacn_np, то узнаешь имя канала. Если ncacn_ip_tcp, то порт.

3.4.3. pywinrm (для HTTP)​

Если вдруг нужно через HTTP, можно использовать pywinrm, который поддерживает WS-Management. Но это скорее для управления, чем для DCSync.

3.4.4. Собственные скрипты на Python с библиотеками impacket.dcerpc.v5​

Ты уже видел примеры. Главное - правильно выбрать строку привязки.

3.5. Как выбирать протокол в зависимости от окружения​

Ты заходишь в сеть заказчика (с разрешением, конечно). У тебя есть учётка с правами на репликацию, но ты не знаешь, что включено.
  • Сценарий А: сеть гудит SMB-трафиком, куча файловых серверов, админы ленятся. Выбирай ncacn_np. Смешаешься с общим шумом.
  • Сценарий Б: админы продвинутые, поставили NDR, который анализирует SMB. Тогда пробуй MS-AP через HTTPS, если порт 9389 открыт.
  • Сценарий В: нужно быстро и надёжно, и плевать на шум. Бери классический RPC через TCP - Mimikatz в зубы и вперёд.
  • Сценарий Г: есть данные, что на DC настроен статический порт для DRSUAPI. Тогда можно сразу лупить на него.
Ни один метод не даёт 100% гарантии необнаружения. Всегда есть шанс, что где-то включён мониторинг, о котором ты не знаешь. Поэтому разведка - наше всё. Пощупай сеть, посмотри, какие порты открыты, какие логи генерируются (если есть доступ к SIEM через подставную учётку).


3.6. О сложностях и подводных камнях​

  • Аутентификация: для всех протоколов требуется либо NTLM, либо Kerberos. Если у тебя только NTLM-хэш (overpass-the-hash), ты сможешь пройти NTLM-аутентификацию для SMB и RPC, но для Kerberos нужен TGT. Учитывай это.
  • Права: даже если протокол выбран верно, без прав DS-Replication-Get-Changes ничего не выйдет. BloodHound в помощь.
  • Версии ОС: ADWS (MS-AP) работает только на Server 2008 R2 и выше. На старых DC его нет.
  • Фаерволы: даже если порт 445 открыт, могут быть правила, блокирующие доступ с не-DC машин.
  • IPv6: не забывай, что AD может использовать IPv6, и там тоже есть свои порты.

3.7. Заключение главы: что мы вынесли​

Мы рассмотрели альтернативные пути вызова DRSR: через SMB, прямой TCP, HTTP и даже локальные вызовы. Теперь у тебя есть выбор: идти тихо, но сложно, или быстро, но шумно. Выбор зависит от конкретной ситуации.

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

Microsoft создала так много протоколов для AD, что мы теперь можем выбирать, как именно украсть пароли. Спасибо, Microsoft, за diversity!

Глава 4: Защита от этих "чудес"​

Теперь поставим себя на место защитника. Что можно сделать, чтобы наш эмулятор DC не прошел?

4.1. Мониторинг - это всё​

Microsoft продает нам "безопасность по умолчанию", но чтобы поймать хакера, надо ставить сторонние софтины или писать свои правила.

Что мониторить:
  1. Event ID 4662 (DS Access). Это святое. Любая операция с правами на репликацию должна генерировать это событие. Но! Генерирует ли его ADWS-доступ? Тут надо проверять. Возможно, да, но с другим типом доступа.
  2. Event ID 5136 (Directory Service Changes). Если кто-то меняет объекты. Но при DCSync изменений нет, только чтение.
  3. Сетевой трафик. Аномалии: если ваш DC вдруг начал слать SOAP-запросы самому себе или получать SOAP-запросы от рабочей станции отдела кадров - это повод насторожиться.
  4. Логи IIS (если включен). ADWS хостится в IIS. Там будут логи с User Agent и конечными точками. Если вы видите POST-запросы к ActiveDirectory.asmx с необычного хоста - копайте.

4.2. Extended Protection for Authentication (EPA)​

Для ADWS (MS-AP) нужно включать Extended Protection. Это механизм, который привязывает аутентификацию к каналу (TLS). Он должен предотвращать атаки с перехватом билетов. Включается в настройках IIS для сайта ADWS.

На практике EPA часто ломает легитимные сценарии, поэтому его редко включают. И это плохо.

4.3. Ограничение прав на репликацию​

Не давайте права на репликацию всем подряд. Это база. Проверьте, у кого есть эти права (Powershell):

Код:
Get-ADObject -SearchBase "CN=Configuration,DC=domain,DC=local" -Filter {ObjectClass -eq "user"} -Properties * | Where-Object {$_.'msDS-ReplicationAttributeMetaData' -ne $null}
(Шутка, так просто не найдешь. Надо копать ACL.)
Реально надо смотреть делегирование. Права Replicating Directory Changes и Replicating Directory Changes All должны быть только у контроллеров домена и доверенных администраторов.

4.4. Делегирование и учетные записи компьютеров​

Наш эмулятор использует учетку пользователя. А что, если завести отдельную учетку компьютера (с суффиксом $), которая имеет права на репликацию? Это выглядит легитимнее? Да. И такие учетки тоже надо мониторить.

Глава 5: Заключение.​

Мы прошли с тобой путь от поверхностного понимания DCSync как «кнопки в Mimikatz» до глубокого погружения в протоколы MS-AP и MS-DRSR. Мы разобрали, как работает репликация в Active Directory, почему хэши паролей - это просто ещё одни атрибуты, и как можно дёргать эти атрибуты не только через RPC, но и через SMB, и через SOAP-запросы на порт 9389.

Но зачем нам всё это? Чтобы просто потешить своё хакерское эго? Нет. Чтобы понять одну простую вещь: безопасность AD - это не про установку заплаток и запуск антивируса. Это про понимание того, как система работает на уровне протоколов. Потому что, пока ты не поймёшь, как работает механизм, ты никогда не сможешь его ни защитить, ни обойти по-настоящему.


5.1. Сравнительный анализ протоколов для DCSync: RPC, SMB, HTTP/ADWS​

Давай положим на стол три основных способа вызвать IDL_DRSGetNCChanges и посмотрим, чем они отличаются с точки зрения атакующего и защитника.

5.1.1. Классический RPC (ncacn_ip_tcp)​

Как работает:
  1. Клиент (мы) подключается к эндпоинт-мапперу на порт 135.
  2. Запрашивает идентификатор интерфейса DRSUAPI (UUID = e3514235-4b06-11d1-ab04-00c04fc2dcd2).
  3. Получает динамический порт (обычно в диапазоне 49152–65535).
  4. Подключается к этому порту и вызывает методы DRSUAPI.
Плюсы для атакующего:
  • Самый изученный и документированный метод.
  • Есть куча готовых инструментов (Mimikatz, impacket и т.д.).
  • Работает на любых версиях Windows.
Минусы для атакующего:
  • Максимальная обнаруживаемость. Современные EDR/AV прекрасно знают этот UUID. Любой вызов к e351... с не-DC машины - это практически 100% сигнал тревоги.
  • Сетевой трафик легко идентифицировать: обращение к 135 порту, затем к высокому порту с характерным RPC-трафиком.
  • Event ID 4662 (доступ к объекту AD) генерируется, если включён аудит. Правда, его ещё надо настроить.
Что видит защитник:
  • В логах сети: соединения с 135 портом и последующие соединения с динамическими портами.
  • В Event Log: 4662 с GUID интерфейса DRSUAPI и типом доступа «Control Access».
  • В логах EDR: подозрительный процесс (например, cmd.exe или powershell.exe), выполняющий RPC-вызовы к LSASS или напрямую к DRSUAPI.
Если ты используешь RPC для DCSync в 2026 году, ты либо на очень плохо защищённом объекте, либо ты просто не хочешь жить долго. Это самый шумный вектор.

5.1.2. SMB (ncacn_np) через именованные каналы​

Как работает:
  1. Клиент устанавливает SMB-соединение с целевым DC (порт 445).
  2. Открывает именованный канал (например, \pipe\lsass или специальный канал для DRSUAPI).
  3. Поверх SMB работает RPC (протокол SMB, несущий RPC-пакеты).
  4. Вызовы DRSUAPI идут через этот канал.
Плюсы для атакующего:
  • Порт 445 почти всегда открыт (нужен для файлового обмена, групповых политик и т.д.).
  • Меньше подозрений: SMB-трафик - это фоновый шум в любой корпоративной сети.
  • Обходит некоторые детекты, которые смотрят только на 135 порт.
Минусы для атакующего:
  • SMB-трафик тоже мониторится, особенно аномалии (например, соединения с DC от не-DC машин с высоким объёмом данных).
  • Именованные каналы можно отслеживать через Event ID 5140 (сетевой доступ к объекту файловой системы) и 5142 (создание именованного канала).
  • Некоторые EDR анализируют SMB-пакеты на предмет RPC-вызовов.
Что видит защитник:
  • В логах сети: много SMB-трафика между не-DC хостом и DC.
  • Event ID 5140: доступ к \pipe\* (если настроен аудит).
  • Sysmon Event ID 17 (создание именованного канала) и 18 (подключение к именованному каналу). Если имя канала нестандартное (не lsass, не netlogon, а что-то типа protected_storage или drsuapi), это повод насторожиться.
SMB - это как чёрный вход. Вроде и не парадный, но и не совсем служебный. Если охрана смотрит только на главные двери, ты пройдёшь. Но если у них камеры везде - увидят.

5.1.3. HTTP/ADWS (MS-AP) через порт 9389​

Как работает:
  1. Клиент (мы) устанавливает TCP-соединение с DC на порт 9389 (HTTP) или 9389 с SSL (HTTPS).
  2. Отправляет SOAP-запрос с аутентификацией (Kerberos).
  3. В теле SOAP - base64-кодированный вызов DRSR.
  4. Получает ответ, парсит XML, извлекает base64, декодирует, парсит бинарные структуры DRSR.
Плюсы для атакующего:
  • Минимальная обнаруживаемость. Порт 9389 часто не мониторится вообще. Админы знают, что это ADWS, но считают его «безопасным».
  • Трафик может быть зашифрован (HTTPS), тогда EDR видит только факт соединения, но не содержимое.
  • Можно смешаться с легитимным трафиком PowerShell-модуля ActiveDirectory.
  • Обходит детекты, ориентированные на RPC.
Минусы для атакующего:
  • Сложность реализации: нужно возиться с Kerberos, SOAP, XML, base64, бинарными структурами.
  • Некоторые EDR умеют расшифровывать HTTPS, если у них есть сертификат MITM.
  • Event ID 4662 всё равно может сработать, потому что внутри ADWS вызывает те же API, что и RPC.
Что видит защитник:
  • В логах IIS (если включены) - записи о POST-запросах к ActiveDirectory.asmx. Если они идут от необычного источника (например, с рабочей станции пользователя) - повод задуматься.
  • Event ID 4662 с теми же GUID, но с пометкой, что доступ получен через процесс Microsoft.ActiveDirectory.WebServices.exe (это процесс ADWS на DC, а не процесс клиента). Но это сложнее отследить.
  • Сетевые логи: соединения с портом 9389 от не-DC машин.
Microsoft создала удобный веб-интерфейс для AD, и теперь любой хакер может сказать: «Спасибо, Microsoft, за такой удобный API». Безопасность через неудобство не работает, господа.


5.2. Практические рекомендации по защите (от которых админы обычно отмахиваются, пока их не взломают)​

Итак, что же делать, чтобы наш эмулятор DC не прошёл? Собрал здесь самые работающие методы, без маркетинговой чуши.

5.2.1. Включи аудит и мониторинг событий 4662​

Это база. Настрой групповая политика для включения аудита доступа к AD:

Код:
Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Advanced Audit Policy Configuration -> DS Access -> Audit Directory Service Access
Включи для Success и Failure. Затем настрой SACL на домене (или на всех важных объектах), чтобы логировать обращения с правами на репликацию.

Важно: тестируй в пилотном режиме, чтобы не захлебнуться в логах.

5.2.2. Ограничь права на репликацию​

Проверь, у кого есть права на репликацию. Для этого можно использовать PowerShell:

Код:
Get-ADObject -SearchBase "CN=Configuration,DC=domain,DC=local" -Filter {ObjectClass -eq "user"} -Properties nTSecurityDescriptor | ForEach-Object {
    $_.nTSecurityDescriptor.Access | Where-Object {
        $_.ObjectType -eq "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" -or
        $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
    } | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType
}

Удали эти права у всех, кроме:

  • Контроллеров домена.
  • Доверенных администраторов домена.
  • Специальных сервисов, которым это реально нужно (и то - лучше создать отдельную группу и мониторить её).

5.2.3. Изолируй ADWS (порт 9389)​

Если ADWS не нужен для управления (а в эпоху PowerShell Remoting он часто не нужен), отключи его полностью. Или ограничь доступ к нему по IP-адресам с помощью Windows Firewall.

Как отключить:

Код:
Get-Service -Name ADWS | Stop-Service
Set-Service -Name ADWS -StartupType Disabled

Но учти: это может сломать удалённое администрирование через PowerShell модуль ActiveDirectory.

5.2.4. Включи Extended Protection for Authentication (EPA) для ADWS​

Это настраивается в IIS на DC. Открой IIS Manager, найди сайт ActiveDirectoryWebServices, зайди в Authentication, выбери Windows Authentication, нажми Advanced Settings и включи Extended Protection со значением Required.

Это привяжет Kerberos-билет к конкретному каналу (TLS), и украденный билет нельзя будет использовать с другого IP.

EPA может вызвать проблемы с некоторыми клиентами (старые версии PowerShell). Но в современном мире должно работать.

5.2.5. Мониторь процессы, которые обращаются к AD API​

На каждом DC можно включить аудит процессов, которые загружают ntdsapi.dll или обращаются к LSASS. Это даст тебе понимание, кто именно (какой процесс) выполняет репликационные вызовы.

5.2.6. Используй решения класса PAM (Privileged Access Management)​

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


5.3. Инструментарий для тестирования (не только названия, но и как использовать)​

Если ты пентестер или защитник, тебе нужно уметь проверять защищённость своих доменов. Вот набор инструментов, которые стоит иметь в арсенале.

5.3.1. Impacket (secretsdump.py)​

Самый популярный инструмент. Используй с осторожностью, потому что он по умолчанию использует RPC.

Пример:

Bash:
secretsdump.py domain/user:password@dc.domain.local -just-dc
Как заставить его работать через SMB? В impacket можно указать транспорт:

Python:
from impacket.dcerpc.v5 import transport
string_binding = r"ncacn_np:dc.domain.local[\pipe\protected_storage]"
rpctransport = transport.DCERPCTransportFactory(string_binding)
# дальше привязка к DRSUAPI

Но это требует доработки кода.

5.3.2. Mimikatz​

Классика: lsadump::dcsync /domain:domain.local /user:krbtgt

Работает только через RPC.

5.3.3. SharpKatz / SafetyKatz​

C# версии, которые могут быть загружены в память через Cobalt Strike и т.д. Тоже RPC.

5.3.4. PowerShell с кастомным модулем​

Ты можешь написать свой модуль, который использует ADWS. Пример концепта (не рабочий, но идея):

Код:
$uri = "http://dc.domain.local:9389/ActiveDirectoryWebServices/ActiveDirectory.asmx"
$soap = @"
<?xml...>
<GetChanges>...</GetChanges>
"@
$headers = @{
    "Content-Type" = "text/xml; charset=utf-8"
    "SOAPAction" = "http://schemas.microsoft.com/2008/1/ActiveDirectory/GetChanges"
}
$response = Invoke-WebRequest -Uri $uri -Method Post -Body $soap -Headers $headers -UseDefaultCredentials
# Далее парсим XML и base64

Этот скрипт будет использовать текущие учетные данные пользователя. Если у пользователя есть права на репликацию - ты получишь хэши.

5.3.5. Python + requests + impacket​

Мы уже начали писать такой скрипт в главе 2. Его можно довести до ума, добавив:
  • Получение вектора обновлений через первый вызов.
  • Цикл для постраничного получения.
  • Парсинг ответов DRSR.
Это работа на несколько вечеров, но результат того стоит.

5.3.6. BloodHound​

Для разведки: BloodHound покажет, у кого есть права на репликацию. Используй коллекторы SharpHound, они собирают данные через LDAP, но могут показать и эти разрешения.


5.4. Напутствие и призыв к действию​

Мы проделали огромный путь. Мы поняли, что DCSync - это не просто атака, а целый класс техник, использующих легитимные протоколы AD. Мы увидели, что можно обходить стандартные детекты, используя нестандартные транспорты. И мы поняли, что защита от этого - сложная, но выполнимая задача.

Ни один из методов защиты не даст 100% гарантии. Если злоумышленник достаточно упорен и квалифицирован, он найдёт способ. Но твоя задача как защитника - сделать так, чтобы это было максимально дорого, долго и шумно. Чтобы он предпочёл пойти в другую сеть.

Мы все на одной стороне. Мы все хотим, чтобы системы были безопасными, но при этом оставались управляемыми. Не будь тем админом, который отключает всё подряд и делает работу невозможной. Будь тем, кто понимает риски и находит баланс.
 
Мы в соцсетях:

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