Copié !
Chapitre 05

Système de Fichiers NTFS

ACLs, héritage, Alternate Data Streams, Mark Of The Web - le socle sur lequel repose toute la sécurité des fichiers Windows, et l'un des vecteurs les plus discrets pour dissimuler du code.

INTERMÉDIAIRE OFFENSIF + DÉFENSIF 4 – 5h
5.1

Structure des Répertoires Windows - La Carte du Territoire

Avant NTFS, Windows utilisait FAT (File Allocation Table) - un système hérité de MS-DOS sans permissions, sans journalisation, sans noms longs. Microsoft développe NTFS avec Windows NT 3.1 en 1993, en s'inspirant de HPFS (OS/2) et de DEC VMS, avec trois priorités de conception : sécurité, fiabilité, performances sur grands volumes.

La version moderne - NTFS 3.1 (Windows XP) - est encore utilisée aujourd'hui. Elle introduit les Alternate Data Streams, les Sparse Files, les Reparse Points (liens symboliques, points de montage) et le support de volumes jusqu'à 256 To.

Arborescence standard Windows
Arborescence C:\ annotée - sécuritéARBRE
C:\ ├── Windows\ ← Système d'exploitation │ ├── System32\ ← Binaires 64-bit, DLLs, outils système │ │ ├── config\ ← Hives registre (SAM, SYSTEM, SECURITY...) │ │ ├── drivers\ ← Drivers kernel (.sys) │ │ └── spool\ ← File d'attente d'impression │ ├── SysWOW64\ ← Binaires 32-bit (WOW64 = Windows On Windows 64) │ ├── WinSxS\ ← Side-by-Side Assemblies (versions DLLs) │ └── Temp\ ← Fichiers temporaires système │ ├── Program Files\ ← Applications 64-bit ├── Program Files (x86)\ ← Applications 32-bit │ ├── Users\ │ ├── <Username>\ │ │ ├── AppData\ │ │ │ ├── Local\ ← Données app locales (non synchronisées) │ │ │ ├── LocalLow\ ← Données intégrité basse (IE Protected Mode) │ │ │ └── Roaming\ ← Données synchronisées via profil itinérant │ │ ├── Desktop\ │ │ ├── Documents\ │ │ └── Downloads\ │ ├── Public\ ← ⚠ Partagé - écriture sans admin │ └── Default\ ← Profil template pour nouveaux comptes │ ├── ProgramData\ ← Données app partagées - caché, souvent oublié └── $Recycle.Bin\ ← Un sous-dossier par SID utilisateur
Offensif - Zones d'écriture sans admin

C:\Users\Public\, C:\Windows\Temp\ et %APPDATA% sont des zones d'écriture sans droits admin - cibles privilégiées pour déposer des payloads. C:\ProgramData\ est souvent oublié des audits mais accessible en écriture par défaut pour tous les utilisateurs authentifiés.

SysWOW64 vs System32 - le paradoxe

Contre-intuitivement, System32 contient les binaires 64-bit et SysWOW64 les 32-bit. C'est un héritage : lors du passage à Windows 64-bit, Microsoft a conservé le nom System32 pour les binaires 64-bit afin de ne pas casser la compatibilité des applications qui codaient ce chemin en dur. WOW64 signifie littéralement Windows On Windows 64.

5.2

ACL & ACE - Définitions, Héritage, Types

Chaque objet NTFS (fichier, dossier, lien symbolique) possède un Security Descriptor - exactement le même mécanisme que pour le registre et les processus. C'est le SRM (Security Reference Monitor) du kernel qui évalue les permissions à chaque tentative d'accès.

Structure d'un Security Descriptor
Security Descriptor - anatomie complèteSTRUCTURE
Security Descriptor d'un fichier ├── Owner SID → Propriétaire (peut toujours modifier les permissions) ├── Group SID → Groupe propriétaire (héritage POSIX - peu utilisé sous Windows) ├── DACL → Qui peut faire quoi │ ├── ACE 1 : Allow - SYSTEM - Full Control │ ├── ACE 2 : Allow - Administrators - Full Control │ ├── ACE 3 : Allow - Alice - Read & Execute │ └── ACE 4 : Deny - Bob - Write └── SACL → Ce qui génère des Event IDs d'audit (Event 4663) └── ACE Audit : Everyone - Delete - Success/Failure
Anatomie d'une ACE

Une ACE (Access Control Entry) est l'unité atomique des permissions. Elle contient cinq champs :

ChampValeurs possiblesRôle
TypeAllow · Deny · AuditNature de l'entrée - Audit = ACE de SACL
SIDUtilisateur ou groupeÀ qui s'applique cette ACE
RightsMasque de bits 32-bitQuelles opérations sont concernées
FlagsCI · OI · IO · NPHéritage - vers enfants ? dossiers ? fichiers ?
InheritanceObjectInherit · ContainerInheritPropagation aux fichiers vs dossiers
L'ordre d'évaluation des ACEs - immuable

