Esempio n. 1
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "/some/path/file.txt", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing pkg module for id: {0}'.format(block_id))
    # fetch required param
    name = runner_utils.get_chained_param(extra_args)
    if not name:
        name = runner_utils.get_param_for_module(block_id, block_dict, 'name')

    installed_pkgs_dict = __mods__['pkg.list_pkgs']()
    filtered_pkgs_list = fnmatch.filter(installed_pkgs_dict, name)
    result_dict = {}
    for package in filtered_pkgs_list:
        result_dict[package] = installed_pkgs_dict[package]

    return runner_utils.prepare_positive_result_for_module(
        block_id, result_dict)
Esempio n. 2
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "/some/path/file.txt", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing stat module for id: {0}'.format(block_id))
    # fetch required param
    filepath = runner_utils.get_chained_param(extra_args)
    if filepath and isinstance(filepath, dict):
        # in case, the result is a dictionary. Fetch the path
        for key, value in filepath.items():
            filepath = value
    if not filepath:
        filepath = runner_utils.get_param_for_module(block_id, block_dict, 'path')

    # check filepath existence
    if not os.path.exists(filepath):
        return runner_utils.prepare_negative_result_for_module(block_id, 'file_not_found')

    stat_res = __mods__['file.stats'](filepath)
    return runner_utils.prepare_positive_result_for_module(block_id, stat_res)
