Automatisation de la détection des chemins d'interception DLL possibles (DLL Hijacks)

Bonjour, Khabrovites. Recrutement pour le nouveau volet du cours «Pentest. Pratique des tests de pénétration " . En prévision du début du cours, nous partageons avec vous la traduction de matériel intéressant.







introduction



Dans cet article, nous examinerons le concept de détournement de DLL et comment il peut être utilisé pour obtenir la persistance de l'espace utilisateur sur les systèmes Windows. Cette méthode est décrite dans MITRE ATT & CK sous: "Interception de l'ordre de recherche DLL (T1038) ".



L'usurpation de DLL peut être utilisée par des attaquants à de nombreuses fins différentes, mais cet article se concentrera sur l'obtention de la résilience à l'aide d'applications à démarrage automatique. Par exemple, comme Slack et Microsoft Teams sont lancés au démarrage (par défaut), l'usurpation de DLL dans l'une de ces applications permettrait à un attaquant d'obtenir un accès robuste à sa cible - chaque fois qu'un utilisateur se connecte.



Après avoir présenté le concept des DLL, de l'ordre de recherche des DLL et de l'usurpation de DLL, je vous guiderai à travers le processus d'automatisation de la détection des interceptions DLL . Cet article traite de la détection des chemins d'interception DLL dans Slack, Microsoft Teams et Visual Studio Code.



Enfin, j'ai découvert plusieurs chemins d'interception DLL utilisés par différentes applications, recherché la cause première et constaté que les applications utilisant certains appels d'API Windows sont sujettes à l'interception DLL lorsqu'elles ne s'exécutent pas à partir de C:\Windows\System32\.



Je tiens à remercier mon collègue Josiah Massari ( @Airzero24) d'avoir été le premier à repérer certains de ces hooks DLL, à expliquer leur méthodologie et à m'inspirer pour automatiser la détection.



Qu'est-ce qu'une DLL?



Une DLL est une bibliothèque contenant du code et des données qui peuvent être utilisées simultanément par plusieurs programmes. ( Source ) La



fonctionnalité d'une DLL peut être utilisée par une application Windows en utilisant l'une des fonctions LoadLibrary*. Les applications peuvent référencer des DLL conçues spécifiquement pour ces applications ou des DLL Windows déjà présentes sur le disque dans System32. Les développeurs peuvent charger des DLL à partir de System32 pour utiliser les fonctionnalités déjà implémentées dans Windows dans leurs applications sans avoir à écrire cette fonctionnalité à partir de zéro.



Par exemple, un développeur qui a besoin de faire des requêtes HTTP peut utiliser la bibliothèque WinHTTP ( winhttp.dll) au lieu d'implémenter des requêtes HTTP à l'aide de sockets bruts.



Ordre de recherche et interception des DLL



Étant donné que les DLL existent sous forme de fichiers sur le disque, vous vous demandez peut-être comment une application sait où charger la DLL? Microsoft a documenté l'ordre de recherche des DLL en détail ici .



À partir de Windows XP SP2, le mode de recherche sans échec DLL est activé par défaut ( HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode). Lorsque le mode sans échec est activé, l'ordre de recherche des DLL est le suivant:



  1. Le répertoire à partir duquel l'application a été chargée.
  2. Répertoire système. Utilisez la fonction GetSystemDirectory pour obtenir le chemin d'accès à ce répertoire.
  3. Répertoire système 16 bits. Il n'y a pas de fonction qui fournit un chemin vers ce répertoire, mais il est recherché.
  4. Répertoire Windows. Utilisez la fonction GetWindowsDirectory pour obtenir le chemin d'accès à ce répertoire.
  5. Répertoire actuel.
  6. , PATH. , , App Paths. App Paths DLL.


Un système peut contenir plusieurs versions de la même DLL. Les applications peuvent contrôler le choix de l'emplacement à partir duquel la DLL doit être chargée en spécifiant le chemin d'accès complet ou en utilisant un autre mécanisme tel qu'un manifeste. ( Source )



Si l'application ne spécifie pas où charger la DLL, Windows utilise l'ordre de recherche de DLL par défaut indiqué ci-dessus. La première position dans l'ordre de recherche des DLL (le répertoire à partir duquel l'application est chargée) intéresse les attaquants.



