Ejemplo n.º 1
0
def get_sca_checks(policy_id=None,
                   agent_list=None,
                   q="",
                   offset=0,
                   limit=common.database_limit,
                   sort=None,
                   search=None,
                   select=None,
                   filters=None):
    """ Get a list of checks analyzed for a policy

    :param policy_id: policy id to get the checks from
    :param agent_list: agent id to get the policies from
    :param q: Defines query to filter in DB.
    :param offset: First item to return.
    :param limit: Maximum number of items to return.
    :param sort: Sorts the items. Format: {"fields":["field1","field2"],"order":"asc|desc"}.
    :param search: Looks for items with the specified string. Format: {"fields": ["field1","field2"]}
    :param select: Select fields to return. Format: {"fields":["field1","field2"]}.
    :param filters: Define field filters required by the user. Format: {"field1":"value1", "field2":["value2","value3"]}
    :return: AffectedItemsWazuhResult
    """
    result = AffectedItemsWazuhResult(
        all_msg='All selected sca/policy information was returned',
        some_msg='Some sca/policy information was not returned',
        none_msg='No sca/policy information was returned')
    if len(agent_list) != 0:
        if agent_list[0] in get_agents_info():
            fields_translation = {
                **fields_translation_sca_check,
                **fields_translation_sca_check_compliance,
                **fields_translation_sca_check_rule
            }

            full_select = (
                list(fields_translation_sca_check.keys()) +
                list(fields_translation_sca_check_compliance.keys()) +
                list(fields_translation_sca_check_rule.keys()))

            db_query = WazuhDBQuerySCA(agent_id=agent_list[0],
                                       offset=offset,
                                       limit=limit,
                                       sort=sort,
                                       search=search,
                                       select=full_select,
                                       count=True,
                                       get_data=True,
                                       query=f"policy_id={policy_id}" if q
                                       == "" else f"policy_id={policy_id};{q}",
                                       filters=filters,
                                       default_query=default_query_sca_check,
                                       default_sort_field='policy_id',
                                       fields=fields_translation,
                                       count_field='id')

            result_dict = db_query.run()

            if 'items' in result_dict:
                checks = result_dict['items']
            else:
                raise WazuhInternalError(2007)

            groups = groupby(checks, key=itemgetter('id'))
            select_fields = full_select if select is None else select
            select_fields = set([
                field if field != 'compliance' else 'compliance'
                for field in select_fields
                if field in fields_translation_sca_check
            ])
            # Rearrange check and compliance fields
            for _, group in groups:
                group_list = list(group)
                check_dict = {
                    k: v
                    for k, v in group_list[0].items() if k in select_fields
                }

                for extra_field, field_translations in [
                    ('compliance', fields_translation_sca_check_compliance),
                    ('rules', fields_translation_sca_check_rule)
                ]:
                    if (select is None or extra_field in select) \
                            and set(field_translations.keys()) & group_list[0].keys():
                        check_dict[extra_field] = [
                            dict(zip(field_translations.values(), x))
                            for x in set((
                                map(itemgetter(
                                    *field_translations.keys()), group_list)))
                        ]

                result.affected_items.append(check_dict)
            result.total_affected_items = result_dict['totalItems']
        else:
            result.add_failed_item(id_=agent_list[0],
                                   error=WazuhResourceNotFound(1701))
            result.total_affected_items = 0

    return result
Ejemplo n.º 2
0
    (WazuhPermissionError, 4000, ['remediation', 'code'], 403, ProblemException),
    (WazuhResourceNotFound, 1710, ['remediation', 'code'], 404, ProblemException),
    (WazuhInternalError, 1000, ['remediation', 'code'], 500, ProblemException)
])
def test_create_problem(exception_type, code, extra_fields, returned_code, returned_exception):
    """Check that _create_problem returns exception with expected data"""
    with pytest.raises(returned_exception) as exc_info:
        util._create_problem(exception_type(code))

    if returned_exception == ProblemException:
        assert exc_info.value.status == returned_code
    if extra_fields:
        assert all(x in exc_info.value.ext.keys() for x in extra_fields)
        assert None not in exc_info.value.ext.values()


@pytest.mark.parametrize('obj, code', [
    ((WazuhError(6001), ['value0', 'value1']), 429),
    ((WazuhInternalError(1000), ['value0', 'value1']), None),
    ((WazuhPermissionError(4000), ['value0', 'value1']), None),
    ((WazuhResourceNotFound(1710), ['value0', 'value1']), None)
])
@patch('api.util._create_problem')
def test_raise_if_exc(mock_create_problem, obj, code):
    """Check that raise_if_exc calls _create_problem when an exception is given"""
    result = util.raise_if_exc(obj)
    if isinstance(obj, Exception):
        mock_create_problem.assert_called_once_with(obj, code)
    else:
        assert result == obj
Ejemplo n.º 3
0
    def remove_bulk_agents(agent_ids_list: KeysView, logger):
        """
        Removes files created by agents in worker nodes. This function doesn't remove agents from client.keys since the
        client.keys file is overwritten by the master node.
        :param agent_ids_list: List of agents ids to remove.
        :param logger: Logger to use
        :return: None.
        """
        def remove_agent_file_type(agent_files: List[str]):
            """
            Removes files if they exist
            :param agent_files: Path regexes of the files to remove
            :return: None
            """
            for filetype in agent_files:

                filetype_glob = filetype.format(ossec_path=common.ossec_path,
                                                id='*',
                                                name='*',
                                                ip='*')
                filetype_agent = {
                    filetype.format(ossec_path=common.ossec_path,
                                    id=a['id'],
                                    name=a['name'],
                                    ip=a['ip'])
                    for a in agent_info
                }

                for agent_file in set(
                        glob.iglob(filetype_glob)) & filetype_agent:
                    logger.debug2("Removing {}".format(agent_file))
                    if os.path.isdir(agent_file):
                        shutil.rmtree(agent_file)
                    else:
                        os.remove(agent_file)

        if not agent_ids_list:
            return  # the function doesn't make sense if there is no agents to remove

        logger.info("Removing files from {} agents".format(
            len(agent_ids_list)))
        logger.debug("Agents to remove: {}".format(', '.join(agent_ids_list)))
        # the agents must be removed in groups of 997: 999 is the limit of SQL variables per query. Limit and offset are
        # always included in the SQL query, so that leaves 997 variables as limit.
        for agents_ids_sublist in itertools.zip_longest(*itertools.repeat(
                iter(agent_ids_list), 997),
                                                        fillvalue='0'):
            agents_ids_sublist = list(
                filter(lambda x: x != '0', agents_ids_sublist))
            # Get info from DB
            agent_info = Agent.get_agents_overview(q=",".join(
                ["id={}".format(i) for i in agents_ids_sublist]),
                                                   select=['ip', 'id', 'name'],
                                                   limit=None)['items']
            logger.debug2("Removing files from agents {}".format(
                ', '.join(agents_ids_sublist)))

            files_to_remove = [
                '{ossec_path}/queue/agent-info/{name}-{ip}',
                '{ossec_path}/queue/rootcheck/({name}) {ip}->rootcheck',
                '{ossec_path}/queue/diff/{name}',
                '{ossec_path}/queue/agent-groups/{id}',
                '{ossec_path}/queue/rids/{id}',
                '{ossec_path}/var/db/agents/{name}-{id}.db'
            ]
            remove_agent_file_type(files_to_remove)

            logger.debug2("Removing agent group assigments from database")
            # remove agent from groups
            db_global = glob.glob(common.database_path_global)
            if not db_global:
                raise WazuhInternalError(1600)

            conn = Connection(db_global[0])
            agent_ids_db = {
                'id_agent{}'.format(i): int(i)
                for i in agents_ids_sublist
            }
            conn.execute(
                'delete from belongs where {}'.format(' or '.join([
                    'id_agent = :{}'.format(i) for i in agent_ids_db.keys()
                ])), agent_ids_db)
            conn.commit()

            # Tell wazuhbd to delete agent database
            wdb_conn = WazuhDBConnection()
            wdb_conn.delete_agents_db(agents_ids_sublist)

        logger.info("Agent files removed")
