Obtenir une liste de processus ou de threads

Méthode pour obtenir un vecteur de processus :

bool GetListeProcessus(vector<PROCESSENTRY32> *maListeDeProcessus)
{
	HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	if(hProcessSnapshot != INVALID_HANDLE_VALUE)
	{
		PROCESSENTRY32 monProcessus;
		monProcessus.dwSize = sizeof(PROCESSENTRY32);

		if(Process32First(hProcessSnapshot, &monProcessus))
		{
			do
			{
				maListeDeProcessus->push_back(monProcessus);
			}
			while(Process32Next(hProcessSnapshot, &monProcessus));
		}
		CloseHandle(hProcessSnapshot);
		return true;
	}
	else
	{
		return false;
	}
}

Méthode pour obtenir un vecteur de threads :

bool GetListeThreads(vector<THREADENTRY32> *maListeDeThreads)
{
	HANDLE hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL); 
	if(hThreadSnapshot != INVALID_HANDLE_VALUE)
	{
		THREADENTRY32 monThread;
		monThread.dwSize = sizeof(THREADENTRY32);

		if(Thread32First(hThreadSnapshot, &monThread))
		{
			do
			{
				maListeDeThreads->push_back(monThread);
			}
			while(Thread32Next(hThreadSnapshot, &monThread));
		}
		CloseHandle(hThreadSnapshot);
		return true;
	}
	else
	{
		return false;
	}
}

Positionner une ACL à NULL sur un process, thread ou service…

En positionnant une ACL à NULL sur un process, thread ou service, tous les droits sont à accordés à tout le monde…
… ne pas oublier de demander le privilège : SE_SECURITY_NAME (« SeSecurityPrivilege »)

Méthode générique positionnant une ACL NULL sur un HANDLE de processus, thread ou service…

bool 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;
}

Lire la suite

Lister les services Windows

Un petit bout de code pour lister les services (et donc pilotes) Windows…
les retours de fonctions EnumServicesStatusEx ne sont pas vérifiés…

SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);

if (hSCM != NULL)
{
	DWORD dwEnumSizeNeeded;
	DWORD dwServicesCount;
	BYTE * bufferServiceState;

	EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_TYPE_ALL, SERVICE_STATE_ALL, NULL, 0, &dwEnumSizeNeeded, &dwServicesCount, NULL, NULL);
	bufferServiceState = new BYTE[dwEnumSizeNeeded];
	EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_TYPE_ALL, SERVICE_STATE_ALL, bufferServiceState,  dwEnumSizeNeeded, &dwEnumSizeNeeded, &dwServicesCount, NULL, NULL);

	ENUM_SERVICE_STATUS_PROCESS * pEnumStatus = reinterpret_cast<ENUM_SERVICE_STATUS_PROCESS *>(bufferServiceState);
	for(DWORD i = 0; i < dwServicesCount; i++)
	{
		wcout << pEnumStatus[i].lpServiceName << L'\t' << pEnumStatus[i].lpDisplayName << endl;
	}
	delete[] bufferServiceState;
}
CloseServiceHandle(hSCM);

Question de sécurité : Windows conserve-t-il la clé privée lors de la suppression d’un certificat ?

A vide, sans certificat

Du point de vue de certutil

c:\temp>certutil -user -store my
CertUtil: -store La commande s'est terminée correctement.

c:\temp>certutil -store my
CertUtil: -store La commande s'est terminée correctement.

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
Conteneur(s) machine :

Avec des certificats…

Installation de deux certificats (un dans le magasin utilisateur, l’autre machine)

c:\temp>certutil -user -p password -importpfx user.p12
c:\temp>certutil -p password -importpfx machine.p12

Du point de vue de certutil

c:\temp>certutil -user -store my
================ Certificat 0 ================
Objet: CN=user_export_noprotect
Conteneur de clé = user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1

c:\temp>certutil -store my
================ Certificat 0 ================
Objet: CN=machine_export_noprotect
Conteneur de clé = machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1
Conteneur(s) machine :
machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

A vide, en ayant supprimé les certificats

Suppression des certificats précédemment importés

c:\temp>certutil -user -delstore my "user_export_noprotect"
Suppression du certificat 0

c:\temp>certutil -delstore my "machine_export_noprotect"
Suppression du certificat 0

Du point de vue de certutil

c:\temp>certutil -user -store my
CertUtil: -store La commande s'est terminée correctement.

c:\temp>certutil -store my
CertUtil: -store La commande s'est terminée correctement.

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1
Conteneur(s) machine :
machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

Conclusion

Il semblerait que les conteneurs des clés privées des certificats précédemment importés soient encore présent…
Astuce disponible dans mimikatz (export des clés privées orphelines) !

Code de l’éxecutable : pkconteneurs

#pragma comment(lib, "advapi32.lib")

#include <windows.h>
#include <iostream>

using namespace std;

void listContainers(bool isMachine)
{
	DWORD flags = CRYPT_VERIFYCONTEXT | (isMachine ? CRYPT_MACHINE_KEYSET : NULL);

	HCRYPTPROV hCryptProv = NULL;
	if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, flags))
	{
		DWORD buflen = 0;
		if(CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST))
		{
			char * cname = new char[buflen];
			for (DWORD idx = 0;;idx++)
			{
				if(CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, reinterpret_cast<BYTE *>(cname), &buflen, (idx == 0 ? CRYPT_FIRST : CRYPT_NEXT)))
				{
					wcout << cname << endl;
				}
				else
				{
					break;
				}
			}
			delete[] cname;
		}
	}
	CryptReleaseContext(hCryptProv, 0);
}

int wmain(int argc, wchar_t * argv[])
{
	wcout << L"Conteneur(s) utilisateur :" << endl << endl;
	listContainers(false);
	wcout << endl;
	
	wcout << L"Conteneur(s) machine :" << endl << endl;
	listContainers(true);
	wcout << endl;

	return ERROR_SUCCESS;
}