Si le développeur de l'application a l'intention de charger la DLL à partir deC:\Windows\System32, mais ne l'a pas explicitement écrite dans l'application, la DLL malveillante placée dans le répertoire de l'application sera chargée avant la DLL légitime de System32. Le chargement d'une DLL malveillante est appelé usurpation de DLL (ou interception) et est utilisé par les attaquants pour charger du code malveillant dans des applications approuvées / signées.



Utilisation de l'usurpation de DLL pour atteindre la résilience



L'usurpation de DLL peut être utilisée pour obtenir la résilience lorsqu'une application / service vulnérable est démarré et qu'une DLL malveillante est placée dans un emplacement vulnérable. Un de mes collègues a @Airzero24découvert l'usurpation de DLL dans Microsoft OneDrive, Microsoft Teams et Slack comme userenv.dll.



Ce sont ces programmes qui sont devenus la cible de l'interception, car par défaut ils sont configurés pour démarrer au démarrage de Windows. Cela peut être vu ci-dessous dans le Gestionnaire des tâches:





Applications Windows configurées pour démarrer automatiquement



Pour tester l'usurpation de DLL, j'ai créé un chargeur de shellcode DLL qui a démarré Cobalt Strike Beacon. J'ai renommé la DLL malveillante userenv.dllet je l'ai copiée dans le répertoire d'application concerné. J'ai lancé l'application et j'ai vu mon nouveau rappel Beacon.





Cobalt grève Beacon Par DLL d' interception



utilisantProcess Explorer , je peux vérifier si ma DLL malveillante a été effectivement chargée par une application vulnérable.





Process Explorer montrant la DLL malveillante chargée



Détection automatique du potentiel d'interception DLL



Après avoir confirmé le piratage de DLL précédemment connu, je voulais voir si je pouvais trouver d'autres capacités d'usurpation de DLL qui pourraient être exploitées.



Le code utilisé lors de ma commande peut être trouvé ici .



Utiliser Slack comme exemple



Pour démarrer ce processus, j'ai exécuté Process Monitor (ProcMon) avec les filtres suivants:



  • Nom du processus -slack.exe
  • Le résultat contientNOT FOUND
  • Le chemin se termine par .dll.




Recherchez les DLL manquantes dans ProcMon.



Ensuite, j'ai lancé Slack et examiné ProcMon pour toutes les DLL que Slack recherchait mais ne pouvait pas les trouver.





Chemins d'interception DLL possibles découverts par ProcMon



J'ai exporté ces données de ProcMon sous forme de fichier CSV pour faciliter l'analyse dans PowerShell.



Avec ma DLL de chargement de shellcode actuelle, je ne pouvais pas facilement comprendre les noms de DLL qui ont été chargés avec succès par Slack. J'ai créé une nouvelle DLL, qui est utilisée GetModuleHandleEx, et GetModuleFileNamepour déterminer le nom de la DLL chargée et l' écrire dans un fichier texte .



Mon objectif suivant était d'analyser le fichier CSV pour les chemins DLL dans la liste, afficher cette liste, copier ma DLL de test dans le chemin spécifié, démarrer le processus cible, arrêter le processus cible et supprimer la DLL de test. Si la DLL de test a été chargée avec succès, elle écrira son nom dans le fichier résultant.



Lorsque ce processus sera terminé, j'aurai une liste des détournements de DLL possibles (j'espère) écrits dans un fichier texte.



Toute la magie de mon projet DLLHijackTest est réalisée par un script PowerShell . Il accepte le chemin du fichier CSV généré par ProcMon, le chemin de votre DLL malveillante, le chemin du processus que vous souhaitez exécuter et tous les arguments que vous souhaitez transmettre au processus.





Paramètres





Get-PotentialDLLHijack Get-PotentialDLLHijack.ps1



Après quelques minutes, je vérifie le fichier texte répertorié dans ma DLL «malveillante» pour d'éventuels détournements de DLL. J'ai trouvé les chemins d'interception possibles suivants pour Slack:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\slack\slack.exe"
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL


Utiliser Microsoft Teams comme exemple