Le SRM évalue les ACEs dans un ordre précis non modifiable. Dès qu'une ACE satisfait la demande d'accès, l'évaluation stoppe immédiatement.

Ordre d'évaluation SRM - priorité des ACEsLOGIQUE
1. ACEs Deny EXPLICITES ← Priorité maximale - bloque immédiatement 2. ACEs Allow EXPLICITES ← Accordé si le deny n'a pas bloqué 3. ACEs Deny HÉRITÉS ← Deny propagé depuis le parent 4. ACEs Allow HÉRITÉS ← Allow propagé depuis le parent → Un Deny explicite sur l'utilisateur bat un Allow hérité sur son groupe. → Un utilisateur dans Administrators (Allow hérité) + Deny Write explicite = ÉCRITURE REFUSÉE.
Piège classique - Deny explicite vs Allow hérité

Un utilisateur membre du groupe Administrators (Allow Full Control hérité) avec un Deny Write explicite sur son compte → l'écriture est refusée malgré l'appartenance au groupe. Le Deny explicite gagne toujours sur l'Allow hérité. Ce comportement surprend régulièrement les administrateurs qui pensent que les droits Admin écrasent tout.

L'héritage - Propagation des permissions
FlagSignificationPropagé à
CIContainerInheritSous-dossiers
OIObjectInheritFichiers
IOInheritOnlyEnfants uniquement - n'affecte pas l'objet courant
NPNoPropagateInheritLimité à un seul niveau d'enfants
Héritage - propagation et bris d'héritageARBRE
C:\Projet\ ACE: Allow Alice - Full Control (CI)(OI) ├── docs\ ← Hérite Allow Alice - Full Control (I)(CI)(OI) │ └── note.txt ← Hérite Allow Alice - Full Control (I) └── config.ini ← Hérite Allow Alice - Full Control (I) Si on brise l'héritage sur docs\ : C:\Projet\docs\ ← ACEs héritées supprimées OU converties en explicites ← Les nouvelles ACEs sont indépendantes du parent
Inspecter l'héritage - ACEs héritées vs explicitesPOWERSHELL
# Voir si l'héritage est actif sur un dossier $acl = Get-Acl "C:\MonDossier" $acl.AreAccessRulesProtected # True = héritage BRISÉ (les ACEs héritées ne s'appliquent plus) # False = héritage ACTIF (les ACEs du parent se propagent) # Voir les ACEs héritées vs explicites $acl.Access | Select-Object IdentityReference, FileSystemRights, IsInherited, AccessControlType | Format-Table -AutoSize # IsInherited = True → ACE propagée depuis le parent # IsInherited = False → ACE explicite posée directement sur cet objet
5.3

Permissions NTFS Détaillées

Ce que l'interface graphique présente comme "permissions" sont des regroupements de droits atomiques. Chaque permission de haut niveau correspond à un masque de bits combinant plusieurs droits élémentaires.

Droits atomiques par permission de haut niveau
Droit atomique Lecture Écriture Modif. R+X Full
Lire les données / Lister
Lire les attributs
Lire les attributs étendus
Créer des fichiers / Écrire
Créer des dossiers / Ajouter
Écrire les attributs
Supprimer les sous-dossiers
Supprimer
Lire les permissions
Changer les permissions
Prendre possession
Traverser / Exécuter
Masques de bits FileSystemRights
Valeurs numériques des droits FileSystemRightsPOWERSHELL
# Lister toutes les valeurs de l'enum FileSystemRights avec leur masque [System.Security.AccessControl.FileSystemRights] | Get-Member -Static -MemberType Property | Select-Object Name, @{N="Value";E={[int][System.Security.AccessControl.FileSystemRights]::($_.Name)}} | Sort-Object Value # Valeurs principales : # ReadData = 1 # WriteData = 2 # AppendData = 4 # ReadExtendedAttributes= 8 # WriteExtendedAttributes= 16 # ExecuteFile = 32 # DeleteSubdirectoriesAndFiles= 64 # ReadAttributes = 128 # WriteAttributes = 256 # Delete = 65536 # ReadPermissions = 131072 # ChangePermissions = 262144 # TakeOwnership = 524288 # FullControl = 2032127 ← combinaison de tous les droits
5.4

Gestion avec icacls.exe & Get-Acl / Set-Acl

