PTH-PassTheHash
| Fiche express | |
|---|---|
| Domaine | Réutilisation d'identifiants / mouvement latéral |
| Cible | Authentification Windows (LM/NTLM) |
| Origine | Paul Ashton, 1997 |
| Outils | Mimikatz, WCE, pass-the-hash toolkit |
| Voir aussi | Hash injection · Squirtle · L0phtCrack |
Le pass-the-hash (PTH) permet de réaliser une authentification Windows à l'aide d'un hash (LM/NTLM) sans avoir à en retrouver le mot de passe en clair. L'attaquant réutilise directement l'empreinte cryptographique, ce qui en fait une technique classique de mouvement latéral après compromission d'une machine.
Historique
- 1997 — Paul Ashton découvre le pass-the-hash et en crée le premier toolkit. Celui-ci contient un unique binaire permettant de récupérer le hash LM/NTLM depuis la mémoire :
whosthere.exe
- 2007 — Benjamin Delpy développe Mimikatz.
- 2011 — Hernan Ochoa publie WCE (Windows Credential Editor), qui déchiffre les mots de passe stockés en mémoire : il parcourt le processus LSASS à la recherche des identifiants.
- 2012 — Benjamin Delpy présente de nouvelles fonctions reposant sur des patterns (les premiers outils fonctionnaient avec des offsets précalculés sur des versions de Windows non patchées).
Rappel sur LSASS
LSASS (Local Security Authority Sub-System) est le processus central du mécanisme d'authentification. Il est appelé par winlogon.exe.
- Les Authentication Packages (AP) gèrent les authentifications des sessions interactives.
- Les Security Support Providers (SSP) gèrent les sessions non interactives.
Lors d'un AP, Windows appelle, selon le type de compte :
msv1_0pour un compte local ;- Kerberos pour un compte de domaine.
La liste des packages est présente dans le registre :
HKLM\SYSTEM\CurrentControlSet\Control\LSA\AuthenticationPackages
Par défaut, les SSP sont enregistrés dans :
HKLM\SYSTEM\CurrentControlSet\Control\LSA\
Commande utile pour inspecter le contexte courant :
whoami /all
Génération du condensat (RFC 2617)
L'algorithme utilisé pour générer le condensat cryptographique (digest) :
Hash = MD5(HashA1:nonce:[...]:HashA2)
HashA1 = MD5(username:realm:password)
HashA2 = MD5(method:digestURI:[...])
Accès à la mémoire de LSASS
Le privilège SeDebugPrivilege et les niveaux d'intégrité (Mandatory Levels) conditionnent l'accès à la mémoire du processus :
Untrusted SID S-1-16-0 ML_LOW
Faible SID S-1-16-4096 ML_LOW
Moyen SID S-1-16-8192 ML_MEDIUM
Moyen haut SID S-1-16-8448 ML_MEDIUM_HIGH
Haut SID S-1-16-12288 ML_HIGH
Système SID S-1-16-16384 ML_SYSTEM
Protégé SID S-1-16-20480 ML_PROTECTED
Pour accéder à la mémoire du processus LSASS, il faut devenir SYSTEM ou posséder le droit SeDebugPrivilege. Ce droit permet de contourner cette protection et d'accéder à la mémoire de tous les processus, même si le processus cible requiert un niveau d'intégrité plus élevé.
Une fois le privilège SeDebugPrivilege obtenu et activé, on accède à l'ensemble de la mémoire de lsass.exe via les API :
OpenProcess()
ReadProcessMemory()
Stockage des identifiants par les SSP
Chaque SSP stocke les informations requises de manière séparée. Par exemple :
- le package
wdigest.dllstocke les informations (nom d'utilisateur et mot de passe) au sein de la structureSESSION_ENTRY; - le package
lsasrv.dllstocke les informations dansLogonSessionList.
Les mots de passe sont chiffrés en mémoire via LSAProtectMemory() :
- Windows XP / 2003 : algorithme DESX en mode CBC ;
- Windows Vista / 7 / 2008 : 3DES (ou AES-128-CFB).
Il faut donc le vecteur d'initialisation (IV) et la clé de chiffrement.
- Remarque — La longueur du blob à déchiffrer détermine (modulo 8) quel algorithme de chiffrement est utilisé (AES ou 3DES). Or l'ensemble des blobs des comptes en mémoire contient du padding pour être un multiple de 8 ; c'est la raison pour laquelle l'algorithme AES n'est en pratique jamais utilisé pour déchiffrer les mots de passe en mémoire.
Ces éléments (IV, clé) sont générés aléatoirement au démarrage du système et stockés en mémoire. Deux approches permettent ensuite de déchiffrer les identifiants :
- charger la fonction
LSAProtectMemory()depuislsasrv.dll:
- → charger la librairie
lsasrv.dll(LoadLibrary()) ; - → récupérer l'adresse de la fonction
LSAProtectMemory()(GetProcAddress()) ; - → copier les clés de chiffrement et le vecteur d'initialisation du processus lsass dans son propre processus (
ReadProcessMemory()/WriteProcessMemory()) puis déchiffrer les identifiants ;
- ou réimplémenter la fonction
LSAProtectMemory()à l'aide de la CryptoAPI ou de CNG (Cryptography API Next Generation) fournie par Windows.
Pour l'analyse statique, ouvrir lsasrv.dll avec IDA et étudier notamment :
LsaInitializeProtectedMemory()— initialise les paramètres de chiffrement (longueur et valeur de la clé, type d'algorithme AES, mode CFB) ;LsaEncryptMemory().
Transcription grossière de l'initialisation de l'algorithme AES :
void init_cipher() {
BCRYPT_HANDLE h3AESProv = NULL;
BCryptOpenAlgorithmProvider(&h3AESProv, BCRYPT_AES_ALGORITHM, 0, 0);
BCryptSetProperty(h3AESProv, BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_CFB, sizeof(BCRYPT_CHAIN_MODE_CFB), 0);
}
Il manque la donnée essentielle : la clé de chiffrement, normalement générée via BCryptGenerateSymmetricKey(). On ne peut pas utiliser cette fonction, car on cherche à obtenir la même clé que celle en mémoire. Microsoft propose BCryptImportKey() (option BCRYPT_KEY_DATA_BLOB) pour importer une clé au sein d'un provider CNG. Il faut fournir un blob respectant le format attendu : un en-tête BCRYPT_KEY_DATA_BLOB_HEADER suivi d'un blob contenant la clé.
Localisation des éléments en mémoire
Pour récupérer et déchiffrer les mots de passe, il faut connaître les adresses mémoire de :
- la fonction de chiffrement
LSAProtectMemory(); - le vecteur d'initialisation (IV) ;
- la liste chaînée
LSASRV.DLL!LogonSessionList; - la clé de chiffrement utilisée (AES / DES).
Ces éléments sont gérés par les bibliothèques chargées par lsass.exe (ici lsasrv.dll et wdigest.dll), initialisées par winlogon.exe.
Du fait de l'ASLR, l'adresse de base du processus LSASS (et des DLL chargées) diffère à chaque session. En revanche, les offsets d'accès aux éléments recherchés sont fixes et peuvent être précalculés : l'adresse de base d'une DLL se détermine facilement via l'API Windows, puis l'emplacement des variables (dans le segment .data) s'obtient par analyse statique.
Microsoft fournit des fichiers .PDB (symboles de debug) réalisant la correspondance entre noms de variables/fonctions et code assembleur. Il existe un fichier .PDB par version de binaire. Les symboles « publics » sont disponibles via le serveur de symboles :
https://msdl.microsoft.com/download/symbols
Ces symboles ne sont pas exhaustifs (le schéma des structures SESSION_ENTRY ou LogonSessionList n'y figure pas), mais contiennent l'adresse des variables et fonctions utiles. Le nom des symboles varie légèrement entre 32 et 64 bits (ex. h3DesKey@@3PAXA / h3DesKey@@3PEAXEA). On les obtient avec WinDBG, en configurant le serveur de symboles ou via la variable d'environnement :
_NT_SYMBOL_PATH=SRV*c:\symbols*https://msdl.microsoft.com/download/symbols;
Symboles utiles
| Nom du symbole | Description |
|---|---|
LsaEncryptMemory@@YGXPAEKH@Z |
Fonction de chiffrement LSAProtectMemory()
|
InitializationVector@@3PAEA |
Vecteur d'initialisation (IV) |
g_pDESXKey@@3PAU_desxtable@@A |
Clé de chiffrement DESX |
h3DesKey@@3PEAXEA |
Clé de chiffrement 3DES |
LogonSessionList@@3PAU_LIST_ENTRY@@A |
Liste chaînée de type LIST_ENTRY
|
Mise en œuvre du pass-the-hash (Linux)
apt-get install passing-the-hash
export SMBHASH="votre:hash"
Dans <commande>, utiliser cmd pour obtenir un terminal :
pth-winexe -U Administrator% //IPcible <commande>
Voir aussi
- Hash injection — injection d'un hash dans une session
- Squirtle — capture / relais NTLM
- L0phtCrack — audit et dump de mots de passe Windows