Ejemplo n.º 4
0
def last_scan(agent_list):
    """Get the last scan of an agent.

    Parameters
    ----------
    agent_list : str
        Agent ID.

    Returns
    -------
    result : AffectedItemsWazuhResult
        Confirmation/Error message.
    """
    my_agent = Agent(agent_list[0])
    result = AffectedItemsWazuhResult(
        all_msg='Last syscheck scan of the agent was returned',
        none_msg='No last scan information was returned')
    # If agent status is never_connected, a KeyError happens
    try:
        agent_version = my_agent.get_basic_information(
            select=['version'])['version']
    except KeyError:
        # If the agent is never_connected, it won't have either version (key error) or last scan information.
        result.affected_items.append({'start': None, 'end': None})
        result.total_affected_items += 1

        return result

    if WazuhVersion(agent_version) < WazuhVersion('Wazuh v3.7.0'):
        db_agent = glob('{0}/{1}-*.db'.format(common.database_path_agents,
                                              agent_list[0]))
        if not db_agent:
            raise WazuhInternalError(1600, extra_message=agent_list[0])
        else:
            db_agent = db_agent[0]
        conn = Connection(db_agent)

        data = {}
        # end time
        query = "SELECT max(date_last) FROM pm_event WHERE log = 'Ending rootcheck scan.'"
        conn.execute(query)
        for t in conn:
            data['end'] = t['max(date_last)'] if t[
                'max(date_last)'] is not None else "ND"

        # start time
        query = "SELECT max(date_last) FROM pm_event WHERE log = 'Starting rootcheck scan.'"
        conn.execute(query)
        for t in conn:
            data['start'] = t['max(date_last)'] if t[
                'max(date_last)'] is not None else "ND"

        result.affected_items.append(data)
    else:
        with WazuhDBQuerySyscheck(agent_id=agent_list[0],
                                  query='module=fim',
                                  offset=0,
                                  sort=None,
                                  search=None,
                                  limit=common.database_limit,
                                  select={'end', 'start'},
                                  fields={
                                      'end': 'end_scan',
                                      'start': 'start_scan',
                                      'module': 'module'
                                  },
                                  table='scan_info',
                                  default_sort_field='start_scan') as db_query:
            fim_scan_info = db_query.run()['items'][0]

        end = None if not fim_scan_info['end'] else fim_scan_info['end']
        start = None if not fim_scan_info['start'] else fim_scan_info['start']
        # If start is None or the scan is running, end will be None.
        result.affected_items.append({
            'start':
            start,
            'end':
            None
            if start is None else None if end is None or end < start else end
        })
    result.total_affected_items = len(result.affected_items)

    return result
Ejemplo n.º 5
0
def upload_group_configuration(group_id, file_content):
    """
    Updates group configuration
    :param group_id: Group to update
    :param file_content: File content of the new configuration in a string.
    :return: Confirmation message.
    """
    if not os_path.exists(os_path.join(common.shared_path, group_id)):
        raise WazuhResourceNotFound(1710, group_id)
    # path of temporary files for parsing xml input
    tmp_file_path = os_path.join(
        common.ossec_path, "tmp",
        f"api_tmp_file_{time.time()}_{random.randint(0, 1000)}.xml")
    # create temporary file for parsing xml input and validate XML format
    try:
        with open(tmp_file_path, 'w') as tmp_file:
            custom_entities = {
                '_custom_open_tag_': '\\<',
                '_custom_close_tag_': '\\>',
                '_custom_amp_lt_': '&lt;',
                '_custom_amp_gt_': '&gt;'
            }

            # Replace every custom entity
            for character, replacement in custom_entities.items():
                file_content = re.sub(replacement.replace('\\', '\\\\'),
                                      character, file_content)

            # Beautify xml file using a minidom.Document
            xml = parseString(f'<root>\n{file_content}\n</root>')

            # Remove first line (XML specification: <? xmlversion="1.0" ?>), <root> and </root> tags, and empty lines
            pretty_xml = '\n'.join(
                filter(lambda x: x.strip(),
                       xml.toprettyxml(indent='  ').split('\n')[2:-2])) + '\n'

            # Revert xml.dom replacements and remove any whitespaces and '\n' between '\' and '<' if present
            # github.com/python/cpython/blob/8e0418688906206fe59bd26344320c0fc026849e/Lib/xml/dom/minidom.py#L305
            pretty_xml = re.sub(
                r'(?:(?<=\\) +)', '',
                pretty_xml.replace("&amp;", "&").replace("&lt;", "<").replace(
                    "&quot;",
                    "\"",
                ).replace("&gt;", ">").replace("\\\n", "\\"))

            # Restore the replaced custom entities
            for replacement, character in custom_entities.items():
                pretty_xml = re.sub(replacement,
                                    character.replace('\\',
                                                      '\\\\'), pretty_xml)

            tmp_file.write(pretty_xml)
    except Exception as e:
        raise WazuhError(1113, str(e))

    try:
        # check Wazuh xml format
        try:
            subprocess.check_output([
                os_path.join(common.ossec_path, "bin", "verify-agent-conf"),
                '-f', tmp_file_path
            ],
                                    stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            # extract error message from output.
            # Example of raw output
            # 2019/01/08 14:51:09 verify-agent-conf: ERROR: (1230):
            # Invalid element in the configuration: 'agent_conf'.\n2019/01/08 14:51:09 verify-agent-conf: ERROR: (1207):
            # Syscheck remote configuration in '/var/ossec/tmp/api_tmp_file_2019-01-08-01-1546959069.xml' is corrupted.
            # \n\n
            # Example of desired output:
            # Invalid element in the configuration: 'agent_conf'.
            # Syscheck remote configuration in '/var/ossec/tmp/api_tmp_file_2019-01-08-01-1546959069.xml' is corrupted.
            output_regex = re.findall(
                pattern=
                r"\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2} verify-agent-conf: ERROR: "
                r"\(\d+\): ([\w \/ \_ \- \. ' :]+)",
                string=e.output.decode())
            if output_regex:
                raise WazuhError(1114, ' '.join(output_regex))
            else:
                raise WazuhError(1115, e.output.decode())
        except Exception as e:
            raise WazuhInternalError(1743, str(e))

        # move temporary file to group folder
        try:
            new_conf_path = os_path.join(common.shared_path, group_id,
                                         "agent.conf")
            safe_move(tmp_file_path, new_conf_path, permissions=0o660)
        except Exception as e:
            raise WazuhInternalError(1016, extra_message=str(e))

        return 'Agent configuration was successfully updated'
    except Exception as e:
        # remove created temporary file
        if os.path.exists(tmp_file_path):
            remove(tmp_file_path)
        raise e
Ejemplo n.º 6
0
                                      relative_dirname=relative_dirname,
                                      parents=parents)
        assert isinstance(result, AffectedItemsWazuhResult)
        # Build result names set from response for filter validation
        result_names = {d['name'] for d in result.affected_items}
        assert result_names == expected_names
        # Assert failed items length matches expected result
        assert result.total_failed_items == expected_total_failed
    finally:
        os.rename(wrong_decoder_tmp_path, wrong_decoder_original_path)