Esempio n. 3
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "vm.zone_reclaim_mode", 'status': True},
                  'caller': 'Audit'}
    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing sysctl module for id: {0}'.format(block_id))
    # fetch required param
    name = runner_utils.get_chained_param(extra_args)
    if not name:
        name = runner_utils.get_param_for_module(block_id, block_dict, 'name')

    sysctl_res = __mods__['sysctl.get'](name)
    result = {name: sysctl_res}
    if not sysctl_res or "No such file or directory" in sysctl_res:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "Could not find attribute %s in the kernel" % (name))
    if sysctl_res.lower().startswith("error"):
        return runner_utils.prepare_negative_result_for_module(
            block_id, "An error occurred while reading the value "
            "of kernel attribute %s" % (name))

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 4
0
def _filter(block_id, seq, filter_rules):
    """
    Filter a sequence.

    block_id
        Block id

    seq
        The input sequence to be filtered.

    filter_rules
        A dict of (comparison_type, value) pairs that dictate the type of filtering
        where comparison_type can be [gt, lt, eq, ne, ge, le].
        For e.g. for ``seq`` = [1, 2, 3, 4, 5] ``filter_rules``={le: 4, gt: 1, ne: 2}
        the function outputs [3, 4] - values less than or equal to 4, greater than 1,
        not equal to 2.
    """
    if not isinstance(filter_rules, dict):
        log.error("``filter_rules`` should be of type dict")
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')
    ret = seq
    for comp, value in filter_rules.items():
        try:
            ret = [x for x in ret if _compare(comp, x, value)]
        except ArgumentValueError:
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')

    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 5
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "/some/path/file.txt", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing stat module for id: {0}'.format(block_id))
    # fetch required param
    name = runner_utils.get_chained_param(extra_args)
    if not name:
        name = runner_utils.get_param_for_module(block_id, block_dict, 'name')

    result = []
    matched_services = fnmatch.filter(__mods__['service.get_all'](), name)
    for matched_service in matched_services:
        service_status = __mods__['service.status'](matched_service)
        is_enabled = __mods__['service.enabled'](matched_service)
        result.append({
            "name": matched_service,
            "running": service_status,
            "enabled": is_enabled
        })

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 6
0
def _get_key(block_id, block_dict, extra_args):
    """
    Given a dictionary, return an element by ``key``.

    block_id:
        Block id

    block_dict:
        key:           (Mandatory)
                        Key value to get
        starting_dict: (Optional)
                        Starting dictionary param
        extend_chained: (Default True)
                        By default, ``chained`` will have ``.update()`` called on it with
                        ``starting_dict`` as the only argument. Set ``extend_chained`` to False
                        to ignore ``starting_dict``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the key is found, and
    False othewise. The second argument will be the value found by the key or
    None if the key is not present in the dictionary.
    """
    chained = runner_utils.get_chained_param(extra_args)

    key = runner_utils.get_param_for_module(block_id, block_dict, 'key')
    starting_dict = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'starting_dict')
    update_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'update_chained', True)

    if update_chained and starting_dict:
        try:
            chained.update(starting_dict)
        except (TypeError, ValueError):
            log.error("Arguments should be of type dict.", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    try:
        ret = chained[key]
    except KeyError:
        log.error("Key not found: %s", key, exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'key_not_found')
        return False, None
    except TypeError:
        log.error("Arguments should be of type dict.", exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')
    status = bool(ret)

    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 7
0
def _sort(block_id, block_dict, extra_args):
    """
    Given a target sequence, sort it and return the sorted result.

    block_id:
        Block id

    block_dict:
        seq:            (Optional)
                        Input sequence to be sorted
        lexico:         (Optional) (Default False)
                        Set to True if the sorting thould be in lexicographical order.
        desc:           (Optional) (Default False)
                        Set to True if the sorting should be in descending order.
        extend_chained: (Default True)
                        By default, ``chained`` will have ``.extend()`` or
                        ``.update()`` or ``.format()``
                        called on it with ``seq`` as the only argument.
                        Set ``extend_chained`` to False to ignore ``seq``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the sort is successful, and
    False othewise. The second argument will be the sorted sequence.
    """
    chained = runner_utils.get_chained_param(extra_args)

    extend_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'extend_chained', True)
    lexico = runner_utils.get_param_for_module(block_id, block_dict, 'lexico',
                                               False)
    desc = runner_utils.get_param_for_module(block_id, block_dict, 'desc',
                                             False)
    seq = runner_utils.get_param_for_module(block_id, block_dict, 'seq')

    if extend_chained and seq:
        try:
            if isinstance(chained, (dict, set)):
                chained.update(seq)
            elif isinstance(chained, list):
                chained.extend(seq)
            elif isinstance(chained, str):
                chained = seq.format(chained)
        except (AttributeError, TypeError, ValueError):
            log.error("Invalid arguments type.", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    ret = _sort_helper(chained, desc, lexico)
    status = bool(ret)

    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 8
0
def _get_index(block_id, block_dict, extra_args):
    """
    Given a list list, return the item found at ``index``.

    block_id:
        Block id

    block_dict:
        index:         (Mandatory)
                        Index value for which value is needed
        starting_list: (Optional)
                        Starting list param
        extend_chained: (Default True)
                        By default, ``chained`` will have ``.extend()`` called on it with
                        ``starting_list`` as the only argument.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the return was successful, and
    False othewise. The second argument will be the requested list element.

    """
    chained = runner_utils.get_chained_param(extra_args)

    index = runner_utils.get_param_for_module(block_id, block_dict, 'index', 0)
    starting_list = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'starting_list')
    extend_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'extend_chained', True)

    if extend_chained and starting_list:
        try:
            chained.extend(starting_list)
        except (AttributeError, TypeError):
            log.error("Invalid argument type", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    try:
        ret = chained[index]
    except IndexError:
        log.error('List index out of range %d', index, exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')
    except TypeError:
        log.error('Arguments should be of type list', exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')

    status = bool(ret)
    if status:
        return runner_utils.prepare_positive_result_for_module(block_id, ret)
    return runner_utils.prepare_negative_result_for_module(
        block_id, 'invalid_result')
Esempio n. 9
0
def _join(block_id, block_dict, extra_args):
    """
    Given a list of strings, join them into a string, using ``sep`` as delimiter.

    block_id:
        Block id

    block_dict:
        words:          (Mandatory)
                        List of string
        sep:            (Optional)
                        Separator, Default: ''
        extend_chained: (Default True)
                        By default, ``chained`` will have ``.extend()`` called on it with
                        ``words`` as the only argument.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the join was successful, and
    False othewise. The second argument will be the output of the ``join``
    command.

    ``extend_chained`` is set to True when ``chained`` should be extended with ``words``.
    If set to False, ``words`` is ignored.
    """
    chained = runner_utils.get_chained_param(extra_args)

    extend_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'extend_chained', True)
    sep = runner_utils.get_param_for_module(block_id, block_dict, 'sep', '')
    words = runner_utils.get_param_for_module(block_id, block_dict, 'words',
                                              None)

    if extend_chained and words:
        try:
            chained.extend(words)
        except (AttributeError, TypeError):
            log.error("Arguments should be of type list.", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    try:
        ret = sep.join(chained)
    except (TypeError, AttributeError):
        log.error("Invalid arguments type.", exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')

    status = bool(ret)
    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')

    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 10
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "/some/path/file.txt", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing FDG Connector module for id: {0}'.format(block_id))

    fdg_file = runner_utils.get_chained_param(extra_args)
    if not fdg_file:
        fdg_file = runner_utils.get_param_for_module(block_id, block_dict,
                                                     'fdg_file')

    # read other params for fdg connector module
    starting_chained = runner_utils.get_param_for_module(
        block_id, block_dict, 'starting_chained')
    use_status = runner_utils.get_param_for_module(block_id, block_dict,
                                                   'use_status', False)
    consolidation_operator = runner_utils.get_param_for_module(
        block_id, block_dict, 'consolidation_operator', 'and')
    try:
        # fdg runner class
        fdg_runner = runner_factory.get_fdg_runner()
        fdg_runner.init_loader()

        # Handover to fdg_runner
        _, fdg_run = fdg_runner.execute(fdg_file,
                                        {'starting_chained': starting_chained})
    except Exception as e:
        raise HubbleCheckValidationError(
            'fdg_runner raised {0}: in file {1}, {2}'.format(
                e.__class__, fdg_file, e))

    if not isinstance(fdg_run, tuple):
        log.debug("consolidation_operator is %s", consolidation_operator)
        fdg_run = _get_consolidated_result(fdg_run, consolidation_operator)

    fdg_result, fdg_status = fdg_run
    if isinstance(fdg_result, dict) and 'error' in (k.lower()
                                                    for k in fdg_result):
        return runner_utils.prepare_negative_result_for_module(block_id, False)

    check_value = fdg_status if use_status else bool(fdg_result)
    if check_value:
        return runner_utils.prepare_positive_result_for_module(block_id, True)
    return runner_utils.prepare_negative_result_for_module(block_id, False)
Esempio n. 11
0
def _dict_convert_none(block_id, block_dict, extra_args):
    """
    Given a target sequence, look for dictionary keys that have empty string values
     and replace them with None.

    block_id:
        Block id

    block_dict:
        starting_seq:  (Optional)
                        Initial dictionary
        extend_chained: (Default True)
                        By default, ``chained`` will have ``.extend()`` or  ``.update()``  called on it with
                        ``starting_seq`` as the only argument.
                        Set ``extend_chained`` to False to ignore ``starting_seq``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the replacing is successful, and
    False othewise. The second argument will be the updated sequence.
    """
    chained = runner_utils.get_chained_param(extra_args)

    extend_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'extend_chained', True)
    starting_seq = runner_utils.get_param_for_module(block_id, block_dict,
                                                     'starting_seq')

    if extend_chained and starting_seq:
        try:
            if isinstance(chained, (set, dict)):
                chained.update(starting_seq)
            elif isinstance(chained, list):
                chained.extend(starting_seq)
        except (AttributeError, TypeError, ValueError):
            log.error("Invalid type of arguments", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    if isinstance(chained, dict):
        ret = _dict_convert_none_helper(chained)
    elif isinstance(chained, (set, list, tuple)):
        ret = _seq_convert_none_helper(chained)
    else:
        log.error("Invalid arguments type - dict or sequence expected")
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_error')
    status = bool(ret)

    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 12
0
def _nop(block_id, block_dict, extra_args):
    """
    This function just returns the chained value. It is a nop/no operation.

    This can be useful if you want to do a pipe_on_true to filter out
    False values -- you can pipe_on_true to util's nop, and stick a
    returner on the nop operation to just return the True values.
    """
    chained_params = runner_utils.get_chained_param(extra_args)
    return runner_utils.prepare_positive_result_for_module(
        block_id, chained_params)
Esempio n. 13
0
def _split(block_id, block_dict, extra_args):
    """
    Given a ``phrase`` string, split it into a list of words by a ``sep`` delimiter.

    block_id:
        Block id

    block_dict:
        phrase:         (Mandatory)
                        Input Phrase(string) to be split.
        sep:            (Optional)
                        Separator to split by. It can either be a delimiter or a regex.
                        If it's None it will split by whitespace.
        regex:          (Optional) (Default False)
                        Set to True if ``sep`` should be treated as a regex instead of a delimiter.
        format_chained: (Default True)
                        By default, the ``phrase`` will have ``.format()`` called on it with
                        ``chained`` as the only argument. (So, use ``{0}`` in your phrase to
                        substitute the chained value.) If you want to avoid having to escape
                        curly braces, set ``format_chained=False``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the delimiter is found and
    the splitting is successful, and False othewise. The second argument will be
    the output of the ``split`` command.
    """
    chained = runner_utils.get_chained_param(extra_args)

    format_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'format_chained', True)
    phrase = runner_utils.get_param_for_module(block_id, block_dict, 'phrase')
    sep = runner_utils.get_param_for_module(block_id, block_dict, 'sep')
    regex = runner_utils.get_param_for_module(block_id, block_dict, 'regex',
                                              False)

    if format_chained and chained:
        try:
            phrase = phrase.format(chained)
        except AttributeError:
            log.error("Invalid attributes type.", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    ret = _split_helper(phrase, sep, regex)
    status = bool(ret) and len(ret) > 1

    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 14
0
def execute(block_id, block_dict, extra_args=None):
    """
    For getting params to log, in non-verbose logging

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': {'host_ip': '127.0.0.1',
                                                'host_port': 443},
                                    'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    start_time = time.time()
    log.debug('Executing ssl_certificate module for id: {0}'.format(block_id))
    endpoint_chained = runner_utils.get_chained_param(extra_args)
    if endpoint_chained:
        host_ip = endpoint_chained.get('host_ip')
        host_port = endpoint_chained.get('host_port')
    else:
        host_ip = runner_utils.get_param_for_module(block_id, block_dict,
                                                    'host_ip')
        host_port = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'host_port')

    ssl_timeout = runner_utils.get_param_for_module(block_id, block_dict,
                                                    'ssl_timeout', 3)
    path = runner_utils.get_param_for_module(block_id, block_dict, 'path')

    cert = _get_cert(host_ip, host_port,
                     ssl_timeout=ssl_timeout) if host_ip else _get_cert(
                         path, from_file=True)
    if not cert:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unable_to_load_certificate')

    log.debug("ssl_certificate - cert found, parsing certificate")
    cert_details = _parse_cert(cert, host_ip, host_port, path)
    if 'error' in cert_details:
        log.debug('Error in parsing certificate. {0}'.format(
            cert_details['error']))
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unable_to_parse_certificate')
    stop_time = time.time()
    cert_details['execution_time'] = stop_time - start_time
    return runner_utils.prepare_positive_result_for_module(
        block_id, cert_details)
Esempio n. 15
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Chained argument dictionary, (If any)
        Example: {'chaining_args': {'result': {"name": "LogFileName", "value_type": "public"}, 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing win_firewall module for id: {0}'.format(block_id))
    __firewalldata__ = _import_firewall()
    if not __firewalldata__:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "firewall data couldn't be fetched")

    chained_result = runner_utils.get_chained_param(extra_args)
    if chained_result:
        name = chained_result.get('name')
        value_type = chained_result.get('value_type')
    else:
        name = runner_utils.get_param_for_module(block_id, block_dict, 'name')
        value_type = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'value_type')

    try:
        setting_value = __firewalldata__.get(value_type).get(name).lower()
    except Exception as e:
        log.debug(
            "for block id %s, setting name %s and value type %s is not "
            "found in firewall data", block_id, name, value_type)
        setting_value = "Not Found"
    result = {
        "name": name,
        "value_type": value_type,
        "setting_value": setting_value
    }
    log.debug("win_firewall module output for block_id %s, is %s", block_id,
              result)

    if not result:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "firewall setting couldn't be fetched")

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 16
0
def _print_string(block_id, block_dict, extra_args):
    """
    Given a string, return it.

    block_id:
        Block id

    block_dict:
        starting_string:  (Optional)
                        Initial string
        format_chained: (Default True)
                        By default, ``starting_string`` will have ``.format()`` called on it
                        with ``chained`` as the only argument. (So, use ``{0}`` in your pattern to
                        substitute the chained value.) If you want to avoid having to escape curly braces,
                        set ``format_chained=False``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be False only if an error will occur.
    """
    chained = runner_utils.get_chained_param(extra_args)

    format_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'format_chained', True)
    starting_string = runner_utils.get_param_for_module(
        block_id, block_dict, 'starting_string')

    if format_chained:
        try:
            starting_string = starting_string.format(chained)
        except AttributeError:
            log.error("Invalid type for starting_string - has to be string.",
                      exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    if not isinstance(starting_string, str):
        log.error('Invalid arguments - starting_string should be a string')
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'invalid_format')

    if not bool(starting_string):
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(
        block_id, starting_string)
Esempio n. 17
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Chained argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Local Administrator Password Solution", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing win_pkg module for id: {0}'.format(block_id))
    try:
        __pkgdata__ = __mods__['pkg.list_pkgs']()
    except CommandExecutionError:
        __mods__['pkg.refresh_db']()
        __pkgdata__ = __mods__['pkg.list_pkgs']()
    if not __pkgdata__:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "package list couldn't be fetched")

    chained_result = runner_utils.get_chained_param(extra_args)
    if chained_result:
        pkg_name = chained_result.get('name')
    else:
        pkg_name = runner_utils.get_param_for_module(block_id, block_dict,
                                                     'name')

    if pkg_name in __pkgdata__:
        audit_value = __pkgdata__.get(pkg_name)
    else:
        log.debug("for block id %s, pkg %s is not found in pkg data", block_id,
                  pkg_name)
        audit_value = "Not Found"

    result = {"package_name": pkg_name, "package_version": audit_value}
    log.debug("win_pkg module output for block_id %s, is %s", block_id, result)

    if audit_value == "Not Found":
        return runner_utils.prepare_negative_result_for_module(
            block_id, "package information couldn't be fetched")

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 18
0
def _dict_to_list(block_id, block_dict, extra_args):
    """
    Given a target dictionary, convert it to a list of (key, value) tuples.

    block_id:
        Block id

    block_dict:
        starting_dict:  (Optional)
                        Initial dictionary
        update_chained: (Default True)
                        By default, ``chained`` will have ``.update()`` called on it with
                        ``starting_dict`` as the only argument.
                        Set ``update_chained`` to False to ignore ``starting_dict``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be True if the conversion is successful,
    and False othewise. The second argument will be the list of tuples.
    """
    chained = runner_utils.get_chained_param(extra_args)

    update_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'update_chained', True)
    starting_dict = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'starting_dict')

    if update_chained and starting_dict:
        try:
            chained.update(starting_dict)
        except (AttributeError, ValueError, TypeError):
            log.error("Invalid arguments type.", exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')
    ret = [(key, value) for key, value in chained.items()]
    status = bool(ret)

    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 19
0
def execute(block_id, block_dict, extra_args=None):
    """
    Function that queries a list of NTP servers and checks if the
    offset is bigger than `max_offset` minutes. It expects the results from
    at least `nb_servers` servers in the list, otherwise the check fails.

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': ['server1', 'server2'], 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing time_sync module for id: {0}'.format(block_id))

    ntp_servers = _get_ntp_servers(block_id, block_dict, extra_args)

    time_sync_result = []

    for ntp_server in ntp_servers:
        offset = _query_ntp_server(ntp_server)
        if not offset:
            time_sync_result.append({
                'ntp_server': ntp_server,
                'replied': False
            })
            continue

        time_sync_result.append({
            'ntp_server': ntp_server,
            'replied': True,
            'offset': offset
        })

    return runner_utils.prepare_positive_result_for_module(
        block_id, time_sync_result)
Esempio n. 20
0
def execute(block_id, block_dict, extra_args=None):
    r"""
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Chained argument dictionary, (If any)
        Example: {'chaining_args': {'result': "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\EventLog\Application\MaxSize", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug("Executing win_reg module for id: {0}".format(block_id))

    chained_result = runner_utils.get_chained_param(extra_args)
    if chained_result:
        reg_name = chained_result.get("name")
    else:
        reg_name = runner_utils.get_param_for_module(block_id, block_dict,
                                                     "name")
    reg_dict = _reg_path_splitter(reg_name)
    secret = _find_option_value_in_reg(reg_dict.get("hive"),
                                       reg_dict.get("key"),
                                       reg_dict.get("value"))
    result = {reg_name: secret}
    log.debug("win_reg module output for block_id %s, is %s", block_id, result)

    if secret is False:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "registry value couldn't "
            "be fetched for reg_name {0}".format(reg_name))

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 21
0
def _encode_base64(block_id, block_dict, extra_args):
    """
    Given a string, base64 encode it and return it.

    block_id:
        Block id

    block_dict:
        starting_string:(Optional)
                        Initial string
        format_chained: (Default True)
                        By default, ``starting_string`` will have ``.format()`` called on it
                        with ``chained`` as the only argument. (So, use ``{0}`` in your pattern to
                        substitute the chained value.) If you want to avoid having to escape curly braces,
                        set ``format_chained=False``.

    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "Output", 'status': True},
                  'caller': 'Audit'}

    The first return value (status) will be False only if an error will occur.
    """
    chained = runner_utils.get_chained_param(extra_args)

    format_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'format_chained', True)
    starting_string = runner_utils.get_param_for_module(
        block_id, block_dict, 'starting_string')

    status, ret = utils_encode_base64(starting_string,
                                      format_chained=format_chained,
                                      chained=chained)
    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'unknown_error')
    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 22
0
def _filter_dict_helper(block_id, dct, filter_values, filter_rules):
    """
    Filter a dictionary.

    block_id
        Block id

    dct
        The input dictionary to be filtered.

    filter_values
        ``True`` if the function should filter the values instead of keys,
        ``False`` otherwise.

    filter_rules
        A dict of (comparison_type, value) pairs that dictate the type of filtering
        where comparison_type can be [gt, lt, eq, ne, ge, le].
        For e.g. for ``dct`` = {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}
                      ``kwargs``={le: 4, gt: 1, ne: 2}
        the function outputs {3: 'c', 4: 'd'} - key values less than or equal to 4, greater than 1,
        not equal to 2.
    """
    ret = dct
    for comp, value in filter_rules.items():
        try:
            ret = {
                key: val
                for key, val in ret.items()
                if (filter_values and _compare(comp, val, value)) or (
                    not filter_values and _compare(comp, key, value))
            }
        except ArgumentValueError:
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'invalid_format')

    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 23
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': {'cmdline': 'app --config-file=test test'}, 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug(
        'Executing command_line_parser module for id: {0}'.format(block_id))

    try:
        command_line = None

        chained_param = runner_utils.get_chained_param(extra_args)
        if chained_param:
            command_line = chained_param.get('cmdline')
        if not command_line:
            # get it from args
            command_line = runner_utils.get_param_for_module(
                block_id, block_dict, 'cmdline')

        key_aliases = runner_utils.get_param_for_module(
            block_id, block_dict, 'key_aliases')
        delimiter = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'delimiter')

        log.debug("command_line: {0}, key_aliases: {1}, delimeter: {2}".format(
            command_line, key_aliases, delimiter))
        ret_match_list = []

        for key_alias in key_aliases:
            log.debug("looping with key_alias %s", key_alias)
            key_alias = key_alias.lstrip("-")

            if key_alias not in command_line:
                log.info("key_alias %s not found in command line %s",
                         key_alias, command_line)
                continue

            regex_base = "".join([
                r"(?<=(\s|{))-{0,2}\"{0,1}'{0,1}", key_alias,
                r"\"{0,1}'{0,1}\s*", delimiter
            ])
            regex_list = []
            regex_pattern = "".join(
                [regex_base, r"\s*openingbracket.*closingbracket(?=(\s|$))"])
            braces_list = [(r'\[', r'\]'), (r'\{', r'\}'), (r'\(', r'\)')]
            for item in braces_list:
                regex = re.sub("openingbracket", item[0], regex_pattern)
                regex = re.sub("closingbracket", item[1], regex)
                regex_list.append(regex)
            regex1 = "".join([regex_base, r"\s*([\"']).*?\2"])
            regex2 = "".join([regex_base, r"\s*.+?(?=(\s|$))"])
            regex_list.append(regex1)
            regex_list.append(regex2)

            for regex in regex_list:
                log.debug("looping with regex : %s", regex)
                match_list = _get_match_list(regex, key_alias, command_line,
                                             delimiter)
                if match_list:
                    ret_match_list.extend(match_list)
                    break
        log.debug("command_line_parser module output for block_id %s, is %s",
                  block_id, ret_match_list)
        return runner_utils.prepare_positive_result_for_module(
            block_id, ret_match_list)

    except Exception as e:
        log.exception(
            "Some exception occurred in command_line_parser's parse_cmdline function %s",
            e)
        return runner_utils.prepare_negative_result_for_module(block_id, None)
Esempio n. 24
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Chained argument dictionary, (If any)
        Example: {'chaining_args': {'result': "SeRemoteInteractiveLogonRight", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing win_secedit module for id: {0}'.format(block_id))
    chained_result = runner_utils.get_chained_param(extra_args)
    if chained_result:
        sec_name = chained_result.get("name")
    else:
        sec_name = runner_utils.get_param_for_module(block_id, block_dict,
                                                     'name')

    try:
        value_type = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'value_type')
    except Exception as e:
        log.debug(
            "optional param, 'value_type' not provided as input, taking '' as value type"
        )
        value_type = ''

    __secdata__ = _secedit_export()
    coded_sec_value = __secdata__.get(sec_name)

    if coded_sec_value is None:
        result = {
            'sec_name': sec_name,
            'coded_sec_value': "No One",
            'sec_value': ['']
        }
        log.debug("win_secedit module output for block_id %s, is %s", block_id,
                  result)
        return runner_utils.prepare_positive_result_for_module(
            block_id, result)
    if 'account' == value_type:
        sec_value = _get_account_name(coded_sec_value)
    elif 'MACHINE\\' in sec_name:
        sec_value = _reg_value_reverse_translator(coded_sec_value)
    else:
        if ',' in coded_sec_value:
            sec_value = coded_sec_value.split(',')
        else:
            sec_value = [coded_sec_value]

    if not sec_value:
        return runner_utils.prepare_negative_result_for_module(
            block_id, "security config value couldn't be fetched")

    result = {
        'sec_name': sec_name,
        'coded_sec_value': coded_sec_value,
        'sec_value': sec_value
    }
    log.debug("win_secedit module output for block_id %s, is %s", block_id,
              result)

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 25
0
def execute(block_id, block_dict, extra_args=None):
    """
    For getting params to log, in non-verbose logging

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "/some/path/file.txt", 'status': True},
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing grep module for id: {0}'.format(block_id))
    # default mode=file, search in file.
    # In chaining, there can be two modes:
    #   filepath from chaining
    #   content from chaining

    filepath = None
    chained_filepath = None
    file_mode = True

    pattern = runner_utils.get_param_for_module(block_id, block_dict,
                                                'pattern')
    flags = runner_utils.get_param_for_module(block_id, block_dict, 'flags')
    if flags is None:
        flags = []
    if isinstance(flags, str):
        flags = [flags]

    # check if chained content is available
    format_chained = runner_utils.get_param_for_module(block_id, block_dict,
                                                       'format_chained', True)
    starting_string = runner_utils.get_param_for_module(
        block_id, block_dict, 'starting_string', False)
    chaining_file_mode = runner_utils.get_param_for_module(
        block_id, block_dict, 'chain_filepath', False)
    if chaining_file_mode:
        # in chain_filepath mode, filepath from chaining is mandatory
        chained_filepath = runner_utils.get_chained_param(extra_args)
        filepath = runner_utils.get_param_for_module(block_id, block_dict,
                                                     'path')
        if format_chained:
            pattern = pattern.format(chained_filepath)
            filepath = filepath.format(chained_filepath)
    else:
        file_content = runner_utils.get_chained_param(extra_args)
        if file_content:
            file_mode = False
            if format_chained and starting_string:
                file_content = starting_string.format(file_content)
        # fetch required param
        if file_mode:
            filepath = runner_utils.get_param_for_module(
                block_id, block_dict, 'path')
            if format_chained:
                filepath = filepath.format(file_content)

    # check filepath existence
    if file_mode:
        file_paths = filepath.split(' ')
        for file_path in file_paths:
            if not os.path.exists(file_path.strip()):
                return runner_utils.prepare_negative_result_for_module(
                    block_id, 'file_not_found')

    grep_result = _grep(filepath, file_content, pattern, *flags)
    ret_code = grep_result.get('retcode')
    result = grep_result.get('stdout')
    log.debug("grep module output for block_id %s, is %s", block_id, result)
    if ret_code != 0:
        if ret_code == 1:
            return runner_utils.prepare_negative_result_for_module(
                block_id, "pattern_not_found")
        else:
            return runner_utils.prepare_negative_result_for_module(
                block_id, "non_zero_return_code")

    return runner_utils.prepare_positive_result_for_module(block_id, result)
