Mouvement latéral et Amcache : pivot par ProgramId entre hôtes

Lorsque vous confirmez la présence d'outils attaquants sur un hôte Windows, la question suivante est toujours : où d'autre ? Cadrer le mouvement latéral — identifier chaque autre hôte que l'attaquant a atteint — est l'une des étapes les plus difficiles d'une enquête, et Amcache est l'un des outils les plus utiles pour cela.

La raison : Amcache stocke deux pivots cross-hôtes que presque aucun autre artefact Windows ne stocke :

  • Hash — le SHA-1 des 31 premiers Mio de chaque PE que l'appraiser a vu.
  • ProgramId — le hash d'identité applicative de 44 caractères, stable entre hôtes pour la même application.

Un seul Hash ou ProgramId suspect sur l'Hôte A devient une requête que vous pouvez exécuter contre les CSVs Amcache analysés de chaque autre hôte que vous avez collecté. Cette page est le playbook complet.

Pour les prérequis, voir Référence complète Amcache, FileId Amcache expliqué, et ProgramId Amcache expliqué.


Le prérequis de collecte#

Le pattern ne fonctionne que si vous avez collecté Amcache depuis de nombreux hôtes d'une manière qui permet de joindre entre eux. Deux patterns pratiques de collecte :

Collecte par hôte basée sur KAPE#

Utilisez une seule racine de collecte avec des sous-répertoires par hôte :

\\fileshare\incident-042\
├── HOST01\
│   └── Windows\AppCompat\Programs\Amcache.hve (+ logs)
├── HOST02\
│   └── ...
├── HOST03\
│   ...

Analysez avec AmcacheParser pointé sur chaque répertoire par hôte :

Get-ChildItem '\\fileshare\incident-042' -Directory | ForEach-Object {
    $host = $_.Name
    AmcacheParser.exe `
      -f "$($_.FullName)\Windows\AppCompat\Programs\Amcache.hve" `
      --csv "\\fileshare\parsed\$host" `
      --csvf "${host}_amcache.csv" `
      --mp
}

Vous vous retrouvez avec <host>_amcache_UnassociatedFileEntries.csv par hôte, tous dans un seul répertoire.

Hunt sur parc Velociraptor#

L'artefact Windows.Forensics.Amcache, exécuté comme hunt, dépose la sortie analysée par hôte dans le serveur Velociraptor. Les CSVs sont nommés avec le hostname de l'hôte ; les mêmes requêtes cross-hôtes ci-dessous s'appliquent.


Le pivot par hash#

Le pivot le plus simple et de plus haute précision. Vous avez un SHA-1 connu comme malveillant depuis l'Hôte A ; trouvez chaque autre hôte qui l'a.

$badHash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
 
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
  ForEach-Object {
    $host = $_.PSChildName.Split('_')[0]
    Import-Csv $_.FullName |
      Where-Object { $_.Hash -eq $badHash } |
      Select-Object @{n='Host';e={$host}}, FullPath, KeyLastWriteTimestamp, Size
  } |
  Sort-Object KeyLastWriteTimestamp

La sortie est une timeline par hôte de quand le binaire malveillant est apparu pour la première fois sur chaque hôte. L'horodatage le plus ancien est votre candidat patient-zero ; les horodatages suivants sont la propagation.

Quand les correspondances de hash sur-collent#

Le pivot par hash manque les recompilations du même outil. Les attaquants qui recompilent leur loader avant chaque mouvement latéral ont un hash différent sur chaque hôte. Pour ceux-là, repliez-vous sur ProgramId.


Le pivot par ProgramId#

ProgramId est plus permissif que Hash — il attrape les recompilations qui partagent nom/éditeur/version même quand le contenu binaire diffère. Voir ProgramId Amcache expliqué pour comment l'identité est construite.

$badProgramId = '0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff'
 
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
  ForEach-Object {
    $host = $_.PSChildName.Split('_')[0]
    Import-Csv $_.FullName |
      Where-Object { $_.ProgramId -eq $badProgramId } |
      Select-Object @{n='Host';e={$host}}, FullPath, Hash, KeyLastWriteTimestamp
  } |
  Sort-Object KeyLastWriteTimestamp

Cela trouve chaque hôte qui a un binaire s'identifiant comme la même application — même avec des hashes de contenu différents. Couplez avec le pivot par hash : hash pour les correspondances de haute précision, ProgramId pour les correspondances au niveau famille.

Quand ProgramId sur-colle#

ProgramId attrape des faux positifs si l'attaquant se greffe sur une identité applicative légitime (ex. recompiler du tooling nommé PsExec.exe qui obtient le même ProgramId que le vrai PsExec). Couplez avec Hash pour désambiguïser ; une ligne correspondant au ProgramId mais avec un hash que personne d'autre dans votre environnement n'a est hautement suspecte.


Le pivot par pattern de chemin#

Pour les patterns de chemin d'installation attaquants connus, regex contre FullPath :

$pattern = '\\AppData\\Roaming\\[a-z0-9]{8}\\update\.exe$'
 
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
  ForEach-Object {
    $host = $_.PSChildName.Split('_')[0]
    Import-Csv $_.FullName |
      Where-Object { $_.FullPath -match $pattern } |
      Select-Object @{n='Host';e={$host}}, FullPath, Hash, ProgramId, KeyLastWriteTimestamp
  }

Utile quand :

  • Vous connaissez la convention d'installation de l'intrusion set.
  • L'attaquant fait tourner les hashes et métadonnées mais réutilise les patterns de chemin.
  • Vous voulez trouver des variantes qui partagent un style de chemin.

