Comment obtenir un hash MD5
sous Windows, déchiffrer un bloc DES
?
j’ai totalement conscience d’évoquer dans ce post des algorithmes considérés comme dépassés, mais ces derniers sont toujours massivement utilisés dans les mécanismes internes de Windows
mimikatz 2.0 s’en sert lui aussi massivement ;)
Limitations
Les algorithmes évoqués dans ce post sont seulement les suivants :
MD4 |
LM |
DES (ECB) |
MD5 |
NTLM |
RC4 |
SHA1 |
Déjà vu sur Internet *
- assemblage de bouts de code provenant d’Internet (réimplémentation des algorithmes)
- utilisation des librairies d’
OpenSSL
- utilisation de la
CryptoAPI
- utilisation de la
CNG
* je passe sur l’utilisation de CSP
/PKCS#11
pour communiquer avec son HSM préféré ;)
A notre disposition sous Windows
Comme déjà listé, il est possible d’utiliser nativement la CryptoAPI
, ou sa nouvelle version la CNG
… mais n’est-ce-pas un peu lourd pour de si simples besoins ?
Windows incorpore déjà beaucoup de routines dans ses librairies système et, si l’on en utilise une grande partie via les SDK référençant ces API, l’on en occulte quelques-unes très pratiques !
Une majorité de ces API se situent dans la librairie advapi32
.
API clairement identifiées
MD4Init |
MD5Init |
A_SHAInit |
MD4Update |
MD5Update |
A_SHAUpdate |
MD4Final |
MD5Final |
A_SHAFinal |
API derrières SystemFunctionXXX
RtlEncryptDES1block1key |
SystemFunction001 |
RtlDecryptDES1block1key |
SystemFunction002 |
RtlEncryptDESMagicBlock1key |
SystemFunction003 |
RtlEncryptDESblocksECB |
SystemFunction004 |
RtlDecryptDESblocksECB |
SystemFunction005 |
RtlDigestLM |
SystemFunction006 |
RtlDigestNTLM |
SystemFunction007 |
RtlLMResponseToChallenge NTLMv1 aussi sans doute |
SystemFunction008 |
SystemFunction009 |
|
RtlDigestMD4only16Bytes |
SystemFunction010 |
SystemFunction011 |
|
RtlEncryptDES2blocks2keys |
SystemFunction012 |
SystemFunction014 |
|
SystemFunction020 |
|
SystemFunction022 |
|
RtlDecryptDES2blocks2keys |
SystemFunction013 |
SystemFunction015 |
|
SystemFunction021 |
|
SystemFunction023 |
|
RtlEncryptDES2blocks1key |
SystemFunction016 |
SystemFunction018 |
|
RtlDecryptDES2blocks1key |
SystemFunction017 |
SystemFunction019 |
|
RtlEncryptDES2blocks1DWORD |
SystemFunction024 |
SystemFunction026 |
|
RtlDecryptDES2blocks1DWORD |
SystemFunction025 |
SystemFunction027 |
|
RtlEqualMemory16Bytes |
SystemFunction030 |
SystemFunction031 |
|
RtlEncryptDecryptRC4 |
SystemFunction032 |
SystemFunction033 |
|
RtlCheckSignatureInFile |
SystemFunction035 |
Clé de session RPC fonctions non identiques |
SystemFunction028 |
SystemFunction029 |
|
SystemFunction034 |
Téléchargement
La majorité des API sont référencées via des SystemFunctionXXX
qui peuvent déjà être liées par la librairie advapi32.lib
du SDK ou WDK.
Malheureusement pas les API A_SHAFinal
, A_SHAInit
, A_SHAUpdate
, MD4Final
, MD4Init
, MD4Update
, MD5Final
, MD5Init
, MD5Update
et RtlCheckSignatureInFile
(SystemFunction035
).
J’ai donc créé trois fichiers :
kull_m_crypto_system.h
– en-tête à adapter au projet ciblé pour inclure les prototypes et structures manquantswin32\advapi32.hash.lib
– librairie x86 à lier pour les API manquantesx64\advapi32.hash.lib
– librairie x64 à lier pour les API manquantes
Exemple de petit code
Il est là pour exposer l’utilisation du CRYPTO_BUFFER
, du MD5
, SHA1
et DES-ECB
const BYTE data[] = "my super secret is a kiwi :)"; const BYTE key[] = "42 & 0xdeadbeef of course !"; CRYPTO_BUFFER bData = {sizeof(data) - 1, sizeof(data) - 1, (PBYTE) data}, bKey = {sizeof(key) - 1, sizeof(key) - 1, (PBYTE) key}, bCipData = {0, 0, NULL}, bDecData = {0, 0, NULL} ; MD5_CTX md5ctxInput, md5ctxOutput; // MD5 digest in context SHA_CTX shactxInput, shactxOutput; SHA_DIGEST shaInput, shaOutput; NTSTATUS status; MD5Init(&md5ctxInput); MD5Update(&md5ctxInput, bData.Buffer, bData.Length); MD5Final(&md5ctxInput); // original data MD5 hash A_SHAInit(&shactxInput); A_SHAUpdate(&shactxInput, bData.Buffer, bData.Length); A_SHAFinal(&shactxInput, &shaInput); // original data SHA1 hash status = RtlEncryptDESblocksECB(&bData, &bKey, &bCipData); if(status == STATUS_BUFFER_TOO_SMALL) { if(bCipData.Buffer = (PBYTE) LocalAlloc(LPTR, bCipData.Length)) { bCipData.MaximumLength = bCipData.Length; status = RtlEncryptDESblocksECB(&bData, &bKey, &bCipData); } } else status = STATUS_NONCONTINUABLE_EXCEPTION; if(NT_SUCCESS(status)) // Cipher operation OK ? { status = RtlDecryptDESblocksECB(&bCipData, &bKey, &bDecData); if(status == STATUS_BUFFER_TOO_SMALL) { if(bDecData.Buffer = (PBYTE) LocalAlloc(LPTR, bDecData.Length)) { bDecData.MaximumLength = bDecData.Length; status = RtlDecryptDESblocksECB(&bCipData, &bKey, &bDecData); } } else status = STATUS_NONCONTINUABLE_EXCEPTION; } if(NT_SUCCESS(status)) // Decipher operation OK ? { MD5Init(&md5ctxOutput); MD5Update(&md5ctxOutput, bDecData.Buffer, bDecData.Length); MD5Final(&md5ctxOutput); // deciphered data MD5 hash A_SHAInit(&shactxOutput); A_SHAUpdate(&shactxOutput, bDecData.Buffer, bDecData.Length); A_SHAFinal(&shactxOutput, &shaOutput); // deciphered data SHA1 hash // data compare works too, but it's for expose MD5 & SHA1 functions ;) wprintf(L"MD5 match : %s\n", RtlEqualMemory(md5ctxInput.digest, md5ctxOutput.digest, MD5_DIGEST_LENGTH) ? L"OK" : L"KO"); wprintf(L"SHA1 match : %s\n", RtlEqualMemory(shaInput.digest, shaOutput.digest, SHA_DIGEST_LENGTH) ? L"OK" : L"KO"); } LocalFree(bDecData.Buffer); LocalFree(bCipData.Buffer);
Correction d’un en-tête Windows
Les seules API un tant soit peu présentes dans les en-têtes standards de Windows sont les suivantes :
RtlEncryptMemory
RtlDecryptMemory
RtlGenRandom
Lors de l’utilisation de ces fonctions, avec les fichiers proposés ou non, si les erreurs suivantes apparaissent lors de la création des liens :
error LNK2001: symbole externe non résolu _SystemFunction036 error LNK2001: symbole externe non résolu _SystemFunction040 error LNK2001: symbole externe non résolu _SystemFunction041
C’est que l’en-tête ntsecapi.h
déclare incorrectement les prototypes des fonctions.
Il faut malheureusement les corriger :
BOOLEAN RtlGenRandom( __out_bcount(RandomBufferLength) PVOID RandomBuffer, __in ULONG RandomBufferLength ); //... NTSTATUS RtlEncryptMemory( __inout_bcount(MemorySize) PVOID Memory, __in ULONG MemorySize, __in ULONG OptionFlags ); NTSTATUS RtlDecryptMemory( __inout_bcount(MemorySize) PVOID Memory, __in ULONG MemorySize, __in ULONG OptionFlags );
en rajoutant la convention d’appel WINAPI
(__stdcall
) :
BOOLEAN WINAPI RtlGenRandom( __out_bcount(RandomBufferLength) PVOID RandomBuffer, __in ULONG RandomBufferLength ); //... NTSTATUS WINAPI RtlEncryptMemory( __inout_bcount(MemorySize) PVOID Memory, __in ULONG MemorySize, __in ULONG OptionFlags ); NTSTATUS WINAPI RtlDecryptMemory( __inout_bcount(MemorySize) PVOID Memory, __in ULONG MemorySize, __in ULONG OptionFlags );
Ping : Active Directory Password Encryption | Florian Sailer's Knowledge Space