@pytest.mark.parametrize('conf, exception', [(decoder_ossec_conf, None),
                                             ({
                                                 'ruleset': None
                                             }, WazuhInternalError(1500))])
def test_get_decoders_files(conf, exception):
    with patch('wazuh.core.configuration.get_ossec_conf', return_value=conf):
        try:
            # UUT call
            result = decoder.get_decoders_files()
            assert isinstance(result, AffectedItemsWazuhResult)
            # Assert result is a list with at least one dict element with the appropriate fields
            assert isinstance(result.affected_items, list)
            assert len(result.affected_items) != 0
            for item in result.affected_items:
                assert {'filename', 'relative_dirname',
                        'status'}.issubset(set(item))
            assert result.total_affected_items == len(result.affected_items)
        except WazuhInternalError as e:
            # If the UUT call returns an exception we check it has the appropriate error code
Ejemplo n.º 7
0
         'mycallable': get_node},
        {'foo': 'bar',
         'foo2': 3,
         'mycallable': get_agents_summary_status},
        {'foo': 'bar',
         'foo2': 3,
         'mycallable': status},
        {'foo': 'bar',
         'foo2': 3,
         'exception': WazuhError(1500,
                                 extra_message="test message",
                                 extra_remediation="test remediation")},
        {'foo': 'bar',
         'foo2': 3,
         'exception': WazuhInternalError(1000,
                                         extra_message="test message",
                                         extra_remediation="test remediation")},
        {'foo': 'bar',
         'foo2': 3,
         'result': WazuhResult({'field1': 'value1', 'field2': 3}, str_priority=['KO', 'OK'])},
        {'foo': 'bar',
         'foo2': 3,
         'result': affected}
    ]


@pytest.mark.parametrize('obj', objects_to_encode)
@patch('wazuh.common.wazuh_path', new=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data'))
def test_encoder_decoder(obj):
    # Encoding first object
    encoded = json.dumps(obj, cls=WazuhJSONEncoder)
Ejemplo n.º 8
0
def test_check_status(status, expected_result):
    try:
        # UUT call
        result = decoder.check_status(status)
        assert result == expected_result
    except WazuhError as e:
        # If the UUT call returns an exception we check it has the appropriate error code
        assert e.code == expected_result.code


@pytest.mark.parametrize(
    "filename, relative_dirname, status, permissions, exception", [
        ('test1_decoders.xml', 'decoders', "all", 777, None),
        ('test2_decoders.xml', 'decoders', "enabled", 777, None),
        ('wrong_decoders.xml', 'decoders', "all", 777,
         WazuhInternalError(1501)),
        ('non_existing.xml', 'decoders', "disabled", 777, WazuhError(1502)),
        ('test1_decoders.xml', 'decoders', "all", 000, WazuhError(1502)),
    ])
@patch('wazuh.core.common.ossec_path', new=test_data_path)
def test_load_decoders_from_file(filename, relative_dirname, status,
                                 permissions, exception):
    full_file_path = os.path.join(test_data_path, relative_dirname, filename)
    try:
        old_permissions = stat.S_IMODE(os.lstat(full_file_path).st_mode)
    except FileNotFoundError:
        old_permissions = None
    try:
        # Set file permissions if the file exists
        os.path.exists(full_file_path) and os.chmod(full_file_path,
                                                    permissions)
Ejemplo n.º 9
0
    def send_msg_to_agent(self, msg: str = '', agent_id: str = '', msg_type: str = '') -> str:
        """Send message to agent.

        Active-response
          Agents: /var/ossec/queue/alerts/ar
            - Existing command:
              - (msg_to_agent) [] NNS 001 restart-ossec0 arg1 arg2 arg3
              - (msg_to_agent) [] ANN (null) restart-ossec0 arg1 arg2 arg3
            - Custom command:
              - (msg_to_agent) [] NNS 001 !test.sh arg1 arg2 arg3
              - (msg_to_agent) [] ANN (null) !test.sh arg1 arg2 arg3
          Agents with version >= 4.2.0:
            - Existing and custom commands:
              - (msg_to_agent) [] NNS 001 {JSON message}
          Manager: /var/ossec/queue/alerts/execq
            - Existing or custom command:
              - {JSON message}

        Parameters
        ----------
        msg : str
            Message to be sent to the agent.
        agent_id : str
            ID of the agent we want to send the message to.
        msg_type : str
            Message type.

        Raises
        ------
        WazuhInternalError(1012)
            If the message was invalid to queue.
        WazuhError(1014)
            If there was an error communicating with socket.

        Returns
        -------
        str
            Message confirming the message has been sent.
        """
        # Variables to check if msg is a non active-response message or a restart message
        msg_is_no_ar = msg in [WazuhQueue.HC_SK_RESTART, WazuhQueue.HC_FORCE_RECONNECT]
        msg_is_restart = msg in [WazuhQueue.RESTART_AGENTS, WazuhQueue.RESTART_AGENTS_JSON]

        # Create flag and string used to specify the agent ID
        if agent_id:
            flag = 'NNS' if not msg_is_no_ar else 'N!S'
            str_agent_id = agent_id
        else:
            flag = 'ANN' if not msg_is_no_ar else 'A!N'
            str_agent_id = '(null)'

        # AR
        if msg_type == WazuhQueue.AR_TYPE:
            socket_msg = create_wazuh_queue_socket_msg(flag, str_agent_id, msg) if agent_id != '000' else msg
            # Return message
            ret_msg = "Command sent."

        # NO-AR: Restart syscheck and reconnect
        # Restart agents
        else:
            # If msg is not a non active-response command and not a restart command, raises WazuhInternalError
            if not msg_is_no_ar and not msg_is_restart:
                raise WazuhInternalError(1012, msg)
            socket_msg = create_wazuh_queue_socket_msg(flag, str_agent_id, msg, is_restart=msg_is_restart)
            # Return message
            if msg == WazuhQueue.HC_SK_RESTART:
                ret_msg = "Restarting Syscheck on agent" if agent_id else "Restarting Syscheck on all agents"
            elif msg == WazuhQueue.HC_FORCE_RECONNECT:
                ret_msg = "Reconnecting agent" if agent_id else "Reconnecting all agents"
            else:  # msg == WazuhQueue.RESTART_AGENTS or msg == WazuhQueue.RESTART_AGENTS_JSON
                ret_msg = "Restarting agent" if agent_id else "Restarting all agents"

        try:
            # Send message
            self._send(socket_msg.encode())
        except:
            raise WazuhError(1014, extra_message=f": WazuhQueue socket with path {self.path}")

        return ret_msg
Ejemplo n.º 10
0
 def _connect(self):
     try:
         self.s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         self.s.connect(self.path)
     except Exception as e:
         raise WazuhInternalError(1013, extra_message=str(e))
Ejemplo n.º 11
0
    ("wrong", WazuhError(1202))
])
def test_check_status(status, expected_result):
    try:
        # UUT call
        result = decoder.check_status(status)
        assert result == expected_result
    except WazuhError as e:
        # If the UUT call returns an exception we check it has the appropriate error code
        assert e.code == expected_result.code