Esempio n. 26
0
def _handle_config_helper(block_id,
                          path,
                          pattern=None,
                          ignore_pattern=None,
                          dictsep=None,
                          valsep=None,
                          subsep=None,
                          chained_param=None):
    """
    This is a fairly specialized function designed to pull data from a file
    with formatting similar to this::

        APP_ATTRIBUTES=cluster_role:control;zone:3;provider:aws
        APP_ATTRIBUTES=cluster_role:worker;zone:1;provider:aws
        APP_ATTRIBUTES=cluster_role:master;zone:0;provider:aws

    The arguments decide how the data is parsed and are documented below.

    path
        Required argument. The file from which data will be extracted.

    pattern
        Optional. Only lines with this pattern will be collected. Regex is
        supported. If ``pattern`` is not provided, the whole file will be
        collected.

    ignore_pattern
        Optional. Lines with this pattern will be ignored. This overrides
        ``pattern``.

    dictsep
        Optional. Because this is a config-like file, we assume that each line
        has a key and a value. This is the separator for that key and value.
        If no ``dictsep`` is provided, we will take the whole line and just
        return a list of strings instead of a dict with keys and values.

        Note also that if a file, like the sample data above, has duplicate
        keys, there will be one key in the resulting dict, with a list
        of values underneath that key.

    valsep
        Optional. A value could be a list, with a defined separator. If this
        is defined, values will be split on this character or string.

    subsep
        Optional. As in the example above, there can be key-value pairs within
        a value. If this argument is defined, we will split the value (or
        each member of the value list if ``valsep`` is defined) and turn the
        result into a key-value pair in a dictionary. If this is defined in
        conjunction with ``valsep``, the result will be a dictionary, not
        a list of single-key dictionaries.

    chained_param
        Chained values will be called with ``.format()`` on the ``path``.

    Example:

    Assuming we have a file ``/tmp/data`` with the lines shown in the sample
    data above, we could write an fdg file like this:

    .. code-block:: yaml

        main:
          module: readfile.config
          kwargs:
            path: /tmp/data
            pattern: '^APP_ATTRIBUTES'
            dictsep: '='
            valsep: ';'
            subsep: ':'

    We would have this data (shown as json)

    .. code-block:: json

        {"APP_ATTRIBUTES":
            [
                {"cluster_role": "control",
                 "zone": "3",
                 "provider": "aws"},
                {"cluster_role": "worker",
                 "zone": "1",
                 "provider": "aws"},
                {"cluster_role": "master",
                 "zone": "0",
                 "provider": "aws"}
            ]
        }
    """
    if chained_param is not None:
        path = path.format(chained_param)

    if not os.path.isfile(path):
        log.error('Path %s not found.', path)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'file_not_found')

    if dictsep is None:
        ret = _lines_as_list(path, pattern, ignore_pattern)
    else:
        # Lines as key/value pairs in a dict
        ret = _lines_as_dict(path, pattern, ignore_pattern, dictsep, valsep,
                             subsep)

    if ret is not None:
        return runner_utils.prepare_positive_result_for_module(block_id, ret)

    return runner_utils.prepare_negative_result_for_module(block_id, ret)
