PTH-PassTheHash

De wiki.nexiat.fr
Aller à la navigation Aller à la recherche
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_0 pour 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.dll stocke les informations (nom d'utilisateur et mot de passe) au sein de la structure SESSION_ENTRY ;
  • le package lsasrv.dll stocke les informations dans LogonSessionList.

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() depuis lsasrv.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