Пример #1
0
    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)
Пример #2
0
 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)
Пример #3
0
 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))
Пример #4
0
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))
Пример #5
0
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
Пример #6
0
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
Пример #7
0
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
Пример #8
0
 def event_callback(*args):
     engine.debug('calling callback for event {}'.format(name))
     callback(*args)
Пример #9
0
 def command_callback(*args):
     engine.debug('calling callback for command {}'.format(name))
     callback(*args)
Пример #10
0
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')
Пример #11
0
def beacon_top_callback(bids):
    engine.debug('')
Пример #12
0
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