Руководство по созданию кастомного билда Mimikatz для обхода детекта

Руководство по созданию кастомного билда Mimikatz для обхода детекта

@Leakinfo

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

Введение

Я впервые сделал это несколько месяцев назад и интегрировал полученный результат в свой скрипт WinPwn. Некоторые люди спрашивали меня, откуда у меня появилась такая сборка. Пришло время раскрыть секреты. В различных блогах уже есть много сообщений о том, как обфусцировать Mimikatz. Но, как правило, они рассказывают только то, что лежит на поверхности: как обойти AMSI для Invoke-Mimikatz или как правильно использовать инструменты для обфускации Powershell-версии Mimikatz. На создание собственной сборки несколько месяцев назад меня вдохновили комментарии в готовом скрипте:

# This script downloads and slightly "obfuscates" the mimikatz project.
# Most AV solutions block mimikatz based on certain keywords in the binary like "mimikatz", "gentilkiwi", "benjamin@gentilkiwi.com" ..., 
# so removing them from the project before compiling gets us past most of the AV solutions.
# We can even go further and change some functionality keywords like "sekurlsa", "logonpasswords", "lsadump", "minidump", "pth" ....,
# but this needs adapting to the doc, so it has not been done, try it if your victim's AV still detects mimikatz after this program.

git clone https://github.com/gentilkiwi/mimikatz.git windows
mv windows/mimikatz windows/windows
find windows/ -type f -print0 | xargs -0 sed -i 's/mimikatz/windows/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/MIMIKATZ/WINDOWS/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/Mimikatz/Windows/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/DELPY/James/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/Benjamin/Troy/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/benjamin@gentilkiwi.com/jtroy@hotmail.com/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/creativecommons/python/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/gentilkiwi/MSOffice/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/KIWI/ONEDRIVE/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/Kiwi/Onedrive/g'
find windows/ -type f -print0 | xargs -0 sed -i 's/kiwi/onedrive/g'
find windows/ -type f -name '*mimikatz*' | while read FILE ; do
 newfile="$(echo ${FILE} |sed -e 's/mimikatz/windows/g')";
 mv "${FILE}" "${newfile}";
done
find windows/ -type f -name '*kiwi*' | while read FILE ; do
 newfile="$(echo ${FILE} |sed -e 's/kiwi/onedrive/g')";
 mv "${FILE}" "${newfile}";
done

Мы можем пойти даже дальше - ну что ж, вызов брошен.

Mimikatz содержит ВИРУС

Если вы пытались скачать Mimikatz с включенным антивирусом, то, наверняка, замечали, что это невозможно, потому что каждая его сборка полыхает красным, как новогодняя гирлянда. И это очевидно, ведь сегодня злоумышленники используют Mimikatz и многие другие проекты с открытым исходным кодом в реальных инцидентах. Я почти уверен, что Mimikatz - наиболее часто используемая программа для извлечения учетных данных из процесса lsass или базы данных, с которой работает sam, выполнения хэш-атак, расшифровки DPAPI секретов и многого другого. Хороший, но далеко не полный функционал этой утилиты можно найти на ADSecurity.org или в Mimikatz Wiki. Многие люди совершенно точно не знают, почему эти проекты с открытым исходным кодом помечаются как вредоносы:

ПАМАГИТЕ

Однако настоящие хакеры или ноу-хау пентестеры не используют готовые билды, а создают собственные. Зачастую изменяются только некоторые фрагменты исходного кода Mimikatz. В этом случае мы не теряем в функционале, а лишь видоизменяем исходники, чтобы понизить уровень обнаружения.

Основные сигнатуры

Мы уже увидели некоторые распространенные сигнатуры Mimikatz из приведенного выше кода. Для начала, это строки:

  • mimikatz, MIMIKATZ and Mimikatz
  • DELPY, Benjamin, benjamin@gentilkiwi.com
  • creativecommons
  • gentilkiwi
  • KIWI, Kiwi and kiwi

Поставьте себя на место AV-вендора. В первую очередь следует найти очевидные факторы, характеризующие исследуемые файл как зловредный. Если вы откроете меню Mimikatz, то увидите следующее:

Все строки, выведенные в консоли, просто кричат о том, что МЫ ЗАПУСТИЛИ MIMIKATZ, поэтому сразу добавляем следующие строки в наш скрипт для замены:

  • “A La Vie, A L’Amour”
  • http://blog.gentilkiwi.com/mimikatz
  • Vincent LE TOUX
  • vincent.letoux@gmail.com
  • http://pingcastle.com
  • http://mysmartlogon.com

Ну или можно было бы просто открыть mimikatz.c и заменить этот баннер чем-нибудь другим или даже удалить его. Как говорит автор в комментариях того скрипта выше, мы можем пойти дальше, заменив ключевые слова используемых модулей. Основными модулями в Mimikatz на момент написания являются следующие:

  • crypto, dpapi, kerberos, lsadump, ngc, sekurlsa
  • standard, privilege, process, service, ts, event
  • misc, token, vault, minesweeper, net, busylight
  • sysenv, sid, iis, rpc, sr98, rdm, acr

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