Esempio n. 27
0
def _handle_file_helper(file_format,
                        block_id,
                        path,
                        subkey=None,
                        sep=None,
                        chained_param=None):
    """
    Pull data (optionally from a subkey) of a json object in a file at ``path``

    path
        Path of file to be read in

    subkey
        Optional. Key to pull out of json dict. If ``sep`` is defined, you can
        use it to separate subkeys and pull a value out of the depths of a
        dictionary. Note that we try to detect non-dict objects and assume if
        we find a non-dict object that it is a list, and that the subkey at
        that level is an integer.

    sep
        Separator in ``subkey``. If not defined, ``subkey`` will not be split.

    chained_param
        Value passed in via chaining in fdg. Will be called with ``.format()``
        on the path and subkey if defined.
    """
    if chained_param:
        path = path.format(chained_param)
        if subkey:
            subkey = subkey.format(chained_param)

    if not os.path.isfile(path):
        log.error('Path %s not found.', path)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'file_not_found')

    ret = None
    try:
        with open(path, 'r') as file_handle:
            if file_format == 'json':
                ret = _json.load(file_handle)
            elif file_format == 'yaml':
                ret = _yaml.safe_load(file_handle)
            else:
                return runner_utils.prepare_negative_result_for_module(
                    block_id, 'unknown_format')
    except Exception:
        log.error('Error reading file %s.', path, exc_info=True)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'exception while reading file')

    if subkey:
        subkey = [subkey] if not sep else subkey.split(sep)
        try:
            # Traverse dictionary
            for key in subkey:
                if not isinstance(ret, dict):
                    # If it's not a dict, assume it's a list and that `key` is an int
                    key = int(key)
                if key in ret:
                    ret = ret[key]
                elif isinstance(key, int):
                    ret = ret[key]
                else:
                    log.error("key '%s' not found in dictionary '%s'", key,
                              ret)
                    return runner_utils.prepare_negative_result_for_module(
                        block_id, 'KeyError')
        except (KeyError, TypeError, ValueError, IndexError):
            log.error('Error traversing dict.', exc_info=True)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'unknown_error')

    return runner_utils.prepare_positive_result_for_module(block_id, ret)
