def run(self): time = self.trigger['time'] engine.debug('thread running {}'.format(time)) while not self.stop_event.wait(time): engine.debug('conditional timer trigger') for bid in aggressor.beacon_ids(): _conditionally_run(bid, self.trigger)
def modifier_callback(*args): engine.debug('calling callback for modifier {}'.format(name)) try: return callback(*args) except Exception as exc: engine.handle_exception_softly(exc) return '[!] An Exception occurred in the {} output modifier. See Script Console for more details.'.format( name)
def alias_callback(*args): bid = int(args[0]) if utils.check_args(callback, args): try: engine.debug('calling callback for alias {}'.format(name)) callback(*args) except Exception as e: aggressor.berror( bid, "Caught Python exception while executing alias '{}': {}\n See Script Console for more details." .format(name, str(e))) raise e else: syntax = '{}{}'.format(name, utils.signature(callback, trim=1)) aggressor.berror(bid, "Syntax: " + syntax) engine.error( "Invalid number of arguments passed to alias '{}'. Syntax: {}". format(name, syntax))
def call(name, args): """ Call a function callback by name :param name: Name of callback :param args: Arguments to pass to callback (checked by `utils.check_args` first) """ global _callbacks if name in _callbacks: callback = _callbacks[name] if utils.check_args(callback, args): callback(*args) else: syntax = '{}{}'.format(name, utils.signature(callback)) engine.error("{} is an invalid number of arguments for callback '{}'. syntax: {}".format(len(args), name, syntax)) else: engine.debug('unknown callback {}'.format(name))
def _conditionally_run(bid, trigger): """ Run a trigger if the conditions match :param bid: Bid to run on :param trigger: Trigger to match :return: Whether or not command was run """ user = aggressor.beacon_info(bid, 'user') computer = aggressor.beacon_info(bid, 'computer') if 'all' in trigger and trigger['all'] or \ 'bid' in trigger and bid == trigger['bid'] or \ 'user' in trigger and user == trigger['user'] or \ 'computer' in trigger and computer == trigger['computer']: engine.debug('running command: ' + str(trigger['command'])) _run_command(bid, trigger['command']) return True else: return False
def call(name, args, return_id=None): """ Call a function callback by name :param name: Name of callback :param args: Arguments to pass to callback (checked by `utils.check_args` first) :param return_id: Write a return value to the script with this ID (optional) :return: Return value of callback """ engine.debug('Calling callback {}'.format(name)) global _callbacks if name in _callbacks: callback = _callbacks[name] if utils.check_args(callback, args): return_value = callback(*args) # send return value if return_id: return_message = {'value': return_value, 'id': return_id} engine.debug('Return sync: {} {}'.format( return_id, return_value)) engine.write('return', return_message) return True else: syntax = '{}{}'.format(name, utils.signature(callback)) raise RuntimeError( "{} is an invalid number of arguments for callback '{}'. Syntax: {}" .format(len(args), name, syntax)) return False else: engine.debug('Tried to call unknown callback: {}'.format(name)) return False
def compile( # Input options source, # Wrapper options use_wrapper=True, assembly_name=None, class_name=None, function_name=None, function_type=None, using=None, add_using=None, # Compilation options output_kind='console', platform='AnyCpu', dotnet_framework=None, optimization=True, out=None, # Confuser options confuser_config=None, confuser_protections=None, # Additional SharpGen options (passed through raw) additional_options=None, # Resources/references resources=None, references=None, add_resources=None, add_references=None, # Cache options cache=None, cache_overwrite=None, no_cache_write=False, # Dependency info sharpgen_location=None, sharpgen_runner=None ): """ Compile some C# code using SharpGen. :param source: Source to compile :param use_wrapper: Use a class and function Main code wrapper (default: True) :param class_name: Name of generated class (default: random) :param function_name: Name of function for wrapper (default: Main for .exe, Execute for .dll) :param function_type: Function return type (default: void for .exe, object for .dll) :param using: Namespaces to use (C# `using`) in the wrapper. See `sharpgen.set_using()` for more information. :param add_using: Additional namespaces to use (C# `using`) in the wrapper. These are added on top of the defaults. See `sharpgen.set_using()` for more information. :param assembly_name: Name of generated assembly (default: random) :param output_kind: Type of output (exe/console or dll/library) (default: console) :param platform: Platform to compile for (any/AnyCpu, x86, or x64) (default: AnyCpu) :param confuser_config: ConfuserEx configuration file. Set a default for this option with `set_confuser_config(<file>)`. :param confuser_protections: ConfuserEx protections to enable. Setting this argument will generate a temporary ConfuserEx config file for this build. For more information and to set a default for this option see `set_confuser_protections(<protections>)`. :param dotnet_framework: .NET Framework version to compile against (net35 or net40) (default: value passed to `set_dotnet_framework(<version>)` or net35) :param optimization: Perform code optimization (default: True) :param out: Output file (default: file in /tmp) :param additional_options: List of additional SharpGen options/flags (passed through raw) :param resources: List of resources to whitelist (by Name). This option temporarily modifies your `resources.yml` file so listed resources must be present in that file. By default resources.yml will not be touched. Call `set_resources(<resources>)` to change the default. :param references: List of references to whitelist (by File). This option temporarily modifies your `references.yml` file so listed references must be present in that file. By default references.yml will not be touched. Call `set_references(<references>)` to change the default. :param add_resources: List of resources to add, on top of the defaults (see `set_resources(<resources>)`) :param add_references: List of references to add, on top of the defaults (see `set_references(<references>)`) :param cache: Use the build cache. Not setting this option will use the global settings (`enable_cache()`/`disable_cache()`). By default the build cache is off. :param cache_overwrite: Force overwriting this build in the cache (disable cache retrieval but not writing). The default is `False` unless `enable_cache_overwrite()` is called. :param no_cache_write: Allow for cache retrieval but not cache writing :param sharpgen_location: Location of SharpGen directory (default: location passed to `set_location()` or PyCobalt repo copy) :param sharpgen_runner: Program used to run the SharpGen dll (default: sharpgen.default_runner or 'dotnet') :return: Tuple containing (out, cached) where `out` is the name of the output file and `cached` is a boolean containing True if the build is from the build cache :raises RuntimeError: If one of the options is invalid """ # check output_kind if output_kind not in ('exe', 'console', 'dll', 'library'): raise RuntimeError('Argument output_kind must be exe/console or dll/library') if output_kind == 'exe': output_kind = 'console' if output_kind == 'library': output_kind = 'dll' # check dotnet_framework if not dotnet_framework: global _default_dotnet_framework dotnet_framework = _default_dotnet_framework if dotnet_framework not in ('net35', 'net40'): raise RuntimeError('Argument dotnet_framework must be net35 or net40') if not out: # use a temporary output file if output_kind == 'dll': suffix = '_build.dll' else: suffix = '_build.exe' out = tempfile.NamedTemporaryFile(prefix='pycobalt.sharpgen.', suffix=suffix, delete=False).name # cache settings # set default cache_overwrite global _default_cache_overwrite if not cache_overwrite is None: cache_overwrite = _default_cache_overwrite # determine cache write and retrieval settings based on `cache`, # `cache_overwrite`, and `no_cache_write` global _default_cache_enabled if cache is None: # use global settings cache_write = _default_cache_enabled and not no_cache_write cache_retrieval = _default_cache_enabled and not cache_overwrite else: # override global settings cache_write = cache and not no_cache_write cache_retrieval = cache and not cache_overwrite if cache_retrieval or cache_write: # get cache source hash source_hash = cache_source_hash(source) if cache_retrieval: # try to retrieve build from cache if cache_retrieve(source_hash, out): # successfully retrieved file from the cache engine.debug('Retrieved {} from the SharpGen cache'.format(source_hash)) return out, True # default sharpgen_location if not sharpgen_location: global _sharpgen_location sharpgen_location = _sharpgen_location # find SharpGen.dll sharpgen_dll = _find_sharpgen_dll(_sharpgen_location) # wrapper options if use_wrapper: if not function_name: if output_kind == 'dll': function_name = 'Execute' else: function_name = 'Main' if not function_type: if output_kind == 'dll': function_type = 'object' else: function_type = 'void' if not using: # default is sharpgen.default_using global default_using using = default_using if add_using: using += add_using # de-duplicate using using = list(set(using)) source = wrap_code(source, function_name=function_name, function_type=function_type, class_name=class_name, using=using) # check platform platform = platform.lower() if platform not in ('any', 'anycpu', 'x86', 'x64'): raise RuntimeError('Argument platform must be any/AnyCpu, x86, or x64') if platform in ('any', 'anycpu'): platform = 'AnyCpu' args = [] # compiler options args += ['--dotnet-framework', dotnet_framework, '--output-kind', output_kind, '--platform', platform] if not optimization: args.append('--no-optimization') if assembly_name: args += ['--assembly-name', assembly_name] # ConfuserEx config # if neither flag is passed, pick a global default if not (confuser_config or confuser_protections): global _default_confuser_config global _default_confuser_protections # prefer `set_confuser_config()` over `set_confuser_protections()` if _default_confuser_config: confuser_config = _default_confuser_config elif _default_confuser_protections: confuser_protections = _default_confuser_protections # check to make sure both arguments were not passed if confuser_protections and confuser_config: raise RuntimeError('Arguments confuser_protections and confuser_config are not compatible together') # if confuser_protections is passed generate a ConfuserEx config file confuser_tempfile = None if confuser_protections: # this is cleaned up way at the bottom of the function confuser_tempfile = tempfile.NamedTemporaryFile('w+', prefix='pycobalt.sharpgen.', suffix='_confuser_config.cr') config = generate_confuser_config(confuser_protections) engine.debug('Confuser config: ' + config) confuser_tempfile.write(config) confuser_tempfile.flush() confuser_config = confuser_tempfile.name if confuser_config: args += ['--confuse', confuser_config] # additional options if additional_options: args += additional_options def filter_yaml(yaml, key, enabled_items): """ Filter references.yml or resources.yml :param yaml: Original yaml :param key: Key to filter on :param enabled_items: Values to filter on :return: Filtered yaml """ # parse content items = utils.yaml_basic_load(yaml) # filter out the items we want for item in items: if item[key].lower() in [item.lower() for item in enabled_items]: item['Enabled'] = 'true' else: item['Enabled'] = 'false' # dump new yaml return utils.yaml_basic_dump(items) resources_yaml_file = '{}/Resources/resources.yml'.format(sharpgen_location) references_yaml_file = '{}/References/references.yml'.format(sharpgen_location) original_resources_yaml = None original_references_yaml = None # figure out resources behavior global default_resources if resources is None: resources = default_resources if add_resources: if resources in (None, no_changes): resources = add_resources else: resources.extend(add_resources) # de-duplicate resources if resources is not no_changes: resources = list(set(resources)) # figure out references behavior global default_references if references is None: references = default_references if add_references: if references in (None, no_changes): references = add_references else: references.extend(add_references) # de-duplicate references if references is not no_changes: references = list(set(references)) # this feels a bit ugly but I can't think of a better way to do it try: # pick resources? if resources is not no_changes: # read in original yaml with open(resources_yaml_file, 'r') as fp: original_resources_yaml = fp.read() # filter yaml new_yaml = filter_yaml(original_resources_yaml, 'Name', resources) engine.debug('Temporarily overwriting {} with:\n{}'.format(resources_yaml_file, new_yaml)) # overwrite yaml file with new yaml with open(resources_yaml_file, 'w+') as fp: fp.write(new_yaml) # pick references? if references is not no_changes: # read in original yaml with open(references_yaml_file, 'r') as fp: original_references_yaml = fp.read() # filter yaml new_yaml = filter_yaml(original_references_yaml, 'File', references) engine.debug('Temporarily overwriting {} with:\n{}'.format(references_yaml_file, new_yaml)) # overwrite yaml file with new yaml with open(references_yaml_file, 'w+') as fp: fp.write(new_yaml) # write source to a file and build it with tempfile.NamedTemporaryFile('w+', prefix='pycobalt.sharpgen.', suffix='_code.cs') as source_file: source_file.write(source) source_file.flush() # in and out args += ['--file', out, '--source-file', source_file.name] if not sharpgen_runner: # default sharpgen_runner is default_runner ('dotnet' by # default) global default_runner sharpgen_runner = default_runner # call the SharpGen dll args = [sharpgen_runner, sharpgen_dll] + args #engine.debug('Compiling code: ' + source) #engine.debug('Running SharpGen: {}'.format(' '.join(args))) code, output, _ = helpers.capture(args, merge_stderr=True) output = output.decode() #engine.debug('Finished running SharpGen') if code != 0 or not os.path.isfile(out) or not os.path.getsize(out): # SharpGen failed engine.message('SharpGen invocation: {}'.format(' '.join(args))) engine.message('SharpGen error code: {}'.format(code)) engine.message('SharpGen error output:\n' + output) engine.message('End SharpGen error output') if os.path.isfile(out): os.remove(out) raise RuntimeError('SharpGen failed with code {}'.format(code)) else: engine.debug('SharpGen return: {}'.format(code)) engine.debug('SharpGen output: {}'.format(output)) finally: if original_resources_yaml: # set the resources yaml back to the original with open(resources_yaml_file, 'w+') as fp: fp.write(original_resources_yaml) if original_references_yaml: # set the references yaml back to the original with open(references_yaml_file, 'w+') as fp: fp.write(original_references_yaml) if cache_write and os.path.isfile(out): # copy build to the cache engine.debug('Adding {} to SharpGen cache'.format(source_hash)) _cache_add(source_hash, out) if confuser_tempfile: # we have to explictly close the tempfile here. otherwise python's # garbage collector might "optimize" out the object early, causing the # file to be deleted. confuser_tempfile.close() return out, False
def event_callback(*args): engine.debug('calling callback for event {}'.format(name)) callback(*args)
def command_callback(*args): engine.debug('calling callback for command {}'.format(name)) callback(*args)
def _(*args): global _triggers parser = helpers.ArgumentParser(prog='auto', event_log=True) parser.add_argument('-b', '--bid', action='append', type=int, help='Bid to trigger on') parser.add_argument('-u', '--user', action='append', help='User to trigger on') parser.add_argument('-c', '--computer', action='append', help='Computer to trigger on') parser.add_argument('-a', '--all', action='store_true', help='Trigger on all beacons') parser.add_argument( '-i', '--initial', action='store_true', help='Trigger on initial beacon (default for --user and --computer)') parser.add_argument('-o', '--output', action='store_true', help='Trigger on beacon output (default for --bid)') #parser.add_argument('-t', '--timed', metavar='SECONDS', type=int, help='Trigger every X seconds') parser.add_argument('-r', '--remove', type=int, help='Remove a trigger') parser.add_argument('-l', '--list', action='store_true', help='List triggers') parser.add_argument('command', nargs='*', help='Command to run') try: args = parser.parse_args(args) except: return # -r/--remove if args.remove: if args.remove < len(_triggers) and args.remove >= 0: trigger = _triggers[args.remove] if trigger['type'] == timed: trigger['timer'].stop() del _triggers[args.remove] bot.say('Removed trigger {}'.format(args.remove)) else: bot.error('Trigger {} does not exist'.format(args.remove)) # -l/--list elif args.list: output = 'Triggers:\n' for num, trigger in enumerate(_triggers): output += '{}: {}\n'.format(num, str(trigger)) bot.say(output) else: if not (args.bid or args.user or args.computer or args.all): bot.error('Specify --bid, --user, --computer, or --all') return if not args.command: bot.error('Specify command') return trigger = {} trigger['command'] = args.command if args.bid: trigger['bids'] = args.bid if args.user: trigger['users'] = args.user if args.computer: trigger['computers'] = args.computer if args.all: trigger['all'] = True # -o/--output if args.output: # on output trigger['type'] = 'output' # -t/--timed elif args.timed: # timed trigger['type'] = 'timed' trigger['time'] = args.timed trigger['timer'] = TriggerTimer(trigger) trigger['timer'].start() else: # on initial trigger['type'] = 'initial' _triggers.append(trigger) engine.debug('Adding trigger: {}'.format(str(trigger))) bot.good('Added trigger')
def beacon_top_callback(bids): engine.debug('')
def compile_file( # Input options source, # SharpGen options dotnet_framework='net35', output_kind='console', platform='x86', no_optimization=False, assembly_name=None, class_name=None, confuse=None, out=None, # Additional SharpGen options (passed through raw) additional_options=None, # Resources/references resources=None, references=None, # Dependency info sharpgen_location=None ): """ Compile a file using SharpGen. :param source: File name to compile :param dotnet_framework: .NET version to compile against (net35 or net40) (SharpGen's --dotnet-framework) :param output_kind: Type of output (console or dll) (SharpGen's --output-kind) :param platform: Platform to compile for (AnyCpy, x86, or x64) (SharpGen's --platform) :param no_optimization: Do not perform code optimization (SharpGen's --no-optimization) :param assembly_name: Name of generated assembly (SharpGen's --assembly-name) :param class_name: Name of generated class (SharpGen's --class-name) :param confuse: ConfuserEx configuration file (SharpGen's --confuse) :param out: Output file (SharpGen's --file) :param additional_options: List of additional SharpGen options/flags (passed through raw) :param resources: List of resources to include (by Name). These must be present in your resources.yml file. :param references: List of references to include (by File). These must be present in your references.yml file. :param sharpgen_location: Location of SharpGen directory (default: location passed to `set_location()` or repo copy) :return: Name of output file :raises: RuntimeError: If one of the options is invalid """ global _sharpgen_location # default sharpgen_location if not sharpgen_location: sharpgen_location = _sharpgen_location sharpgen_dll = _find_sharpgen_dll(_sharpgen_location) # python 3.5 typing is still too new so I do this instead # check dotnet_framework if dotnet_framework not in ['net35', 'net40']: raise RuntimeError('compile_file: dotnet_framework must be net35 or net40') # check output_kind if output_kind not in ['console', 'dll']: raise RuntimeError('compile_file: output_kind must be console or dll') # check platform if platform not in ['AnyCpy', 'x86', 'x64']: raise RuntimeError('compile_file: platform must be AnyCpy, x86, or x64') args = ['dotnet', sharpgen_dll, '--dotnet-framework', dotnet_framework, '--output-kind', output_kind, '--platform', platform] # other options if no_optimization: args.append('--no-optimization') if assembly_name: args += ['--assembly-name', assembly_name] if class_name: args += ['--class-name', class_name] if confuse: args += ['--confuse', confuse] if additional_options: args += additional_options resources_yaml_overwritten = False references_yaml_overwritten = False # this is a bit ugly but I can't think of a better way to do it try: if resources is not None: # pick resources resources_yaml_file = '{}/Resources/resources.yml'.format(sharpgen_location) # read in original yaml with open(resources_yaml_file, 'r') as fp: original_resources_yaml = fp.read() # and parse it items = utils.yaml_basic_load(original_resources_yaml) # filter out the items we want for item in items: if item['Name'] in resources: item['Enabled'] = 'true' else: item['Enabled'] = 'false' # overwrite yaml file with new yaml with open(resources_yaml_file, 'w+') as fp: new_yaml = utils.yaml_basic_dump(items) fp.write(new_yaml) resources_yaml_overwritten = True if references is not None: # pick references references_yaml_file = '{}/References/references.yml'.format(sharpgen_location) # read in original yaml with open(references_yaml_file, 'r') as fp: original_references_yaml = fp.read() # and parse it items = utils.yaml_basic_load(original_references_yaml) # filter out the items we want for item in items: if item['File'] in references: item['Enabled'] = 'true' else: item['Enabled'] = 'false' # overwrite yaml file with new yaml with open(references_yaml_file, 'w+') as fp: new_yaml = utils.yaml_basic_dump(items) fp.write(new_yaml) references_yaml_overwritten = True if not out: # use a temporary file if output_type == 'dll': suffix = '.dll' else: suffix = '.exe' out = tempfile.NamedTemporaryFile(prefix='pycobalt.sharpgen.', suffix=suffix, delete=False).name args += ['--file', out, '--source-file', source] engine.debug('running SharpGen: ' + ' '.join(args)) code, output, _ = helpers.capture(args, merge_stderr=True) output = output.decode() engine.debug('SharpGen return: {}'.format(code)) engine.debug('SharpGen output: {}'.format(output)) if code != 0: # SharpGen failed engine.message('SharpGen invocation: {}'.format(' '.join(args))) engine.message('SharpGen error code: {}'.format(code)) engine.message('SharpGen error output:\n' + output) engine.message('End SharpGen error output') raise RuntimeError('SharpGen failed with code {}'.format(code)) finally: if resources_yaml_overwritten: # set the resources yaml back to the original with open(resources_yaml_file, 'w+') as fp: fp.write(original_resources_yaml) if references_yaml_overwritten: # set the references yaml back to the original with open(references_yaml_file, 'w+') as fp: fp.write(original_references_yaml) return out