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
.
Image may be NSFW.
Clik here to view.
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 :
LsaUnprotectMemory
– http://msdn.microsoft.com/library/windows/desktop/ff714510.aspx
Le chiffrement des mots de passe est quant à lui effectué par :
LsaProtectMemory
– http://msdn.microsoft.com/library/windows/desktop/ff714509.aspx
Ces deux fonctions reposent sur : LsaEncryptMemory
Windows NT 5
- Algorithme :
RC4
Clé : dérivée depuisg_pRandomKey
, de longueurg_cbRandomKey
(256) - Algorithme :
DES
Clé :g_pDESXKey
, de longueur 144
IV :g_Feedback
, de longueur 8
Méthodologie
- Charger
lsasrv.dll
dansmimikatz
- Copier les 8 octets de
LSASS:lsasrv!g_Feedback
versmimikatz:lsasrv!g_Feedback
- Copier les 4 octets (
DWORD
) deLSASS:lsasrv!g_cbRandomKey
versmimikatz:lsasrv!g_cbRandomKey
- Instancier un nouveau tableau de taille
mimikatz:lsasrv!g_cbRandomKey
octets - Placer l’adresse de ce tableau dans
mimikatz:lsasrv!g_pRandomKey
- Copier les
mimikatz:lsasrv!g_cbRandomKey
octets ciblés parLSASS:lsasrv!g_pRandomKey
vers le tableau ciblé parmimikatz:lsasrv!g_pRandomKey
- Instancier un nouveau tableau de taille 144 octets
- Placer l’adresse de ce tableau dans
mimikatz:lsasrv!g_pDESXKey
- Copier les 144 octets ciblés par
LSASS:lsasrv!g_pDESXKey
vers le tableau ciblé parmimikatz:lsasrv!g_pDESXKey
Windows NT 6
- Algorithme :
3DES
Clé : référencée par le handleh3DesKey
IV :InitializationVector
, de longueur 8 (sur 16) - Algorithme :
AES
Clé : référencée par le handlehAesKey
IV :InitializationVector
, de longueur 16
Méthodologie
- Charger
lsasrv.dll
dansmimikatz
- Copier les 16 octets de
LSASS:lsasrv!InitializationVector
versmimikatz:lsasrv!InitializationVector
- Appeler la fonction
mimikatz:lsasrv!LsaInitializeProtectedMemory
pour initialiser correctement les handles de clésh3DesKey
ethAesKey
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;
- Copier les
LSASS:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA.size
octets deLSASS:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA
versmimikatz:lsasrv!h3DesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA
- Copier les
(LSASS:lsasrv!hAesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA.size - 2*sizeof(PVOID))
octets* deLSASS:lsasrv!hAesKey->KIWI_BCRYPT_KEY->KIWI_BCRYPT_KEY_DATA
versmimikatz: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 ?
Image may be NSFW.
Clik here to view.