Couplez les correspondances avec hash et ProgramId des résultats par ligne pour construire une détection plus riche.


Vue en série temporelle de la propagation#

Pour chaque pivot, triez les résultats par KeyLastWriteTimestamp pour voir la propagation dans le temps. Un pattern typique :

2026-04-01 14:23 HOST01  -- patient zero, attacker initial access
2026-04-03 09:11 HOST02  -- 2 days later
2026-04-03 11:34 HOST07
2026-04-03 14:55 HOST09
2026-04-04 02:08 HOST15  -- weekend; attacker working overnight
2026-04-04 02:33 HOST22
2026-04-04 02:51 HOST31

Deux lectures :

  1. La cadence (plusieurs hôtes en quelques heures les uns des autres) est caractéristique d'un outillage de mouvement latéral automatisé (basé sur PsExec / WMI / SMB).
  2. La rafale de nuit-pendant-la-nuit est le pattern attaquant typique : accès initial pendant les heures ouvrables, puis mouvement accéléré une fois qu'ils ont des credentials et du contrôle.

Utilisez ces patterns pour borner dans le temps le reste de votre collecte de preuves. Tirez Sysmon / Security 4624 / 4688 pour chaque hôte dans sa fenêtre KeyLastWriteTimestamp ± 1 h — vous obtenez les lignes de commande réelles de l'attaquant et les événements de credentials avec une haute précision.


Pivot croisé sur les preuves de pilotes et périphériques#

Le pattern cross-hôtes n'est pas limité à *_UnassociatedFileEntries.csv. Pour des enquêtes plus approfondies, exécutez les mêmes patterns de pivot contre :

*_DriverBinaries.csv#

Pour les enquêtes BYOVD — un pilote vulnérable que l'attaquant a chargé sur un hôte est presque certainement chargé sur les autres qu'il a atteints. Requête par Hash ou DriverName du pilote :

$badDriver = 'mhyprot2.sys'
 
Get-ChildItem -Recurse -Filter *_DriverBinaries.csv |
  ForEach-Object {
    $host = $_.PSChildName.Split('_')[0]
    Import-Csv $_.FullName |
      Where-Object { $_.DriverName -eq $badDriver } |
      Select-Object @{n='Host';e={$host}}, DriverName, Service, DriverSigned, KeyLastWriteTimestamp
  }

*_DeviceContainers.csv#

Pour les enquêtes où l'attaquant a connecté du matériel (rare dans les attaques à distance, central dans les cas de menace interne) — requête par Manufacturer ou FriendlyName :

$suspiciousVendor = 'HakShop'
 
Get-ChildItem -Recurse -Filter *_DeviceContainers.csv |
  ForEach-Object {
    $host = $_.PSChildName.Split('_')[0]
    Import-Csv $_.FullName |
      Where-Object { $_.Manufacturer -match $suspiciousVendor } |
      Select-Object @{n='Host';e={$host}}, FriendlyName, Manufacturer, KeyLastWriteTimestamp
  }

Voir Historique USB et périphériques depuis Amcache pour les patterns côté périphérique en détail.


Combiner avec des sources non-Amcache#

Le pivot Amcache vous dit où le binaire a été inventorié. Pour confirmer l'exécution et identifier la méthode de mouvement, corrélez avec :

  • 4624 (Logon) + 4625 (Failed logon) sur les hôtes destination — quand l'attaquant s'est-il authentifié, et en tant que qui ?
  • 4648 (Explicit credential logon) — mouvement latéral avec credentials (PsExec, RDP avec credentials passés).
  • Sysmon 1 / 4688 (Process create) avec processus parent — le processus attaquant s'est-il lancé sous services.exe (PsExec / service distant), sous wmiprvse.exe (WMI), ou sous explorer.exe (interactif) ?
  • Sysmon 3 (Network connect) + Sysmon 22 (DNS query) — C2 sortant.
  • Arbres de processus Velociraptor / EDR — mêmes données, plus faciles à naviguer.

Un seul pivot Amcache cadrant la propagation, joint aux événements d'authentification et de processus par hôte sur les hôtes correspondants, vous donne une timeline défendable de : qui, quand, depuis où, via quel binaire, avec quel credential.


Quand le pivot manque#

Trois situations où le pivot cross-hôtes Amcache sous-performe :

L'appraiser n'a pas encore tourné sur les hôtes destination#

Si l'attaquant s'est déplacé latéralement dans les heures suivant votre collecte, les appraisers des hôtes destination peuvent ne pas avoir encore inventorié le binaire. Amcache les montre comme propres. Re-collectez 24-48 heures plus tard ; la propagation apparaîtra.

L'attaquant a nettoyé Amcache sur chaque hôte atteint#

Peu courant (surtout parce que c'est bruyant et que la plupart des attaquants ne s'en embêtent pas) mais possible. Utilisez le workflow de récupération via Volume Shadow Copy dans Où se trouve Amcache.hve sur disque sur chaque hôte où vous suspectez un nettoyage.

L'attaquant a utilisé des binaires différents par hôte#

Si l'attaquant a généré des implants par-hôte (vrais malwares par-victime), les pivots par hash et ProgramId échouent par construction. Les patterns de chemin et les détections comportementales plus larges (4624 logon depuis la même IP inhabituelle sur de nombreux hôtes) deviennent primaires.


Voir aussi#

Pour explorer vos propres ruches collectées sans rien installer, déposez un fichier sur la page d'accueil de l'analyseur — il s'analyse entièrement dans votre navigateur.

Articles liés

Retour à tous les articles