Далее у нас есть два варианта. Либо мы меняем все имена функций, написанные исключительно в верхнем или нижнем регистре, либо полностью меняем абсолютно все имеющиеся имена. В первом варианте знакомые нам команды остаются на месте, во втором варианте мы должны переназначать и запоминать новые наименования функций. Чтобы не усложнять, мы будем придерживаться первого случая. Я не стал заменять названия функций, потому что строки, которые я использовал, могли существовать бы и в других строках кода, и это могло бы повлиять на функциональность. Таким образом, чтобы создать собственную сборку, мы заменяем строки, не относящиеся к именам функций, случайными именами.

Еще одна важная вещь, которую нужно отметить, - это иконка файла. Очевидно, она также влияет на детектирование, поэтому в модифицированной версии мы заменяем существующую иконку какой-нибудь случайной из интернета.

У каждой функции mimikatz есть свои подфункции. Вероятно, самая используемая функция sekurlsa, например, включает следующие подфункции:

  • msv, wdigest, kerberos, tspkg
  • livessp, cloudap, ssp, logonpasswords
  • process, minidump, bootkey, pth
  • krbtgt, dpapisystem, trust, backupkeys
  • tickets, ekeys, dpapi, credman

Чтобы быть уверенным, что наиболее известные сигнатуры Mimikatz изменены, мы включили большинство названий подфункций в скрипт замены. Это приводит к следующему. Выполнив bash-сценарий, скомпилировав код и загрузив его на VirusTotal, мы получаем следующий результат:

25/67 обнаружений. Это неплохо, но все же недостаточно хорошо.

netapi32.dll

Чтобы обнаружить больше сигнатур, можно разделить файл на части при помощи head -c byteLength mimikatz.exe > split.exe. Если результат удалится, считайте, что в перспективе, это принесет несколько детектов на Virustotal и часть файла требует доработки. Иначе - все в порядке и ничего изменять не нужно. Вы также можете автоматизировать эту задачу с помощью инструмента Мэтта Хэндса DefenderCheck. Он делает практически тоже самое: разбивает файлы на части, копирует их в папку C:\temp\ и сканирует Защитником Windows. Давайте проверим это для получившегося бинарника:

Windows Defender отметил три следующие функции библиотеки netapi32.dll:

  • I_NetServerAuthenticate2
  • I_NetServerReqChallenge
  • I_NetServerTrustPasswordsGet

Поискав немного в Интернете, я нашел вот эту статью, в которой объясняется, как пересоздать netapi32.min.lib, изменив его структуру. Как там написано, чтобы создать собственный netapi32.min.lib, необходимо предварительно создать собственный .def-файл со следующим содержимым:

lib /DEF:netapi32.def /OUT:netapi32.min.lib

После этого, мы перемещаем получившийся netapi32.min.lib в каталог lib\x64\ и рекомпилируем. Повторный запуск DefenderCheck больше не выдает результатов:

Это означает, что мы обошли функцию «защиты в реальном времени» Защитника Windows. Но если мы включим облачную защиту и скопируем файл в другое место, он снова будет повержен великим защитником:

Нужно больше замены строк

Предстоит еще многое заменить. Давайте сначала смотреть на очевидное. Меню Mimikatz содержит описания каждой используемого компонента. Подфункции privilege, например, имеют следующее описание:

Чтобы удалить эти строки, нам придется заменить почти все строки из описания, добавив каждую в наш скрипт для замены. Мы уже у цели? Некоторые функции и их описание не являются критически важными, но все же чертовски хорошо звучат, поэтому они остаются такими, какие есть:

  • answer - ответ на главный вопрос жизни, вселенной и всего остального
  • coffee - пожалуйста, сделай мне кофе!

Многие AV-вендоры помечают секции файлов, в которые подгружаются соответствующие DLL. Чтобы найти все импортируемые .DLL-файлы в исходном коде Mimikatz, мы можем запустить Visual Studio, нажать STRG + SHIFT + F. Это откроет поиск по всему проекту. Поиск .dll выдаст нам все имена DLL-файлов, используемые в проекте. Мы также добавим их в наш bash, заменяя каждое на мешанину из заглавных и строчных букв.

sekurlsa с подфункцией logonpasswords - это наиболее часто используемая функция, которая дампит почти все возможные учетные данные. Поэтому детект по фрагментам кода не заставит себя ждать. Взгляните на kuhl_m_sekurlsa.c и поищите, какие операторы kprintf () содержат подозрительные выражения. Мы всегда ищем слова с низким уровнем ложных срабатываний, потому что AV-вендоры не любят ошибаться. В итоге я нашел следующие строки:

  • Switch to MINIDUMP, Switch to PROCESS
  • UndefinedLogonType, NetworkCleartext, NewCredentials, RemoteInteractive, CachedInteractive, CachedRemoteInteractive, CachedUnlock
  • DPAPI_SYSTEM, replacing NTLM/RC4 key in a session, Token Impersonation , UsernameForPacked, LSA Isolated Data