Esempio n. 28
0
def execute(block_id, block_dict, extra_args=None):
    """
    For getting params to log, in non-verbose logging

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing Curl module for id: {0}'.format(block_id))

    chained_param = runner_utils.get_chained_param(extra_args)
    if chained_param:
        log.warn('Chained value detected in curl.request module. Chained '
                 'values are unsupported in the curl module.')

    url = runner_utils.get_param_for_module(block_id, block_dict, 'url')

    kwargs = {}
    function_name = runner_utils.get_param_for_module(block_id, block_dict,
                                                      'function')
    if not function_name:
        function_name = 'GET'

    params = runner_utils.get_param_for_module(block_id, block_dict, 'params')
    if params:
        kwargs['params'] = params
    data = runner_utils.get_param_for_module(block_id, block_dict, 'data')
    if data:
        kwargs['data'] = data
    username = runner_utils.get_param_for_module(block_id, block_dict,
                                                 'username')
    password = runner_utils.get_param_for_module(block_id, block_dict,
                                                 'password')
    if username:
        kwargs['auth'] = (username, password)
    verify = runner_utils.get_param_for_module(block_id, block_dict, 'verify')
    if verify:
        kwargs['verify'] = verify
    headers = runner_utils.get_param_for_module(block_id, block_dict,
                                                'headers')
    if headers:
        kwargs['headers'] = headers
    timeout = runner_utils.get_param_for_module(block_id, block_dict,
                                                'timeout')
    if not timeout:
        timeout = 9
    kwargs['timeout'] = int(timeout)

    decode_json = runner_utils.get_param_for_module(block_id, block_dict,
                                                    'decode_json')
    if not decode_json:
        decode_json = True

    # Make the request
    status, response = _make_request(function_name, url, **kwargs)
    if not status:
        return runner_utils.prepare_negative_result_for_module(
            block_id, response)

    # Pull out the pieces we want
    ret = _parse_response(response, decode_json)

    # Status in the return is based on http status
    try:
        response.raise_for_status()
        return runner_utils.prepare_positive_result_for_module(block_id, ret)
    except requests.exceptions.HTTPError:
        return runner_utils.prepare_negative_result_for_module(block_id, ret)
Esempio n. 29
0
def _osquery(block_id,
             query,
             osquery_path=None,
             args=None,
             cast_to_string=None):
    """
    Format the osquery command and run it

    Returns a tuple, (status, ret) where status is True if the return code is 0,
    False otherwise, and ``ret`` is the stdout of the osquery command
    """
    max_file_size = 104857600

    if not query:
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'Empty query passed')
    if 'attach' in query.lower() or 'curl' in query.lower():
        log.critical(
            'Skipping potentially malicious osquery query \'%s\' '
            'which contains either \'attach\' or \'curl\'', query)
        return runner_utils.prepare_negative_result_for_module(
            block_id, 'Curl/Attach passed in query')

    # Prep the command
    if not osquery_path:
        if not os.path.isfile(__grains__['osquerybinpath']):
            log.error('osquery binary not found: %s',
                      __grains__['osquerybinpath'])
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'osquery binary not found')
        cmd = [
            __grains__['osquerybinpath'], '--read_max', max_file_size,
            '--json', query
        ]
    else:
        if not os.path.isfile(osquery_path):
            log.error('osquery binary not found: %s', osquery_path)
            return runner_utils.prepare_negative_result_for_module(
                block_id, 'osquery binary not found')
        cmd = [osquery_path, '--read_max', max_file_size, '--json', query]
    if isinstance(args, (list, tuple)):
        cmd.extend(args)

    # Run the command
    res = __mods__['cmd.run_all'](cmd, timeout=10000, python_shell=False)
    if res['retcode'] == 0:
        ret = json.loads(res['stdout'])
        for result in ret:
            for key, value in result.items():
                if value and isinstance(
                        value, str) and value.startswith('__JSONIFY__'):
                    result[key] = json.loads(value[len('__JSONIFY__'):])
        if cast_to_string:
            try:
                ret = _convert_to_str(ret)
            except (KeyError, TypeError):
                log.error('Invalid data type returned by osquery call %s.',
                          res,
                          exc_info=True)
                return runner_utils.prepare_negative_result_for_module(
                    block_id, 'Error while casting to string')
        return runner_utils.prepare_positive_result_for_module(block_id, ret)
    else:
        ret = {'stdout': res.get('stdout'), 'stderr': res.get('stderr')}
        return runner_utils.prepare_negative_result_for_module(block_id, ret)
Esempio n. 30
0
def execute(block_id, block_dict, extra_args=None):
    """
    Execute the module

    :param block_id:
        id of the block
    :param block_dict:
        parameter for this module
    :param extra_args:
        Extra argument dictionary, (If any)
        Example: {'chaining_args': {'result': "True", 'status': True},
                  'extra_args': [{'check_id': 'ADOBE-01',
                                  'check_status': 'Success'}]
                  'caller': 'Audit'}

    returns:
        tuple of result(value) and status(boolean)
    """
    log.debug('Executing bexpr module for check-id: %s' % block_id)
    result_list = extra_args.get('extra_args')
    keyword_list = ['AND', 'OR', 'NOT', '(', ')']
    operand_list = ['AND', 'OR', 'NOT']
    expression = runner_utils.get_param_for_module(block_id, block_dict,
                                                   'expr')
    original_expression = expression
    # Separating keywords on the basis of space
    expression = expression.replace('(', ' ( ')
    expression = expression.replace(')', ' ) ')
    # Parse the expression and evaluate the result
    # Splitting the expression on the basis of spaces
    expr_list = expression.split(" ")
    # Filtering out empty spaces
    expr_list = list(filter(None, expr_list))
    referred_checks_list = []
    referred_checks_result = {}
    operand_present = 0
    for expr in expr_list:
        if expr.upper() not in keyword_list:
            referred_checks_list.append(expr)
        elif expr.upper() in operand_list:
            operand_present += 1
    # Fetch the result of check from result list and store the result of referenced checks
    # In case a check is not present in result list or referred check result is not Success or Failure, raise an Error
    error = {}
    if len(referred_checks_list) == 0:
        error[
            block_id] = "No checks are referred in the boolean expression: %s" % original_expression
    if len(referred_checks_list) > 1 and operand_present == 0:
        error[
            block_id] = "No operand is present for multiple referred checks in boolean expression: %s" % original_expression

    if error:
        raise HubbleCheckValidationError(error)

    for referred_check_id in referred_checks_list:
        check_found = False
        for result in result_list:
            if result.get('check_unique_id', '') == referred_check_id:
                check_found = True
                check_result = result.get('check_result', '')
                if check_result == "Success":
                    referred_checks_result[referred_check_id] = "True"
                elif check_result == "Failure":
                    referred_checks_result[referred_check_id] = "False"
                else:
                    error[
                        block_id] = "Referred check: %s result is %s. Setting boolean expression check result to error." % (
                            referred_check_id, check_result)
                break

    if not check_found:
        error[
            block_id] = "Referred check: %s is not available. Please verify correct check is referred." % (
                referred_check_id)
    if error:
        raise HubbleCheckValidationError(error)

    try:
        check_result = _evaluate_expression(expr_list, keyword_list,
                                            referred_checks_result)
    except Exception as e:
        error[
            block_id] = "Error in evaluating boolean expression: %s Please verify the expression" % original_expression
        raise HubbleCheckValidationError(error)

    if not bool(check_result):
        log.info("Boolean expression: '%s' evaluated to failure" %
                 original_expression)
        return runner_utils.prepare_positive_result_for_module(block_id, False)

    return runner_utils.prepare_positive_result_for_module(block_id, True)