@pytest.mark.parametrize("filename, relative_dirname, status, permissions, exception", [
    ('test1_decoders.xml', 'decoders', "all", 777, None),
    ('test2_decoders.xml', 'decoders', "enabled", 777, None),
    ('wrong_decoders.xml', 'decoders', "all", 777, WazuhInternalError(1501)),
    ('non_existing.xml', 'decoders', "disabled", 777, WazuhError(1502)),
    ('test1_decoders.xml', 'decoders', "all", 000, WazuhError(1502)),
])
@patch('wazuh.core.common.wazuh_path', new=test_data_path)
def test_load_decoders_from_file(filename, relative_dirname, status, permissions, exception):
    full_file_path = os.path.join(test_data_path, relative_dirname, filename)
    try:
        old_permissions = stat.S_IMODE(os.lstat(full_file_path).st_mode)
    except FileNotFoundError:
        old_permissions = None
    try:
        # Set file permissions if the file exists
        os.path.exists(full_file_path) and os.chmod(full_file_path, permissions)
        # UUT call
        result = decoder.load_decoders_from_file(filename, relative_dirname, status)
Ejemplo n.º 12
0
def get_decoders_files(status=None,
                       relative_dirname=None,
                       filename=None,
                       offset=0,
                       limit=common.database_limit,
                       sort_by=None,
                       sort_ascending=True,
                       search_text=None,
                       complementary_search=False,
                       search_in_fields=None):
    """Gets a list of the available decoder files.

    :param status: Filters by status: enabled, disabled, all.
    :param relative_dirname: Filters by relative dirname.
    :param filename: List of filenames to filter by.
    :param offset: First item to return.
    :param limit: Maximum number of items to return.
    :param sort_by: Fields to sort the items by
    :param sort_ascending: Sort in ascending (true) or descending (false) order
    :param search_text: Text to search
    :param complementary_search: Find items without the text to search
    :param search_in_fields: Fields to search in
    :return: AffectedItemsWazuhResult
    """
    result = AffectedItemsWazuhResult(
        none_msg='No decoder files were returned',
        some_msg='Some decoder files were not returned',
        all_msg='All decoder files were returned')
    status = check_status(status)
    ruleset_conf = configuration.get_ossec_conf(section='ruleset')['ruleset']
    if not ruleset_conf:
        raise WazuhInternalError(1500)

    decoders_files = list()
    tags = ['decoder_include', 'decoder_exclude', 'decoder_dir']
    if isinstance(filename, list):
        for f in filename:
            decoders_files.extend(
                format_rule_decoder_file(
                    ruleset_conf, {
                        'status': status,
                        'relative_dirname': relative_dirname,
                        'filename': f
                    }, tags))
    else:
        decoders_files = format_rule_decoder_file(
            ruleset_conf, {
                'status': status,
                'relative_dirname': relative_dirname,
                'filename': filename
            }, tags)

    data = process_array(decoders_files,
                         search_text=search_text,
                         search_in_fields=search_in_fields,
                         complementary_search=complementary_search,
                         sort_by=sort_by,
                         sort_ascending=sort_ascending,
                         offset=offset,
                         limit=limit)
    result.affected_items = data['items']
    result.total_affected_items = data['totalItems']

    return result