Если мы посмотрим на функцию standard из kuhl_m_standard.c, то встретим еще парочку интересных строк:

  • isBase64InterceptInput, isBase64InterceptOutput
  • Credential Guard may be running, SecureKernel is running

Этот метод поиска можно применить и ко всем другим файлам исходного кода. Я не буду описывать их все здесь, потому что это слишком долго. Помните, что замена строк поможет снизить уровень обнаружения.

Структура файла

Я также взглянул на всю структуру проекта, чтобы увидеть, какие части повторяются вновь и вновь. Здесь мое внимание привлекла одна вещь. Все имена переменных и функций объявляются, начинаясь на kuhl_ или KULL_:

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

kuhl=$(cat /dev/urandom | tr -dc "a-z" | fold -w 4 | head -n 1)
find windows/ -type f -print0 | xargs -0 sed -i "s/kuhl/$kuhl/g"

kull=$(cat /dev/urandom | tr -dc "a-z" | fold -w 4 | head -n 1)
find windows/ -type f -print0 | xargs -0 sed -i "s/kull/$kull/g"

find windows/ -type f -name "*kuhl*" | while read FILE ; do
 newfile="$(echo ${FILE} |sed -e "s/kuhl/$kuhl/g")";
 mv "${FILE}" "${newfile}";
done


find windows/ -type f -name "*kull*" | while read FILE ; do
 newfile="$(echo ${FILE} |sed -e "s/kull/$kull/g")";
 mv "${FILE}" "${newfile}";
done

under=$(cat /dev/urandom | tr -dc "a-z" | fold -w 4 | head -n 1)
find windows/ -type f -print0 | xargs -0 sed -i "s/_m_/$under/g"

find windows/ -type f -name "*_m_*" | while read FILE ; do
 newfile="$(echo ${FILE} |sed -e "s/_m_/$under/g")";
 mv "${FILE}" "${newfile}";
done

Теперь выполните сценарий, скомпилируйте и загрузите файл в Virustotal:

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

Часть чего-то большего

Если вы все еще хотите пойти дальше и попытаться получить FUD, вы можете полностью изменить имена функций вместо использования прописных и строчных букв. Вы можете просмотреть все другие C-файлы и библиотеки, чтобы найти индикаторы Mimikatz с низким уровнем ложных срабатываний и заменить их или просто вырезать функции, которые вам не нужны.

Что насчет сообщений об ошибках? Они также могут содержать индикаторы Mimikatz. Устранение ошибок не всегда имеет смысл. Но если вам не нужны подробные сообщения об ошибках, вы можете просто удалить их, чтобы понизить вес итогового файла. С помощью сочетания клавиш STRG + SHIFT + H вы можете искать и заменять строки во всем проекте. Вот так можно удалить все сообщения об ошибках

AV/EDR-вендоры также переходят к методам обнаружения по API импортам. Есть две действительно хорошие статьи об обфускации исходного кода C/C++, рассказывающие о том, как скрыть API импорт с помощью Plowsec. Это Engineering antivirus evasion и Engineering antivirus evasion (Part II). Mimikatz использует множество функций Windows API. Например, чтобы скрыть LSAOpenSecret, вы можете использовать следующий код:

typedef NTSTATUS(__stdcall* _LsaOSecret)(
 __in LSA_HANDLE PolicyHandle,
 __in PLSA_UNICODE_STRING SecretName,
 __in ACCESS_MASK DesiredAccess,
 __out PLSA_HANDLE SecretHandle
 );
char hid_LsaLIB_02zmeaakLCHt[] = { 'a','d','v','a','p','i','3','2','.','D','L','L',0 };
char hid_LsaOSecr_BZxlW5ZBUAAe[] = { 'L','s','a','O','p','e','n','S','e','c','e','t',0 };
HANDLE hhid_LsaLIB_asdasdasd = LoadLibrary(hid_LsaLIB_02zmeaakLCHt);
_LsaOSecret ffLsaOSecret = (_LsaOSecret)GetProcAddress(hhid_LsaLIB_asdasdasd, hid_LsaOSecr_BZxlW5ZBUAAe);

Скрывая SamEnumerateUserDomain, SamOpenUser, LsaSetSecret, I_NetServerTrustPasswordsGet и многие другие вызовы, в сочетании с вышеперечисленными методами обхода, возможно, вы прийдете к FUD.

Но модификация исходного кода - это только один из способов достичь цели. Вдохновите себя статьей Phras о PEzor - Designing and Implementing PEzor, an Open-Source PE Packer. Внедрение шелл-кода с встраиванием системных вызовов, удаление хуков на уровне пользователя, превращение сгенерированного исполняемого файла в полиморфный, чтобы избежать тривиальных детектов и многое другое.

Вывод

Мы рассмотрели методы замены строк для создания собственной сборки Mimikatz. Мы выяснили, что детект Mimikatz сокращается примерно до 1/3, когда мы заменяем наиболее частые названия, но его можно уменьшить еще больше, удаляя ненужные фрагменты кода. Такие методы как сокрытие импорта API-функций, могут еще больше снизить уровень обнаружения.

Прочитать оригинал этого материала на английском можно здесь.





Report Page