Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Сегодня расскажу про внутренний пентест, в ходе которого мы без учетной записи добрались до администратора домена.
В этом проекте использовались много разнообразных техник: от декомпиляции приложения и расшифровки извлеченных учетных данных, до повышения привилегий через базу данных на сервере и сбора информации от имени учетной записи компьютера. Под катом подробно разобрано, как они сложились в успешный вектор атаки.
На этот раз мы исследовали большую промышленную компанию. Как и в любом внутреннем пентесте мы выступали с позиции злоумышленника, который уже подключился к корпоративной сети, но не имеет никаких доступов и привилегий. Обычная цель таких проверок — обнаружить недостатки и уязвимости в сети заказчика и, в идеале, получить привилегии доменного администратора. По сути, это означает захватить полный контроль над инфраструктурой организации.
Мы уже работали с этим заказчиком примерно год назад. В результате, руководство службы безопасности начало крупную реструктуризацию и модернизацию ИБ и вернулось к нам со словами: «У нас все безопасно. Вы ничего не сделаете, просто потеряете напрасно время. Но помогать не будем. Делайте что хотите, но даже самую простую учетную запись вам не дадим».
Глава СБ даже хотел поспорить на несколько ящиков пива для своей команды, что мы не найдем ничего серьезного. Такая уверенность подогревала профессиональный интерес. Заинтригованные, мы выехали в офис заказчика.
Начало обследования
Приехали на объект втроем, заняли свободные LAN-розетки и стали изучать сеть при помощи Nmap. Слона проще есть по частям, так что мы поделили сферы интереса: один пентестер сосредоточился на всем, что связано с Active Directory, я изучал внутренний веб, третий работал со своим скоупом. Справедливости ради, отмечу, что сотрудники заказчика все же дали диапазон адресов, в рамках которых мы и работали. И все равно пришлось просканировать и изучить больше тысячи хостов. Это была действительно большая компания.
Прошло несколько дней методичной, скрупулезной работы, прежде чем наше внимание привлек веб-ресурс и размещенное на нем .NET приложение. Похоже, что им пользовались уже довольно давно, но мы не видели приложение в прошлом году. Скорее всего до начала реконструкции этот хост располагался за NAT, а теперь оказался на виду.
Декомпилируй это
Само приложение предназначалось для доступа к базе данных, некому каталогу запасных частей.
Работает оно так: после нажатия кнопки «Start» в веб-интерфейсе, исполняемые файлы загружаются во временную директорию на компьютере пользователя и запускаются оттуда. Затем появляется форма авторизации, куда нужно ввести логин и пароль, затем происходит подключение к базе данных MS SQL, размещенной на хосте. Логика подсказывает, что программа должна где-то брать параметры для подключения к базе. Значит надо покопаться под капотом.
Я обнаружил, что имя и адрес базы данных, логин для подключения к ней указаны в конфигурационном файле start.exe.config, который скачивается вместе с приложением. Там же есть и пароль, но он хранится в зашифрованном виде.
Вообще в подобных проектах не часто приходится что-то декомпилировать, но это dotNET. Он восстанавливается в исходный код практически в первозданном виде. Поэтому я решил посмотреть, как реализовано шифрование. Закинул приложение в ILSpy и стал искать ключевые слова: decrypt, encrypt. В результате в одной из .dll библиотек нашлась функция DecryptConnectionString, которая содержала ключ шифрования и алгоритм расшифровки.
Функция, содержащая алгоритм дешифрования пароля
Оставалось только вынести фрагмент кода text to Decrypt в отдельный скрипт, подать на вход зашифрованный пароль из файла конфигурации и прогнать эту функцию автономно.
Исследование базы данных
Так мы получили расшифрованный пароль, но он давал доступ лишь к базе данных, а не к домену или компьютеру. Подключились к ней при помощи DBeaver. Эта утилита включает в себя редактор запросов, при помощи которого можно посмотреть в контексте какой учетной записи ты работаешь. Для этого можно использовать, например, такую команду:
USE <database>
SELECT * FROM fn_my_permissions(NULL, 'DATABASE');
Выяснилось, что скомпрометированная учетная запись обладает административными правами sysadmin в пределах MS SQL.
Затем мы использовали другую команду:
sp_configure 'show advanced options', '1'
RECONFIGURE
#This enables xp_cmdshell
sp_configure 'xp_cmdshell', '1'
RECONFIGURE
Включили оболочку xp_cmdshell, позволяющую исполнять команды операционной системы, на которой крутится система управления базой данных. В данном случае — Windows Server 2016.
Команда Whoami Priv подсказала, что мы имеем дело с MSSQL Server Express. Так как база данных работает в контексте служебной учетной записи с SQLexpress, ей необходима привилегия имперсонализации.
SeImpersonatePrivilege позволяет выполнять команды в контексте любой учетной записи, в том числе системной. Используя эту особенность, можно повысить свои привилегии и подняться до уровня системы. Для этого я использовал инструмент под названием SharpImpersonation, но сперва его нужно загрузить на машину.
Для этого мы сперва подняли веб-сервер, но запросы до него не доходили. Попробовали закинуть инструмент на шару – не закидывался. В итоге подняли на нашей рабочей станции FTP-сервер, и через оболочку xp_cmdshell команда за командой без нормальной обратной связи запросили файл с инструментом.
Наконец, можно было выполнить команду через SharpImpersonation, создать административную учетную запись и нормально зайти на хост.
Начало эскалации
Подключившись по протоколу RDP к BD.local — хосту, где располагалась база, мы нашли в списке процессов антивирус Касперского. Очевидно, он мешал работе. Однако теперь у нас был полноценный буфер обмена и понимание, с чем придется бороться.
Я закинул туда Mimikatz, который коллеги обфусцировали так, чтобы его не засекла конкретно эта версия антивируса. Mimikatz позволил создать дамп памяти системного процесса lsass.exe и извлечь хранящиеся в ней учетные данные.
В дампе памяти нашелся NTLM-хеш пароля учетной записи компьютера domain\pro-db$ – PRO.BD.
Далее с помощью инструмента Rubeus для учетной записи PPO-BD с использованием NTLM-хеша ее пароля был запрошен TGT-билет Kerberos. Таким образом мы получили доступ в домен Local и подключились к домен-контроллеру.
Если долго мучаться
Учетная запись PRO.BD позволила собрать информацию о домене Local, в том числе о групповых политиках. В скриптах групповых политик на одной из шар нашлось несколько скриптов, содержащих пароль для локальной учетной записи LocalAdmin.
LocalAdmin имел доступ еще к ряду машин. Мы стали последовательно изучать их. Обошли порядка 40 хостов и нигде не нашли ничего полезного — сплошные тупики.
Вот попали мы на машину, которая является SIEM-агентом и радуемся, что вот-вот получим доступ ко всему. Предупреждаем заказчика: так и так, сейчас будем ее хакать. Проследите, пожалуйста, за процессом, на случай если что-то сломается. А нам говорят, что не надо ее трогать: «Мы сегодня выводим ее из эксплуатации. Вот прям сегодня. Ага». Мы такие: «Блин, ну ладно».
Дальше ищем… Еще дня 3-4. Нашли еще одну SIEM. А нам в ответ: «Мы эту машину тоже не сегодня, завтра выведем из эксплуатации. Сейчас меняем полностью SIEM, переходим там с одного вендора на другой. Вы, конечно, можете в отчете написать, но пока отчет попадет к руководству, это уже будет неактуально».
Вечером мы что-то нашли, а утром оно уже не доступно — машины гасли прямо на глазах. Можно подумать, что это все из-за пари, но на пиво мы так и не поспорили. В общем, непросто проводить пентесты в разгар модернизации инфраструктуры. Даже чисто психологически тяжело, две недели были такие качели.
Принцип домино
Затем пришла очередь ничем не примечательного с виду сервера OMO. Там тоже использовалась учетка LocalAdmin.
Беглый осмотр диска сервера не дал полезной информации. Сессии администраторов не были обнаружены, но я сделал дамп хранилища локальных учетных записей, LSA.
Дамп LSA на хосте OMO
Так в наши руки попал NTLM хеш еще одной локальной учетной записи Admin-region, которая входит в группу локальных администраторов. Запустили перебор и получили из этого NTLM-хеша пароль.
Локальная учетная запись Admin-region позволила получить доступ к серверу OMO-2.
На данном сервере обнаружились активные сессии администраторов в регионе D.
Права локального администратора позволяют извлекать из памяти билеты Kerberos и использовать их в атаке Pass-the-Ticket.
Экспорт Kerberos билета доменной учетной записи с сервера OMO-2
С помощью атаки Pass-the-Ticket мы получили доступ к учетке Admin-region D.
Оказалось, что администраторы в регионе D входят в группу D-admin-group, которая имеет права (ACL) более чем над 4500 объектами в домене Local: пользователями, компьютерами и подразделениями (OU). Так сказать, вышли на оперативный простор.
(Почти) прямой путь к домену
В числе полученных прав было GenericWrite для сервера PROD.
На сервере не было никаких процессов, так что дамп памяти процесса lsass не дал бы результатов. Поэтому мы собрали данные о локальных учетных записях из хранилища SAM. В результате был получен NTLM хеш для локальной учетной записи Administrator.
NTLM хеш для локального администратора на хосте PROD
При помощи перебора мы получили пароль от нее в открытом виде, а затем при помощи техники Password Spraying выяснили, что учетная запись и такой же пароль используются еще на 5 серверах.
Один из этих серверов представлял особый интерес, так как являлся членом группы exchange trusted subsystem и exchange windows permissions как сервер Exchange.
Членство в группах компьютерной учетной записи WITNESS
А члены exchange windows permissions обладают привилегией добавления членов в группу ad, которая имеет права GenericWrite на контроллеры домена.
Для начала, используя права локального администратора, мы извлекли NTLM-хеш пароля компьютера из локального хранилища LSA на хосте WITNESS. Полученный NTLM-хеш использовался в атаке Overpass-The-Hash для получения TGT билета Kerberos. Это действие позволило внести изменений в состав доменной группы ad.
В качестве конечной цели был выбран контроллер домена SR. Выполнив атаку Shadow Credentials, мы получили пару ключей, которая позволяет получить TGT билет Kerberos для учетной записи контроллера домена.
Получив TGT билет Kerberos для контроллера домена, мы выполнили атаку DCSync в отношении административной доменной учетной записи admin-Ivanov, в результате чего был получен AES256 хеш ее пароля. После получения TGT билета был получен доступ на контроллер домена.
Миссия выполнена.
Разбор полетов
В теории, подобную атаку можно реализовать за несколько часов, однако на практике на проверку гипотез и поиск правильной последовательности действий ушли недели планомерной работы. Это действительно было сложно, но в результате получился довольно элегантный, на мой взгляд, вектор. Такое развитие событий непросто предусмотреть, а злоумышленника было бы сложно обнаружить и выкурить из инфраструктуры.
Shadow Credential, потому так и называется, что пользователь может раз за разом менять пароль, но ключ как был, так и останется у него в атрибуте. Так что это не столько техника эксплуатации, сколько уверенного качественного закрепления, которое трудно засечь. Мало кто отслеживает, что авторизация была по сертификату, а не по паролю и проверяет содержимое msDS-KeyCredentialLink.
Засечь аутентификацию и сбор информации от имени машины также достаточно сложно. Мониторинг активности машин – трудоемкое дело. Аутентификация под локал-админом, в отличие от доменного не светится в SIEM. Впрочем, это был пентест, а не редтимминг и никто не пытался нас ловить, так что я не буду говорить, что эту атаку нельзя было обнаружить вовсе.
Есть в этом векторе и пара узких мест, которые легко устранить. Так, вряд ли все прошло бы так тихо, если бы не избыточные права у почтового сервера. Чтобы обезопасить его, хватило бы выполнения стандартных рекомендаций Microsoft. Мы бы его захватили, но не смогли бы продвинуться дальше. А если бы в файле групповой политики не было паролей, в том числе от Local admin, то ничего этого вообще не было бы. Дьявол кроется в деталях, как и всегда.