Ejemplo n.º 13
0
    def send_msg_to_agent(self, msg: Union[str, dict] = '', agent_id: str = '', msg_type: str = '') -> str:
        """Send message to agent.

        Active-response
          Agents: /var/ossec/queue/alerts/ar
            - Existing command:
              - (msg_to_agent) [] NNS 001 restart-ossec0 arg1 arg2 arg3
              - (msg_to_agent) [] ANN (null) restart-ossec0 arg1 arg2 arg3
            - Custom command:
              - (msg_to_agent) [] NNS 001 !test.sh arg1 arg2 arg3
              - (msg_to_agent) [] ANN (null) !test.sh arg1 arg2 arg3
          Agents with version >= 4.2.0:
            - Existing and custom commands:
              - (msg_to_agent) [] NNS 001 {JSON message}
          Manager: /var/ossec/queue/alerts/execq
            - Existing or custom command:
              - {JSON message}

        Parameters
        ----------
        msg : str
            Message to be sent to the agent.
        agent_id : str
            ID of the agent we want to send the message to.
        msg_type : str
            Message type.

        Raises
        ------
        WazuhError(1652)
            If it was unable to run the command.
        WazuhInternalError(1012)
            If the message was invalid to queue.
        WazuhError(1601)
            If it was unable to run the syscheck scan on the agent because it is a non active agent.
        WazuhError(1702)
            If it was unable to restart the agent.

        Returns
        -------
        str
            Message confirming the message has been sent.
        """

        # Build message
        ALL_AGENTS_C = 'A'
        NONE_C = 'N'
        SPECIFIC_AGENT_C = 'S'
        NO_AR_C = '!'

        if agent_id:
            str_all_agents = NONE_C
            str_agent = SPECIFIC_AGENT_C
            str_agent_id = agent_id
        else:
            str_all_agents = ALL_AGENTS_C
            str_agent = NONE_C
            str_agent_id = "(null)"

        # AR
        if msg_type == WazuhQueue.AR_TYPE:

            if agent_id != "000":
                # Example restart 'msg': restart-ossec0 - null (from_the_server) (no_rule_id)
                socket_msg = "{0} {1}{2}{3} {4} {5}".format("(msg_to_agent) []", str_all_agents, NONE_C, str_agent,
                                                            str_agent_id, msg)
            elif agent_id == "000":
                socket_msg = msg

            # Send message
            try:
                self._send(socket_msg.encode())
            except Exception:
                raise WazuhError(1652)

            return "Command sent."

        # Legacy: Restart syscheck, restart agents
        else:
            if msg == WazuhQueue.HC_SK_RESTART:
                socket_msg = "{0} {1}{2}{3} {4} {5}".format("(msg_to_agent) []", str_all_agents, NO_AR_C, str_agent,
                                                            str_agent_id, WazuhQueue.HC_SK_RESTART)
            elif msg == WazuhQueue.RESTART_AGENTS or msg == WazuhQueue.RESTART_AGENTS_JSON:
                socket_msg = "{0} {1}{2}{3} {4} {5} - {6} (from_the_server) (no_rule_id)".format("(msg_to_agent) []",
                                                                                                 str_all_agents, NONE_C,
                                                                                                 str_agent,
                                                                                                 str_agent_id,
                                                                                                 msg, "null")
            else:
                raise WazuhInternalError(1012, msg)

            # Send message
            try:
                self._send(socket_msg.encode())
            except:
                if msg == WazuhQueue.HC_SK_RESTART:
                    if agent_id:
                        raise WazuhError(1601, "on agent")
                    else:
                        raise WazuhError(1601, "on all agents")
                elif msg == WazuhQueue.RESTART_AGENTS:
                    raise WazuhError(1702)

            # Return message
            if msg == WazuhQueue.HC_SK_RESTART:
                return "Restarting Syscheck on agent" if agent_id else "Restarting Syscheck on all agents"
            elif msg == WazuhQueue.RESTART_AGENTS:
                return "Restarting agent" if agent_id else "Restarting all agents"
Ejemplo n.º 14
0
def totals(date):
    """
    Returns the totals file.
    :param date: date object with the date value of the stats
    :return: Array of dictionaries. Each dictionary represents an hour.
    """

    stat_filename = ""
    try:
        stat_filename = os.path.join(
            common.stats_path, "totals", str(date.year),
            MONTHS[date.month - 1], f"ossec-totals-{date.strftime('%d')}.log")
        stats = open(stat_filename, 'r')
    except IOError:
        raise WazuhError(1308, extra_message=stat_filename)

    result = AffectedItemsWazuhResult(
        all_msg='Statistical information for each node was successfully read',
        some_msg='Could not read statistical information for some nodes',
        none_msg='Could not read statistical information for any node')
    alerts = []

    for line in stats:
        data = line.split('-')

        if len(data) == 4:
            sigid = int(data[1])
            level = int(data[2])
            times = int(data[3])

            alert = {'sigid': sigid, 'level': level, 'times': times}
            alerts.append(alert)
        else:
            data = line.split('--')

            if len(data) != 5:
                if len(data) in (0, 1):
                    continue
                else:
                    result.add_failed_item(
                        id_=node_id if cluster_enabled else 'manager',
                        error=WazuhInternalError(1309))
                    return result

            hour = int(data[0])
            total_alerts = int(data[1])
            events = int(data[2])
            syscheck = int(data[3])
            firewall = int(data[4])

            result.affected_items.append({
                'hour': hour,
                'alerts': alerts,
                'totalAlerts': total_alerts,
                'events': events,
                'syscheck': syscheck,
                'firewall': firewall
            })
            alerts = []

    result.total_affected_items = len(result.affected_items)
    return result
Ejemplo n.º 15
0
def validation():
    """Check if Wazuh configuration is OK.

    :return: AffectedItemsWazuhResult.
    """
    result = AffectedItemsWazuhResult(**_validation_default_result_kwargs)

    lock_file = open(execq_lockfile, 'a+')
    fcntl.lockf(lock_file, fcntl.LOCK_EX)
    try:
        # Sockets path
        api_socket_relative_path = join('queue', 'alerts', 'execa')
        api_socket_path = join(common.ossec_path, api_socket_relative_path)
        execq_socket_path = common.EXECQ
        # Message for checking Wazuh configuration
        execq_msg = 'check-manager-configuration '

        # Remove api_socket if exists
        try:
            remove(api_socket_path)
        except OSError as e:
            if exists(api_socket_path):
                extra_msg = f'Socket: WAZUH_PATH/{api_socket_relative_path}. Error: {e.strerror}'
                raise WazuhInternalError(1014, extra_message=extra_msg)

        # up API socket
        try:
            api_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
            api_socket.bind(api_socket_path)
            # Timeout
            api_socket.settimeout(5)
        except OSError as e:
            extra_msg = f'Socket: WAZUH_PATH/{api_socket_relative_path}. Error: {e.strerror}'
            raise WazuhInternalError(1013, extra_message=extra_msg)

        # Connect to execq socket
        if exists(execq_socket_path):
            try:
                execq_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
                execq_socket.connect(execq_socket_path)
            except OSError as e:
                extra_msg = f'Socket: WAZUH_PATH/queue/alerts/execq. Error {e.strerror}'
                raise WazuhInternalError(1013, extra_message=extra_msg)
        else:
            raise WazuhInternalError(1901)

        # Send msg to execq socket
        try:
            execq_socket.send(execq_msg.encode())
            execq_socket.close()
        except socket.error as e:
            raise WazuhInternalError(1014, extra_message=str(e))
        finally:
            execq_socket.close()

        # If api_socket receives a message, configuration is OK
        try:
            buffer = bytearray()
            # Receive data
            datagram = api_socket.recv(4096)
            buffer.extend(datagram)
        except socket.timeout as e:
            raise WazuhInternalError(1014, extra_message=str(e))
        finally:
            api_socket.close()
            # Remove api_socket
            if exists(api_socket_path):
                remove(api_socket_path)

        try:
            response = parse_execd_output(buffer.decode('utf-8').rstrip('\0'))
        except (KeyError, json.decoder.JSONDecodeError) as e:
            raise WazuhInternalError(1904, extra_message=str(e))

        result.affected_items.append({'name': node_id, **response})
        result.total_affected_items += 1
    except WazuhError as e:
        result.add_failed_item(id_=node_id, error=e)
    finally:
        fcntl.lockf(lock_file, fcntl.LOCK_UN)
        lock_file.close()

    return result
