mirror of
https://github.com/jsecurity101/JonMon
synced 2026-06-08 15:08:08 +00:00
199 lines
5.9 KiB
C++
199 lines
5.9 KiB
C++
#include "thread.h"
|
|
#include "token.h"
|
|
|
|
PAGED_FILE();
|
|
|
|
NTSTATUS GetThreadHandle(CLIENT_ID ThreadId, PHANDLE hToken) {
|
|
HANDLE handleToken = NULL;
|
|
HANDLE hThread = NULL;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES attr = { 0 };
|
|
|
|
PAGED_CODE();
|
|
status = ZwOpenThread(&hThread, 0x0040, &attr, &ThreadId);
|
|
status = ZwOpenThreadTokenEx(hThread, TOKEN_ALL_ACCESS, TRUE, OBJ_KERNEL_HANDLE, &handleToken);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Exit;
|
|
}
|
|
Exit:
|
|
*hToken = handleToken;
|
|
if(hThread != NULL)
|
|
{
|
|
ZwClose(hThread);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// Define the process object and thread object structures
|
|
VOID GetThreadToken(HANDLE hThread) {
|
|
HANDLE hToken = NULL;
|
|
NTSTATUS status;
|
|
PTOKEN_STATISTICS pTokenInfo = NULL;
|
|
ULONG returnLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
//DbgPrint("Getting Thread Token\n");
|
|
status = ZwOpenProcessTokenEx(hThread, TOKEN_QUERY, OBJ_KERNEL_HANDLE, &hToken);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
status = ZwQueryInformationToken(hToken, TokenStatistics, NULL, 0, &returnLength);
|
|
pTokenInfo = (PTOKEN_STATISTICS)ExAllocatePool2(POOL_FLAG_PAGED, returnLength, THREAD_TAG);
|
|
|
|
if (pTokenInfo == NULL)
|
|
{
|
|
DbgPrint("ExAllocatePoolWithTag Failed: %08x\n", status);
|
|
goto Exit;
|
|
}
|
|
status = ZwQueryInformationToken(hToken, TokenStatistics, pTokenInfo, returnLength, &returnLength);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DbgPrint("ZwQueryInformationToken Failed: %08x\n", status);
|
|
goto Exit;
|
|
}
|
|
DbgPrint("Token Type: %d\n", pTokenInfo->TokenType);
|
|
|
|
|
|
Exit:
|
|
if (pTokenInfo != NULL) {
|
|
ExFreePoolWithTag(pTokenInfo, THREAD_TAG);
|
|
}
|
|
if (hToken != NULL) {
|
|
ZwClose(hToken);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//Crashing for some reason here - debug.
|
|
NTSTATUS GetThreadImpersonationLevel(PETHREAD thread, PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel, PUNICODE_STRING ImpersonationName) {
|
|
PAGED_CODE();
|
|
PACCESS_TOKEN token = NULL;
|
|
BOOLEAN copyOnOpen;
|
|
BOOLEAN effectiveOnly;
|
|
SECURITY_IMPERSONATION_LEVEL impersonationLevel;
|
|
NTSTATUS status = STATUS_ABANDONED;
|
|
token = PsReferenceImpersonationToken(thread, ©OnOpen, &effectiveOnly, &impersonationLevel);
|
|
if (token == NULL) {
|
|
return STATUS_NO_TOKEN;
|
|
}
|
|
else {
|
|
*ImpersonationLevel = impersonationLevel;
|
|
UNICODE_STRING ImpersonationString{};
|
|
switch (impersonationLevel) {
|
|
case SecurityImpersonation:
|
|
{
|
|
RtlInitUnicodeString(&ImpersonationString, L"SecurityImpersonation");
|
|
break;
|
|
}
|
|
case SecurityDelegation:
|
|
{
|
|
RtlInitUnicodeString(&ImpersonationString, L"SecurityDelegation");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (ImpersonationString.Buffer != NULL) {
|
|
RtlCopyUnicodeString(ImpersonationName, &ImpersonationString);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
PsDereferenceImpersonationToken(token);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// JonMonToDo: Update unicode_strings to properly clear. Also need to re-write because I am doing SourceThreadId and passing in CLIENT_ID.
|
|
//
|
|
|
|
NTSTATUS ThreadImpersonationEvent(HANDLE hToken, PETHREAD eThread, PCWSTR OperationType, WCHAR* RequestorImagePath, ULONGLONG USourceProcessId, ULONGLONG sourceProcStartKey, ULONGLONG UTargetProcessId, ULONGLONG targetProcStartKey) {
|
|
UNREFERENCED_PARAMETER(OperationType);
|
|
UNREFERENCED_PARAMETER(UTargetProcessId);
|
|
UNREFERENCED_PARAMETER(targetProcStartKey);
|
|
UNICODE_STRING SourceFullUserName{}, ProcessIntegrityLevel{}, ThreadIntegrityLevel{}, ImpersonatedUser{}, ImpersonationString{};
|
|
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
|
|
FILETIME fileTime;
|
|
ULONGLONG SourceThreadId = HandleToULong(PsGetThreadId(eThread));
|
|
CLIENT_ID sourceClientId;
|
|
sourceClientId.UniqueProcess = (HANDLE)USourceProcessId;
|
|
sourceClientId.UniqueThread = (HANDLE)SourceThreadId;
|
|
HANDLE hThreadToken = NULL;
|
|
PAGED_CODE();
|
|
|
|
/*
|
|
* Update function to only write event if the target and source user are different or the integrity levels are different
|
|
*/
|
|
SourceFullUserName.Length = 0;
|
|
SourceFullUserName.MaximumLength = MAX_ALLOC;
|
|
SourceFullUserName.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, THREAD_TAG);
|
|
NTSTATUS status = GetTokenUserName(hToken, &SourceFullUserName);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("GetTokenUserName Failed: %08x\n", status);
|
|
goto Exit;
|
|
}
|
|
|
|
status = GetTokenIntegrityLevel(hToken, &ProcessIntegrityLevel);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("GetTokenIntegrityLevel Failed: %08x\n", status);
|
|
goto Exit;
|
|
}
|
|
|
|
KeQuerySystemTime(&fileTime);
|
|
if (eThread != NULL) {
|
|
status = GetThreadHandle(sourceClientId, &hThreadToken);
|
|
if (!NT_SUCCESS(status) || hThreadToken == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
ImpersonatedUser.Length = 0;
|
|
ImpersonatedUser.MaximumLength = MAX_ALLOC;
|
|
ImpersonatedUser.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, THREAD_TAG);
|
|
status = GetTokenUserName(hThreadToken, &ImpersonatedUser);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("GetTokenUserName Failed: %08x\n", status);
|
|
ImpersonatedUser.Buffer = NULL;
|
|
}
|
|
|
|
status = GetTokenIntegrityLevel(hThreadToken, &ThreadIntegrityLevel);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("GetTokenIntegrityLevel Failed: %08x\n", status);
|
|
ImpersonatedUser.Buffer = NULL;
|
|
}
|
|
ImpersonationString.Length = 0;
|
|
ImpersonationString.MaximumLength = MAX_ALLOC;
|
|
ImpersonationString.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, MAX_ALLOC, THREAD_TAG);
|
|
status = GetThreadImpersonationLevel(eThread, &ImpersonationLevel, &ImpersonationString);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Exit;
|
|
}
|
|
EventWriteImpersonationAction(NULL, &fileTime, RequestorImagePath, USourceProcessId, sourceProcStartKey, ProcessIntegrityLevel.Buffer, SourceFullUserName.Buffer, SourceThreadId, ImpersonationLevel, ImpersonationString.Buffer, ImpersonatedUser.Buffer, ThreadIntegrityLevel.Buffer, OperationType);
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (SourceFullUserName.Buffer != NULL)
|
|
{
|
|
ExFreePoolWithTag(SourceFullUserName.Buffer, THREAD_TAG);
|
|
}
|
|
if (ImpersonationString.Buffer != NULL)
|
|
{
|
|
ExFreePoolWithTag(ImpersonationString.Buffer, THREAD_TAG);
|
|
}
|
|
if (ImpersonatedUser.Buffer != NULL)
|
|
{
|
|
ExFreePoolWithTag(ImpersonatedUser.Buffer, THREAD_TAG);
|
|
}
|
|
if (hThreadToken != NULL)
|
|
{
|
|
ZwClose(hThreadToken);
|
|
}
|
|
return status;
|
|
}
|