Résolu Filtrer EventID 4662 par "Account Name" ou "SubjectUserName"

Plus d'informations
il y a 11 mois 2 semaines #34651 par David M
Mon objectif : je vise à distinguer les synchronisations normales (ou "légitimes") entre contrôleurs de domaine et celles qui résultent d'une attaque DCSync.

En me fondant sur diverses sources en ligne, j'ai appris qu'il faut passer (en gros) par trois étapes pour ce faire :

1. Filtrer toutes les entrées (EventID) 4662 dans le journal de Sécurité

2. Filtrer toutes les entrées qui contiennent l'un des GUID suivants dans les propriétés ou la section "message" :

1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
1131f6ad-9c07-11d1-f79f-00c04fc2dcd2

(certaines sources ajoutent le GUID suivant, d'autres semblent estimer qu'il n'est pas essentiel)

89e95b76-444d-4c62-991a-0facbeda640c


Certaines sources suggèrent de filtrer sur "ObjectServer = DS" ou "Access Mask = 0x100". J'ai découvert que cela ne change pas les résultats mais pourrait les filtrer avant de les passer à Where-Object pour trouver les entrées avec les GUID.


3. Filtrer les entrées où :

Option 1: "Account Name" ne finit pas en $ (onglet général)
Option 2: "SubjectUserName" ne finit pas en $ (onglet détails).

Il s'agit de distinguer les comptes ordinateurs qui se terminent en $ (comme DC1$ ou DC2$ pour un contrôleur de domaine) et les utilisateurs qui exécutent l'attaque DCSync avec un compte qui ne se termine pas en $.

Après avoir étudié la question, je suis conscient qu'il est possible d'effectuer l'attaque DCSync en utilisant un compte ordinateur, ce qui déjoue ma méthode de détection, mais je tiens tout de même à savoir comment trouver les comptes avec $ à la fin, dans la mesure où savoir le faire pourrait être utile ailleurs.

Quoi qu'il en soit, j'ai réussi à atteindre les deux premiers objectifs avec ce script :

Get-WinEvent -Logname security -FilterXPath "Event[System[(EventID=4662)]]and Event[EventData[Data[@Name='ObjectServer']='DS']]" | Where-Object {$_.Message -like "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*" -and $_.Message -like "*1131f6ad-9c07-11d1-f79f-00c04fc2dcd2*"}

J'ai choisi l'option -FilterXPath simplement parce que je l'avais utilisé avec succès dans d'autres scripts.

J'aurais voulu tout faire sans devoir recourir à Where-Object mais je n'ai pas su trouver les GUID avec la logique XPath.

Mais le plus difficile, c'est de faire la différence entre les comptes ordi finissant en $ et les comptes utilisateur.


Quelques exemples dont j'ai essayé de m'inspirer

Le Fortinet SIEM utilise la recherche suivante :

(eventType="Win-Security-4662" AND propName REGEXP ".*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2.*|.*1131f6ad-9c07-11d1-f79f-00c04fc2dcd2.*|.*89e95b76-444d-4c62-991a-0facbeda640c.*|.*9923a32a-3607-11d2-b9be-0000f87a36b2.*|.*Replicating Directory Changes All.*" AND fileAccess="0x100") AND ((domain!="Window Manager") AND (user NOT REGEXP "^MSOL_|^NT AUT") AND (user NOT REGEXP "\$$"))

help.fortinet.com/fsiem/Public_Resource_...Mimikatz_DC_Sync.htm

Apparemment cela utilise une sorte de REGEX - quelque chose que je ne maîtrise pas.


J'ai essayé de disséquer ce script (qui ne semble pas correct en ce qui concerne les opérateurs : aucune entrée 4662 n'aura TOUS les GUID, il aurait fallu, me semble-t-il, mettre -ou au lieu de -and) :

$Events = get-eventlog -LogName security | where {$_.EventId -eq 4662 -and $_.Message -like "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*" -and $_.Message -like "*19195a5b-6da0-11d0-afd3-00c04fd930c9*" -and $_.Message -like "*128d83d7-1a6e-4e6d-936a-21579652d757*" -and $_.Message -like "*Object Server:*DS*" };foreach($event in $Events){$Account=$event.ReplacementStrings[1];if($Account -notmatch '\$$'){write-host "CRITICAL: Possible DCSync Executed.",$event.TimeGenerated,$event.MachineName,$event.EventId,$Account}}

www.linkedin.com/pulse/mimikatz-dcsync-e...etections-john-dwyer

