+38 067 569 61 50

info@clapkey.com

KeePass2 : détournement de DLL et interception de l'API Windows

KeePass2 : détournement de DLL et interception de l'API Windows

Récemment publiée, la vulnérabilité KeePass2 CVE-2023-24055 et toute l'agitation autour de celle-ci m'ont poussé à terminer un petit projet que j'avais commencé l'an dernier. Mon objectif était de savoir si je pouvais trouver un moyen d'intercepter le mot de passe principal de la base de données KeePass2. Pour le plaisir et l'apprentissage, bien sûr ;)

L'équipe Clapkey a traduit mot pour mot la note d'un pentesteur sur la vulnérabilité de KeePass2.

Le matériel est présenté EXCLUSIVEMENT À DES FINS ÉDUCATIVES.

Introduction

Imaginez la situation. Vous obtenez les droits d'administrateur sur un poste de travail et vous venez de récupérer une base de données KeePass2.

Problème : KeeFarce/KeeThief ne fonctionnent plus.

Trouvons un autre moyen d'obtenir ce mot de passe principal.

DLL Hijacking

Was ist das?

Le détournement de DLL (DLL hijacking) est un type d'attaque où l'on exploite l'ordre de recherche des bibliothèques d'un programme pour charger des bibliothèques de liens dynamiques. Lorsqu'un programme tente de charger un fichier DLL, il recherche le fichier dans un ordre précis. Cet ordre est le suivant :

  1. Le répertoire depuis lequel le programme est chargé
  2. Le répertoire système : C:\Windows\System32
  3. Le répertoire système 16 bits : C:\Windows\System
  4. Le répertoire Windows : C:\Windows
  5. Le répertoire courant
  6. Les répertoires indiqués dans la variable d'environnement PATH

Si un attaquant parvient à placer un fichier DLL malveillant dans l'un de ces répertoires sous le même nom que le fichier DLL légitime, le programme chargera la DLL malveillante au lieu de la légitime, permettant à l'attaquant d'exécuter du code arbitraire dans le processus.

Cela concerne-t-il aussi KeePass ?

DLL cible

Le moyen le plus simple de trouver une DLL potentiellement détournable est de faire une recherche avec promon. Trouvez CreateFile dans la bibliothèque DLL qui renvoie une erreur NAME NOT FOUND, comme celle-ci :

Que se passe-t-il ?

Ici, KeePass tente de créer une DLL nommée UxTheme.dll, mais essaie de la charger depuis son propre dossier d'installation dans C:\Program Files\KeePass Password Safe 2.

Or il s'agit habituellement d'une DLL système présente dans C:\Windows\System32 :

Ainsi, cette DLL peut être une bonne candidate pour un détournement.

Compilons une DLL et essayons de voir si elle se charge dans KeePass2 si nous la renommons. Nous utiliserons ce code :

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;

}

Notez l'appel à TraceEvents à la place de printf. C'est parce que, comme nous travaillons avec une DLL, il n'y a pas de moyen simple d'obtenir son résultat.

TraceEvents utilise le préprocesseur de traçage logiciel Windows (WPP), qui est un composant de ETW.

Nous pourrons voir nos événements dans TraceView.

Maintenant que nous avons notre DLL, déplaçons-la dans C:\Program Files\KeePass Password Safe 2 et renommons-la en UxTheme.dll :

Et lançons KeePass :

ça marche !! Ça a fonctionné. Nous avons un journal dans TraceView, qui montre notre DLL chargée dans KeePass2.

C'était facile. Et maintenant ?

Interception de l'API Windows

L'interception (hooking) permet d'intercepter et/ou de modifier le comportement des fonctions appelées par un programme donné. Dans notre cas, nous voulons pouvoir enregistrer les paramètres et les valeurs de retour des appels à l'API Windows.

Sur le schéma ci-dessous, vous pouvez voir un appel API normal (en vert) et un appel API intercepté (en rouge) :

Fait intéressant : c'est exactement ainsi que les AV/EDR surveillent les appels API.

J'ai commencé à travailler sur un mécanisme d'interception personnalisé avant de tomber sur la propre bibliothèque de Microsoft, faite précisément pour cela : Detours