icacls.exe - L'outil natif
icacls - lecture, modification, héritage, sauvegardeCMD
rem ── LECTURE ───────────────────────────────────────────────────── icacls C:\Windows\System32\lsass.exe icacls "C:\Users" /T rem Récursif rem OUTPUT exemple : rem C:\secret.txt rem NT AUTHORITY\SYSTEM:(I)(F) I=Inherited F=Full Control rem BUILTIN\Administrators:(I)(F) rem BUILTIN\Users:(I)(R) R=Read rem ── DROITS - LETTRES DE RACCOURCI ─────────────────────────────── rem F=Full M=Modify RX=Read+Execute R=Read W=Write D=Delete N=None rem ── MODIFICATION ───────────────────────────────────────────────── icacls "C:\Dossier" /grant "Alice:(OI)(CI)RX" rem Allow icacls "C:\Dossier" /deny "Bob:(W)" rem Deny icacls "C:\Dossier" /remove "Alice" rem Supprimer toutes les ACEs rem ── HÉRITAGE ───────────────────────────────────────────────────── icacls "C:\Dossier" /inheritance:d rem Désactiver (conserver ACEs héritées) icacls "C:\Dossier" /inheritance:r rem Désactiver (supprimer ACEs héritées) icacls "C:\Dossier" /inheritance:e rem Réactiver rem ── SAUVEGARDE / RESTAURATION ─────────────────────────────────── icacls "C:\Dossier" /save acls_backup.txt /T icacls "C:\Dossier" /restore acls_backup.txt rem ── RÉINITIALISER à l'état par défaut ──────────────────────────── icacls "C:\Dossier" /reset /T
Get-Acl / Set-Acl - Approche PowerShell
Lecture, ajout Allow, ajout Deny, suppression ACE, changement propriétairePOWERSHELL
# ── LECTURE ───────────────────────────────────────────────────────── $acl = Get-Acl -Path "C:\Windows\System32\lsass.exe" $acl.Access | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags | Format-Table -AutoSize $acl.Owner # Voir le propriétaire # ── AJOUTER UNE ACE ALLOW ─────────────────────────────────────────── $acl = Get-Acl "C:\TestDossier" $rule = New-Object System.Security.AccessControl.FileSystemAccessRule( "restricteduser", # Identité "ReadAndExecute", # Droits "ContainerInherit,ObjectInherit", # Héritage "None", # Propagation "Allow" # Type ) $acl.AddAccessRule($rule) Set-Acl -Path "C:\TestDossier" -AclObject $acl # ── AJOUTER UN DENY ───────────────────────────────────────────────── $deny = New-Object System.Security.AccessControl.FileSystemAccessRule( "restricteduser", "Write,Delete", "None", "None", "Deny" ) $acl.AddAccessRule($deny) Set-Acl -Path "C:\TestDossier\secret.txt" -AclObject $acl # ── SUPPRIMER UNE ACE ─────────────────────────────────────────────── $acl = Get-Acl "C:\TestDossier" $toRemove = $acl.Access | Where-Object { $_.IdentityReference -match "restricteduser" -and $_.AccessControlType -eq "Allow" } $acl.RemoveAccessRule($toRemove) Set-Acl -Path "C:\TestDossier" -AclObject $acl # ── CHANGER LE PROPRIÉTAIRE (nécessite SeRestorePrivilege ou admin) ─ $acl = Get-Acl "C:\TestDossier" $owner = New-Object System.Security.Principal.NTAccount("Administrators") $acl.SetOwner($owner) Set-Acl -Path "C:\TestDossier" -AclObject $acl
Offensif - SeBackupPrivilege & SeRestorePrivilege

Les membres du groupe Backup Operators disposent de SeBackupPrivilege et SeRestorePrivilege - ces deux privilèges permettent de lire et écrire n'importe quel fichier indépendamment de son ACL NTFS. C'est le bypass ACL par excellence, abordé en profondeur au chapitre 10.

5.5

ADS - Alternate Data Streams

Les Alternate Data Streams sont une caractéristique fondamentale de NTFS introduite dès NT 3.1 - conçue originellement pour la compatibilité avec le système de fichiers HFS d'Apple Macintosh via les services AppleTalk. Sur HFS, chaque fichier avait deux "fourches" : une pour les données, une pour les ressources (icône, métadonnées). NTFS a implémenté une abstraction similaire via les flux de données nommés.

Structure interne d'un fichier NTFS
Flux de données d'un fichier NTFSSTRUCTURE
fichier.txt ├── ::$DATA ← Flux principal - contenu visible, sans nom ├── :Zone.Identifier:$DATA ← ADS créé par Windows lors d'un téléchargement ├── :thumb:$DATA ← ADS créé par l'Explorateur (miniature image) ├── :SecondFlux:$DATA ← ADS personnalisé (vous ou un malware) └── ::$INDEX_ALLOCATION ← Flux spécial pour les dossiers (MFT) Syntaxe d'accès : NomFichier:NomFlux C:\test.txt:secret
Créer, lire et lister des ADSPOWERSHELL
# Créer un ADS manuellement Set-Content -Path "C:\test.txt" -Value "Contenu visible" Set-Content -Path "C:\test.txt:secret" -Value "Contenu caché dans l'ADS" # Lire le fichier normalement - ADS totalement invisible Get-Content "C:\test.txt" # → "Contenu visible" # Lire l'ADS directement Get-Content "C:\test.txt:secret" # → "Contenu caché dans l'ADS" # La taille du fichier n'inclut PAS l'ADS (Get-Item "C:\test.txt").Length # → taille du flux principal uniquement ! # ── LISTER TOUS LES STREAMS D'UN FICHIER ──────────────────────────── Get-Item -Path "C:\test.txt" -Stream * # → Stream :$DATA Length 17 # → Stream secret Length 28 # ── ÉQUIVALENT CMD.EXE ────────────────────────────────────────────── # dir /R C:\test.txt ← Affiche tous les streams avec leur taille # more < C:\test.txt:secret
Invisible pour la plupart des outils

