+38 067 569 61 50

moc.yekpalc%40ofni

KeePass2: Викрадення DLL та Підключення Windows API

KeePass2: Викрадення DLL та Підключення Windows API

Нещодавно оприлюднено KeePass2 CVE-2023-24055 і вся метушня навколо нього спонукали мене завершити маленький проект, який я розпочав минулого року. Моєю метою було дізнатися, чи зможу я знайти спосіб перехопити головний пароль бази даних KeePass2. Для розваги та навчання звісно ж ;)

Команда Клапкей дослівно переклала замітку пентестера по вразливості KeePass2. 

Матеріал приведено ВИКЛЮЧНО В НАВЧАЛЬНИХ ЦІЛЯХ. 

Введення

Уявіть собі це. Ви берете адміністратор на робочій станції та щойно отримали базу даних KeePass2.

Проблема: KeeFarce/KeeThief більше не працюють.

Давайте знайдемо інший спосіб отримати цей майстер-пароль.

DLL Hijacking

Was ist das?

Викрадення DLL – це тип атаки, коли ви використовуєте порядок пошуку програми для завантаження бібліотек динамічних посилань. Коли програма намагається завантажити файл DLL, вона шукатиме файл у певному порядку. Порядок такий:

  1. Каталог, з якого завантажується програма
  2. Системний каталог: C:\Windows\System32
  3. 16-бітний системний каталог: C:\Windows\System
  4. Каталог Windows: C:\Windows
  5. Поточний каталог
  6. Каталоги, указані в змінній середовища PATH

Якщо зловмиснику вдасться розмістити зловмисний DLL-файл в одному з цих каталогів із таким же ім’ям, що й законний DLL-файл, програма завантажить шкідливу DLL замість легітимної, дозволяючи зловмисникові виконувати довільний код у процесі.

Це також стосується KeePass?

Цільова DLL

Найпростіший спосіб знайти потенційну DLL, яку можна захопити, — це пошук за допомогою promon. Знайдіть CreateFile у бібліотеці DLL, яка повертає помилку NAME NOT FOUND, як-от ця тут:

Що відбувається?

Тут KeePass намагається створити DLL під назвою UxTheme.dll, але намагається завантажити її для власної папки встановлення в C:\Program Files\KeePass Password Safe 2.

Однак зазвичай це системна DLL і присутня в C:\Windows\System32:

Таким чином, ця DLL може бути хорошим кандидатом для викрадення.

Давайте скомпілюємо DLL і спробуємо побачити, чи завантажиться він у KeePass2, якщо ми його перейменуємо. Ми будемо використовувати цей код:

BOOL APIENTRY DllMain(

HMODULE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

WPP_INIT_TRACING(L"Test");

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

TraceEvents(TRACE_LEVEL_VERBOSE, GENERAL, "[+ dllmain] DLL_PROCESS_ATTACH\n");

}

return TRUE;

}

Зверніть увагу на виклик TraceEvents замість printf. Це тому, що, оскільки ми працюємо з DLL, немає простого способу отримати її результат.

TraceEvents використовує програмний препроцесор трасування Windows (WPP), який є компонентом ETW.

Ми зможемо бачити наші події в TraceView.

Тепер, коли у нас є наша DLL, давайте перемістимо її в C:\Program Files\KeePass Password Safe 2 і перейменуємо її на UxTheme.dll:

І запустіть KeePass:

так!! Це спрацювало. У нас є журнал у TraceView, який показує нашу DLL, завантажену в KeePass2.

Це було легко. що тепер?

Підключення Windows API

Перехоплення дозволяє перехоплювати та/або змінювати поведінку функцій, викликаних даною програмою. У нашому випадку ми хочемо мати можливість реєструвати параметри та повертати значення викликів Windows API.

На наведеній нижче діаграмі ви можете побачити звичайний виклик API (зеленим) і підключений виклик API (червоним):

Цікавий факт: саме так AV/EDR відстежують виклики API.

Я почав працювати над спеціальним механізмом підключення, перш ніж натрапити на власну бібліотеку Microsoft, щоб зробити саме це: Detours

Я не буду вдаватися в подробиці реалізації хуків, оскільки документація доступна в Інтернеті.

Приклад MessageBoxW 

Почнемо з простого з виклику MessageBoxW.

MessageBoxW(

NULL,TEXT("Hello Twitter!"),

TEXT("SimpleEXE"),

MB_OK);

Якщо ми подивимося на документацію для MessageBoxW на MSDN, ми отримаємо цей прототип функції:

