Comment importer un fichier .evtx dans ELK depuis Linux via Python ?
Sommaire
I. Présentation
Dans cet article, nous allons apprendre à importer des logs au format ".evtx" dans un SIEM ELK par l'intermédiaire d'un système Linux, nous utiliserons pour cela un script écrit en Python3.
À plusieurs reprises ces derniers mois, j'ai eu le besoin d'importer des logs Windows que j'avais à analyser "à froid" dans un SIEM ELK, c'est-à-dire sans accès direct au système les ayant produits. Il est vrai que les outils natifs de Windows se prêtent assez peu au rôle qui est le leur, à savoir rechercher efficacement des informations dans les milliers ou millions d'évènements qui peuvent se produire sur un système. C'est pourquoi je préfère généralement utiliser ELK plutôt que de réimporter mes fichiers .evtx dans un autre système Windows.
Je vous propose donc une méthode fonctionnelle que j'utilise à présent fréquemment pour effectuer cette tâche depuis un système Linux. Cet article se base sur un script proposé par le site https://dragos.com que nous allons remettre au goût du jour et améliorer. Vous pourrez retrouver ce script amélioré sur notre dépôt GitHub. Également, j'ai à ma disposition un socle ELK sous Docker qui dispose d'une configuration minimaliste et issue du docker-compose proposé par le dépôt GitHub suivant : https://github.com/deviantony/docker-elk.
II. EVTX et ELK : quelques rappels
Commençons par faire un bref rappel de ce que sont les logs EVTX. Les fichiers qui disposent d'une extension ".evtx" sous Windows sont tout simplement les journaux d'évènements produits par le système. Nous pouvons les parcourir les journaux d'un système à l'aide de l'Observateur d'évènements natif de Windows, mais aussi les transporter et importer (ou simplement sauvegarder) dans d'autres outils grâce à ce format de fichier. Il ne s'agit pas de fichier "texte", ils disposent d'un format bien spécifique qui nécessite des outils sachant les traiter.
Un SIEM (Security Information and Event Management) est une plateforme (ensemble d'outils) qui permet d'agréger, traiter, analyser et filtrer en temps réel les journaux d'évènements et de sécurité, mais aussi recevoir des alertes de sécurité. Son rôle est de centraliser les journaux d'évènements de plusieurs systèmes pour en simplifier le traitement.

Aujourd'hui, les SIEM ont une grande importance au niveau de la sécurité du système d'information. C'est via les logs que nous pouvons effectuer une analyse en temps réel ou a posteriori sur les cyberattaques et les évènements de sécurité.
Dans ce contexte, la suite ELK (ElasticSearch, Logstach, Kibana) est un socle technique qui peut jouer ce rôle de SIEM, puisqu'il s'agit d'un ensemble d'outils en charge de la réception, du stockage, du traitement des recherches et de la visualisation des journaux d'évènements. Des alternatives classiques à ELK pour remplir ce rôle sont Splunk ou Graylog.
III. Script d'import des .evtx vers ELK
Passons à présent à la procédure d'import des fichiers ".evtx". En prérequis pour effectuer cette opération, il vous faut :
- Un accès réseau au port TCP/9200 de votre instance ElasticSearch.
- Les identifiants d'accès si nécessaire (peut aussi être un Bearer ou clé API, mais nécessitera une modification du script).
- Votre fichier avec l'extension ".evtx".
- Un OS Linux avec Python3.
- Un ELK en version 8 ou plus, sinon le script indiqué dans le paragraphe suivant pourra être utilisé tel quel.
Comme indiqué en introduction, j'ai repris un script venant du dépôt https://github.com/dgunter/evtxtoelk qui présente quelques limitations et instructions obsolètes. Vous pourrez retrouver notre script mis à jour et amélioré sur notre GitHub :

Nous allons dans un premier temps voir comment utiliser ce script pour ensuite étudier son fonctionnement, notamment pour adapter son utilisation à votre contexte. Pour qu'il fonctionne correctement, il est nécessaire d'installer les bibliothèques suivantes :
# Installation des dépendances Python
pip install python-evtx elasticsearch xmltodict
Voici comment s'y prendre pour importer le contenu d'un fichier "Security.evtx" vers un ElasticSearch protégé en Auth Basic avec le login "elastic" et le mot de passe "changeme" (ce qui n'est pas très original, je vous l'accorde) :
# Import des logs au format EVTX vers ELK via evtxtoelk.py
$ python3 evtxtoelk.py -f SECURITY-DC.evtx -k http://127.0.0.1:9200 -u elastic -p changeme
Bulking final set of records to ES: 293
Un problème corrigé dans ce script, notamment pour qu'il soit compatible avec ElasticSearch en version 8 et supérieures, est la suppression de la clé event_data["_type"] qui causait l'erreur suivante :
elasticsearch.BadRequestError: BadRequestError(400, 'illegal_argument_exception', 'Action/metadata line [1] contains an unknown parameter [_type]')
La seconde est l'ajout de l'authentification Basic Auth, qui n'était pas implémentée et qui causait l'erreur suivante :
elasticsearch.AuthenticationException: AuthenticationException(401, 'security_exception', 'missing authentication credentials for REST request [/_bulk]')
Hormis ces deux modifications, la logique du script reste la même. Suite à la phase classique de récupération des arguments, une connexion à l'instance Elasticsearch est établie à l'aide de l'URL de Kibana, du nom d'utilisateur, et du mot de passe. Le script ouvre ensuite le fichier EVTX et le transforme en XML, puis il utilise "xmltodict" pour convertir ce XML en un dictionnaire Python. Chaque événement est analysé pour extraire les informations importantes (date) et les rendre utilisables par Elasticsearch.
Le champ "@timestamp" est formaté en utilisant un format compatible ISO 8601. Si les événements contiennent des données spécifiques dans le champ "EventData", elles sont converties pour être plus facilement indexables (conversion de listes en dictionnaires nommés).
Les événements formatés sont ajoutés à une file d'attente ("bulk_queue"). Lorsque cette file d'attente atteint une certaine taille définie (argument "--size"), les événements sont envoyés en bloc vers Elasticsearch. Le script utilise la méthode "bulk_to_elasticsearch" pour envoyer les événements en une seule requête "bulk" à Elasticsearch, ce qui améliore les performances. Si l'envoi échoue, une erreur est affichée et le script s'arrête. Une fois que tous les événements ont été traités, si la file d'attente contient encore des événements, ils sont envoyés à Elasticsearch dans une dernière requête "bulk".
IV. Visualisation des données dans le Discover ELK
Une fois que l'import a été réalisé grâce à ce script, il est nécessaire de se rendre au niveau de l'interface Kibana dans "Management > Index Management" et de vérifier que vous avez bien un index nommé "hostlog".

Pour information, le nom de l'index qui sera ajouté dans ELK peut-être modifié lors de l'import avec l'option "-i <nom_index>" :
$ python3 evtxtoelk.py -f SECURITY-DC.evtx -k http://127.0.0.1:9200 -u elastic -p changeme -i monindex
Si c'est bien le cas et que vous souhaitez visualiser vos données dans la fonction principale de recherche d'ELK (Discover), vous pourrez vous rendre, toujours dans le menu "Management", dans "Data Views" et cliquer sur "Create Data Views" :

Ici, vous pourrez donner un nom à votre vue et sélectionner l'index qu'il exposera parmi ceux présents dans "All sources". Si vous avez laissé l'index par défaut du script, saisissez "hostlogs" et cliquez sur "Save data view to Kibana" :

Vous pourrez ensuite vous rendre dans le menu "Analytics > Discover" et sélectionner votre vue pour visualiser et rechercher dans les données importées.

À présent, les données de votre fichier ".evtx" sont bien dans votre ELK, que vous pouvez utiliser pour simplifier leur analyse. Il est à noter que vous pouvez de la même manière importer plusieurs fichiers ".evtx", provenant de plusieurs machines différentes, dans le même index.
V. Conclusion
J'espère que la petite remise au goût du jour de ce script pourra vous aider. Pour ma part, elle suffit aux besoins que j'ai dans la plupart des cas, mais peut nécessiter des adaptations en fonction des contextes, notamment pour des instances ELK d'entreprise parfois plus complexes.
Pour corriger et mettre à jour le script initial, je me suis notamment aidé de la documentation ElasticSearch qui est très claire et comporte des exemples de code Python. Cela peut vous être utile pour adapter le script à votre contexte. Par exemple si l'authentification est faite via Bearer ou clé API au lieu d'un Auth Basic ou si vous utilisez le HTTPS et souhaitez vérifier le certificat serveur.
- elastic.co : Elastic Docs - Elasticsearch Python Client
Vous pouvez récupérer notre script pour y ajouter vos propres modifications en fonction de votre contexte.