Cette partie est celle qui m'intéresse mais je n'ai pas pu la faire fonctionner dans mon script (et je vous épargne toutes les itérations que j'ai essayées) :

foreach($event in $Events){$Account=$event.ReplacementStrings[1];if($Account -notmatch '\$$')

Est-ce qu'il y a quelqu'un qui aurait une idée sur le meilleur moyen de trouver les comptes qui ne finissent pas en $ ?

Merci d'avance !

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 11 mois 1 semaine #34652 par Laurent Dardenne
Salut,
vérifie le type d'objet que renvoi $event.ReplacementStrings[1]

Avec
$event.ReplacementStrings[1] | Get-member 

#virgule si c'est une collection ( tableau)
,$event.ReplacementStrings[1] | Get-member # la structure /type de l'objet et son contenu

#ou 
$event.ReplacementStrings[1].psobject | select-object -Property  *
[code]

Ceci fonctionne, à priori ce n'est pas la regex qui pose problème:
[code]
$Account='AvecDollar$'
$Account2='Sans$Dollar'

$Account -match '\$$'
$Account2 -match '\$$'

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 11 mois 1 semaine - il y a 11 mois 1 semaine #34653 par David M
Merci pour la suggestion, Laurent. Je vais essayer cela.


D'abord, je devrais mettre le script (mon script) complet pour référence :

$Events = Get-WinEvent -Logname Security -FilterXPath "Event[System[(EventID=4662)]]and Event[EventData[Data[@Name='ObjectServer']='DS']]" | Where-Object {$_.Message -like "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*"}

foreach($event in $Events) {$Account=$event.ReplacementStrings[1];if($Account -notmatch '\$$') {Write-Host $Event}}


À ce que je vois, un message d'erreur s'affiche pour chacun des $event dans $Events :

InvalidOperation: C:\Scripts\Find-DCSyncEvents_v1.ps1:3
Line |
   3 |  … ach($event in $Events) {$Account=$event.ReplacementStrings[1];if($Acc …
     |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot index into a null array.
System.Diagnostics.Eventing.Reader.EventLogRecord


Pour les vérifications qui ont été suggérées, voici ce que cela donne :

PS C:\Scripts> $event.ReplacementString[1] | Get-Member
InvalidOperation: Cannot index into a null array.
PS C:\Scripts>
PS C:\Scripts> $event.ReplacementString[1].psobject | Select-Object -Property *
InvalidOperation: Cannot index into a null array.


Je vais essayer d'attacher des images pour mieux montrer la chose:



 

Mais que signifie : "Cannot index into a null array" ?
Pièces jointes :
Dernière édition: il y a 11 mois 1 semaine par David M. Raison: Ajouter les résultats de mes essais

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 11 mois 1 semaine - il y a 11 mois 1 semaine #34655 par Arnaud Petitjean
Bonjour David,

Merci pour ce sujet très intéressant.

Alors, tout d'abord tu dois savoir que la commande Get-EventLog bien qu'intéressante et facile à utiliser est dépréciée. Elle n'est d'ailleurs plus disponible dans PowerShell 7. Je t'encourage donc à traiter ton sujet avec Get-WinEvent.

D'après ce que j'ai pu voir, la propriété ReplacementStrings n'est pas présente sur les objets retournés par la commande Get-WinEvent. D'où ton erreur...

Je te propose une petite variante pour (si j'ai bien compris ton besoin) aller rechercher le nom du compte dans la propriété Message et dans la ligne AccountName: ; ce qui donne ceci :
$Events = Get-WinEvent -Logname Security -FilterXPath "Event[System[(EventID=4662)]]and Event[EventData[Data[@Name='ObjectServer']='DS']]" | Where-Object {$_.Message -like "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*"}

# Analyse chaque évènement et extrait la chaine de caractères se trouvant dans le champ Message qui contient "AccountName:"
$Events | Foreach {if ($_.Message -match 'Account Name\:\s+(.*)') {$matches[1]}} | Get-Unique


Comme il y a de nombreux résultats, je récupère uniquement les résultats uniques pour enlever les doublons.

Si tu souhaites ne récupérer QUE les comptes d'ordinateurs, tu peux modifier la REGEX ainsi : 
'Account Name\:\s+(.*\$)'


En espérant que ça t'aide.

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?
Dernière édition: il y a 11 mois 1 semaine par Arnaud Petitjean. Raison: Correction orthographe

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 11 mois 1 semaine - il y a 11 mois 1 semaine #34665 par David M
Merci Arnaud

Ce qui tu proposes me permet de surmonter l'obstacle de l'erreur "Cannot index into a null array". Le script ainsi corrigé affiche les ordinateurs ou les personnes ayant forcé la synchronisation de l'annuaire Active Directory.

En fait, je voudrais avoir les entrées complètes (donc avec tous les détails, y compris la date et l'heure) qui correspondent au critère en question, c'est-à-dire quand le compte qui force la synchronisation n'est pas un compte d'ordinateur.

Autrement dit, une fois que je trouve les entrées correspondant à tous mes critères, comment afficher ces entrées comme elles seraient normalement affichées ? L'affichage par défaut suffit. Je peux toujours le modifier après avec Format-List ou Out-GridView.

Un affichage comme ceci, par example (juste un exemple - ceci n'a rien à voir avec le script) :



Sinon, j'ai essayé de faire un pas en plus en modifiant la REGEX pour ne retourner que les comptes qui ne sont pas des comptes d'ordinateurs mais je n'ai pas réussi. Comment modifier ceci pour n'afficher que les comptes d'utilisateur :

'Account Name\:\s+(.*\$)'

?

J'ai essayé -notmatch mais il paraît que seul -match fonctionne avec REGEX? J'ai essayé plein de variations en m'inspirant des exemples REGEX en ligne mais cela n'a rien affiché ou pas ce que je voulais.

Merci encore pour le progrès que tu m'as fait faire !

David
Pièces jointes :
Dernière édition: il y a 11 mois 1 semaine par David M. Raison: Ajouter l'image

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 11 mois 6 jours #34669 par Arnaud Petitjean
Bonjour David,

Alors, on va essayer de combiner tout ça ;-) :
# Récupère les logs 
$Events = Get-WinEvent -Logname Security -FilterXPath "Event[System[(EventID=4662)]]and Event[EventData[Data[@Name='ObjectServer']='DS']]" | Where-Object {$_.Message -like "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*"}

# Filtre pour aller chercher dans la propriété Message uniquement les évènements qui contiennent par exemple ceci : "Account Name:           Arnaud" mais rejette ceci car ça termine par un $ : Account Name:           SRV2019DESK1$" 
$Events | Where-Object { $_.Message -match 'Account Name:\s+\S*[^\s$](?=\s|$)'}

Est-ce que j'ai bon ? Ca t'exclura tous les comptes d'ordinateur car l'idée est d'exclure toutes les valeurs qui se terminent par un caractère dollar.

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.078 secondes
Propulsé par Kunena