intMessageBoxW(

[in,optional]HWNDhWnd,

[in,optional]LPCWSTRlpText,

[in,optional]LPCWSTRlpCaption,

[in]UINTuType);

Our hook function to log the lpText and lpCaption parameter would look something like this:

int(*real_MessageBoxW)(HWNDhWnd,LPCWSTRlpText,LPCWSTRlpCaption,UINTuType)=MessageBoxW;inthook_MessageBoxW(HWNDhWnd,LPCWSTRlpText,LPCWSTRlpCaption,UINTuType){TraceEvents(TRACE_LEVEL_VERBOSE,GENERAL,"[+ Hook] MessageBoxW(lpText=%ls, lpCaption=%ls, uType=%u)",lpText,lpCaption,uType);returnreal_MessageBoxW(hWnd,lpText,lpCaption,uType);}

Цей код досить простий. Коли викликається MessageBoxW, він спочатку реєструє аргументи за допомогою TraceEvents перед тим, як продовжити виконання для «справжнього» MessageBoxW.

Давайте спробуємо!

Hook the box

Це було перевірено за допомогою спеціального завантажувача, який вставляє DLL під час запуску процесу. І коли з’явиться MessageBox:

Виклик функції реєструється в TraceView! З аргументами і все.

Тепер уявіть, що ви можете запускати код у конфіденційному процесі та мати можливість перехоплювати функції, які обробляють конфіденційні дані.

Автоматична генерація коду

Але спочатку генерація коду.

Тепер, коли у нас є перший робочий приклад підключення, ми повинні збільшити його масштаб. В Windows API є багато функцій. Пам’ятайте, наша мета — перехопити головний пароль бази даних, коли він вводиться.

Очевидно, я не пишу код для кожної функції Windows API сам. Ні в кого немає на це часу. Я використав сценарій Python і файл Json, щоб створити код для dll-перехоплення.

MSDN — ваш найкращий друг для документації, або ви також можете перевірити файли заголовків у Visual Studio.

Ось короткий вибір файлу json:

І генерація: 

Генерація коду за замовчуванням викликає TraceEvents для реєстрації викликів функцій і аргументів. Ось зразок згенерованого коду:

Він дуже схожий на код у нашому першому прикладі, але генерується автоматично, якщо функцію додано до файлу json. Я також додав спеціальні фрагменти коду, щоб розширити функціональні можливості, якщо це необхідно. Таким чином ми можемо реєструвати повернуті значення, друкувати аргументи певним чином тощо.

І ось так у нас є робоча генерація коду. Ми можемо контролювати будь-яку функцію Windows API, додавши її прототип до файлу json!

Об'єднаємо то все разом: 

Під час тестування я звузив пошук до функцій, які обробляють рядки та роботу буфера обміну. Після невеликого дослідження я знайшов два цікавих виклики API для нашого випадку використання:

- SetClipboardData: розміщує дані в буфері обміну у вказаному форматі

HANDLE SetClipboardData(

[in] UINT uFormat,

[in, optional] HANDLE hMem

);

ToUnicodeEx: перетворює вказаний код віртуальної клавіші та стан клавіатури на відповідний символ або символи Unicode

int ToUnicodeEx(

[in] UINT wVirtKey,

[in] UINT wScanCode,

[in] const BYTE *lpKeyState,

[out] LPWSTR pwszBuff,

[in] int cchBuff,

[in] UINT wFlags,

[in, optional] HKL dwhkl

);

Після генерації хуків для цих двох функцій ми копіюємо DLL у C:\Program Files\KeePass Password Safe 2 і перейменовуємо її на UxTheme.dll.

А тепер давайте знову запустимо KeePass2 і введемо пароль, щоб розблокувати базу даних:

Як це круто? Пароль реєструється в TraceView!

Записи в базі даних також можна перехопити, коли натиснуто CTRL+C, завдяки хуку SetClipboardData:

Висновок

Мені ще потрібно трохи попрацювати, щоб записати пароль у файл, але ви зрозуміли ідею. Сподіваюся, вам сподобалося те, що ви сьогодні прочитали, і ви дізналися щось нове.

У мене немає розділу для коментарів, але надішліть мені повідомлення в Twitter, перш ніж платформа зникне, ха-ха.

Корисні посилання

https://keepass.info/

https://learn.microsoft.com/en-us/sysinternals/

https://github.com/microsoft/Detours

https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/traceview https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/wpp-software-tracing