Nous effectuons à nouveau le processus décrit ci-dessus:



  1. Utilisez ProcMon pour identifier les chemins d'interception DLL potentiels, exportez ces données sous forme de fichier CSV.
  2. Déterminez le chemin pour démarrer le processus.
  3. Définissez tous les arguments que vous souhaitez transmettre au processus.
  4. Exécutez Get-PotentialDLLHijack.ps1avec les arguments appropriés.


J'ai trouvé les chemins d'interception possibles suivants pour Microsoft Teams:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Microsoft\Teams\Update.exe" -ProcessArguments '--processStart "Teams.exe"'
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll


Remarque : J'ai dû apporter de petites modifications au script PowerShell pour terminer Teams.exe, car mon script tente de mettre fin au processus qu'il essayait de démarrer, dans ce cas, c'est le cas Update.exe.


Utilisation de Visual Studio Code comme exemple



En répétant le processus ci-dessus, j'ai trouvé les chemins d'interception potentiels suivants pour Visual Studio Code:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Programs\Microsoft VS Code\Code.exe"
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll


Partage de DLL



J'ai remarqué que Slack, Microsoft Teams et Visual Studio Code partagent les DLL suivantes:



  • WINSTA.dll
  • LINKINFO.dll
  • ntshrui.dll
  • srvcli.dll
  • cscapi.dll


J'ai trouvé cela intéressant et je voulais comprendre ce qui cause ce comportement.



Méthodologie: comprendre les moyens d'intercepter les DLL partagées



J'ai regardé pile Tracy quand Slack essayé de charger WINSTA.dll, LINKINFO.dll, ntshrui.dll, srvcli.dllet cscapi.dll.



DLL avec chargement paresseux



j'ai remarqué des similitudes dans Tracy pile lors du chargement WINSTA.dll, LINKINFO.dll, ntshrui.dllet srvcli.dll.





Trace de pile lorsque Code.exe tente de charger WINSTA.dll





une trace de pile lors d'une Teams.exetentative de chargement LINKINFO.dll,





trace de pile lorsque Slack tente de chargerntshrui.dll



une trace de pile contient constamment un appel _tailMerge_<dllname>_dll, delayLoadHelper2suivi LdrResolveDelayLoadedAPI. Ce comportement était le même pour les trois applications.



J'ai déterminé que ce comportement est lié au chargement de DLL paresseux . À partir de la pile de trace au démarrageWINSTA.dllJe pouvais voir que le module responsable de ce chargement paresseux était wtsapi32.dll.



J'ai ouvert wtsapi32.dllà Ghidra et utilisé Search -> For Strings -> Filter: WINSTA.dll. Double-cliquez sur la ligne trouvée pour accéder à son emplacement en mémoire.





La ligne " WINSTA.dll" danswtsapi32.dll



En cliquant avec le bouton droit de la souris sur un emplacement en mémoire, nous pouvons trouver toutes les références à cette adresse.





Liens vers EnWINSTA.dll



suivant les liens, nous pouvons voir que la chaîne WINSTA.dllest passée à une structure nommée ImgDelayDescr. En regardant la documentation de cette structure, nous pouvons confirmer qu'elle est liée au chargement de DLL paresseux.



typedef struct ImgDelayDescr {
   DWORD        grAttrs;        // 
   RVA          rvaDLLName;     // RVA   dll 
   RVA          rvaHmod;        // RVA  
   RVA          rvaIAT;         // RVA IAT
   RVA          rvaINT;         // RVA INT
   RVA          rvaBoundIAT;    // RVA   IAT
   RVA          rvaUnloadIAT;   // RVA    IAT
   DWORD        dwTimeStamp;    // 0,   ,
                                // O.W. / DLL,   (Old BIND)
   } ImgDelayDescr, * PImgDelayDescr;


Cette structure peut être transmise à __delayLoadHelper2, qui utilisera LoadLibrary/ GetProcAddresspour charger la DLL spécifiée et corriger l'adresse de la fonction importée dans la table d'adresses d'importation de chargement différé (IAT).



FARPROC WINAPI __delayLoadHelper2(
   PCImgDelayDescr pidd,  //     ImgDelayDescr
   FARPROC * ppfnIATEntry //     IAT  
);


