From 37d3c296ad814886e7d4c63c447abbc3c52bd93b Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Fri, 9 Sep 2022 16:33:23 -0400 Subject: [PATCH] Add compiler support when mingw is available --- LICENSE | 4 ++ data/headers/windows/c_payload_util/beacon.h | 69 +++++++++++++++++++ .../console/command_dispatcher/bofloader.rb | 46 ++++++++++++- 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 data/headers/windows/c_payload_util/beacon.h diff --git a/LICENSE b/LICENSE index 86ab66690f..c17fc755d5 100644 --- a/LICENSE +++ b/LICENSE @@ -15,6 +15,10 @@ License: BSD-3-clause # Last updated: 2013-Nov-04 # +Files: data/headers/windows/c_payload_util/beacon.h +Copyright: 2022, Copyright Help/Systems LLC and its group of companies. +License: Apache 2.0 + Files: data/exploits/mysql/lib_mysqludf_sys_*.so Copyright: 2007 Roland Bouman 2008-2010 Roland Bouman and Bernardo Damele A. G. diff --git a/data/headers/windows/c_payload_util/beacon.h b/data/headers/windows/c_payload_util/beacon.h new file mode 100644 index 0000000000..d656a3d29e --- /dev/null +++ b/data/headers/windows/c_payload_util/beacon.h @@ -0,0 +1,69 @@ +/* + * 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 + */ + +/* 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, char * text, int len); +DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, 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 + +DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); +DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); + + +/* 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); diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/bofloader.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/bofloader.rb index df2c678dd6..e9ca6d45bd 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/bofloader.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/bofloader.rb @@ -24,10 +24,11 @@ module Rex 'Beacon Object File Loader' end - DEFAULT_ENTRY = 'go' + DEFAULT_ENTRY = 'go'.freeze @@execute_bof_opts = Rex::Parser::Arguments.new( ['-h', '--help'] => [ false, 'Help Banner' ], + ['-c', '--compile'] => [ true, 'Compile the input file (requires mingw).' ], ['-e', '--entry'] => [ true, "The entry point (default: #{DEFAULT_ENTRY})." ], ['-f', '--format-string'] => [ true, 'bof_pack compatible format-string. Choose combination of: b, i, s, z, Z' ] ) @@ -54,6 +55,8 @@ module Rex return tab_complete_filenames(str, words) if words.length == 1 fmt = { + '-c' => [ nil ], + '--compile' => [ nil ], '-e' => [ true ], '--entry' => [ true ], '-f' => [ true ], @@ -63,7 +66,7 @@ module Rex end def cmd_execute_bof(*args) - if args.length == 0 || args.include?('-h') || args.include?('--help') + if args.empty? || args.include?('-h') || args.include?('--help') cmd_execute_bof_help return false end @@ -72,9 +75,12 @@ module Rex bof_args_format = nil bof_cmdline = [] entry = DEFAULT_ENTRY + compile = false @@execute_bof_opts.parse(args) do |opt, _idx, val| case opt + when '-c', '--compile' + compile = true when '-f', '--format-string' bof_args_format = val when '-e', '--entry' @@ -104,7 +110,12 @@ module Rex print_status('No argument format specified, executing bof with no arguments.') end - bof_data = ::File.binread(bof_filename) + if compile + bof_data = compile_c(bof_filename) + return unless bof_data + else + bof_data = ::File.binread(bof_filename) + end # loading all data will hang on invalid files like DLLs, so only parse the 20-byte header at first parsed = Metasm::COFF.decode_header(bof_data[0...20]) @@ -145,6 +156,35 @@ module Rex private + def compile_c(source) + if client.arch == ARCH_X86 + mingw = Metasploit::Framework::Compiler::Mingw::X86.new + elsif client.arch == ARCH_X64 + mingw = Metasploit::Framework::Compiler::Mingw::X64.new + else + print_error("Unsupported client architecture: #{client.arch}") + return + end + + unless mingw.class.available? + print_error("#{mingw.mingw_bin} is unavailable, can not compile source code") + return + end + + ::Dir::Tmpname.create([::File.basename(source, '.c'), '.o']) do |destination| + output, status = Open3.capture2e(mingw.mingw_bin, '-c', source, '-I', Metasploit::Framework::Compiler::Mingw::INCLUDE_DIR, '-o', destination) + unless status.exitstatus == 0 + print_error("Compilation exited with error code: #{status.exitstatus}") + print_line(output) unless output.blank? + return + end + + bof_data = ::File.binread(destination) + ::File.delete(destination) + return bof_data + end + end + def get_executable_symbols(coff) executable_symbols = [] coff.symbols.each do |sym|