Un ADS est invisible pour l'Explorateur Windows (taille masquée, stream non affiché), pour dir sans /R, et pour la majorité des antivirus legacy qui ne scannent que le flux principal ::$DATA. De plus, les ADS ne survivent pas aux copies sur FAT32 ou vers certains partages SMB - ils sont silencieusement perdus.

5.6

MOTW - Mark Of The Web

Le Mark Of The Web (MOTW) est un mécanisme introduit avec Windows XP SP2 (2004) qui consiste à taguer automatiquement tout fichier téléchargé depuis Internet ou reçu d'une source non fiable. Ce tag est implémenté comme un ADS spécifique nommé Zone.Identifier.

Structure du Zone.Identifier
Contenu d'un ADS Zone.IdentifierINI
[ZoneTransfer] ZoneId=3 ReferrerUrl=https://github.com/gentilkiwi/mimikatz/releases HostUrl=https://objects.githubusercontent.com/mimikatz_trunk.zip
Zones de sécurité Windows
ZoneIdZoneDescription
0Mon OrdinateurFichiers locaux - confiance totale
1Intranet localRéseau local d'entreprise
2Sites de confianceWhitelist manuelle
3InternetToute source internet - zone par défaut des téléchargements
4Sites sensiblesBlacklist - restrictions maximales
Ce que le MOTW déclenche (ZoneId=3)
Mécanismes activés par le MOTW + gestion PowerShellPOWERSHELL
# Fichier avec ZoneId=3 active : # SmartScreen → Alerte "Fichier téléchargé d'Internet" # Office Protected → Documents Office ouverts en lecture seule # AppLocker → Peut bloquer l'exécution selon la politique # Windows Defender → Analyse renforcée (AMSI activé même pour scripts) # UAC Elevation → Confirmation supplémentaire demandée # Voir le MOTW d'un fichier téléchargé Get-Content "C:\Users\Alice\Downloads\outil.exe:Zone.Identifier" # Supprimer le MOTW (débloquer le fichier) Remove-Item "C:\fichier.exe:Zone.Identifier" -Force # Équivalent GUI : clic droit → Propriétés → "Débloquer" # Via cmdlet PowerShell Unblock-File -Path "C:\fichier.exe" # Vérifier si un fichier a un MOTW [bool](Get-Item "C:\fichier.exe" -Stream "Zone.Identifier" -ErrorAction SilentlyContinue)
Bypass MOTW - Techniques utilisées par les attaquants

Le MOTW est un rempart important mais contournable. MITRE ATT&CK référence ces techniques sous T1553.005.

TechniqueMécanismeExemples réels
Conteneurs non-NTFS .iso, .vhd, .img montés comme lecteur - fichiers extraits sans MOTW Emotet, BazarLoader distribuaient via .iso
Archives corrompues .zip corrompus lus par des outils tiers qui n'étendent pas le MOTW aux fichiers extraits 7-zip versions anciennes
Copie via SMB Fichiers copiés via chemin UNC \\partage\ - pas de MOTW selon la configuration Livraison en réseau interne
Suppression directe Remove-Item "fichier:Zone.Identifier" - si accès en écriture disponible Post-exploitation locale
5.7

ADS comme Vecteur de Dissimulation de Code