En trouvant d'autres références à notre structure ImgDelayDescr, nous pouvons trouver un appel __delayLoadHelper2qui appelle ensuite ResolveDelayLoadedAPI. J'ai renommé le nom de la fonction, les types et les variables pour la rendre plus facile à comprendre.





__delayLoadHelper2et ResolveDelayLoadedAPIchez Ghidra



Excellent! Ceci est cohérent avec ce que nous avons vu dans notre trace de pile ProcMon lorsque Slack a essayé de se charger WINSTA.dll.





__delayLoadHelper2 et ResolveDelayLoadedAPIdans ProcMon.



Ce comportement était uniformément pour WINSTA.dll, LINKINFO.dll, ntshrui.dllet srvcli.dll. La principale différence entre chaque DLL à chargement différé était la DLL «parent». Dans les trois applications:



  • wtsapi32.dll différé chargé WINSTA.dll
  • shell32.dll paresseux chargé LINKINFO.dll
  • LINKINFO.dll différé chargé ntshrui.dll
  • ntshrui.dll différé chargé srvcli.dll


Avez-vous remarqué quelque chose d'intéressant? On dirait qu'il shell32.dlltélécharge LINKINFO.dll, qui télécharge ntshrui.dll, qui enfin télécharge srvcli.dll. Cela nous amène à notre dernière option commune d'usurpation de DLL potentielle - cscapi.dll.



Substitution de DLL dans NetShareGetInfo et NetShareEnum



Je regardais la trace de la pile lorsque Slack essayait de charger cscapi.dllet j'ai vu un appel LoadLibraryExWqui provenait apparemment srvcli.dll. J'ai ouvert la





trace decscapi.dll



la pile au démarragesrvcli.dll dans Ghidra et utilisé Search -> For Strings -> Filter: cscapi.dll. Double-cliquer sur la ligne trouvée et suivre les liens conduit à l' LoadLibraryappel attendu .





srvcli.dllappelle LoadLibrary pourcscapi.dll



renommer la fonction contenant l'appel LoadLibraryet suivre les liens, j'ai eu deux endroits où la fonction est utilisée:







Téléchargements NetShareEnum





cscapi.dll Téléchargements NetShareGetInfocscapi.dll



J'ai vérifié cela avec les programmes PoC qui ont appelé NetShareEnumet NetShareGetInfo:





NetShareEnum.exetéléchargements cscapi.dll





NetShareGetInfo.exetéléchargementscscapi.dll



résultats



Les chemins d'usurpation de DLL suivants sont disponibles dans Slack:



C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL


Les chemins de spoofing DLL suivants sont disponibles dans Microsoft Teams:



C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll


Les chemins de spoofing DLL suivants sont disponibles dans Visual Studio Code:



C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll


En outre, j'ai constaté que les programmes utilisant NetShareEnumet NetShareGetInfooffrent la possibilité de remplacer la DLL sous la forme en cscapi.dllraison de l'appel codé en dur LoadLibrary. J'ai vérifié ce comportement avec Ghidra et PoC.



Conclusion



Pour rappel, l'interception DLL est une méthode par laquelle les attaquants peuvent interférer avec l'exécution de code dans des applications signées / approuvées. J'ai créé des outils pour aider à automatiser la détection des chemins d'interception DLL. À l'aide de cet outil, j'ai découvert des chemins d'interception DLL dans Slack, Microsoft Teams et Visual Studio Code.



J'ai remarqué que les chemins d'interception DLL de ces trois applications se chevauchent et j'en ai recherché la cause. J'ai mis en évidence ma méthode pour comprendre cette coïncidence. J'ai appris le chargement paresseux des DLL et découvert deux appels d'API qui permettent d'intercepter les DLL dans n'importe quel programme qui les appelle:



  • NetShareEnum charges cscapi.dll
  • NetShareGetInfo charges cscapi.dll


Merci d'avoir pris le temps de lire cet article, j'espère que vous avez appris une chose ou deux sur les API Windows, Ghidra, ProcMon, les DLL et l'interception de DLL!



Liens



Un grand bonjour à mes collègues Daniel Heinsen ( @hotnops), Lee Christensen ( @tifkin_) et Matt Hand ( @matterpreter) pour leur aide avec Ghidra / ProcMon!






Vérification des PoC publics pour une utilisation dans le pentesting






Lire la suite:






All Articles