Je ne rentrerai pas dans les détails de mise en œuvre des hooks, car la documentation est disponible en ligne.

Exemple avec MessageBoxW

Commençons simplement avec l'appel MessageBoxW.

MessageBoxW(

NULL,TEXT("Hello Twitter!"),

TEXT("SimpleEXE"),

MB_OK);

Si l'on regarde la documentation pour MessageBoxW sur MSDN, on obtient ce prototype de fonction :

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);}

Ce code est assez simple. Lorsque MessageBoxW est appelé, il enregistre d'abord les arguments via TraceEvents avant de poursuivre l'exécution vers le « vrai » MessageBoxW.

Essayons !

Hook the box

Ceci a été testé à l'aide d'un chargeur personnalisé qui injecte la DLL au démarrage du processus. Et lorsque la MessageBox apparaît :

L'appel de fonction est enregistré dans TraceView ! Avec les arguments et tout.

Maintenant, imaginez que vous pouvez exécuter du code dans un processus sensible et intercepter les fonctions qui traitent des données sensibles.

Génération automatique de code

Mais d'abord, la génération de code.

Maintenant que nous avons un premier exemple fonctionnel d'interception, nous devons le faire monter en échelle. L'API Windows compte de nombreuses fonctions. Rappelez-vous, notre objectif est d'intercepter le mot de passe principal de la base de données lorsqu'il est saisi.

Bien évidemment, je n'écris pas le code pour chaque fonction de l'API Windows moi-même. Personne n'a le temps pour ça. J'ai utilisé un script Python et un fichier Json pour générer le code d'interception de DLL.

MSDN — votre meilleur ami pour la documentation, ou vous pouvez aussi consulter les fichiers d'en-tête dans Visual Studio.

Voici un court extrait du fichier json :

Et la génération :

La génération de code par défaut appelle TraceEvents pour enregistrer les appels de fonction et les arguments. Voici un exemple de code généré :

Il est très similaire au code de notre premier exemple, mais il est généré automatiquement dès qu'une fonction est ajoutée au fichier json. J'ai aussi ajouté des extraits de code personnalisés pour étendre les fonctionnalités si nécessaire. Ainsi, nous pouvons enregistrer les valeurs de retour, afficher les arguments d'une certaine manière, etc.

Et voilà, nous avons une génération de code fonctionnelle. Nous pouvons contrôler n'importe quelle fonction de l'API Windows en ajoutant son prototype au fichier json !

Rassemblons tout cela :

Pendant les tests, j'ai restreint la recherche aux fonctions qui traitent les chaînes de caractères et le presse-papiers. Après une petite recherche, j'ai trouvé deux appels API intéressants pour notre cas d'usage :

- SetClipboardData : place des données dans le presse-papiers dans le format spécifié

HANDLE SetClipboardData(

[in] UINT uFormat,

[in, optional] HANDLE hMem

);

- ToUnicodeEx : convertit le code de touche virtuelle spécifié et l'état du clavier en le ou les caractères Unicode correspondants

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

);

Après avoir généré les hooks pour ces deux fonctions, nous copions la DLL dans C:\Program Files\KeePass Password Safe 2 et la renommons en UxTheme.dll.

Et maintenant, relançons KeePass2 et saisissons le mot de passe pour déverrouiller la base de données :

C'est plutôt cool, non ? Le mot de passe est enregistré dans TraceView !

Les entrées de la base de données peuvent aussi être interceptées lors d'un CTRL+C, grâce au hook SetClipboardData :

Conclusion

J'ai encore un peu de travail pour écrire le mot de passe dans un fichier, mais vous avez compris l'idée. J'espère que ce que vous avez lu aujourd'hui vous a plu et que vous avez appris quelque chose de nouveau.

Je n'ai pas de section de commentaires, mais envoyez-moi un message sur Twitter, avant que la plateforme ne disparaisse, ha ha.

Liens utiles

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

Cette page a été traduite partiellement ou entièrement à l'aide de l'IA. Merci d'envoyer vos remarques sur la traduction à info@clapkey.com.

#StandWithUkraine

Soutenir les Forces armées d'Ukraine pendant l'invasion russe

Contacts

Bureau

4e étage, CC Metropoliten (rue Gogolia 38), Poltava, Ukraine, 36000