From 6d639a0b3d9c3fa4d04a70d5404e65c3fad57e42 Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Wed, 17 May 2017 02:58:53 +0200 Subject: [PATCH] Can decrypt the user privatekey (and files) if malware privatekey (!) and user encrypted privatekey are provided --- wanadecrypt.c | 170 ++++++++++++++++++++++++++++++++++---------- wanadecrypt.vcxproj | 1 + 2 files changed, 134 insertions(+), 37 deletions(-) diff --git a/wanadecrypt.c b/wanadecrypt.c index d90a622..c2d1c35 100644 --- a/wanadecrypt.c +++ b/wanadecrypt.c @@ -12,10 +12,14 @@ Licence : https://creativecommons.org/licenses/by/4.0/ */ #include +#include #include #define RSA_2048_ENC 256 // 2048 / 8 #define WANA_MAGIC ((ULONGLONG) 0x21595243414e4157) // WANACRY! +#define RSA_ENC_SIZE (RSA_2048_ENC * 5) +#define RSA_DEC_SIZE 1172 +#define RSA_BAD_PAD 1225 typedef struct _WANA_FORMAT { ULONGLONG magic; // WANA_MAGIC @@ -31,76 +35,168 @@ typedef struct _GENERICKEY_BLOB { DWORD dwKeyLen; } GENERICKEY_BLOB, *PGENERICKEY_BLOB; +typedef struct _ENC_PRIV_KEY { + DWORD totalBytes; + BYTE data[ANYSIZE_ARRAY][RSA_2048_ENC]; +} ENC_PRIV_KEY, *PENC_PRIV_KEY; + +typedef struct _DEC_PRIV_KEY { + DWORD totalBytes; + BYTE data[ANYSIZE_ARRAY]; +} DEC_PRIV_KEY, *PDEC_PRIV_KEY; + BOOL SIMPLE_kull_m_crypto_hkey(HCRYPTPROV hProv, ALG_ID calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey); BOOL SIMPLE_kull_m_file_readData(PCWCHAR fileName, PBYTE * data, PDWORD lenght); BOOL SIMPLE_kull_m_file_writeData(PCWCHAR fileName, LPCVOID data, DWORD lenght); +void decryptFileWithKey(HCRYPTPROV hProv, HCRYPTKEY hUserRsaKey, int argc, wchar_t * argv[]); int wmain(int argc, wchar_t * argv[]) { HCRYPTPROV hProv; - HCRYPTKEY hRsaKey, hAesKey; + HCRYPTKEY hMalwareRsaKey, hUserRsaKey; PBYTE pbRsaKey; - PWANA_FORMAT pbEncData; - DWORD cbRsaKey, cbEncData, cbRealDataLen, cryptoMode = CRYPT_MODE_CBC; - PWCHAR p; + DWORD cbRsaKey, cbData, i, dataLen; + PENC_PRIV_KEY pEnc; + PDEC_PRIV_KEY pDec; + PWSTR ext; if(argc > 2) { - wprintf(L"Using \'%s\' to decrypt \'%s\' file...\n\n", argv[1], argv[2]); - if(SIMPLE_kull_m_file_readData(argv[1], &pbRsaKey, &cbRsaKey)) + if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) // we'll do RSA / AES stuff { - if(SIMPLE_kull_m_file_readData(argv[2], (PBYTE *) &pbEncData, &cbEncData)) + ext = PathFindExtension(argv[2]); + if(ext && (_wcsicmp(ext, L".eky") == 0)) { - if(p = wcsrchr(argv[2], L'.')) + wprintf(L"Malware PK: %s\nUser EncPK: %s\n", argv[1], argv[2]); + if(SIMPLE_kull_m_file_readData(argv[1], &pbRsaKey, &cbRsaKey)) { - *p = L'\0'; // 'delete' the WNCRY extension - if(pbEncData->magic == WANA_MAGIC) + if(CryptImportKey(hProv, pbRsaKey, cbRsaKey, 0, 0, &hMalwareRsaKey)) // let's import the malware PrivateKey - We all hope you have it :( { - wprintf(L"Mode(?) : %u\nFilesize : %llu\n", pbEncData->unkOperation, pbEncData->qwDataSize); - if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) // we'll do RSA / AES stuff + if(SIMPLE_kull_m_file_readData(argv[2], (PBYTE *) &pEnc, &cbData)) { - if(CryptImportKey(hProv, pbRsaKey, cbRsaKey, 0, 0, &hRsaKey)) // let's import the user PrivateKey - I hope you have it :( + if((pEnc->totalBytes == RSA_ENC_SIZE) && (cbData == (pEnc->totalBytes + FIELD_OFFSET(ENC_PRIV_KEY, data)))) { - if(CryptDecrypt(hRsaKey, 0, TRUE, 0, pbEncData->key, &pbEncData->enc_keysize)) // decrypt the raw AES key from your RSA key + if(pDec = (PDEC_PRIV_KEY) LocalAlloc(LPTR, FIELD_OFFSET(DEC_PRIV_KEY, data) + pEnc->totalBytes)) // 0 { - if(SIMPLE_kull_m_crypto_hkey(hProv, CALG_AES_128, pbEncData->key, pbEncData->enc_keysize, 0, &hAesKey)) // let's make a AES 128 Windows key from raw bytes + for(i = 0; i < pEnc->totalBytes / RSA_2048_ENC; i++) + { + RtlCopyMemory(pDec->data + pDec->totalBytes, pEnc->data[i], RSA_2048_ENC); + dataLen = RSA_2048_ENC; + if(CryptDecrypt(hMalwareRsaKey, 0, TRUE, 0, pDec->data + pDec->totalBytes, &dataLen)) + pDec->totalBytes += dataLen; + else wprintf(L"ERROR: CryptDecrypt(user - %u): %u\n", i, GetLastError()); + } + + switch(pDec->totalBytes) + { + case RSA_BAD_PAD: + wprintf(L"WARNING: user privatekey was encrypted with bad data at the end, fixed from %u to %u\n", RSA_BAD_PAD, RSA_DEC_SIZE); + pDec->totalBytes = RSA_DEC_SIZE; + break; + case RSA_DEC_SIZE: + wprintf(L"W00T: user privatekey good size ?\n"); + break; + default: + wprintf(L"ERROR: Invalid user privatekey size: %u\n", pDec->totalBytes); + } + + if(pDec->totalBytes == RSA_DEC_SIZE) { - if(CryptSetKeyParam(hAesKey, KP_MODE, (PBYTE) &cryptoMode, 0)) // we'll do CBC + if(CryptImportKey(hProv, pDec->data, pDec->totalBytes, 0, 0, &hUserRsaKey)) { - cbRealDataLen = cbEncData - FIELD_OFFSET(WANA_FORMAT, data); - if(CryptDecrypt(hAesKey, 0, FALSE, 0, pbEncData->data, &cbRealDataLen)) // decrypt final data (padding issue, so 'FALSE' arg) - { - if(SIMPLE_kull_m_file_writeData(argv[2], pbEncData->data, (ULONG) pbEncData->qwDataSize)) - wprintf(L"Final file: %s\n", argv[2]); - else wprintf(L"ERROR: writing final file \'%s\': %u\n", argv[2], GetLastError()); - } - else wprintf(L"ERROR: CryptDecrypt: %u\n", GetLastError()); + ext[1] = L'p'; + wprintf(L"\nSave DecPK: %s\n", argv[2]); + if(!SIMPLE_kull_m_file_writeData(argv[2], pDec->data, pDec->totalBytes)) + wprintf(L"ERROR: saving raw user privatekey file \'%s\': %u\n", argv[2], GetLastError()); + decryptFileWithKey(hProv, hUserRsaKey, argc - 3, &argv[3]); + CryptDestroyKey(hUserRsaKey); } - CryptDestroyKey(hAesKey); + else wprintf(L"ERROR: CryptImportKey(user): %u\n", GetLastError()); } + LocalFree(pDec); } - else wprintf(L"ERROR: CryptDecrypt: %u\n", GetLastError()); - CryptDestroyKey(hRsaKey); } - else wprintf(L"ERROR: CryptImportKey: %u\n", GetLastError()); - CryptReleaseContext(hProv, 0); + else wprintf(L"ERROR: abnormal encrypted size (H:%08x, D:%08x, N:%08x)\n", pEnc->totalBytes, cbData - FIELD_OFFSET(ENC_PRIV_KEY, data), RSA_ENC_SIZE); + LocalFree(pEnc); } - else wprintf(L"ERROR: CryptAcquireContext: %u\n", GetLastError()); + else wprintf(L"ERROR: reading user encrypted privatekey file \'%s\': %u\n", argv[2], GetLastError()); + } + else wprintf(L"ERROR: CryptImportKey(malware): %u\n", GetLastError()); + LocalFree(pbRsaKey); + } + else wprintf(L"ERROR: reading malware privatekey file \'%s\': %u\n", argv[1], GetLastError()); + } + else + { + wprintf(L"Using raw user private key: \'%s\' to decrypt\n", argv[1]); + if(SIMPLE_kull_m_file_readData(argv[1], &pbRsaKey, &cbRsaKey)) + { + if(CryptImportKey(hProv, pbRsaKey, cbRsaKey, 0, 0, &hUserRsaKey)) // let's import the user PrivateKey - I hope you have it :( + { + decryptFileWithKey(hProv, hUserRsaKey, argc - 2, &argv[2]); + CryptDestroyKey(hUserRsaKey); } - else wprintf(L"ERROR: WANACRY! magic number not found\n"); + else wprintf(L"ERROR: CryptImportKey: %u\n", GetLastError()); + LocalFree(pbRsaKey); } - else wprintf(L"ERROR: no \'.\' at the end of the user file ?\n"); - LocalFree(pbEncData); + else wprintf(L"ERROR: reading user privatekey file \'%s\': %u\n", argv[1], GetLastError()); } - else wprintf(L"ERROR: reading userfile \'%s\': %u\n", argv[2], GetLastError()); - LocalFree(pbRsaKey); + CryptReleaseContext(hProv, 0); } - else wprintf(L"ERROR: reading privatekey file \'%s\': %u\n", argv[1], GetLastError()); + else wprintf(L"ERROR: CryptAcquireContext: %u\n", GetLastError()); } - else wprintf(L"ERROR: program needs two arguments: \n"); + else wprintf(L"ERROR: program needs at least two arguments:\n %s ...\n %s ...\n", argv[0], argv[0]); return 0; } +void decryptFileWithKey(HCRYPTPROV hProv, HCRYPTKEY hUserRsaKey, int argc, wchar_t * argv[]) +{ + HCRYPTKEY hUserFileAesKey; + PWANA_FORMAT pbEncData; + PWCHAR p; + DWORD cbEncData, cbRealDataLen, cryptoMode = CRYPT_MODE_CBC; + int i; + + for(i = 0; i < argc; i++) + { + wprintf(L"\nFilename : %s\n", argv[i]); + if(SIMPLE_kull_m_file_readData(argv[i], (PBYTE *) &pbEncData, &cbEncData)) + { + if(p = wcsrchr(argv[i], L'.')) + { + *p = L'\0'; // 'delete' the WNCRY extension + if(pbEncData->magic == WANA_MAGIC) + { + wprintf(L"Mode(?) : %u\nFilesize : %llu\n", pbEncData->unkOperation, pbEncData->qwDataSize); + if(CryptDecrypt(hUserRsaKey, 0, TRUE, 0, pbEncData->key, &pbEncData->enc_keysize)) // decrypt the raw AES key from your RSA key + { + if(SIMPLE_kull_m_crypto_hkey(hProv, CALG_AES_128, pbEncData->key, pbEncData->enc_keysize, 0, &hUserFileAesKey)) // let's make a AES 128 Windows key from raw bytes + { + if(CryptSetKeyParam(hUserFileAesKey, KP_MODE, (PBYTE) &cryptoMode, 0)) // we'll do CBC + { + cbRealDataLen = cbEncData - FIELD_OFFSET(WANA_FORMAT, data); + if(CryptDecrypt(hUserFileAesKey, 0, FALSE, 0, pbEncData->data, &cbRealDataLen)) // decrypt final data (padding issue, so 'FALSE' arg) + { + if(SIMPLE_kull_m_file_writeData(argv[i], pbEncData->data, (ULONG) pbEncData->qwDataSize)) + wprintf(L"Final file: %s\n", argv[i]); + else wprintf(L"ERROR: writing final file \'%s\': %u\n", argv[i], GetLastError()); + } + else wprintf(L"ERROR: CryptDecrypt: %u\n", GetLastError()); + } + CryptDestroyKey(hUserFileAesKey); + } + } + else wprintf(L"ERROR: CryptDecrypt: %u\n", GetLastError()); + } + else wprintf(L"ERROR: WANACRY! magic number not found\n"); + } + else wprintf(L"ERROR: no \'.\' at the end of the user file ?\n"); + LocalFree(pbEncData); + } + else wprintf(L"ERROR: reading input file \'%s\': %u\n", argv[i], GetLastError()); + } +} + BOOL SIMPLE_kull_m_crypto_hkey(HCRYPTPROV hProv, ALG_ID calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey) { BOOL status = FALSE; diff --git a/wanadecrypt.vcxproj b/wanadecrypt.vcxproj index 772a619..9d80f4d 100644 --- a/wanadecrypt.vcxproj +++ b/wanadecrypt.vcxproj @@ -44,6 +44,7 @@ true true true + shlwapi.lib;%(AdditionalDependencies)