Technique 1 - Stocker un exécutable dans un ADS
Cacher un binaire dans un ADS + extraction et exécutionPOWERSHELL
# Écrire un exécutable dans l'ADS d'un fichier texte innocent $malContent = [System.IO.File]::ReadAllBytes("C:\Tools\outil.exe") [System.IO.File]::WriteAllBytes("C:\Users\Public\rapport.txt:hidden", $malContent) # Le fichier rapport.txt affiche seulement quelques Ko dans l'Explorateur (Get-Item "C:\Users\Public\rapport.txt").Length # → taille du texte uniquement # ── EXÉCUTION depuis l'ADS ─────────────────────────────────────────── # Méthode 1 : wmic (Windows Management Instrumentation) wmic process call create "C:\Users\Public\rapport.txt:hidden" # Méthode 2 : PowerShell - extraire puis exécuter $ads = Get-Content "C:\Users\Public\rapport.txt:hidden" -Encoding Byte -Raw [System.IO.File]::WriteAllBytes("$env:TEMP\tmp_extract.exe", $ads) Start-Process "$env:TEMP\tmp_extract.exe"
Technique 2 - Exécuter un script PowerShell depuis un ADS
Script PowerShell stocké et exécuté depuis un ADSPOWERSHELL
# Écrire un script PS dans un ADS Set-Content -Path "C:\Windows\Tasks\schtask.txt:payload" -Value @' # Simulated payload skeleton $ip = "192.168.56.100"; $port = 4444 Write-Host "[PAYLOAD] Connexion vers $ip:$port simulée" '@ # Exécuter directement depuis l'ADS - aucun fichier .ps1 créé powershell.exe -Command "Get-Content 'C:\Windows\Tasks\schtask.txt:payload' | Invoke-Expression"
Technique 3 - ADS sur un dossier
ADS attaché à un dossier (pas seulement les fichiers)POWERSHELL
# Les ADS existent aussi sur les dossiers Set-Content -Path "C:\Windows\Temp:hiddenkey" -Value "S3cr3tD4t4" Get-Content "C:\Windows\Temp:hiddenkey" # → "S3cr3tD4t4" - invisible dans dir, Get-ChildItem, Explorateur
Détection des ADS non standard
Script de détection d'ADS suspects - scan récursif avec heuristiquesPOWERSHELL
function Find-SuspiciousADS { param( [string]$Path = "C:\Users", [string[]]$WhitelistedStreams = @( "Zone.Identifier", "SmartScreen", "encryptable", "{4c8cc155-6c1e-11d1-8e41-00c04fb9386d}" # Miniature Explorateur ) ) Write-Host "`n=== Scan ADS : $Path ===" -ForegroundColor Cyan Get-ChildItem -Path $Path -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $file = $_.FullName try { $streams = Get-Item -Path $file -Stream * -ErrorAction Stop | Where-Object { $_.Stream -ne ':$DATA' } foreach ($stream in $streams) { $nom = $stream.Stream.Trim(":") $size = $stream.Length if ($WhitelistedStreams -contains $nom) { continue } $alert = @() if ($size -gt 10240) { $alert += "Taille > 10 Ko" } if ($nom -match "^\{[0-9a-f-]{36}\}$") { $alert += "GUID inconnu" } if ($nom -notmatch "^[a-zA-Z0-9._-]+$") { $alert += "Nom inhabituel" } [PSCustomObject]@{ Fichier = $file Stream = $nom Taille = "$size bytes" AlerteType = if ($alert) { $alert -join " | " } else { "Inconnu - Vérifier" } } } } catch {} } | Format-Table -AutoSize -Wrap } Find-SuspiciousADS -Path "C:\Users\Public" Find-SuspiciousADS -Path "C:\Windows\Temp"
Défensif - Headers PE dans un ADS

Les premiers bytes d'un ADS permettent de détecter des exécutables cachés : header MZ (0x4D 0x5A) = fichier PE (EXE/DLL). Un ADS avec un header MZ sur un fichier texte est un indicateur de compromission critique. Coupler cette détection avec Sysmon Event ID 11 (File Create) en filtrant les chemins contenant : couvre la création en temps réel.

5.8

Audit Fichiers - Event ID 4663 & Détection ADS

L'Event ID 4663 est généré quand une tentative d'accès à un objet (fichier, dossier, clé de registre) est faite - mais uniquement si une SACL est configurée sur l'objet ET que la politique d'audit est activée. Sans ces deux conditions, rien n'est journalisé.

Configuration en deux étapes obligatoires
Activer l'audit filesystem + configurer la SACLPOWERSHELL
# ── ÉTAPE 1 : Activer la politique d'audit globale ────────────────── auditpol /set /subcategory:"File System" /success:enable /failure:enable auditpol /set /subcategory:"Handle Manipulation" /success:enable /failure:enable # Vérifier auditpol /get /subcategory:"File System" # ── ÉTAPE 2 : Configurer la SACL sur le dossier/fichier critique ──── $acl = Get-Acl -Path "C:\SensitiveData" -Audit $auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule( "Everyone", # Qui surveiller "ReadData,WriteData,Delete", # Quels accès auditer "ContainerInherit,ObjectInherit", # Propagation aux enfants "None", "Success,Failure" # Auditer réussites ET échecs ) $acl.AddAuditRule($auditRule) Set-Acl -Path "C:\SensitiveData" -AclObject $acl
Anatomie d'un Event 4663
Structure Event ID 4663 - champs clésLOG
Event ID : 4663 Message : An attempt was made to access an object. Subject: Account Name : alice Account Domain : WORKSTATION Logon ID : 0x3E7 Object: Object Type : File Object Name : C:\SensitiveData\passwords.txt ← Fichier accédé Handle ID : 0x298 Process Information: Process ID : 0x1A4 Process Name : C:\Windows\System32\notepad.exe ← Quel processus Access Request Information: Accesses : ReadData (or ListDirectory) ← Type d'accès Access Mask : 0x1
Requêter les Event 4663 - filtrage et détection ADSPOWERSHELL
# ── Tous les accès fichiers dans les dernières 24h ────────────────── Get-WinEvent -FilterHashtable @{ LogName = 'Security' Id = 4663 StartTime = (Get-Date).AddHours(-24) } -ErrorAction SilentlyContinue | ForEach-Object { $xml = [xml]$_.ToXml() $data = $xml.Event.EventData.Data [PSCustomObject]@{ Heure = $_.TimeCreated Compte = ($data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text' Fichier = ($data | Where-Object {$_.Name -eq 'ObjectName'}).'#text' Processus = ($data | Where-Object {$_.Name -eq 'ProcessName'}).'#text' Acces = ($data | Where-Object {$_.Name -eq 'Accesses'}).'#text' } } | Where-Object { $_.Compte -notin @("SYSTEM","MsMpEng","TrustedInstaller") } | Format-Table -AutoSize # ── Détection spécifique des accès ADS ────────────────────────────── # Un accès ADS contient ":" dans le chemin (hors lettre de lecteur) Get-WinEvent -FilterHashtable @{LogName='Security';Id=4663;StartTime=(Get-Date).AddHours(-24)} ` -ErrorAction SilentlyContinue | ForEach-Object { $xml = [xml]$_.ToXml() $obj = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'ObjectName'}).'#text' if ($obj -match "^[A-Z]:\\.*:[^\\]+$") { $data = $xml.Event.EventData.Data [PSCustomObject]@{ Heure = $_.TimeCreated Compte = ($data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text' ADS = $obj Processus = ($data | Where-Object {$_.Name -eq 'ProcessName'}).'#text' } } } | Where-Object { $_ -ne $null } | Format-Table -AutoSize
TP 1

ACE Restrictive sur restricteduser

TP 05-A Créer un fichier, appliquer Allow + Deny, vérifier via WinRM, auditer avec Event 4663 INTERMÉDIAIRE
Objectifs
  1. Créer un fichier et appliquer une ACE Allow ReadAndExecute à restricteduser
  2. Tester la lecture depuis une session WinRM - confirmer le succès
  3. Ajouter un Deny Write+Delete - tester l'écriture et la suppression
  4. Configurer une SACL d'audit et observer les Event 4663 générés
Créer fichier + ACE Allow + test lecture WinRMPOWERSHELL
# ── En tant qu'Administrateur ────────────────────────────────────── New-Item -ItemType Directory -Path "C:\LabACL" -Force | Out-Null Set-Content -Path "C:\LabACL\confidentiel.txt" -Value "DONNEES CONFIDENTIELLES" # Voir les ACLs initiales Get-Acl "C:\LabACL\confidentiel.txt" | Format-List # Ajouter ACE Allow ReadAndExecute pour restricteduser $acl = Get-Acl "C:\LabACL\confidentiel.txt" $allowRule = New-Object System.Security.AccessControl.FileSystemAccessRule( "restricteduser", "ReadAndExecute", "None", "None", "Allow" ) $acl.AddAccessRule($allowRule) Set-Acl -Path "C:\LabACL\confidentiel.txt" -AclObject $acl # Test lecture depuis WinRM $secPwd = ConvertTo-SecureString "Restricted@2024!" -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential("restricteduser", $secPwd) $session = New-PSSession -ComputerName localhost -Credential $cred Invoke-Command -Session $session -ScriptBlock { try { $c = Get-Content "C:\LabACL\confidentiel.txt" -ErrorAction Stop Write-Host "Lecture reussie : $c" -ForegroundColor Green } catch { Write-Host "Lecture refusee : $_" -ForegroundColor Red } }
ACE Deny explicite + vérification de la prioritéPOWERSHELL
$acl = Get-Acl "C:\LabACL\confidentiel.txt" $denyRule = New-Object System.Security.AccessControl.FileSystemAccessRule( "restricteduser", "Write,Delete,AppendData", "None", "None", "Deny" ) $acl.AddAccessRule($denyRule) Set-Acl -Path "C:\LabACL\confidentiel.txt" -AclObject $acl # Voir les ACEs complètes (Allow + Deny) Get-Acl "C:\LabACL\confidentiel.txt" | Select-Object -ExpandProperty Access | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited | Format-Table -AutoSize # Tests depuis la session WinRM Invoke-Command -Session $session -ScriptBlock { # Test 1 : Lecture → doit réussir (Allow ReadAndExecute) try { Get-Content "C:\LabACL\confidentiel.txt" -EA Stop | Out-Null Write-Host "[1] Lecture : reussie (attendu)" -ForegroundColor Green } catch { Write-Host "[1] Lecture : refusee (inattendu)" -ForegroundColor Red } # Test 2 : Ecriture → doit ECHOUER (Deny Write) try { Add-Content "C:\LabACL\confidentiel.txt" "test" -EA Stop Write-Host "[2] Ecriture : reussie (inattendu)" -ForegroundColor Red } catch { Write-Host "[2] Ecriture : refusee - Deny gagne (attendu)" -ForegroundColor Green } # Test 3 : Suppression → doit ECHOUER (Deny Delete) try { Remove-Item "C:\LabACL\confidentiel.txt" -EA Stop Write-Host "[3] Suppression: reussie (inattendu)" -ForegroundColor Red } catch { Write-Host "[3] Suppression: refusee - Deny gagne (attendu)" -ForegroundColor Green } } Remove-PSSession $session
Configurer SACL + générer des accès + observer les logsPOWERSHELL
# Activer l'audit filesystem auditpol /set /subcategory:"File System" /success:enable /failure:enable | Out-Null # Ajouter la SACL d'audit $acl = Get-Acl "C:\LabACL\confidentiel.txt" -Audit $auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule( "Everyone", "ReadData,WriteData,Delete", "None", "None", "Success,Failure" ) $acl.AddAuditRule($auditRule) Set-Acl -Path "C:\LabACL\confidentiel.txt" -AclObject $acl # Générer des accès depuis WinRM $session = New-PSSession -ComputerName localhost -Credential $cred Invoke-Command -Session $session -ScriptBlock { Get-Content "C:\LabACL\confidentiel.txt" -EA SilentlyContinue Add-Content "C:\LabACL\confidentiel.txt" "test" -EA SilentlyContinue } Remove-PSSession $session Start-Sleep 2 # Chercher les Event 4663 générés Get-WinEvent -FilterHashtable @{LogName='Security';Id=4663;StartTime=(Get-Date).AddMinutes(-3)} ` -EA SilentlyContinue | ForEach-Object { $xml = [xml]$_.ToXml() $data = $xml.Event.EventData.Data $obj = ($data | Where-Object {$_.Name -eq 'ObjectName'}).'#text' if ($obj -match "confidentiel") { Write-Host "[4663] $($_.TimeCreated) | $($data | Where-Object {$_.Name -eq 'SubjectUserName'} | Select -Expand '#text') | $($data | Where-Object {$_.Name -eq 'Accesses'} | Select -Expand '#text')" -ForegroundColor Yellow } }
TP 2

ADS Caché & Détection

TP 05-B Simuler des payloads dissimulés dans des ADS, détecter avec PowerShell, identifier les headers PE AVANCÉ
Objectifs
  1. Créer plusieurs ADS simulant des techniques d'attaque réelles
  2. Confirmer l'invisibilité des ADS pour les outils standards
  3. Détecter tous les ADS avec dir /R et Get-Item -Stream *
  4. Identifier les headers PE dans les ADS binaires
Injecter 4 ADS - script PS, binaire MZ, clé, MOTWPOWERSHELL
$targetDir = "C:\LabADS" New-Item -ItemType Directory -Path $targetDir -Force | Out-Null # Fichiers leurres totalement innocents Set-Content "$targetDir\rapport_mensuel.txt" -Value "Rapport de performance - Octobre 2024" Set-Content "$targetDir\config.ini" -Value "[Settings]`nDebugMode=0" Set-Content "$targetDir\readme.txt" -Value "Documentation du projet" # ADS 1 : Payload PowerShell caché dans un fichier texte Set-Content -Path "$targetDir\rapport_mensuel.txt:update" -Value @' # Simulated payload - reverse shell skeleton $ip = "192.168.56.100"; $port = 4444 Write-Host "[PAYLOAD] Connexion vers $ip:$port simulee" '@ # ADS 2 : Header MZ (signature PE d'un exécutable) $fakeExe = [byte[]](0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00) [System.IO.File]::WriteAllBytes("$targetDir\config.ini:svchost", $fakeExe) # ADS 3 : Clé de chiffrement simulée Set-Content -Path "$targetDir\readme.txt:aes_key" -Value "4A7F9C2E1B8D6F3A5E0C7B4D2F9A1E8C" # ADS 4 : Zone.Identifier légitime (simulé comme si téléchargé) Set-Content -Path "$targetDir\readme.txt:Zone.Identifier" -Value "[ZoneTransfer]`nZoneId=3" Write-Host "ADS de simulation crees dans $targetDir" -ForegroundColor Yellow # Confirmer l'invisibilité - Get-ChildItem ne montre RIEN d'anormal Write-Host "`n[Get-ChildItem - vue standard] :" Get-ChildItem $targetDir | Select-Object Name, Length
dir /R + PowerShell + détection header PE MZPOWERSHELL
# Méthode 1 : dir /R (cmd.exe) - liste tous les streams Write-Host "`n[dir /R] :" -ForegroundColor Cyan cmd /c "dir /R $targetDir" # Méthode 2 : PowerShell - inventaire avec analyse heuristique Write-Host "`n[Analyse PowerShell] :" -ForegroundColor Cyan $legitStreams = @("Zone.Identifier", "SmartScreen", "encryptable") $results = Get-ChildItem $targetDir | ForEach-Object { $file = $_.FullName $streams = Get-Item -Path $file -Stream * -EA SilentlyContinue | Where-Object { $_.Stream -ne ':$DATA' } foreach ($s in $streams) { $nom = $s.Stream.Trim(":") $size = $s.Length # Détecter un header PE (MZ = 0x4D 0x5A) $isPE = $false try { $bytes = [System.IO.File]::ReadAllBytes("$file`:$nom") if ($bytes.Count -ge 2 -and $bytes[0] -eq 0x4D -and $bytes[1] -eq 0x5A) { $isPE = $true } } catch {} $alerte = @() if ($isPE) { $alerte += "HEADER PE DETECTE" } if ($size -gt 5000) { $alerte += "Taille > 5 Ko" } if ($nom -notin $legitStreams) { $alerte += "Stream non standard" } if ($nom -match "svchost|update|sys") { $alerte += "Nom trompeur (mimicry)" } [PSCustomObject]@{ Fichier = Split-Path $file -Leaf Stream = $nom Taille = "$size bytes" Alerte = if ($alerte) { $alerte -join " | " } else { "Normal" } } } } $results | Format-Table -AutoSize -Wrap # Afficher le contenu des ADS suspects Write-Host "`n=== CONTENU DES ADS SUSPECTS ===" -ForegroundColor Red $results | Where-Object { $_.Alerte -ne "Normal" } | ForEach-Object { $fichier = "$targetDir\$($_.Fichier)" $stream = $_.Stream Write-Host "`n[ADS: $($_.Fichier):$stream]" -ForegroundColor Yellow try { Get-Content "$fichier`:$stream" -EA Stop } catch { # Binaire - afficher les premiers bytes en hex $bytes = [System.IO.File]::ReadAllBytes("$fichier`:$stream") Write-Host "BINAIRE (hex): $($bytes | ForEach-Object { '{0:X2}' -f $_ } | Select-Object -First 16 | Join-String ' ')" } }
Suppression des dossiers de labPOWERSHELL
Remove-Item -Path "C:\LabADS" -Recurse -Force -EA SilentlyContinue Remove-Item -Path "C:\LabACL" -Recurse -Force -EA SilentlyContinue Write-Host "Nettoyage termine" -ForegroundColor Green

Résumé - Points clés à retenir

Architecture NTFS
Security Descriptor sur chaque objet

Chaque fichier, dossier et lien symbolique possède une DACL (permissions) et une SACL (audit). L'ordre d'évaluation SRM est immuable : Deny explicite → Allow explicite → Deny hérité → Allow hérité. Un Deny explicite bat toujours un Allow hérité, même via Administrators.

ADS & MOTW
Flux invisibles, vecteurs actifs

Les ADS sont invisibles pour l'Explorateur, dir sans /R, et les antivirus legacy. Le MOTW est lui-même un ADS - le supprimer débloque le fichier silencieusement. Les ADS ne survivent pas aux copies sur FAT32.

Pour l'Offensif
Surfaces d'écriture et dissimulation

C:\Users\Public\, %TEMP%, %APPDATA% = écriture sans admin. SeBackupPrivilege = bypass total des ACLs (chapitre 10). Bypass MOTW via .iso/.vhd. Stocker un exécutable dans un ADS - taille du fichier parent inchangée, header MZ détectable.

Pour le Défensif
Audit et détection

Event 4663 nécessite deux conditions : politique d'audit activée + SACL sur l'objet. Scanner les ADS avec Get-Item -Stream * ou dir /R. Vérifier les deux premiers bytes - header 4D 5A dans un ADS = indicateur de compromission critique.

  • Identifier les zones d'écriture sans admin dans l'arborescence Windows
  • Expliquer la différence entre DACL et SACL dans un Security Descriptor
  • Appliquer l'ordre d'évaluation SRM et prédire le résultat d'un Deny explicite
  • Utiliser icacls et Get-Acl/Set-Acl pour gérer les permissions
  • Créer, lire et lister des ADS avec Set-Content et Get-Item -Stream *
  • Expliquer l'origine du MOTW et ce que ZoneId=3 déclenche
  • Supprimer un MOTW avec Remove-Item "fichier:Zone.Identifier"
  • Identifier les trois principales techniques de bypass MOTW
  • Détecter un header PE (4D 5A) dans un ADS via lecture des bytes bruts
  • Configurer une SACL et requêter les Event 4663 pour détecter les accès ADS
Prochain chapitre

Le Chapitre 6 - Protocole SMB & Partages Réseau prolonge naturellement ce chapitre : les permissions NTFS que tu viens d'apprendre interagissent directement avec les permissions de partage SMB, et leurs interactions créent des vulnérabilités classiques que tout pentester doit maîtriser.