Ejemplo n.º 16
0
def get_group_files(group_list=None,
                    offset=0,
                    limit=None,
                    search_text=None,
                    search_in_fields=None,
                    complementary_search=False,
                    sort_by=None,
                    sort_ascending=True,
                    hash_algorithm='md5'):
    """Gets the group files.

    :param group_list: List of Group names.
    :param offset: First item to return.
    :param limit: Maximum number of items to return.
    :param sort_by: Fields to sort the items by.
    :param sort_ascending: Sort in ascending (true) or descending (false) order.
    :param search_text: Text to search.
    :param complementary_search: Find items without the text to search.
    :param search_in_fields: Fields to search in.
    :param hash_algorithm: hash algorithm used to get mergedsum and configsum.
    :return: WazuhResult.
    """
    # We access unique group_id from list, this may change if and when we decide to add option to get files for
    # a list of groups
    group_id = group_list[0]
    group_path = common.shared_path
    result = AffectedItemsWazuhResult(
        all_msg='All selected groups files were returned',
        some_msg='Some groups files were not returned',
        none_msg='No groups files were returned')
    if group_id:
        if not Agent.group_exists(group_id):
            result.add_failed_item(id_=group_id,
                                   error=WazuhResourceNotFound(1710))
            return result
        group_path = path.join(common.shared_path, group_id)

    if not path.exists(group_path):
        result.add_failed_item(id_=group_path, error=WazuhError(1006))
        return result

    try:
        data = []
        for entry in listdir(group_path):
            item = dict()
            item['filename'] = entry
            item['hash'] = get_hash(path.join(group_path, entry),
                                    hash_algorithm)
            data.append(item)

        # ar.conf
        ar_path = path.join(common.shared_path, 'ar.conf')
        data.append({
            'filename': "ar.conf",
            'hash': get_hash(ar_path, hash_algorithm)
        })
        data = process_array(data,
                             search_text=search_text,
                             search_in_fields=search_in_fields,
                             complementary_search=complementary_search,
                             sort_by=sort_by,
                             sort_ascending=sort_ascending,
                             offset=offset,
                             limit=limit)
        result.affected_items = data['items']
        result.total_affected_items = data['totalItems']
    except WazuhError as e:
        result.add_failed_item(id_=group_path, error=e)
        raise e
    except Exception as e:
        raise WazuhInternalError(1727, extra_message=str(e))

    return result
Ejemplo n.º 17
0
from os.path import isfile
from distutils.version import LooseVersion
import sqlite3
import sys
import time
# Python 2/3 compatibility
if sys.version_info[0] == 3:
    unicode = str

# Check SQL compatibility: >= 3.7.0.0
if LooseVersion(sqlite3.sqlite_version) < LooseVersion('3.7.0.0'):
    msg = str(sqlite3.sqlite_version)
    msg += "\nTry to export the internal SQLite library:"
    msg += "\nexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{0}/lib".format(
        common.wazuh_path)
    raise WazuhInternalError(2001, extra_message=msg)


class Connection:
    """
    Represents a connection against a database
    """
    def __init__(self,
                 db_path=common.database_path_global,
                 busy_sleep=0.001,
                 max_attempts=50):
        """
        Constructor
        """
        self.db_path = db_path
Ejemplo n.º 18
0
Archivo: wdb.py Proyecto: ignhub/wazuh
    def execute(self, query, count=False, delete=False, update=False):
        """
        Sends a sql query to wdb socket
        """
        def send_request_to_wdb(query_lower, step, off, response):
            try:
                request = query_lower.replace(':limit', 'limit {}'.format(step)).replace(':offset', 'offset {}'.format(off))
                response.extend(self._send(request))
            except ValueError:
                # if the step is already 1, it can't be divided
                if step == 1:
                    raise WazuhInternalError(2007)
                send_request_to_wdb(query_lower, step // 2, off, response)
                # Add step // 2 remaining when the step is odd to avoid losing information
                send_request_to_wdb(query_lower, step // 2 + step % 2, step // 2 + off, response)

        query_lower = self.__query_lower(query)

        self.__query_input_validation(query_lower)

        # only for delete queries
        if delete:
            regex = re.compile(r"\w+ \d+? (sql delete from ([a-z0-9,_ ]+)|\w+ delete$)")
            if regex.match(query_lower) is None:
                raise WazuhError(2004, "Delete query is wrong")
            return self._send(query_lower)

        # only for update queries
        if update:
            # regex = re.compile(r"\w+ \d+? sql update ([a-z0-9,*_ ]+) set value = '([a-z0-9,*_ ]+)' where key (=|like)?"
            regex = re.compile(r"\w+ \d+? sql update ([\w\d,*_ ]+) set value = '([\w\d,*_ ]+)' where key (=|like)?"
                               r" '([a-z0-9,*_%\- ]+)'")
            if regex.match(query_lower) is None:
                raise WazuhError(2004, "Update query is wrong")
            return self._send(query_lower)

        # Remove text inside 'where' clause to prevent finding reserved words (offset/count)
        query_without_where = re.sub(r'where \([^()]*\)', 'where ()', query_lower)

        # if the query has already a parameter limit / offset, divide using it
        offset = 0
        if re.search(r'offset \d+', query_without_where):
            offset = int(re.compile(r".* offset (\d+)").match(query_lower).group(1))
            # Replace offset with a wildcard
            query_lower = ' :offset'.join(query_lower.rsplit((' offset {}'.format(offset)), 1))

        if not re.search(r'.?select count\([\w \*]+\)( as [^,]+)? from', query_without_where):
            lim = 0
            if re.search(r'limit \d+', query_without_where):
                lim = int(re.compile(r".* limit (\d+)").match(query_lower).group(1))
                # Replace limit with a wildcard
                query_lower = ' :limit'.join(query_lower.rsplit((' limit {}'.format(lim)), 1))

            regex = re.compile(r"\w+(?: \d*|)? sql select ([A-Z a-z0-9,*_` \.\-%\(\):\']+?) from")
            select = regex.match(query_lower).group(1)
            gb_regex = re.compile(r"(group by [^\s]+)")
            countq = query_lower.replace(select, "count(*)", 1).replace(":limit", "").replace(":offset", "")
            try:
                group_by = gb_regex.search(query_lower)
                if group_by:
                    countq = countq.replace(group_by.group(1), '')
            except IndexError:
                pass

            try:
                total = list(self._send(countq)[0].values())[0]
            except IndexError:
                total = 0

            limit = lim if lim != 0 else total

            response = []
            step = limit if limit < self.request_slice and limit > 0 else self.request_slice
            if ':limit' not in query_lower:
                query_lower += ' :limit'
            if ':offset' not in query_lower:
                query_lower += ' :offset'

            try:
                for off in range(offset, limit + offset, step):
                    send_request_to_wdb(query_lower, step, off, response)
            except ValueError as e:
                raise WazuhError(2006, str(e))
            except WazuhError as e:
                raise e
            except Exception as e:
                raise WazuhInternalError(2007, str(e))

            if count:
                return response, total
            else:
                return response
        else:
            return list(self._send(query_lower)[0].values())[0]
Ejemplo n.º 19
0
    def execute(self, query, count=False, delete=False, update=False):
        """
        Sends a sql query to wdb socket
        """
        def send_request_to_wdb(query_lower, step, off, response):
            try:
                request = "{} limit {} offset {}".format(
                    query_lower, step, off)
                response.extend(self._send(request))
            except ValueError:
                # if the step is already 1, it can't be divided
                if step == 1:
                    raise WazuhInternalError(2007)
                send_request_to_wdb(query_lower, step // 2, off, response)
                send_request_to_wdb(query_lower, step // 2, step // 2 + off,
                                    response)

        query_lower = self.__query_lower(query)

        self.__query_input_validation(query_lower)

        # only for delete queries
        if delete:
            regex = re.compile(r"\w+ \d+? sql delete from ([a-z0-9,_ ]+)")
            if regex.match(query_lower) is None:
                raise WazuhError(2004, "Delete query is wrong")
            return self._send(query_lower)

        # only for update queries
        if update:
            # regex = re.compile(r"\w+ \d+? sql update ([a-z0-9,*_ ]+) set value = '([a-z0-9,*_ ]+)' where key (=|like)?"
            regex = re.compile(
                r"\w+ \d+? sql update ([\w\d,*_ ]+) set value = '([\w\d,*_ ]+)' where key (=|like)?"
                r" '([a-z0-9,*_%\- ]+)'")
            if regex.match(query_lower) is None:
                raise WazuhError(2004, "Update query is wrong")
            return self._send(query_lower)

        # Remove text inside 'where' clause to prevent finding reserved words (offset/count)
        query_without_where = re.sub(r'where \(.*\)', 'where ()', query_lower)

        # if the query has already a parameter limit / offset, divide using it
        offset = 0
        if 'offset' in query_without_where:
            offset = int(
                re.compile(r".* offset (\d+)").match(query_lower).group(1))
            query_lower = query_lower.replace(" offset {}".format(offset), "")

        if not re.search(r'.?count\(.*\).?', query_without_where):
            lim = 0
            if 'limit' in query_lower:
                lim = int(
                    re.compile(r".* limit (\d+)").match(query_lower).group(1))
                query_lower = query_lower.replace(" limit {}".format(lim), "")

            regex = re.compile(
                r"\w+(?: \d*|)? sql select ([A-Z a-z0-9,*_` \.\-%\(\):\']+) from"
            )
            select = regex.match(query_lower).group(1)
            countq = query_lower.replace(select, "count(*)", 1)
            try:
                total = list(self._send(countq)[0].values())[0]
            except IndexError:
                total = 0

            limit = lim if lim != 0 else total

            response = []
            step = limit if limit < self.request_slice and limit > 0 else self.request_slice
            try:
                for off in range(offset, limit + offset, step):
                    send_request_to_wdb(query_lower, step, off, response)
            except ValueError as e:
                raise WazuhError(2006, str(e))
            except Exception as e:
                raise WazuhInternalError(2007, str(e))

            if count:
                return response, total
            else:
                return response
        else:
            return list(self._send(query_lower)[0].values())[0]
Ejemplo n.º 20
0
def get_active_configuration(agent_id, component, configuration):
    """
    Reads agent loaded configuration in memory
    """
    if not component or not configuration:
        raise WazuhError(1307)

    components = {
        "agent", "agentless", "analysis", "auth", "com", "csyslog",
        "integrator", "logcollector", "mail", "monitor", "request", "syscheck",
        "wmodules"
    }

    # checks if the component is correct
    if component not in components:
        raise WazuhError(1101, f'Valid components: {", ".join(components)}')

    sockets_path = os_path.join(common.ossec_path, "queue", "ossec")

    if agent_id == '000':
        dest_socket = os_path.join(sockets_path, component)
        command = f"getconfig {configuration}"
    else:
        dest_socket = os_path.join(sockets_path, "request")
        command = f"{str(agent_id).zfill(3)} {component} getconfig {configuration}"

    # Socket connection
    try:
        s = OssecSocket(dest_socket)
    except Exception:
        raise WazuhInternalError(1121)

    # Send message
    s.send(command.encode())

    # Receive response
    try:
        # Receive data length
        rec_msg_ok, rec_msg = s.receive().decode().split(" ", 1)
    except ValueError:
        raise WazuhInternalError(1118,
                                 extra_message="Data could not be received")

    s.close()

    if rec_msg_ok.startswith('ok'):
        msg = json.loads(rec_msg)

        # Include password if auth->use_password enabled and authd.pass file exists
        if msg.get('auth', {}).get('use_password') == 'yes':
            try:
                with open(os_path.join(common.ossec_path, "etc", "authd.pass"),
                          'r') as f:
                    msg['authd.pass'] = f.read().rstrip()
            except IOError:
                pass

        return msg
    else:
        raise WazuhError(1117 if "No such file or directory" in rec_msg
                         or "Cannot send request" in rec_msg else 1116,
                         extra_message='{0}:{1}'.format(
                             component, configuration))
Ejemplo n.º 21
0
Wazuh is a python package to manage OSSEC.

"""

__version__ = '4.3.0'

msg = "\n\nPython 2.7 or newer not found."
msg += "\nUpdate it or set the path to a valid version. Example:"
msg += "\n  export PATH=$PATH:/opt/rh/python27/root/usr/bin"
msg += "\n  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/rh/python27/root/usr/lib64"

try:
    from sys import version_info as python_version
    if python_version.major < 2 or (python_version.major == 2
                                    and python_version.minor < 7):
        raise WazuhInternalError(999, msg)
except Exception as e:
    raise WazuhInternalError(999, msg)


class Wazuh:
    """
    Basic class to set up OSSEC directories
    """
    def __init__(self):
        """
        Initialize basic information and directories.
        :return:
        """

        self.version = common.wazuh_version
Ejemplo n.º 22
0
def get_sca_checks(policy_id=None,
                   agent_list=None,
                   q="",
                   offset=0,
                   limit=common.database_limit,
                   sort=None,
                   search=None,
                   select=None,
                   filters=None):
    """ Get a list of checks analyzed for a policy

    Parameters
    ----------
    policy_id : str
        Policy id to get the checks from.
    agent_list : list
        Agent id to get the policies from
    q : str
        Defines query to filter in DB.
    offset : int
        First item to return.
    limit : int
        Maximum number of items to return.
    sort : str
        Sorts the items. Format: {"fields":["field1","field2"],"order":"asc|desc"}.
    search : str
        Looks for items with the specified string. Format: {"fields": ["field1","field2"]}
    select : str
        Select fields to return. Format: {"fields":["field1","field2"]}.
    filters : str
        Define field filters required by the user. Format: {"field1":"value1", "field2":["value2","value3"]}

    Returns
    -------
    AffectedItemsWazuhResult
    """
    result = AffectedItemsWazuhResult(
        all_msg='All selected sca/policy information was returned',
        some_msg='Some sca/policy information was not returned',
        none_msg='No sca/policy information was returned')
    if len(agent_list) != 0:
        sca_checks = list()
        if agent_list[0] in get_agents_info():
            fields_translation = {
                **fields_translation_sca_check,
                **fields_translation_sca_check_compliance,
                **fields_translation_sca_check_rule
            }

            full_select = (
                list(fields_translation_sca_check.keys()) +
                list(fields_translation_sca_check_compliance.keys()) +
                list(fields_translation_sca_check_rule.keys()))

            # Workaround for too long sca_checks results until the chunk algorithm is implemented (1/2)
            db_query = WazuhDBQuerySCA(agent_id=agent_list[0],
                                       offset=0,
                                       limit=None,
                                       sort=None,
                                       filters=filters,
                                       search=None,
                                       select=full_select,
                                       count=True,
                                       get_data=True,
                                       query=f"policy_id={policy_id}",
                                       default_query=default_query_sca_check,
                                       default_sort_field='policy_id',
                                       fields=fields_translation,
                                       count_field='id')
            result_dict = db_query.run()

            if 'items' in result_dict:
                checks = result_dict['items']
            else:
                raise WazuhInternalError(2007)

            groups = groupby(checks, key=itemgetter('id'))
            select_fields = full_select if select is None else select
            select_fields = set([
                field if field != 'compliance' else 'compliance'
                for field in select_fields
                if field in fields_translation_sca_check
            ])
            # Rearrange check and compliance fields

            for _, group in groups:
                group_list = list(group)
                check_dict = {
                    k: v
                    for k, v in group_list[0].items() if k in select_fields
                }

                for extra_field, field_translations in [
                    ('compliance', fields_translation_sca_check_compliance),
                    ('rules', fields_translation_sca_check_rule)
                ]:
                    if (select is None or extra_field in select) \
                            and set(field_translations.keys()) & group_list[0].keys():
                        check_dict[extra_field] = [
                            dict(zip(field_translations.values(), x))
                            for x in set((
                                map(itemgetter(
                                    *field_translations.keys()), group_list)))
                        ]

                sca_checks.append(check_dict)
        else:
            result.add_failed_item(id_=agent_list[0],
                                   error=WazuhResourceNotFound(1701))
            result.total_affected_items = 0

        # Workaround for too long sca_checks results until the chunk algorithm is implemented (2/2)
        data = process_array(
            sca_checks,
            search_text=search['value'] if search else None,
            complementary_search=search['negation'] if search else False,
            sort_by=sort['fields'] if sort else ['policy_id'],
            sort_ascending=False if sort and sort['order'] == 'desc' else True,
            offset=offset,
            limit=limit,
            q=q)

        result.affected_items = data['items']
        result.total_affected_items = data['totalItems']

    return result
Ejemplo n.º 23
0
    def send_msg_to_agent(self, msg, agent_id=None, msg_type=None):
        # Active-response
        #   Agents: /var/ossec/queue/alerts/ar
        #     - Existing command:
        #       - (msg_to_agent) [] NNS 001 restart-ossec0 arg1 arg2 arg3
        #       - (msg_to_agent) [] ANN (null) restart-ossec0 arg1 arg2 arg3
        #     - Custom command:
        #       - (msg_to_agent) [] NNS 001 !test.sh arg1 arg2 arg3
        #       - (msg_to_agent) [] ANN (null) !test.sh arg1 arg2 arg3
        #   Manager: /var/ossec/queue/alerts/execq
        #     - Existing command:
        #       - restart-ossec0 arg1 arg2 arg3
        #     - Custom command:
        #       - !test.sh Hello World

        # Build message
        ALL_AGENTS_C = 'A'
        NONE_C = 'N'
        SPECIFIC_AGENT_C = 'S'
        NO_AR_C = '!'

        if agent_id:
            str_all_agents = NONE_C
            str_agent = SPECIFIC_AGENT_C
            str_agent_id = agent_id
        else:
            str_all_agents = ALL_AGENTS_C
            str_agent = NONE_C
            str_agent_id = "(null)"

        # AR
        if msg_type == OssecQueue.AR_TYPE:

            if agent_id != "000":
                # Example restart 'msg': restart-ossec0 - null (from_the_server) (no_rule_id)
                socket_msg = "{0} {1}{2}{3} {4} {5}".format(
                    "(msg_to_agent) []", str_all_agents, NONE_C, str_agent,
                    str_agent_id, msg)
            elif agent_id == "000":
                socket_msg = msg

            # Send message
            try:
                self._send(socket_msg.encode())
            except Exception:
                raise WazuhError(1652)

            return "Command sent."

        # Legacy: Restart syscheck, restart agents
        else:
            if msg == OssecQueue.HC_SK_RESTART:
                socket_msg = "{0} {1}{2}{3} {4} {5}".format(
                    "(msg_to_agent) []", str_all_agents, NO_AR_C, str_agent,
                    str_agent_id, OssecQueue.HC_SK_RESTART)
            elif msg == OssecQueue.RESTART_AGENTS:
                socket_msg = "{0} {1}{2}{3} {4} {5} - {6} (from_the_server) (no_rule_id)".format(
                    "(msg_to_agent) []", str_all_agents, NONE_C, str_agent,
                    str_agent_id, OssecQueue.RESTART_AGENTS, "null")
            else:
                raise WazuhInternalError(1012, msg)

            # Send message
            try:
                self._send(socket_msg.encode())
            except:
                if msg == OssecQueue.HC_SK_RESTART:
                    if agent_id:
                        raise WazuhError(1601, "on agent")
                    else:
                        raise WazuhError(1601, "on all agents")
                elif msg == OssecQueue.RESTART_AGENTS:
                    raise WazuhError(1702)

            # Return message
            if msg == OssecQueue.HC_SK_RESTART:
                return "Restarting Syscheck on agent" if agent_id else "Restarting Syscheck on all agents"
            elif msg == OssecQueue.RESTART_AGENTS:
                return "Restarting agent" if agent_id else "Restarting all agents"