diff --git a/CHANGELOG.md b/CHANGELOG.md index d84a7628b3..15167e9d82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Release report: TBD ### Added +- Add tests with new options to avoid FIM synchronization overlapping. ([#3318](https://github.com/wazuh/wazuh-qa/pull/3318)) \- (Framework + tests) - Add Logcollector millisecond granularity support test case ([#3910](https://github.com/wazuh/wazuh-qa/pull/3910)) \- (Tests) - Add Windows System folders FIM monitoring tests ([#3720](https://github.com/wazuh/wazuh-qa/pull/3720)) \- (Tests) - Add 'test_whodata_policy_changes' tests ([#3627](https://github.com/wazuh/wazuh-qa/pull/3627)) \- (Framework + Tests) @@ -18,6 +19,8 @@ Release report: TBD ### Changed +- Update FIM test to new FIM DBSync process ([#2728](https://github.com/wazuh/wazuh-qa/pull/2728)) \- (Framework + Tests) +- Update file_limit and registry_limit tests ([#3280](https://github.com/wazuh/wazuh-qa/pull/3280)) \- (Tests) - Change expected timestamp for proftpd analysisd test predecoder test case ([#3900](https://github.com/wazuh/wazuh-qa/pull/3900)) \- (Tests) - Skip test_large_changes test module ([#3783](https://github.com/wazuh/wazuh-qa/pull/3783)) \- (Tests) - Update report_changes tests ([#3405](https://github.com/wazuh/wazuh-qa/pull/3405)) \- (Tests) diff --git a/deps/wazuh_testing/wazuh_testing/__init__.py b/deps/wazuh_testing/wazuh_testing/__init__.py index c2fe261ee8..bcd5b96b91 100644 --- a/deps/wazuh_testing/wazuh_testing/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/__init__.py @@ -24,7 +24,6 @@ WAZUH_CONF_PATH = os.path.join(WAZUH_PATH, 'etc', 'ossec.conf') WAZUH_LOGS_PATH = os.path.join(WAZUH_PATH, 'logs') CLIENT_KEYS_PATH = os.path.join(WAZUH_PATH, 'etc' if platform.system() == 'Linux' else '', 'client.keys') -DB_PATH = os.path.join(WAZUH_PATH, 'queue', 'db') QUEUE_DB_PATH = os.path.join(WAZUH_PATH, 'queue', 'db') QUEUE_SOCKETS_PATH = os.path.join(WAZUH_PATH, 'queue', 'sockets') WAZUH_DB_SOCKET_PATH = os.path.join(QUEUE_DB_PATH, 'wdb') diff --git a/deps/wazuh_testing/wazuh_testing/data/syscheck_event_windows.json b/deps/wazuh_testing/wazuh_testing/data/syscheck_event_windows.json index 331071bd10..32ebe1ed60 100644 --- a/deps/wazuh_testing/wazuh_testing/data/syscheck_event_windows.json +++ b/deps/wazuh_testing/wazuh_testing/data/syscheck_event_windows.json @@ -30,12 +30,18 @@ ], "if": { "properties": { - "mode": {"const": "whodata"} + "mode": { + "const": "whodata" + } }, - "required": ["mode"] + "required": [ + "mode" + ] }, "then": { - "required": ["audit"] + "required": [ + "audit" + ] }, "properties": { "path": { @@ -52,7 +58,11 @@ "mode": { "$id": "#/properties/data/properties/mode", "type": "string", - "enum": ["realtime", "whodata", "scheduled"], + "enum": [ + "realtime", + "whodata", + "scheduled" + ], "examples": [ "whodata" ], @@ -61,7 +71,11 @@ "type": { "$id": "#/properties/data/properties/type", "type": "string", - "enum": ["added", "modified", "deleted"], + "enum": [ + "added", + "modified", + "deleted" + ], "examples": [ "added" ], @@ -70,7 +84,10 @@ "arch": { "$id": "#/properties/data/properties/arch", "type": "string", - "enum": ["[x32]", "[x64]"], + "enum": [ + "[x32]", + "[x64]" + ], "examples": [ "[x32]", "[x64]" @@ -121,7 +138,11 @@ "type": { "$id": "#/properties/data/properties/attributes/properties/type", "type": "string", - "enum": ["file", "registry_key", "registry_value"], + "enum": [ + "file", + "registry_key", + "registry_value" + ], "examples": [ "file" ], @@ -130,14 +151,24 @@ "value_type": { "$id": "#/properties/data/properties/attributes/properties/type", "type": "string", - "enum": ["REG_NONE", "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", "REG_DWORD_BIG_ENDIAN", - "REG_LINK", "REG_MULTI_SZ", "REG_RESOURCE_LIST", "REG_FULL_RESOURCE_DESCRIPTOR", - "REG_RESOURCE_REQUIREMENTS_LIST", "REG_QWORD"], + "enum": [ + "REG_NONE", + "REG_SZ", + "REG_EXPAND_SZ", + "REG_BINARY", + "REG_DWORD", + "REG_DWORD_BIG_ENDIAN", + "REG_LINK", + "REG_MULTI_SZ", + "REG_RESOURCE_LIST", + "REG_FULL_RESOURCE_DESCRIPTOR", + "REG_RESOURCE_REQUIREMENTS_LIST", + "REG_QWORD" + ], "examples": [ "REG_SZ" ], "pattern": "^(.*)$" - }, "size": { "$id": "#/properties/data/properties/attributes/properties/size", @@ -151,69 +182,69 @@ "$id": "#/properties/data/properties/attributes/properties/perm", "type": "object", "patternProperties": { - "^S-[-0-9]*": { - "type": "object", - "properties": { - "name": { - "$id": "#/properties/data/properties/attributes/properties/perm/name", - "type": "string" - }, - "allowed": { - "$id": "#/properties/data/properties/attributes/properties/perm/allowed", - "type": "array", - "items": { - "$id": "#/properties/data/properties/attributes/properties/perm/allowed/items", - "type": "string", - "enum": [ - "generic_read", - "generic_write", - "generic_execute", - "generic_all", - "delete", - "read_control", - "write_dac", - "write_owner", - "synchronize", - "read_data", - "write_data", - "append_data", - "read_ea", - "write_ea", - "execute", - "read_attributes", - "write_attributes" - ] - } - }, - "denied": { - "$id": "#/properties/data/properties/attributes/properties/perm/denied", - "type": "array", - "items": { - "$id": "#/properties/data/properties/attributes/properties/perm/denied/items", - "type": "string", - "enum": [ - "generic_read", - "generic_write", - "generic_execute", - "generic_all", - "delete", - "read_control", - "write_dac", - "write_owner", - "synchronize", - "read_data", - "write_data", - "append_data", - "read_ea", - "write_ea", - "execute", - "read_attributes", - "write_attributes" - ] - } - } + "^S-[-0-9]*": { + "type": "object", + "properties": { + "name": { + "$id": "#/properties/data/properties/attributes/properties/perm/name", + "type": "string" + }, + "allowed": { + "$id": "#/properties/data/properties/attributes/properties/perm/allowed", + "type": "array", + "items": { + "$id": "#/properties/data/properties/attributes/properties/perm/allowed/items", + "type": "string", + "enum": [ + "generic_read", + "generic_write", + "generic_execute", + "generic_all", + "delete", + "read_control", + "write_dac", + "write_owner", + "synchronize", + "read_data", + "write_data", + "append_data", + "read_ea", + "write_ea", + "execute", + "read_attributes", + "write_attributes" + ] + } + }, + "denied": { + "$id": "#/properties/data/properties/attributes/properties/perm/denied", + "type": "array", + "items": { + "$id": "#/properties/data/properties/attributes/properties/perm/denied/items", + "type": "string", + "enum": [ + "generic_read", + "generic_write", + "generic_execute", + "generic_all", + "delete", + "read_control", + "write_dac", + "write_owner", + "synchronize", + "read_data", + "write_data", + "append_data", + "read_ea", + "write_ea", + "execute", + "read_attributes", + "write_attributes" + ] } + } } + } } }, "uid": { @@ -336,7 +367,7 @@ "group_name", "inode", "attributes" - ], + ], "examples": [ "size", "mtime", @@ -356,60 +387,174 @@ } }, "old_attributes": { - "required": ["type" - ], - "allOf": [ - {"$ref": "#/properties/data/properties/attributes"} - ] - }, - "audit": { - "$id": "#/properties/data/properties/audit", + "$id": "#/properties/data/properties/attributes", "type": "object", "required": [ - "process_id", - "process_name", - "user_id", - "user_name" + "type" ], "properties": { - "process_id": { - "$id": "#/properties/data/properties/audit/properties/process_id", - "type": "integer", - "default": 0, - "examples": [ - 1899 - ] - }, - "process_name": { - "$id": "#/properties/data/properties/audit/properties/process_name", + "type": { + "$id": "#/properties/data/properties/attributes/properties/type", "type": "string", - "default": "", + "enum": [ + "file", + "registry_key", + "registry_value" + ], "examples": [ - "/usr/bin/touch" + "file" ], "pattern": "^(.*)$" }, - "user_id": { - "$id": "#/properties/data/properties/audit/properties/user_id", + "value_type": { + "$id": "#/properties/data/properties/attributes/properties/type", "type": "string", - "default": "", + "enum": [ + "REG_NONE", + "REG_SZ", + "REG_EXPAND_SZ", + "REG_BINARY", + "REG_DWORD", + "REG_DWORD_BIG_ENDIAN", + "REG_LINK", + "REG_MULTI_SZ", + "REG_RESOURCE_LIST", + "REG_FULL_RESOURCE_DESCRIPTOR", + "REG_RESOURCE_REQUIREMENTS_LIST", + "REG_QWORD" + ], "examples": [ - "0" + "REG_SZ" ], - "pattern": "^([0-9a-fA-F]|S-1-.*)+$" + "pattern": "^(.*)$" }, - "user_name": { - "$id": "#/properties/data/properties/audit/properties/user_name", - "type": "string", - "default": "", + "size": { + "$id": "#/properties/data/properties/attributes/properties/size", + "type": "integer", + "default": 0, "examples": [ - "root" + 0 + ] + }, + "perm": { + "$id": "#/properties/data/properties/attributes/properties/perm", + "type": "object", + "patternProperties": { + "^S-[-0-9]*": { + "type": "object", + "properties": { + "name": { + "$id": "#/properties/data/properties/attributes/properties/perm/name", + "type": "string" + }, + "allowed": { + "$id": "#/properties/data/properties/attributes/properties/perm/allowed", + "type": "array", + "items": { + "$id": "#/properties/data/properties/attributes/properties/perm/allowed/items", + "type": "string", + "enum": [ + "generic_read", + "generic_write", + "generic_execute", + "generic_all", + "delete", + "read_control", + "write_dac", + "write_owner", + "synchronize", + "read_data", + "write_data", + "append_data", + "read_ea", + "write_ea", + "execute", + "read_attributes", + "write_attributes" + ] + } + }, + "denied": { + "$id": "#/properties/data/properties/attributes/properties/perm/denied", + "type": "array", + "items": { + "$id": "#/properties/data/properties/attributes/properties/perm/denied/items", + "type": "string", + "enum": [ + "generic_read", + "generic_write", + "generic_execute", + "generic_all", + "delete", + "read_control", + "write_dac", + "write_owner", + "synchronize", + "read_data", + "write_data", + "append_data", + "read_ea", + "write_ea", + "execute", + "read_attributes", + "write_attributes" + ] + } + } + } + } + } + }, + "audit": { + "$id": "#/properties/data/properties/audit", + "type": "object", + "required": [ + "process_id", + "process_name", + "user_id", + "user_name" ], - "pattern": "^(.*)$" + "properties": { + "process_id": { + "$id": "#/properties/data/properties/audit/properties/process_id", + "type": "integer", + "default": 0, + "examples": [ + 1899 + ] + }, + "process_name": { + "$id": "#/properties/data/properties/audit/properties/process_name", + "type": "string", + "default": "", + "examples": [ + "/usr/bin/touch" + ], + "pattern": "^(.*)$" + }, + "user_id": { + "$id": "#/properties/data/properties/audit/properties/user_id", + "type": "string", + "default": "", + "examples": [ + "0" + ], + "pattern": "^([0-9a-fA-F]|S-1-.*)+$" + }, + "user_name": { + "$id": "#/properties/data/properties/audit/properties/user_name", + "type": "string", + "default": "", + "examples": [ + "root" + ], + "pattern": "^(.*)$" + } + } } } } } } } -} +} \ No newline at end of file diff --git a/deps/wazuh_testing/wazuh_testing/fim.py b/deps/wazuh_testing/wazuh_testing/fim.py index 0ff0924825..0fa2538acd 100644 --- a/deps/wazuh_testing/wazuh_testing/fim.py +++ b/deps/wazuh_testing/wazuh_testing/fim.py @@ -1093,20 +1093,6 @@ def callback_detect_integrity_event(line): return None -def callback_detect_registry_integrity_state_event(line): - event = callback_detect_integrity_event(line) - if event and event['component'] == 'fim_registry' and event['type'] == 'state': - return event['data'] - return None - - -def callback_detect_registry_integrity_clear_event(line): - event = callback_detect_integrity_event(line) - if event and event['component'] == 'fim_registry' and event['type'] == 'integrity_clear': - return True - return None - - def callback_detect_integrity_state(line): event = callback_detect_integrity_event(line) if event: @@ -1115,8 +1101,24 @@ def callback_detect_integrity_state(line): return None +def callback_start_synchronization(line): + """ Callback that detects if a line contains the FIM sync module has started. + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + if 'FIM sync module started' in line: + return line + return None + + def callback_detect_synchronization(line): - if 'Initializing FIM Integrity Synchronization check' in line: + """ Callback that detects if a line contains a FIM sync has started. + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + if 'Executing FIM sync' in line: return line return None @@ -2506,6 +2508,16 @@ def detect_initial_scan_start(file_monitor): error_message='Did not receive expected "File integrity monitoring scan started" event') +def detect_sync_initial_scan_start(file_monitor): + """Detect initial sync scan start. + + Args: + file_monitor (FileMonitor): file log monitor to detect events + """ + file_monitor.start(timeout=60, callback=callback_start_synchronization, + error_message='Did not receive expected "FIM sync scan started" event') + + def detect_realtime_start(file_monitor): """Detect realtime engine start when restarting Wazuh. diff --git a/deps/wazuh_testing/wazuh_testing/fim_module/__init__.py b/deps/wazuh_testing/wazuh_testing/fim_module/__init__.py deleted file mode 100644 index be2d10de0c..0000000000 --- a/deps/wazuh_testing/wazuh_testing/fim_module/__init__.py +++ /dev/null @@ -1,76 +0,0 @@ - -# Copyright (C) 2015-2022, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -''' -The purpose of this file is to contain all the variables necessary for FIM in order to be easier to -maintain if one of them changes in the future. -''' - -# Variables -SIZE_LIMIT_CONFIGURED_VALUE = 10240 -# Key variables -WINDOWS_HKEY_LOCAL_MACHINE = 'HKEY_LOCAL_MACHINE' -MONITORED_KEY = 'SOFTWARE\\random_key' -MONITORED_KEY_2 = "SOFTWARE\\Classes\\random_key_2" -WINDOWS_REGISTRY = 'WINDOWS_REGISTRY' - - -# Value key -SYNC_INTERVAL = 'SYNC_INTERVAL' -SYNC_INTERVAL_VALUE = MAX_EVENTS_VALUE = 20 - -# Folders variables -TEST_DIR_1 = 'testdir1' -TEST_DIRECTORIES = 'TEST_DIRECTORIES' -TEST_REGISTRIES = 'TEST_REGISTRIES' - -# FIM modules -SCHEDULE_MODE = 'scheduled' - -# Yaml Configuration -YAML_CONF_REGISTRY_RESPONSE = 'wazuh_conf_registry_responses_win32.yaml' -YAML_CONF_SYNC_WIN32 = 'wazuh_sync_conf_win32.yaml' - -# Synchronization options -SYNCHRONIZATION_ENABLED = 'SYNCHRONIZATION_ENABLED' -SYNCHRONIZATION_REGISTRY_ENABLED = 'SYNCHRONIZATION_REGISTRY_ENABLED' - -# Callbacks message -INTEGRITY_CONTROL_MESSAGE = r'.*Sending integrity control message: (.+)$' -REGISTRY_DBSYNC_NO_DATA = r'.*#!-fim_registry dbsync no_data (.+)' -CB_FILE_LIMIT_CAPACITY = r".*Sending DB (\d+)% full alert." -CB_FILE_LIMIT_BACK_TO_NORMAL = r".*(Sending DB back to normal alert)." -CB_COUNT_REGISTRY_FIM_ENTRIES = r".*Fim registry entries: (\d+)" -CB_DATABASE_FULL_COULD_NOT_INSERT = r".*Couldn't insert ('.*')? entry into DB\. The DB is full.*" -CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE = r".*Couldn't insert ('.*')? value entry into DB\. The DB is full.*" -CB_FILE_LIMIT_VALUE = r".*Maximum number of entries to be monitored: '(\d+)'" -CB_FILE_SIZE_LIMIT_BIGGER_THAN_DISK_QUOTA = r".*Setting 'disk_quota' to (\d+), 'disk_quota' must be greater than 'file_size'" -CB_FILE_LIMIT_DISABLED = r".*(No limit set) to maximum number of entries to be monitored" -CB_INODE_ENTRIES_PATH_COUNT = r".*Fim inode entries: (\d+), path count: (\d+)" -CB_FIM_ENTRIES_COUNT = r".*Fim entries: (\d+)" -CB_DETECT_FIM_EVENT = r'.*Sending FIM event: (.+)$' -CB_IGNORING_DUE_TO_SREGEX = r".*?Ignoring path '(.*)' due to sregex '(.*)'.*" -CB_IGNORING_DUE_TO_PATTERN = r".*?Ignoring path '(.*)' due to pattern '(.*)'.*" - - -# Error Messages -ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT = 'Did not receive expected "DEBUG: ...: Sending DB ...% full alert." event' -ERR_MSG_FIM_INODE_ENTRIES = 'Did not receive expected "Fim inode entries: ..., path count: ..." event' -ERR_MSG_DB_BACK_TO_NORMAL = 'Did not receive expected "DEBUG: ...: Sending DB back to normal alert." event' -ERR_MSG_DATABASE_FULL_ALERT_EVENT = 'Did not receive expected "DEBUG: ...: Sending DB 100% full alert." event' -ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT = 'Did not receive expected "DEBUG: ...: Couldn\'t insert \'...\' entry into DB. The DB is full, ..." event' -ERR_MSG_FILE_LIMIT_VALUES = 'Did not receive expected "DEBUG: ...: Maximum number of entries to be monitored: ..." event' -ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL = 'Wrong value for full database alert.' -ERR_MSG_DISK_QUOTA_MUST_BE_GREATER = "Did not receive expected 'DEBUG: ... disk_quota must be greater than file_size message'" -ERR_MSG_CONTENT_CHANGES_EMPTY = "content_changes is empty" -ERR_MSG_CONTENT_CHANGES_NOT_EMPTY = "content_changes isn't empty" -ERR_MSG_FILE_LIMIT_DISABLED = 'Did not receive expected "DEBUG: ...: No limit set to maximum number of entries to be monitored" event' -ERR_MSG_NO_EVENTS_EXPECTED = 'No events should be detected.' -ERR_MSG_DELETED_EVENT_NOT_RECIEVED = 'Did not receive expected deleted event' -ERR_MSG_WRONG_NUMBER_OF_ENTRIES = 'Wrong number of entries counted.' -ERR_MSG_WRONG_INODE_PATH_COUNT = 'Wrong number of inodes and path count' -ERR_MSG_WRONG_FILE_LIMIT_VALUE = 'Wrong value for file_limit.' -ERR_MSG_WRONG_DISK_QUOTA_VALUE = 'Wrong value for disk_quota' -ERR_MSG_WRONG_CAPACITY_LOG_DB_LIMIT = 'Wrong capacity log for DB file_limit' diff --git a/deps/wazuh_testing/wazuh_testing/fim_module/event_monitor.py b/deps/wazuh_testing/wazuh_testing/fim_module/event_monitor.py deleted file mode 100644 index bb18dc7573..0000000000 --- a/deps/wazuh_testing/wazuh_testing/fim_module/event_monitor.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2015-2022, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - - -import re -import json -from sys import platform -from wazuh_testing import logger -from wazuh_testing.fim_module import (CB_INODE_ENTRIES_PATH_COUNT, CB_FIM_ENTRIES_COUNT, CB_DETECT_FIM_EVENT) - - -def callback_detect_event(line): - msg = CB_DETECT_FIM_EVENT - match = re.match(msg, line) - if not match: - return None - - try: - json_event = json.loads(match.group(1)) - if json_event['type'] == 'event': - return json_event - except (json.JSONDecodeError, AttributeError, KeyError) as e: - logger.warning(f"Couldn't load a log line into json object. Reason {e}") - - -def callback_entries_path_count(line): - if platform != 'win32': - match = re.match(CB_INODE_ENTRIES_PATH_COUNT, line) - else: - match = re.match(CB_FIM_ENTRIES_COUNT, line) - - if match: - if platform != 'win32': - return match.group(1), match.group(2) - else: - return match.group(1), None diff --git a/deps/wazuh_testing/wazuh_testing/fim_module/fim_synchronization.py b/deps/wazuh_testing/wazuh_testing/fim_module/fim_synchronization.py deleted file mode 100644 index 889d2b8c8a..0000000000 --- a/deps/wazuh_testing/wazuh_testing/fim_module/fim_synchronization.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2015-2021, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -from wazuh_testing.fim import LOG_FILE_PATH, callback_detect_registry_integrity_state_event -from wazuh_testing import global_parameters -from wazuh_testing.fim_module.fim_variables import MAX_EVENTS_VALUE, CB_REGISTRY_DBSYNC_NO_DATA -from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback - - -def get_sync_msgs(tout, new_data=True): - """Look for as many synchronization events as possible. - - This function will look for the synchronization messages until a Timeout is raised or 'max_events' is reached. - - Args: - tout (int): Timeout that will be used to get the dbsync_no_data message. - new_data (bool): Specifies if the test will wait the event `dbsync_no_data`. - - Returns: - A list with all the events in json format. - """ - wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) - events = [] - if new_data: - wazuh_log_monitor.start(timeout=tout, - callback=generate_monitoring_callback(CB_REGISTRY_DBSYNC_NO_DATA), - error_message='Did not receive expected ' - '"db sync no data" event') - for _ in range(0, MAX_EVENTS_VALUE): - try: - sync_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=callback_detect_registry_integrity_state_event, - accum_results=1, - error_message='Did not receive expected ' - 'Sending integrity control message"').result() - except TimeoutError: - break - - events.append(sync_event) - - return events - - -def find_value_in_event_list(key_path, value_name, event_list): - """Function that looks for a key path and value_name in a list of json events. - - Args: - path (str): Path of the registry key. - value_name (str): Name of the value. - event_list (list): List containing the events in JSON format. - - Returns: - The event that matches the specified path. None if no event was found. - """ - for event in event_list: - if 'value_name' not in event.keys(): - continue - - if event['path'] == key_path and event['value_name'] == value_name: - return event - - return None diff --git a/deps/wazuh_testing/wazuh_testing/fim_module/fim_variables.py b/deps/wazuh_testing/wazuh_testing/fim_module/fim_variables.py deleted file mode 100644 index d2b2f7ba3c..0000000000 --- a/deps/wazuh_testing/wazuh_testing/fim_module/fim_variables.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (C) 2015-2021, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -''' -The purpose of this file is to contain all the variables necessary for FIM in order to be easier to -maintain if one of them changes in the future. - -UPDATE: This file is deprecated. Add new variables to de fim_module/__init__.py file. If this is used -in a test, refactor the imports to adhere to the new standard. -''' - -# Variables -SIZE_LIMIT_CONFIGURED_VALUE = 10 * 1024 - -# Key Variables -WINDOWS_HKEY_LOCAL_MACHINE = 'HKEY_LOCAL_MACHINE' -MONITORED_KEY = 'SOFTWARE\\random_key' -MONITORED_KEY_2 = "SOFTWARE\\Classes\\random_key_2" -WINDOWS_REGISTRY = 'WINDOWS_REGISTRY' - - -# Value Key -SYNC_INTERVAL = 'SYNC_INTERVAL' -SYNC_INTERVAL_VALUE = MAX_EVENTS_VALUE = 20 - - -# Folder Variables -TEST_DIR_1 = 'testdir1' -TEST_DIRECTORIES = 'TEST_DIRECTORIES' -TEST_REGISTRIES = 'TEST_REGISTRIES' - - -# Syscheck Attributes -REPORT_CHANGES = 'report_changes' -DIFF_SIZE_LIMIT = 'diff_size_limit' -FILE_SIZE_ENABLED = 'FILE_SIZE_ENABLED' -FILE_SIZE_LIMIT = 'FILE_SIZE_LIMIT' -DISK_QUOTA_ENABLED = 'DISK_QUOTA_ENABLED' -DISK_QUOTA_LIMIT = 'DISK_QUOTA_LIMIT' - -# Syscheck Values -DIFF_LIMIT_VALUE = 2 -DIFF_DEFAULT_LIMIT_VALUE = 51200 - - -# FIM Modes -SCHEDULE_MODE = 'scheduled' - -# Yaml Configuration -YAML_CONF_REGISTRY_RESPONSE = 'wazuh_conf_registry_responses_win32.yaml' -YAML_CONF_SYNC_WIN32 = 'wazuh_sync_conf_win32.yaml' -YAML_CONF_DIFF = 'wazuh_conf_diff.yaml' - -# Synchronization Options -SYNCHRONIZATION_ENABLED = 'SYNCHRONIZATION_ENABLED' -SYNCHRONIZATION_REGISTRY_ENABLED = 'SYNCHRONIZATION_REGISTRY_ENABLED' - -# Callback Messages -CB_INTEGRITY_CONTROL_MESSAGE = r'.*Sending integrity control message: (.+)$' -CB_REGISTRY_DBSYNC_NO_DATA = r'.*#!-fim_registry dbsync no_data (.+)' -CB_FILE_LIMIT_CAPACITY = r".*Sending DB (\d+)% full alert." -CB_FILE_LIMIT_BACK_TO_NORMAL = r".*(Sending DB back to normal alert)." -CB_COUNT_REGISTRY_FIM_ENTRIES = r".*Fim registry entries: (\d+)" -CB_DATABASE_FULL_COULD_NOT_INSERT = r".*Couldn't insert '.*' (value )?entry into DB\. The DB is full.*" -CB_FILE_LIMIT_VALUE = r".*Maximum number of entries to be monitored: '(\d+)'" -CB_FILE_SIZE_LIMIT_BIGGER_THAN_DISK_QUOTA = r".*Setting 'disk_quota' to (\d+), 'disk_quota' must be greater than 'file_size'" -CB_MAXIMUM_FILE_SIZE = r'.*Maximum file size limit to generate diff information configured to \'(\d+) KB\'.*' -CB_FILE_LIMIT_CAPACITY = r".*Sending DB (\d+)% full alert." -CB_FILE_LIMIT_BACK_TO_NORMAL = r".*(Sending DB back to normal alert)." -CB_COUNT_REGISTRY_FIM_ENTRIES = r".*Fim registry entries: (\d+)" -CB_DATABASE_FULL_COULD_NOT_INSERT = r".*Couldn't insert '.*' (value )?entry into DB\. The DB is full.*" -CB_FILE_LIMIT_VALUE = r".*Maximum number of entries to be monitored: '(\d+)'" -CB_FILE_SIZE_LIMIT_BIGGER_THAN_DISK_QUOTA = r".*Setting 'disk_quota' to (\d+), 'disk_quota' must be greater than 'file_size'" -CB_MAXIMUM_FILE_SIZE = r'.*Maximum file size limit to generate diff information configured to \'(\d+) KB\'.*' - - -#Error Messages -ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT = 'Did not receive expected "DEBUG: ...: Sending DB ...% full alert." event' -ERR_MSG_FIM_INODE_ENTRIES = 'Did not receive expected "Fim inode entries: ..., path count: ..." event' -ERR_MSG_DB_BACK_TO_NORMAL = 'Did not receive expected "DEBUG: ...: Sending DB back to normal alert." event' -ERR_MSG_WRONG_NUMBER_OF_ENTRIES = 'Wrong number of entries counted.' -ERR_MSG_WRONG_FILE_LIMIT_VALUE ='Wrong value for file_limit.' -ERR_MSG_WRONG_DISK_QUOTA_VALUE ='Wrong value for disk_quota' -ERR_MSG_DATABASE_FULL_ALERT_EVENT = 'Did not receive expected "DEBUG: ...: Sending DB 100% full alert." event' -ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT = 'Did not receive expected "DEBUG: ...: Couldn\'t insert \'...\' entry into DB. The DB is full, ..." event' -ERR_MSG_FILE_LIMIT_VALUES = 'Did not receive expected "DEBUG: ...: Maximum number of entries to be monitored: ..." event' -ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL = 'Wrong value for full database alert.' -ERR_MSG_DISK_QUOTA_MUST_BE_GREATER = "Did not receive expected 'DEBUG: ... disk_quota must be greater than file_size message'" -ERR_MSG_CONTENT_CHANGES_EMPTY = "content_changes is empty" -ERR_MSG_CONTENT_CHANGES_NOT_EMPTY = "content_changes isn't empty" -ERR_MSG_MAXIMUM_FILE_SIZE = 'Did not receive expected "Maximum file size limit configured to \'... KB\'..." event' -ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE = 'Wrong value for diff_size_limit' diff --git a/deps/wazuh_testing/wazuh_testing/mocking/__init__.py b/deps/wazuh_testing/wazuh_testing/mocking/__init__.py index 3502f2ca58..44e799bbc9 100644 --- a/deps/wazuh_testing/wazuh_testing/mocking/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/mocking/__init__.py @@ -247,7 +247,7 @@ def delete_mocked_agent(agent_id): global_db.delete_agent(agent_id) # Remove agent id DB file if exists - remove_file(os.path.join(wazuh_testing.DB_PATH, f"{agent_id}.db")) + remove_file(os.path.join(wazuh_testing.QUEUE_DB_PATH, f"{agent_id}.db")) # Remove entry from client keys client_keys.delete_client_keys_entry(agent_id) diff --git a/deps/wazuh_testing/wazuh_testing/modules/__init__.py b/deps/wazuh_testing/wazuh_testing/modules/__init__.py index b6e9a50d28..d9a289651c 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/modules/__init__.py @@ -1,33 +1,37 @@ -# Copyright (C) 2015-2022, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -''' -The purpose of this file is to contain all the variables necessary for Wazuh in order to be easier -to maintain if one of them changes in the future. -''' -import pytest - -# Services Variables -WAZUH_SERVICES_STOPPED = 'stopped' -WAZUH_SERVICE_PREFIX = 'wazuh' -WAZUH_SERVICES_STOP = 'stop' -WAZUH_SERVICES_START = 'start' - -# Configurations -DATA = 'data' -WAZUH_LOG_MONITOR = 'wazuh_log_monitor' - -# Marks Executions - -TIER0 = pytest.mark.tier(level=0) -TIER1 = pytest.mark.tier(level=1) -TIER2 = pytest.mark.tier(level=2) - -WINDOWS = pytest.mark.win32 -LINUX = pytest.mark.linux -MACOS = pytest.mark.darwin -SOLARIS = pytest.mark.sunos5 - -AGENT = pytest.mark.agent -SERVER = pytest.mark.server +# Copyright (C) 2015-2023, Wazuh Inc. +# Created by Wazuh, Inc. . +# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +''' +The purpose of this file is to contain all the variables necessary for Wazuh in order to be easier +to maintain if one of them changes in the future. +''' +import pytest + +WAZUH_SERVICE_PREFIX = 'wazuh' +WAZUH_SERVICES_STOPPED = 'stopped' +WAZUH_SERVICES_STOP = 'stop' +WAZUH_SERVICES_START = 'start' + +# Configurations +DATA = 'data' +WAZUH_LOG_MONITOR = 'wazuh_log_monitor' + +# Marks Executions + +TIER0 = pytest.mark.tier(level=0) +TIER1 = pytest.mark.tier(level=1) +TIER2 = pytest.mark.tier(level=2) + +WINDOWS = pytest.mark.win32 +LINUX = pytest.mark.linux +MACOS = pytest.mark.darwin +SOLARIS = pytest.mark.sunos5 + +AGENT = pytest.mark.agent +SERVER = pytest.mark.server + +# Local internal options +WINDOWS_DEBUG = 'windows.debug' +SYSCHECK_DEBUG = 'syscheck.debug' +VERBOSE_DEBUG_OUTPUT = 2 diff --git a/deps/wazuh_testing/wazuh_testing/modules/fim/__init__.py b/deps/wazuh_testing/wazuh_testing/modules/fim/__init__.py index e7f42d16a8..842cde0c5a 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/fim/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/modules/fim/__init__.py @@ -8,6 +8,8 @@ ''' import sys +import os +from wazuh_testing.tools import PREFIX if sys.platform == 'win32': import win32con @@ -15,6 +17,8 @@ # Variables +SIZE_LIMIT_CONFIGURED_VALUE = 10240 + if sys.platform == 'win32': registry_parser = { @@ -70,7 +74,8 @@ registry_parser = {} registry_class_name = {} registry_value_type = {} - + RegOpenKeyEx = 0 + RegCloseKey = 0 KEY_WOW64_32KEY = 0 KEY_WOW64_64KEY = 0 REG_NONE = 0 @@ -119,10 +124,30 @@ CHECK_SUM: {CHECK_SHA1SUM, CHECK_SHA256SUM, CHECK_MD5SUM} } +REQUIRED_REG_KEY_ATTRIBUTES = { + CHECK_OWNER: ['uid', 'user_name'], + CHECK_GROUP: ['gid', 'group_name'], + CHECK_PERM: 'perm', + CHECK_MTIME: 'mtime', + CHECK_ALL: {CHECK_OWNER, CHECK_GROUP, CHECK_PERM, CHECK_MTIME} +} + +REQUIRED_REG_VALUE_ATTRIBUTES = { + CHECK_SHA1SUM: 'hash_sha1', + CHECK_MD5SUM: 'hash_md5', + CHECK_SHA256SUM: 'hash_sha256', + CHECK_SIZE: 'size', + CHECK_TYPE: 'value_type', + CHECK_ALL: {CHECK_SHA256SUM, CHECK_SHA1SUM, CHECK_MD5SUM, CHECK_SIZE, CHECK_TYPE}, + CHECK_SUM: {CHECK_SHA1SUM, CHECK_SHA256SUM, CHECK_MD5SUM} +} # Key variables -WINDOWS_HKEY_LOCAL_MACHINE = 'HKEY_LOCAL_MACHINE' MONITORED_KEY = 'SOFTWARE\\random_key' +MONITORED_KEY_2 = 'SOFTWARE\\Classes\\random_key_2' +MONITORED_KEY_3 = 'SOFTWARE\\Classes\\random_key_3' + +WINDOWS_HKEY_LOCAL_MACHINE = 'HKEY_LOCAL_MACHINE' WINDOWS_REGISTRY = 'WINDOWS_REGISTRY' @@ -137,14 +162,15 @@ TEST_DIRECTORIES = 'TEST_DIRECTORIES' TEST_REGISTRIES = 'TEST_REGISTRIES' +MONITORED_DIR_1 = os.path.join(PREFIX, TEST_DIR_1) # Syscheck attributes REPORT_CHANGES = 'report_changes' -DIFF_SIZE_LIMIT = 'diff_size_limit' FILE_SIZE_ENABLED = 'FILE_SIZE_ENABLED' FILE_SIZE_LIMIT = 'FILE_SIZE_LIMIT' DISK_QUOTA_ENABLED = 'DISK_QUOTA_ENABLED' DISK_QUOTA_LIMIT = 'DISK_QUOTA_LIMIT' +DIFF_SIZE_LIMIT = 'diff_size_limit' # Syscheck values DIFF_LIMIT_VALUE = 2 @@ -152,7 +178,7 @@ # FIM modes -SCHEDULE_MODE = 'scheduled' +SCHEDULED_MODE = 'scheduled' REALTIME_MODE = 'realtime' WHODATA_MODE = 'whodata' @@ -162,45 +188,11 @@ YAML_CONF_SYNC_WIN32 = 'wazuh_sync_conf_win32.yaml' YAML_CONF_MAX_EPS_SYNC = 'wazuh_sync_conf_max_eps.yaml' + # Synchronization options SYNCHRONIZATION_ENABLED = 'SYNCHRONIZATION_ENABLED' SYNCHRONIZATION_REGISTRY_ENABLED = 'SYNCHRONIZATION_REGISTRY_ENABLED' -# Callbacks message -CB_DETECT_FIM_EVENT = r'.*Sending FIM event: (.+)$' -CB_INTEGRITY_CONTROL_MESSAGE = r'.*Sending integrity control message: (.+)$' -CB_REGISTRY_DBSYNC_NO_DATA = r'.*#!-fim_registry dbsync no_data (.+)' -CB_MAXIMUM_FILE_SIZE = r'.*Maximum file size limit to generate diff information configured to \'(\d+) KB\'.*' -CB_AGENT_CONNECT = r'.* Connected to the server .*' -CB_FOLDERS_MONITORED_REALTIME = r'.*Folders monitored with real-time engine: (\d+)' -CB_REALTIME_WHODATA_ENGINE_STARTED = r'.*File integrity monitoring (real-time Whodata) engine started.*' -CB_DISK_QUOTA_LIMIT_CONFIGURED_VALUE = r'.*Maximum disk quota size limit configured to \'(\d+) KB\'.*' -CB_FILE_EXCEEDS_DISK_QUOTA = r'.*The (.*) of the file size \'(.*)\' exceeds the disk_quota.*' -CB_FILE_SIZE_LIMIT_REACHED = r'.*File \'(.*)\' is too big for configured maximum size to perform diff operation\.' -CB_DIFF_FOLDER_DELETED = r'.*Folder \'(.*)\' has been deleted.*' -CB_STARTING_WINDOWS_AUDIT = r'.*state_checker.*(Starting check of Windows Audit Policies and SACLs)' -CB_SWITCHING_DIRECTORIES_TO_REALTIME = r'.*state_checker.*(Audit policy change detected.\ - Switching directories to realtime)' -CB_RECIEVED_EVENT_4719 = r'.*win_whodata.*(Event 4719).*Switching directories to realtime' - - -# Error message -ERR_MSG_MAXIMUM_FILE_SIZE = 'Did not receive expected "Maximum file size limit configured to \'... KB\'..." event' -ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE = 'Wrong value for diff_size_limit' -ERR_MSG_AGENT_DISCONNECT = 'Agent couldn\'t connect to server.' -ERR_MSG_INTEGRITY_CONTROL_MSG = 'Didn\'t receive control message(integrity_check_global)' -ERR_MSG_FOLDERS_MONITORED_REALTIME = 'Did not receive expected "Folders monitored with real-time engine..." event' -ERR_MSG_WHODATA_ENGINE_EVENT = 'Did not receive "File integrity monitoring real-time Whodata engine started" event' -ERR_MSG_FIM_EVENT_NOT_DETECTED = 'Did not receive expected "Sending FIM event: ..." event.' -ERR_MSG_SCHEDULED_SCAN_STARTED = 'Did not receive expected "File integrity monitoring scan started" event' -ERR_MSG_SCHEDULED_SCAN_ENDED = 'Did not receive expected "File integrity monitoring scan ended" event' -ERR_MSG_DISK_QUOTA_LIMIT = 'Did not receive "Maximum disk quota size limit configured to \'... KB\'." event' -ERR_MSG_FILE_LIMIT_REACHED = 'Did not receive "File ... is too big ... to perform diff operation" event.' -ERR_MSG_FOLDER_DELETED = 'Did not receive expected "Folder ... has been deleted." event.' -ERR_MSG_SACL_CONFIGURED_EVENT = 'Did not receive the expected "The SACL of will be configured" event' -ERR_MSG_WHDATA_REALTIME_MODE_CHANGE_EVENT = 'Expected "directory starts to monitored in real-time" event not received' - - # Setting Local_internal_option file if sys.platform == 'win32': FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS = { diff --git a/deps/wazuh_testing/wazuh_testing/modules/fim/classes.py b/deps/wazuh_testing/wazuh_testing/modules/fim/classes.py index 9d13f33f0a..b35293735f 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/fim/classes.py +++ b/deps/wazuh_testing/wazuh_testing/modules/fim/classes.py @@ -1,4 +1,4 @@ -# Copyright (C) 2015-2022, Wazuh Inc. +# Copyright (C) 2015-2023, Wazuh Inc. # Created by Wazuh, Inc. . # This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 @@ -9,12 +9,14 @@ from jsonschema import validate from collections import Counter from wazuh_testing import global_parameters, logger, WAZUH_TESTING_DATA_PATH -from wazuh_testing.modules.fim import REQUIRED_ATTRIBUTES +from wazuh_testing.modules.fim import REQUIRED_ATTRIBUTES, REQUIRED_REG_KEY_ATTRIBUTES, REQUIRED_REG_VALUE_ATTRIBUTES from wazuh_testing.modules.fim.event_monitor import callback_detect_event if sys.platform == 'linux2' or sys.platform == 'linux': from jq import jq +_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') + def validate_event(event, checks=None, mode=None): """Check if event is properly formatted according to some checks. @@ -76,6 +78,72 @@ def get_required_attributes(check_attributes, result=None): old_intersection_debug) +def validate_registry_event(event, checks=None, mode=None, is_key=True): + """Check if event is properly formatted according to some checks. + + Args: + event (dict): represents an event generated by syscheckd. + checks (:obj:`set`, optional): set of XML CHECK_* options. Default `{CHECK_ALL}` + mode (:obj:`str`, optional): represents the FIM mode expected for the event to validate. + is_key(Boolean): define if event to validate is a registry_key (True) or registry_value(False). Default True + """ + + def get_required_attributes(check_attributes, result=None): + result = set() if result is None else result + for check in check_attributes: + mapped = REQUIRED_REG_KEY_ATTRIBUTES[check] if is_key else REQUIRED_REG_VALUE_ATTRIBUTES[check] + + if isinstance(mapped, str): + result |= {mapped} + elif isinstance(mapped, list): + result |= set(mapped) + elif isinstance(mapped, set): + result |= get_required_attributes(mapped, result=result) + + return result + + json_file = 'syscheck_event_windows.json' if sys.platform == "win32" else 'syscheck_event.json' + with open(os.path.join(_data_path, json_file), 'r') as f: + schema = json.load(f) + + validate(schema=schema, instance=event) + + # Check FIM mode + mode = global_parameters.current_configuration['metadata']['fim_mode'] if mode is None else mode.replace('-', '') + assert (event['data']['mode']).replace('-', '') == mode, f"The event's FIM mode was '{event['data']['mode']}' \ + but was expected to be '{mode}'" + + # Check attributes + if checks: + attributes = event['data']['attributes'].keys() - {'type', 'checksum'} + + required_attributes = get_required_attributes(checks) + + intersection = attributes ^ required_attributes + intersection_debug = "Event attributes are: " + str(attributes) + intersection_debug += "\nRequired Attributes are: " + str(required_attributes) + intersection_debug += "\nIntersection is: " + str(intersection) + + assert (intersection == set()), f'Attributes and required_attributes are not the same. ' + intersection_debug + + # Check add file event + if event['data']['type'] == 'added': + assert 'old_attributes' not in event['data'] and 'changed_attributes' not in event['data'] + + # Check modify file event + if event['data']['type'] == 'modified': + assert 'old_attributes' in event['data'] and 'changed_attributes' in event['data'] + + old_attributes = event['data']['old_attributes'].keys() - {'type', 'checksum'} + old_intersection = old_attributes ^ required_attributes + old_intersection_debug = "Event attributes are: " + str(old_attributes) + old_intersection_debug += "\nRequired Attributes are: " + str(required_attributes) + old_intersection_debug += "\nIntersection is: " + str(old_intersection) + + assert (old_intersection == set()), (f'Old_attributes and required_attributes are not the same. ' + + old_intersection_debug) + + class CustomValidator: """Enable using user-defined validators over the events when validating them with EventChecker""" @@ -293,3 +361,206 @@ def _get_file_list(self): expected_file_path = expected_file_path[:1].lower() + expected_file_path[1:] result_list.append(expected_file_path) return result_list + + +class RegistryEventChecker: + """Utility to allow fetch events and validate them.""" + + def __init__(self, log_monitor, registry_key, registry_dict=None, options=None, custom_validator=None, + encoding=None, callback=callback_detect_event, is_value=False): + self.log_monitor = log_monitor + self.registry_key = registry_key + global registry_ignore_path + registry_ignore_path = registry_key + self.registry_dict = registry_dict + self.custom_validator = custom_validator + self.options = options + self.encoding = encoding + self.events = None + self.callback = callback + self.is_value = is_value + + def __del__(self): + global registry_ignore_path + registry_ignore_path = None + + def fetch_and_check(self, event_type, min_timeout=1, triggers_event=True, extra_timeout=0): + """Call 'fetch_events', 'fetch_key_events' and 'check_events', depending on the type of event expected. + + Args: + event_type (str): Expected type of the raised event {'added', 'modified', 'deleted'}. + min_timeout (int, optional): seconds to wait until an event is raised when trying to fetch. Defaults `1` + triggers_event (boolean, optional): True if the event should be raised. False otherwise. Defaults `True` + extra_timeout (int, optional): Additional time to wait after the min_timeout + """ + assert event_type in ['added', 'modified', 'deleted'], f'Incorrect event type: {event_type}' + + num_elems = len(self.registry_dict) + + error_msg = "TimeoutError was raised because " + error_msg += str(num_elems) if num_elems > 1 else "a single" + error_msg += " '" + str(event_type) + "' " + error_msg += "events were " if num_elems > 1 else "event was " + error_msg += "expected for " + str(self._get_elem_list()) + error_msg += " but were not detected." if num_elems > 1 else " but was not detected." + + key_error_msg = f"TimeoutError was raised because 1 event was expected for {self.registry_key} " + key_error_msg += 'but was not detected.' + + if event_type == 'modified' or self.is_value: + self.events = self.fetch_events(min_timeout, triggers_event, extra_timeout, error_message=error_msg) + self.check_events(event_type) + elif event_type == 'added': + self.events = self.fetch_events(min_timeout, triggers_event, extra_timeout, error_message=error_msg) + self.check_events(event_type) + elif event_type == 'deleted': + self.events = self.fetch_events(min_timeout, triggers_event, extra_timeout, error_message=error_msg) + self.check_events(event_type) + + def fetch_events(self, min_timeout=1, triggers_event=True, extra_timeout=0, error_message=''): + """ Gets as much events that match the callback as possible in the given time. + + Args: + min_timeout (int, optional): seconds to wait until an event is raised when trying to fetch. Defaults `1` + triggers_event (boolean, optional): True if the event should be raised. False otherwise. Defaults `True` + extra_timeout (int, optional): Additional time to wait after the min_timeout + error_message(str, optional): Message that will be printed by the FileMonitor in case of error. + """ + timeout_per_registry_estimation = 0.01 + try: + result = self.log_monitor.start(timeout=max((len(self.registry_dict)) * timeout_per_registry_estimation, + min_timeout), callback=self.callback, accum_results=len(self.registry_dict), + timeout_extra=extra_timeout, encoding=self.encoding, + error_message=error_message).result() + + assert triggers_event, 'No events should be detected.' + return result if isinstance(result, list) else [result] + except TimeoutError: + if triggers_event: + raise + logger.info("TimeoutError was expected and correctly caught.") + + def check_events(self, event_type, mode=None): + """Check and validate all events in the 'events' list. + + Args: + event_type (str): Expected type of the raised event {'added', 'modified', 'deleted'}. + mode (str): expected mode of the raised event. + """ + + def validate_checkers_per_event(events, options, mode): + """Check if each event is properly formatted according to some checks. + + Args: + events (list): event list to be checked. + options (set): set of XML CHECK_* options. Default `{CHECK_ALL}` + mode (str): represents the FIM mode expected for the event to validate. + """ + for ev in events: + if self.is_value: + validate_registry_event(ev, options, mode, is_key=False) + else: + validate_registry_event(ev, options, mode , is_key=False) + + def check_events_type(events, ev_type, reg_list=['testkey0']): + """Checks the event type of each events in a list. + + Args: + events (list): event list to be checked. + ev_type (str): type of expected event. + reg_list (list): list of keys that are being checked. + """ + event_types = Counter(filter_events(events, ".[].data.type")) + + assert (event_types[ev_type] == len(reg_list)), f'Non expected number of \ + events. {event_types[ev_type]} != {len(reg_list)}' + + def check_events_key_path(events, registry_key, reg_list=['testkey0'], mode=None): + """Checks the path for a registry_key event in a list. + + Args: + events (list): event list to be checked. + registry_key (str): path to the key being checked. + reg_list (list, optional): list of keys that are being checked. + mode(str, optional): defines the type of FIM monitoring mode configured + """ + mode = global_parameters.current_configuration['metadata']['fim_mode'] if mode is None else mode + key_path = filter_events(events, ".[].data.path") + + for reg in reg_list: + expected_path = os.path.join(registry_key, reg) + + if self.encoding is not None: + for index, item in enumerate(key_path): + key_path[index] = item.encode(encoding=self.encoding) + + error_msg = f"Expected key path was '{expected_path}' but event key path is '{key_path}'" + assert (expected_path in key_path), error_msg + + def check_events_registry_value(events, key, value_list=['testvalue0'], mode=None): + """Checks the path for a registry_value event in a list. + + Args: + events (list): event list to be checked. + key (str): path to the key being checked where the value has been added. + value_list (list, optional): list of values that are being checked. + mode(str, optional): defines the type of FIM monitoring mode configured + """ + mode = global_parameters.current_configuration['metadata']['fim_mode'] if mode is None else mode + key_path = filter_events(events, ".[].data.path") + value_name = filter_events(events, ".[].data.value_name") + + for value in value_list: + error_msg = f"Expected value name was '{value}' but event value name is '{value_name}'" + assert (value in value_name), error_msg + + error_msg = f"Expected key path was '{key}' but event key path is '{key_path}'" + assert (key in key_path), error_msg + + def filter_events(events, mask): + """Returns a list of elements matching a specified mask in the events list using jq module. + + Args: + events (list): event list to be checked. + mask(str): mask to be used to check events using jq module + """ + if sys.platform in ("win32", 'sunos5', 'darwin'): + stdout = subprocess.check_output(["jq", "-r", mask], input=json.dumps(events).encode()) + + return stdout.decode("utf8").strip().split(os.linesep) + else: + return jq(mask).transform(events, multiple_output=True) + + if self.events is not None: + validate_checkers_per_event(self.events, self.options, mode) + + if self.is_value: + check_events_type(self.events, event_type, self.registry_dict) + check_events_registry_value(self.events, self.registry_key, value_list=self.registry_dict, + mode=mode) + else: + check_events_type(self.events, event_type, self.registry_dict) + check_events_key_path(self.events, self.registry_key, reg_list=self.registry_dict, mode=mode) + + if self.custom_validator is not None: + self.custom_validator.validate_after_cud(self.events) + + if event_type == "added": + self.custom_validator.validate_after_create(self.events) + elif event_type == "modified": + self.custom_validator.validate_after_update(self.events) + elif event_type == "deleted": + self.custom_validator.validate_after_delete(self.events) + + def _get_elem_list(self): + """returns the elements in the registry_dict variable as a list""" + result_list = [] + + for elem_name in self.registry_dict: + if elem_name in self.registry_key: + continue + + expected_elem_path = os.path.join(self.registry_key, elem_name) + result_list.append(expected_elem_path) + + return result_list diff --git a/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py b/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py index eb2a0dfca7..f373b9f881 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py +++ b/deps/wazuh_testing/wazuh_testing/modules/fim/event_monitor.py @@ -5,13 +5,110 @@ import re import json +from sys import platform from datetime import datetime -from wazuh_testing import logger, T_30, T_60, LOG_FILE_PATH -from wazuh_testing.tools.monitoring import generate_monitoring_callback, FileMonitor -from wazuh_testing.modules import fim - -# Callback Messages +from wazuh_testing import LOG_FILE_PATH, logger, T_60 +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback + + +# Variables +file_monitor = FileMonitor(LOG_FILE_PATH) + + +# Callbacks messages +CB_DETECT_FIM_EVENT = r".*Sending FIM event: (.+)$" +CB_FOLDERS_MONITORED_REALTIME = r'.*Folders monitored with real-time engine: (\d+)' +CB_INVALID_CONFIG_VALUE = r".*Invalid value for element '(.*)': (.*)." +CB_INTEGRITY_CONTROL_MESSAGE = r".*Sending integrity control message: (.+)$" +CB_MAXIMUM_FILE_SIZE = r'.*Maximum file size limit to generate diff information configured to \'(\d+) KB\'.*' +CB_AGENT_CONNECT = r'.* Connected to the server .*' +CB_INODE_ENTRIES_PATH_COUNT = r".*Fim inode entries: '(\d+)', path count: '(\d+)'" +CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE = r".*registry_value.*Couldn't insert ('.*') entry into DB. The DB is full.*" +CB_DATABASE_FULL_COULD_NOT_INSERT_KEY = r".*registry_key.*Couldn't insert ('.*') entry into DB. The DB is full.*" +CB_COUNT_REGISTRY_ENTRIES = r".*Fim registry entries count: '(\d+)'" +CB_COUNT_REGISTRY_VALUE_ENTRIES = r".*Fim registry values entries count: '(\d+)'" +CB_REGISTRY_DBSYNC_NO_DATA = r".*fim_registry_(.*) dbsync no_data (.*)'" +CB_REGISTRY_LIMIT_CAPACITY = r".*Registry database is (\d+)% full." +CB_REGISTRY_DB_BACK_TO_NORMAL = r".*(The registry database status returns to normal)." +CB_REGISTRY_LIMIT_VALUE = r".*Maximum number of registry values to be monitored: '(\d+)'" +CB_FILE_LIMIT_CAPACITY = r".*File database is (\d+)% full." +CB_FILE_LIMIT_BACK_TO_NORMAL = r".*(Sending DB back to normal alert)." +CB_FIM_ENTRIES_COUNT = r".*Fim file entries count: '(\d+)'" +CB_FILE_LIMIT_VALUE = r".*Maximum number of files to be monitored: '(\d+)'" +CB_FILE_LIMIT_DISABLED = r".*(No limit set) to maximum number of file entries to be monitored" +CB_PATH_MONITORED_REALTIME = r".*Directory added for real time monitoring: (.*)" +CB_PATH_MONITORED_WHODATA = r".*Added audit rule for monitoring directory: (.*)" +CB_PATH_MONITORED_WHODATA_WINDOWS = r".*Setting up SACL for (.*)" +CB_SYNC_SKIPPED = r".*Sync still in progress. Skipped next sync and increased interval.*'(\d+)s'" +CB_SYNC_INTERVAL_RESET = r".*Previous sync was successful. Sync interval is reset to: '(\d+)s'" +CB_IGNORING_DUE_TO_SREGEX = r".*?Ignoring path '(.*)' due to sregex '(.*)'.*" +CB_IGNORING_DUE_TO_PATTERN = r".*?Ignoring path '(.*)' due to pattern '(.*)'.*" +CB_MAXIMUM_FILE_SIZE = r'.*Maximum file size limit to generate diff information configured to \'(\d+) KB\'.*' +CB_AGENT_CONNECT = r'.* Connected to the server .*' +CB_REALTIME_WHODATA_ENGINE_STARTED = r'.*File integrity monitoring (real-time Whodata) engine started.*' +CB_DISK_QUOTA_LIMIT_CONFIGURED_VALUE = r'.*Maximum disk quota size limit configured to \'(\d+) KB\'.*' +CB_FILE_EXCEEDS_DISK_QUOTA = r'.*The (.*) of the file size \'(.*)\' exceeds the disk_quota.*' +CB_FILE_SIZE_LIMIT_REACHED = r'.*File \'(.*)\' is too big for configured maximum size to perform diff operation\.' +CB_DIFF_FOLDER_DELETED = r'.*Folder \'(.*)\' has been deleted.*' CB_FIM_PATH_CONVERTED = r".*fim_adjust_path.*Convert '(.*) to '(.*)' to process the FIM events." +CB_STARTING_WINDOWS_AUDIT = r'.*state_checker.*(Starting check of Windows Audit Policies and SACLs)' +CB_SWITCHING_DIRECTORIES_TO_REALTIME = r'.*state_checker.*(Audit policy change detected.\ + Switching directories to realtime)' +CB_RECIEVED_EVENT_4719 = r'.*win_whodata.*(Event 4719).*Switching directories to realtime' + +# Error message +ERR_MSG_REALTIME_FOLDERS_EVENT = 'Did not receive expected "Folders monitored with real-time engine" event' +ERR_MSG_WHODATA_ENGINE_EVENT = 'Did not receive expected "real-time Whodata engine started" event' +ERR_MSG_INVALID_CONFIG_VALUE = 'Did not receive expected "Invalid value for element" event' +ERR_MSG_AGENT_DISCONNECT = 'Agent couldn\'t connect to server.' +ERR_MSG_INTEGRITY_CONTROL_MSG = 'Didn\'t receive control message(integrity_check_global)' +ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT = 'Did not receive expected "DEBUG: ...: database is ...% full" alert' +ERR_MSG_WRONG_CAPACITY_LOG_DB_LIMIT = 'Wrong capacity log for DB file_limit' +ERR_MSG_DB_BACK_TO_NORMAL = 'Did not receive expected "DEBUG: ... database status returns to normal." event' +ERR_MSG_DATABASE_FULL_ALERT = 'Did not receive expected "DEBUG: ...: Registry database is 100% full" alert' +ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL = 'Wrong value for full database alert.' +ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT = 'Did not receive expected "DEBUG: ...: Couldn\'t insert \'...\' entry \ + into DB. The DB is full, ..." event' +ERR_MSG_DATABASE_FULL_ALERT_EVENT = 'Did not receive expected "DEBUG: ...: Sending DB 100% full alert." event' +ERR_MSG_WRONG_NUMBER_OF_ENTRIES = 'Wrong number of entries counted.' +ERR_MSG_WRONG_INODE_PATH_COUNT = 'Wrong number of inodes and path count' +ERR_MSG_FIM_INODE_ENTRIES = 'Did not receive expected "Fim inode entries: ..., path count: ..." event' +ERR_MSG_FIM_REGISTRY_ENTRIES = 'Did not receive expected "Fim Registry entries count: ..." event' +ERR_MSG_FIM_REGISTRY_VALUE_ENTRIES = 'Did not receive expected "Fim Registry value entries count: ..." event' +ERR_MSG_REGISTRY_LIMIT_VALUES = 'Did not receive expected "DEBUG: ...: Maximum number of registry values to \ + be monitored: ..." event' +ERR_MSG_WRONG_REGISTRY_LIMIT_VALUE = 'Wrong value for db_value_limit registries tag.' +ERR_MSG_FILE_LIMIT_VALUES = 'Did not receive expected "DEBUG: ...: Maximum number of entries to be monitored: \ + ..." event' +ERR_MSG_WRONG_FILE_LIMIT_VALUE = 'Wrong value for file_limit.' +ERR_MSG_FILE_LIMIT_DISABLED = 'Did not receive expected "DEBUG: ...: No limit set to maximum number of entries \ + to be monitored" event' +ERR_MSG_MAXIMUM_FILE_SIZE = 'Did not receive expected "Maximum file size limit configured to \'... KB\'..." event' +ERR_MSG_NO_EVENTS_EXPECTED = 'No events should be detected.' +ERR_MSG_DELETED_EVENT_NOT_RECIEVED = 'Did not receive expected deleted event' +ERR_MSG_FIM_EVENT_NOT_RECIEVED = 'Did not receive expected "Sending FIM event: ..." event' +ERR_MSG_MONITORING_PATH = 'Did not get the expected monitoring path line' +ERR_MSG_MULTIPLE_FILES_CREATION = 'Multiple files could not be created.' +ERR_MSG_SCHEDULED_SCAN_ENDED = 'Did not recieve the expected "DEBUG: ... Sending FIM event: {type:scan_end"...} event' +ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE = 'Wrong value for diff_size_limit' +ERR_MSG_INTEGRITY_OR_WHODATA_NOT_STARTED = 'Did not receive expected "File integrity monitoring real-time Whodata \ + engine started" or "Initializing FIM Integrity Synchronization check"' +ERR_MSG_INTEGRITY_CHECK_EVENT = 'Did not receive expected "Initializing FIM Integrity Synchronization check" event' +ERR_MSG_SYNC_SKIPPED_EVENT = 'Did not recieve the expected "Sync still in progress. Skipped next sync" event' +ERR_MSG_FIM_SYNC_NOT_DETECTED = 'Did not receive expected "Initializing FIM Integrity Synchronization check" event' +ERR_MSG_SYNC_INTERVAL_RESET_EVENT = 'Did not recieve the expected "Sync interval is reset" event' +ERR_MSG_CONTENT_CHANGES_EMPTY = "content_changes is empty" +ERR_MSG_CONTENT_CHANGES_NOT_EMPTY = "content_changes isn't empty" +ERR_MSG_FOLDERS_MONITORED_REALTIME = 'Did not receive expected "Folders monitored with real-time engine..." event' +ERR_MSG_WHODATA_ENGINE_EVENT = 'Did not receive "File integrity monitoring real-time Whodata engine started" event' +ERR_MSG_FIM_EVENT_NOT_DETECTED = 'Did not receive expected "Sending FIM event: ..." event.' +ERR_MSG_SCHEDULED_SCAN_STARTED = 'Did not receive expected "File integrity monitoring scan started" event' +ERR_MSG_SCHEDULED_SCAN_ENDED = 'Did not receive expected "File integrity monitoring scan ended" event' +ERR_MSG_DISK_QUOTA_LIMIT = 'Did not receive "Maximum disk quota size limit configured to \'... KB\'." event' +ERR_MSG_FILE_LIMIT_REACHED = 'Did not receive "File ... is too big ... to perform diff operation" event.' +ERR_MSG_FOLDER_DELETED = 'Did not receive expected "Folder ... has been deleted." event.' +ERR_MSG_SACL_CONFIGURED_EVENT = 'Did not receive the expected "The SACL of will be configured" event' +ERR_MSG_WHODATA_REALTIME_MODE_CHANGE_EVENT = 'Expected "directory starts to monitored in real-time" event not received' # Callback functions @@ -19,7 +116,7 @@ def callback_detect_event(line): """ Detect an 'event' type FIM log. """ - msg = fim.CB_DETECT_FIM_EVENT + msg = CB_DETECT_FIM_EVENT match = re.match(msg, line) if not match: return None @@ -37,11 +134,9 @@ def callback_detect_end_scan(line): Args: line (String): string line to be checked by callback in FileMonitor. """ - msg = fim.CB_DETECT_FIM_EVENT - match = re.match(msg, line) + match = re.match(CB_DETECT_FIM_EVENT, line) if not match: return None - try: if json.loads(match.group(1))['type'] == 'scan_end': return True @@ -54,7 +149,7 @@ def callback_detect_scan_start(line): Args: line (String): string line to be checked by callback in FileMonitor. """ - msg = fim.CB_DETECT_FIM_EVENT + msg = CB_DETECT_FIM_EVENT match = re.match(msg, line) if not match: return None @@ -66,35 +161,143 @@ def callback_detect_scan_start(line): logger.warning(f"Couldn't load a log line into json object. Reason {e}") +def callback_detect_synchronization(line): + if 'Executing FIM sync' in line: + return line + return None + + def callback_connection_message(line): - match = re.match(fim.CB_AGENT_CONNECT, line) + match = re.match(CB_AGENT_CONNECT, line) if match: return True def callback_detect_integrity_control_event(line): - match = re.match(fim.CB_INTEGRITY_CONTROL_MESSAGE, line) + match = re.match(CB_INTEGRITY_CONTROL_MESSAGE, line) if match: return json.loads(match.group(1)) return None def callback_integrity_message(line): - if callback_detect_integrity_control_event(line): + if callback_detect_event(line): match = re.match(r"(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*({.*?})$", line) if match: return datetime.strptime(match.group(1), '%Y/%m/%d %H:%M:%S'), json.dumps(match.group(2)) +def callback_detect_file_integrity_event(line): + """ Callback that detects if a line contains a file integrity event + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + event = callback_detect_integrity_control_event(line) + if event and event['component'] == 'fim_file': + return event + return None + + +def callback_value_event(line): + event = callback_detect_event(line) + + if event is None or event['data']['attributes']['type'] != 'registry_value': + return None + + return event + + +def callback_detect_registry_integrity_event(line): + """ Callback that detects if a line contains a registry integrity event for a registry_key or registry_value + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + event = callback_detect_integrity_control_event(line) + if event and event['component'] == 'fim_registry_key': + return event + if event and event['component'] == 'fim_registry_value': + return event + return None + + +def callback_detect_registry_integrity_state_event(line): + """ Callback that detects if a line contains a registry integrity event of the state type + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + event = callback_detect_registry_integrity_event(line) + if event and event['type'] == 'state': + return event['data'] + return None + + +def callback_entries_path_count(line): + if platform != 'win32': + match = re.match(CB_INODE_ENTRIES_PATH_COUNT, line) + else: + match = re.match(CB_FIM_ENTRIES_COUNT, line) + + if match: + if platform != 'win32': + return match.group(1), match.group(2) + else: + return match.group(1), None + + +def callback_num_inotify_watches(line): + """ Callback that detects if a line contains the folders monitored in realtime event + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + match = re.match(CB_FOLDERS_MONITORED_REALTIME, line) + + if match: + return match.group(1) + + +def callback_sync_start_time(line): + if callback_detect_synchronization(line): + match = re.match(r"(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*", line) + if match: + return datetime.strptime(match.group(1), '%Y/%m/%d %H:%M:%S') + + +def callback_state_event_time(line): + if callback_detect_integrity_control_event(line): + match = re.match(r"(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*", line) + if match: + return datetime.strptime(match.group(1), '%Y/%m/%d %H:%M:%S') + + +def callback_real_time_whodata_started(line): + """ Callback that detects if a line contains "Whodata engine started" event + Args: + line (String): string line to be checked by callback in File_Monitor. + """ + if CB_REALTIME_WHODATA_ENGINE_STARTED in line: + return True + + def callback_detect_registry_integrity_clear_event(line): + """ Callback that detects if a line contains a registry integrity_clear event + + Args: + line (String): string line to be checked by callback in File_Monitor. + """ event = callback_detect_integrity_control_event(line) - if event and event['component'] == 'fim_registry' and event['type'] == 'integrity_clear': + if event and event['component'] == 'fim_registry_key' and event['type'] == 'integrity_clear': + return True + if event and event['component'] == 'fim_registry_value' and event['type'] == 'integrity_clear': return True return None def callback_disk_quota_limit_reached(line): - match = re.match(fim.CB_FILE_EXCEEDS_DISK_QUOTA, line) + match = re.match(CB_FILE_EXCEEDS_DISK_QUOTA, line) if match: return match.group(2) @@ -154,6 +357,21 @@ def callback_detect_file_deleted_event(line): return None +def callback_restricted(line): + """ Callback that detects if a line in a log if a file is ignored due to configured restrict tag. + + Args: + line (String): string line to be checked by callback in FileMonitor. + + Returns: + returns the entry that is being ignored. + """ + match = re.match(r".*Ignoring entry '(.*?)' due to restriction '.*?'", line) + if match: + return match.group(1) + return None + + # Event checkers def check_fim_event(file_monitor=None, callback='', error_message=None, update_position=True, timeout=T_60, accum_results=1, file_to_monitor=LOG_FILE_PATH): @@ -182,7 +400,7 @@ def detect_initial_scan(file_monitor): file_monitor (FileMonitor): file log monitor to detect events """ file_monitor.start(timeout=T_60, callback=callback_detect_end_scan, - error_message=fim.ERR_MSG_SCHEDULED_SCAN_ENDED) + error_message=ERR_MSG_SCHEDULED_SCAN_ENDED) def detect_initial_scan_start(file_monitor): @@ -192,7 +410,7 @@ def detect_initial_scan_start(file_monitor): file_monitor (FileMonitor): file log monitor to detect events """ file_monitor.start(timeout=T_60, callback=callback_detect_scan_start, - error_message=fim.ERR_MSG_SCHEDULED_SCAN_STARTED) + error_message=ERR_MSG_SCHEDULED_SCAN_STARTED) def detect_realtime_start(file_monitor): @@ -201,8 +419,8 @@ def detect_realtime_start(file_monitor): Args: file_monitor (FileMonitor): file log monitor to detect events """ - file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(fim.CB_FOLDERS_MONITORED_REALTIME), - error_message=fim.ERR_MSG_FOLDERS_MONITORED_REALTIME) + file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(CB_FOLDERS_MONITORED_REALTIME), + error_message=ERR_MSG_FOLDERS_MONITORED_REALTIME) def detect_whodata_start(file_monitor): @@ -211,8 +429,8 @@ def detect_whodata_start(file_monitor): Args: file_monitor (FileMonitor): file log monitor to detect events """ - file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(fim.CB_REALTIME_WHODATA_ENGINE_STARTED), - error_message=fim.ERR_MSG_WHODATA_ENGINE_EVENT) + file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(CB_REALTIME_WHODATA_ENGINE_STARTED), + error_message=ERR_MSG_WHODATA_ENGINE_EVENT) def detect_windows_sacl_configured(file_monitor, file='.*'): @@ -224,9 +442,8 @@ def detect_windows_sacl_configured(file_monitor, file='.*'): """ pattern = fr".*win_whodata.*The SACL of '({file})' will be configured" - file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(pattern), - error_message=fim.ERR_MSG_SACL_CONFIGURED_EVENT) + error_message=ERR_MSG_SACL_CONFIGURED_EVENT) def detect_windows_whodata_mode_change(file_monitor, file='.*'): @@ -240,4 +457,4 @@ def detect_windows_whodata_mode_change(file_monitor, file='.*'): pattern = fr".*set_whodata_mode_changes.*The '({file})' directory starts to be monitored in real-time mode." file_monitor.start(timeout=T_60, callback=generate_monitoring_callback(pattern), - error_message=fim.ERR_MSG_WHDATA_REALTIME_MODE_CHANGE_EVENT) + error_message=ERR_MSG_WHODATA_REALTIME_MODE_CHANGE_EVENT) diff --git a/deps/wazuh_testing/wazuh_testing/modules/fim/utils.py b/deps/wazuh_testing/wazuh_testing/modules/fim/utils.py index a5be76fccd..47b9a5e34d 100644 --- a/deps/wazuh_testing/wazuh_testing/modules/fim/utils.py +++ b/deps/wazuh_testing/wazuh_testing/modules/fim/utils.py @@ -4,13 +4,16 @@ import os import sys - +import time +import platform from datetime import datetime, timedelta from typing import Sequence, Union, Generator, Any from copy import deepcopy -from wazuh_testing import global_parameters, logger, REGULAR -from wazuh_testing.tools.file import create_file, modify_file, delete_file -from wazuh_testing.tools.monitoring import FileMonitor +from hashlib import sha1 + +from wazuh_testing import global_parameters, logger, REGULAR, LOG_FILE_PATH, WAZUH_PATH +from wazuh_testing.tools.file import create_file, modify_file, delete_file, generate_string +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback from wazuh_testing.tools.time import TimeMachine from wazuh_testing.modules import fim from wazuh_testing.modules.fim import event_monitor as ev @@ -25,10 +28,65 @@ # Variables _os_excluded_from_rt_wd = ['darwin', 'sunos5'] -_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') # Functions +def get_sync_msgs(timeout, new_data=True): + """Look for as many synchronization events as possible. + + This function will look for the synchronization messages until a Timeout is raised or 'max_events' is reached. + + Args: + timeout (int): Timeout that will be used to get the dbsync_no_data message. + new_data (bool): Specifies if the test will wait the event `dbsync_no_data`. + + Returns: + A list with all the events in json format. + """ + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + events = [] + if new_data: + wazuh_log_monitor.start(timeout=timeout, + callback=generate_monitoring_callback(ev.CB_REGISTRY_DBSYNC_NO_DATA), + error_message='Did not receive expected ' + '"db sync no data" event') + for _ in range(0, fim.MAX_EVENTS_VALUE): + try: + sync_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=ev.callback_detect_registry_integrity_state_event, + accum_results=1, + error_message='Did not receive expected ' + 'Sending integrity control message"').result() + except TimeoutError: + break + events.append(sync_event) + return events + + +def find_value_in_event_list(key_path, value_name, event_list): + """Function that looks for a key path and value_name in a list of json events. + + Args: + path (str): Path of the registry key. + value_name (str): Name of the value. + event_list (list): List containing the events in JSON format. + + Returns: + The event that matches the specified path. None if no event was found. + """ + for event in event_list: + if 'value_name' not in event.keys(): + continue + if str(event['path']) == key_path and event['value_name'] == value_name: + return event + return None + + +def create_values_content(value_name, size): + """ Create a string of data content of a given size for a specific key value""" + return {value_name: generate_string(size, '0')} + + def create_registry(key, subkey, arch): """Create a registry given the key and the subkey. The registry is opened if it already exists. @@ -54,6 +112,130 @@ def create_registry(key, subkey, arch): logger.warning(f"Registry could not be created: {e}") +def modify_key_perms(key, subkey, arch, user): + """ + Modify the permissions (ACL) of a registry key. + + Args: + key (pyHKEY): the key of the registry (HKEY_* constants). + subkey (str): the subkey (name) of the registry. + arch (str): architecture of the system. + user (PySID): user that is going to be used for the modification. + """ + if sys.platform == 'win32': + print_arch = '[x64]' if arch == fim.KEY_WOW64_64KEY else '[x32]' + logger.info(f"- Changing permissions of {print_arch}{os.path.join(fim.registry_class_name[key], subkey)}") + + try: + key_h = fim.RegOpenKeyEx(key, subkey, 0, fim.KEY_ALL_ACCESS | arch) + sd = win32api.RegGetKeySecurity(key_h, win32con.DACL_SECURITY_INFORMATION) + acl = sd.GetSecurityDescriptorDacl() + acl.AddAccessAllowedAce(ntc.GENERIC_ALL, user) + sd.SetDacl(True, acl, False) + + win32api.RegSetKeySecurity(key_h, win32con.DACL_SECURITY_INFORMATION, sd) + except OSError as e: + logger.warning(f"Registry permissions could not be modified: {e}") + except pywintypes.error as e: + logger.warning(f"Registry permissions could not be modified: {e}") + + +def modify_registry_key_mtime(key, subkey, arch): + """Modify the modification time of a registry key. + + Args: + key (pyHKEY): the key handle of the registry. + subkey (str): the subkey (name) of the registry. + arch (str): architecture of the system. + """ + + if sys.platform == 'win32': + print_arch = '[x64]' if arch == fim.KEY_WOW64_64KEY else '[x32]' + logger.info(f"- Changing mtime of {print_arch}{os.path.join(fim.registry_class_name[key], subkey)}") + + try: + key_h = fim.RegOpenKeyEx(key, subkey, 0, fim.KEY_ALL_ACCESS | arch) + + modify_registry_value(key_h, "dummy_value", fim.REG_SZ, "this is a dummy value") + time.sleep(2) + delete_registry_value(key_h, "dummy_value") + + fim.RegCloseKey(key_h) + key_h = fim.RegOpenKeyEx(key, subkey, 0, fim.KEY_ALL_ACCESS) + except OSError as e: + logger.warning(f"Registry mtime could not be modified: {e}") + except pywintypes.error as e: + logger.warning(f"Registry mtime could not be modified: {e}") + + +def modify_registry_owner(key, subkey, arch, user): + """Modify the owner of a registry key. + + Arch: + key (pyHKEY): the key handle of the registry. + subkey (str): the subkey (name) of the registry. + arch (str): architecture of the system. + user (pySID): identifier of the user (pySID) + + Returns: + str: key of the registry. + """ + if sys.platform == 'win32': + print_arch = '[x64]' if arch == fim.KEY_WOW64_64KEY else '[x32]' + logger.info(f"- Changing owner of {print_arch}{os.path.join(fim.registry_class_name[key], subkey)}") + + try: + key_h = fim.RegOpenKeyEx(key, subkey, 0, fim.KEY_ALL_ACCESS | arch) + desc = win32api.RegGetKeySecurity(key_h, + win32sec.DACL_SECURITY_INFORMATION | win32sec.OWNER_SECURITY_INFORMATION) + desc.SetSecurityDescriptorOwner(user, 0) + + win32api.RegSetKeySecurity(key_h, win32sec.OWNER_SECURITY_INFORMATION | win32sec.DACL_SECURITY_INFORMATION, + desc) + + return key_h + except OSError as e: + logger.warning(f"Registry owner could not be modified: {e}") + except pywintypes.error as e: + logger.warning(f"Registry owner could not be modified: {e}") + + +def modify_registry(key, subkey, arch): + """Modify a registry key. + + Args: + key (pyHKEY): the key handle of the registry. + subkey (str): the subkey (name) of the registry. + arch (str): architecture of the system. + """ + print_arch = '[x64]' if arch == fim.KEY_WOW64_64KEY else '[x32]' + logger.info(f"Modifying registry key {print_arch}{os.path.join(fim.registry_class_name[key], subkey)}") + + modify_key_perms(key, subkey, arch, win32sec.LookupAccountName(None, f"{platform.node()}\\{os.getlogin()}")[0]) + modify_registry_owner(key, subkey, arch, win32sec.LookupAccountName(None, f"{platform.node()}\\{os.getlogin()}")[0]) + modify_registry_key_mtime(key, subkey, arch) + + +def modify_registry_value(key_h, value_name, type, value): + """ + Modify the content of a registry. If the value doesn't not exists, it will be created. + + Args: + key_h (pyHKEY): the key handle of the registry. + value_name (str): the value to be set. + type (int): type of the value. + value (str): the content that will be written to the registry value. + """ + if sys.platform == 'win32': + try: + logger.info(f"Modifying value '{value_name}' of type {fim.registry_value_type[type]} and value '{value}'") + win32api.RegSetValueEx(key_h, value_name, 0, type, value) + except OSError as e: + logger.warning(f"Could not modify registry value content: {e}") + except pywintypes.error as e: + logger.warning(f"Could not modify registry value content: {e}") + + def delete_registry(key, subkey, arch): """Delete a registry key. @@ -76,6 +258,263 @@ def delete_registry(key, subkey, arch): logger.warning(f"Couldn't remove key {str(os.path.join(fim.registry_class_name[key], subkey))}: {e}") +def delete_registry_value(key_h, value_name): + """Delete a registry value from a registry key. + + Args: + key_h (pyHKEY): the key handle of the registry. + value_name (str): the value to be deleted. + """ + if sys.platform == 'win32': + logger.info(f"Removing registry value {value_name}.") + + try: + win32api.RegDeleteValue(key_h, value_name) + except OSError as e: + logger.warning(f"Couldn't remove registry value {value_name}: {e}") + except pywintypes.error as e: + logger.warning(f"Couldn't remove registry value {value_name}: {e}") + + +def calculate_registry_diff_paths(reg_key, reg_subkey, arch, value_name): + """Calculate the diff folder path of a value. + + Args: + reg_key (str): registry name (HKEY_* constants). + reg_subkey (str): path of the subkey. + arch (int): architecture of the registry. + value_name (str): name of the value. + + Returns: + tuple: diff folder path of the key and the path of the value. + """ + key_path = os.path.join(reg_key, reg_subkey) + folder_path = "{} {}".format("[x32]" if arch == fim.KEY_WOW64_32KEY else "[x64]", + sha1(key_path.encode()).hexdigest()) + diff_file = os.path.join(WAZUH_PATH, 'queue', 'diff', 'registry', folder_path, + sha1(value_name.encode()).hexdigest(), 'last-entry.gz') + return (folder_path, diff_file) + + +def transform_registry_list(value_list=['test_value'], value_type=fim.REG_SZ, callback=ev.callback_value_event): + if sys.platform == 'win32': + if value_type in [win32con.REG_SZ, win32con.REG_MULTI_SZ]: + value_default_content = '' + else: + value_default_content = 1 + + aux_dict = {} + if isinstance(value_list, list): + for elem in value_list: + aux_dict[elem] = (value_default_content, callback) + + elif isinstance(value_list, dict): + for key, elem in value_list.items(): + aux_dict[key] = (elem, callback) + + else: + raise ValueError('It can only be a list or dictionary') + + return aux_dict + + +def set_check_options(options): + """ Return set of check options. If options given is none, it will return check_all""" + options_set = fim.REQUIRED_REG_VALUE_ATTRIBUTES[fim.CHECK_ALL] + if options is not None: + options_set = options_set.intersection(options) + return options_set + + +def registry_value_create(root_key, registry_sub_key, log_monitor, arch=fim.KEY_WOW64_64KEY, value_list=['test_value'], + min_timeout=1, options=None, wait_for_scan=False, scan_delay=10, triggers_event=True, + encoding=None, callback=ev.callback_value_event, validators_after_create=None, + value_type=fim.REG_SZ): + """Check if creation of registry value events are detected by syscheck. + + This function provides multiple tools to validate events with custom validators. + + Args: + root_key (str): root key (HKEY_LOCAL_MACHINE, HKEY_LOCAL_USER, etc). + registry_sub_key (str): path of the subkey that will be created. + log_monitor (FileMonitor): file event monitor. + arch (int): Architecture of the registry key (KEY_WOW64_32KEY or KEY_WOW64_64KEY). Default `KEY_WOW64_64KEY` + value_list (list(str) or dict, optional): If it is a list, it will be transformed to a dict with empty + strings in each value. Default `['test_value']` + min_timeout (int, optional): Minimum timeout. Default `1` + options (set, optional): Set with all the checkers. Default `None` + wait_for_scan (boolean, optional): Boolean to determine if there will be time travels or not. + Default `False` + scan_delay (int, optional): time the test sleeps waiting for scan to be triggered. + triggers_event (boolean, optional): Boolean to determine if the + event should be raised or not. Default `True` + encoding (str, optional): String to determine the encoding of the registry value name. Default `None` + callback (callable, optional): Callback to use with the log monitor. Default `callback_value_event` + validators_after_create (list, optional): List of functions that validates an event triggered when a new + registry value is created. Each function must accept a param to receive the event + to be validated. Default `None` + """ + if sys.platform == 'win32': + # Transform registry list + if root_key not in fim.registry_parser: + raise ValueError("root_key not valid") + + registry_path = os.path.join(root_key, registry_sub_key) + + value_list = transform_registry_list(value_list) + if value_type in [fim.REG_SZ, fim.REG_MULTI_SZ]: + value_added_content = 'added' + else: + value_added_content = 0 + + options_set = set_check_options(options) + + custom_validator = CustomValidator(validators_after_create, None, None, None) + + registry_event_checker = RegistryEventChecker(log_monitor=log_monitor, registry_key=registry_path, + registry_dict=value_list, options=options_set, + custom_validator=custom_validator, encoding=encoding, + callback=callback, is_value=True) + + # Open the desired key + key_handle = create_registry(fim.registry_parser[root_key], registry_sub_key, arch) + + # Create registry values + for name, _ in value_list.items(): + if name in registry_path: + continue + modify_registry_value(key_handle, name, value_type, value_added_content) + + wait_for_scheduled_scan(wait_for_scan=wait_for_scan, interval=scan_delay, monitor=log_monitor) + + registry_event_checker.fetch_and_check('added', min_timeout=min_timeout, triggers_event=triggers_event) + + if triggers_event: + logger.info("'added' {} detected as expected.\n".format("events" if len(value_list) > 1 else "event")) + + +def registry_value_update(root_key, registry_sub_key, log_monitor, arch=fim.KEY_WOW64_64KEY, value_list=['test_value'], + wait_for_scan=False, scan_delay=10, min_timeout=1, options=None, triggers_event=True, + encoding=None, callback=ev.callback_value_event, validators_after_update=None, + value_type=fim.REG_SZ): + """Check if update registry value events are detected by syscheck. + + This function provides multiple tools to validate events with custom validators. + + Args: + root_key (str): root key (HKEY_LOCAL_MACHINE, HKEY_LOCAL_USER, etc). + registry_sub_key (str): path of the subkey that will be created. + log_monitor (FileMonitor): file event monitor. + arch (int): Architecture of the registry key (KEY_WOW64_32KEY or KEY_WOW64_64KEY). Default `KEY_WOW64_64KEY` + value_list (list(str) or dict, optional): If it is a list, it will be transformed to a dict with empty + strings in each value. Default `['test_value']` + wait_for_scan (boolean, optional): Boolean to determine if there will waits for scheduled scans. + Default `False` + scan_delay (int, optional): time the test sleeps waiting for scan to be triggered. + min_timeout (int, optional): Minimum timeout. Default `1` + options (set, optional): Set with all the checkers. Default `None` + triggers_event (boolean, optional): Boolean to determine if the + event should be raised or not. Default `True` + encoding (str, optional): String to determine the encoding of the registry value name. Default `None` + callback (callable, optional): Callback to use with the log monitor. Default `callback_value_event` + validators_after_update (list, optional): List of functions that validates an event triggered + when a new registry value is modified. Each function must accept a param to receive the event + to be validated. Default `None` + """ + if sys.platform == 'win32': + # Transform registry list + if root_key not in fim.registry_parser: + raise ValueError("root_key not valid") + + registry_path = os.path.join(root_key, registry_sub_key) + + value_list = transform_registry_list(value_list=value_list, value_type=value_type, callback=callback) + + options_set = set_check_options(options) + + custom_validator = CustomValidator(None, validators_after_update, None, None) + + registry_event_checker = RegistryEventChecker(log_monitor=log_monitor, registry_key=registry_path, + registry_dict=value_list, options=options_set, + custom_validator=custom_validator, encoding=encoding, + callback=callback, is_value=True) + + key_handle = create_registry(fim.registry_parser[root_key], registry_sub_key, arch) + + # Modify previous registry values + for name, content in value_list.items(): + if name in registry_path: + continue + + modify_registry_value(key_handle, name, value_type, content[0]) + + wait_for_scheduled_scan(wait_for_scan=wait_for_scan, interval=scan_delay, monitor=log_monitor) + registry_event_checker.fetch_and_check('modified', min_timeout=min_timeout, triggers_event=triggers_event) + + if triggers_event: + logger.info("'modified' {} detected as expected.\n".format("events" if len(value_list) > 1 else "event")) + + +def registry_value_delete(root_key, registry_sub_key, log_monitor, arch=fim.KEY_WOW64_64KEY, value_list=['test_value'], + wait_for_scan=False, scan_delay=10, min_timeout=1, options=None, triggers_event=True, + encoding=None, callback=ev.callback_value_event, validators_after_delete=None, + value_type=fim.REG_SZ): + """Check if delete registry value events are detected by syscheck. + + This function provides multiple tools to validate events with custom validators. + + Args: + root_key (str): root key (HKEY_LOCAL_MACHINE, HKEY_LOCAL_USER, etc). + registry_sub_key (str): path of the subkey that will be created. + log_monitor (FileMonitor): file event monitor. + arch (int): Architecture of the registry key (KEY_WOW64_32KEY or KEY_WOW64_64KEY). Default `KEY_WOW64_64KEY` + value_list (list(str) or dict, optional): If it is a list, it will be transformed to a dict with empty + strings in each value. Default `['test_value']` + wait_for_scan (boolean, optional): Boolean to determine if there will waits for scheduled scans. + Default `False` + scan_delay (int, optional): time the test sleeps waiting for scan to be triggered. + min_timeout (int, optional): Minimum timeout. Default `1` + options (set, optional): Set with all the checkers. Default `None` + triggers_event (boolean, optional): Boolean to determine if the event should be raised or not. Default `True` + encoding (str, optional): String to determine the encoding of the registry value name. Default `None` + callback (callable, optional): Callback to use with the log monitor. Default `callback_value_event` + validators_after_delete (list, optional): List of functions that validates an event triggered + when a new registry value is deleted. Each function must accept a param to receive the event + to be validated. Default `None` + """ + if sys.platform == 'win32': + # Transform registry list + if root_key not in fim.registry_parser: + raise ValueError("root_key not valid") + + registry_path = os.path.join(root_key, registry_sub_key) + + value_list = transform_registry_list(value_list=value_list, value_type=value_type, callback=callback) + + options_set = set_check_options(options) + + custom_validator = CustomValidator(None, None, validators_after_delete, None) + + registry_event_checker = RegistryEventChecker(log_monitor=log_monitor, registry_key=registry_path, + registry_dict=value_list, options=options_set, + custom_validator=custom_validator, encoding=encoding, + callback=callback, is_value=True) + + key_handle = create_registry(fim.registry_parser[root_key], registry_sub_key, arch) + + # Delete previous registry values + for name, _ in value_list.items(): + if name in registry_path: + continue + delete_registry_value(key_handle, name) + + wait_for_scheduled_scan(wait_for_scan=wait_for_scan, interval=scan_delay, monitor=log_monitor) + registry_event_checker.fetch_and_check('deleted', min_timeout=min_timeout, triggers_event=triggers_event) + + if triggers_event: + logger.info("'deleted' {} detected as expected.\n".format("events" if len(value_list) > 1 else "event")) + + # Old Configuration framework def generate_params(extra_params: dict = None, apply_to_all: Union[Sequence[Any], Generator[dict, None, None]] = None, modes: list = None): @@ -332,3 +771,37 @@ def check_time_travel(time_travel: bool, interval: timedelta = timedelta(hours=1 monitor.start(timeout=timeout, callback=ev.callback_detect_end_scan, update_position=False, error_message=f"End of scheduled scan not detected after {timeout} seconds") + + +def wait_for_scheduled_scan(wait_for_scan=False, interval: timedelta = timedelta(seconds=20), + monitor: FileMonitor = None, timeout=global_parameters.default_timeout): + """Checks if the conditions for waiting for a new scheduled scan. + + Optionally, a monitor may be used to check if a scheduled scan has been performed. + + This function is specially useful to deal with scheduled scans that are triggered on a time interval basis. + + Args: + wait_scan (boolean): True if we need to update time. False otherwise. + interval (timedelta, optional): time interval that will be waited for the scheduled scan to start. + Default: 20 seconds. + monitor (FileMonitor, optional): if passed, after changing system clock it will check for the end of the + scheduled scan. The `monitor` will not consume any log line. Default `None`. + timeout (int, optional): If a monitor is provided, this parameter sets how long to wait for the end of scan. + Raises + TimeoutError: if `monitor` is not `None` and the scan has not ended in the + default timeout specified in `global_parameters`. + """ + + if 'fim_mode' in global_parameters.current_configuration['metadata'].keys(): + mode = global_parameters.current_configuration['metadata']['fim_mode'] + if mode != 'scheduled' or mode not in global_parameters.fim_mode: + return + + if wait_for_scan: + logger.info(f"waiting for scheduled scan to start for {interval} seconds") + time.sleep(interval) + if monitor: + monitor.start(timeout=timeout, callback=ev.callback_detect_end_scan, + update_position=False, + error_message=f"End of scheduled scan not detected after {timeout} seconds") diff --git a/deps/wazuh_testing/wazuh_testing/tools/__init__.py b/deps/wazuh_testing/wazuh_testing/tools/__init__.py index 60fa272e99..1a0d4727be 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/__init__.py +++ b/deps/wazuh_testing/wazuh_testing/tools/__init__.py @@ -34,6 +34,7 @@ WAZUH_UNIX_USER = 'wazuh' WAZUH_UNIX_GROUP = 'wazuh' GLOBAL_DB_PATH = os.path.join(WAZUH_PATH, 'queue', 'db', 'global.db') + ARCHIVES_LOG_FILE_PATH = os.path.join(WAZUH_PATH, 'logs', 'archives', 'archives.log') ACTIVE_RESPONSE_BINARY_PATH = os.path.join(WAZUH_PATH, 'active-response', 'bin') else: WAZUH_SOURCES = os.path.join('/', 'wazuh') diff --git a/deps/wazuh_testing/wazuh_testing/tools/file.py b/deps/wazuh_testing/wazuh_testing/tools/file.py index 9c239ce40f..fd7b602c8f 100644 --- a/deps/wazuh_testing/wazuh_testing/tools/file.py +++ b/deps/wazuh_testing/wazuh_testing/tools/file.py @@ -281,6 +281,25 @@ def remove_file(file_path): delete_path_recursively(file_path) +def modify_all_files_in_folder(folder_path, data): + """Write data into all files in a folder + Args: + file_path (str): File or directory path to modify. + data (str): what to write into the file. + """ + for file in os.listdir(folder_path): + write_file(os.path.join(folder_path, file), data) + + +def delete_all_files_in_folder(folder_path): + """ Remove al files inside a folder + Args: + file_path (str): File or directory path to remove. + """ + for file in os.listdir(folder_path): + os.remove(os.path.join(folder_path, file)) + + def validate_json_file(file_path): try: with open(file_path) as file: diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 17f7ac1e98..0793ac144f 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -2,6 +2,7 @@ # Created by Wazuh, Inc. . # This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + import json import os import re @@ -17,7 +18,8 @@ import wazuh_testing.tools.configuration as conf from wazuh_testing import global_parameters, logger, ALERTS_JSON_PATH, ARCHIVES_LOG_PATH, ARCHIVES_JSON_PATH from wazuh_testing.logcollector import create_file_structure, delete_file_structure -from wazuh_testing.tools import LOG_FILE_PATH, WAZUH_CONF, get_service, ALERT_FILE_PATH, WAZUH_LOCAL_INTERNAL_OPTIONS +from wazuh_testing.tools import (PREFIX, LOG_FILE_PATH, WAZUH_CONF, get_service, ALERT_FILE_PATH, + WAZUH_LOCAL_INTERNAL_OPTIONS) from wazuh_testing.tools.configuration import get_wazuh_conf, set_section_wazuh_conf, write_wazuh_conf from wazuh_testing.tools.file import truncate_file, recursive_directory_creation, remove_file, copy, write_file from wazuh_testing.tools.monitoring import QueueMonitor, FileMonitor, SocketController, close_sockets @@ -1000,7 +1002,7 @@ def file_monitoring(request): logger.debug(f"Trucanted {file_to_monitor}") -@pytest.fixture(scope='function') +@pytest.fixture() def set_wazuh_configuration(configuration): """Set wazuh configuration @@ -1035,15 +1037,17 @@ def truncate_monitored_files(): log_files = [LOG_FILE_PATH, ALERT_FILE_PATH] for log_file in log_files: - truncate_file(log_file) + if os.path.isfile(os.path.join(PREFIX, log_file)): + truncate_file(log_file) yield for log_file in log_files: - truncate_file(log_file) + if os.path.isfile(os.path.join(PREFIX, log_file)): + truncate_file(log_file) -@pytest.fixture(scope='function') +@pytest.fixture() def stop_modules_function_after_execution(): """Stop wazuh modules daemon after finishing a test""" yield diff --git a/tests/integration/test_fim/conftest.py b/tests/integration/test_fim/conftest.py index 7ab907700f..16a8f4c36d 100644 --- a/tests/integration/test_fim/conftest.py +++ b/tests/integration/test_fim/conftest.py @@ -1,18 +1,21 @@ # Copyright (C) 2015-2022, Wazuh Inc. # Created by Wazuh, Inc. . # This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - import os +import re +import subprocess +import time import pytest -from wazuh_testing import (global_parameters, LOG_FILE_PATH, WAZUH_SERVICES_START, WAZUH_SERVICES_STOP, +from distro import id +from wazuh_testing import (global_parameters, LOG_FILE_PATH, REGULAR, WAZUH_SERVICES_START, WAZUH_SERVICES_STOP, WAZUH_LOG_MONITOR) -from wazuh_testing.tools.local_actions import run_local_command_returning_output -from wazuh_testing.tools.file import truncate_file, delete_path_recursively -from wazuh_testing.tools.monitoring import FileMonitor from wazuh_testing.tools.services import control_service -from wazuh_testing.modules.fim import (registry_parser, KEY_WOW64_64KEY, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, - SYNC_INTERVAL_VALUE) +from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.tools.file import truncate_file, delete_path_recursively, create_file +from wazuh_testing.tools.local_actions import run_local_command_returning_output +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, SYNC_INTERVAL_VALUE, KEY_WOW64_64KEY, + MONITORED_DIR_1, registry_parser) from wazuh_testing.modules.fim import event_monitor as evm from wazuh_testing.modules.fim.utils import create_registry, delete_registry @@ -41,7 +44,40 @@ def create_key(request): @pytest.fixture() -def wait_fim_start_function(configuration): +def create_files_in_folder(files_number): + """Create files in monitored folder and files""" + + for file in range(0, files_number): + create_file(REGULAR, MONITORED_DIR_1, f"test_file_{time.time()}_{file}") + + yield + + delete_path_recursively(MONITORED_DIR_1) + + +@pytest.fixture(scope='module') +def install_audit(get_configuration): + """Install auditd before test""" + + # Check distro + linux_distro = id() + + if re.match(linux_distro, "centos"): + package_management = "yum" + audit = "audit" + option = "--assumeyes" + elif re.match(linux_distro, "ubuntu") or re.match(linux_distro, "debian"): + package_management = "apt-get" + audit = "auditd" + option = "--yes" + else: + # Install audit and start the service + process = subprocess.run([package_management, "install", audit, option], check=True) + process = subprocess.run(["service", "auditd", "start"], check=True) + + +@pytest.fixture() +def wait_fim_start(configuration): """ Wait for realtime start, whodata start or end of initial FIM scan. Args: @@ -61,6 +97,26 @@ def wait_fim_start_function(configuration): evm.detect_initial_scan(file_monitor) +@pytest.fixture() +def wait_syscheck_start(metadata): + """ Wait for realtime start, whodata start or end of initial FIM scan. + Args: + metadata (dict): Test additional metadata + """ + file_monitor = FileMonitor(LOG_FILE_PATH) + mode_key = 'fim_mode' if 'fim_mode2' not in metadata else 'fim_mode2' + + try: + if metadata[mode_key] == 'realtime': + evm.detect_realtime_start(file_monitor) + elif metadata[mode_key] == 'whodata': + evm.detect_whodata_start(file_monitor) + else: # scheduled + evm.detect_initial_scan(file_monitor) + except KeyError: + evm.detect_initial_scan(file_monitor) + + @pytest.fixture() def restart_syscheck_function(): """ diff --git a/tests/integration/test_fim/test_files/conftest.py b/tests/integration/test_fim/test_files/conftest.py index e4d6e21bf5..c6ff8eaefd 100644 --- a/tests/integration/test_fim/test_files/conftest.py +++ b/tests/integration/test_fim/test_files/conftest.py @@ -5,11 +5,11 @@ import pytest from wazuh_testing import LOG_FILE_PATH -from wazuh_testing.modules.fim.event_monitor import (detect_initial_scan, detect_realtime_start, detect_whodata_start, - detect_initial_scan_start) from wazuh_testing.tools.file import truncate_file from wazuh_testing.tools.monitoring import FileMonitor from wazuh_testing.tools.services import control_service +from wazuh_testing.modules.fim.event_monitor import (detect_initial_scan, detect_realtime_start, detect_whodata_start, + detect_initial_scan_start) @pytest.fixture(scope="module") @@ -49,7 +49,7 @@ def wait_for_fim_start_function(get_configuration, request): """ Wait for fim to start """ - wait_for_fim_start(get_configuration, request) + wait_for_fim_active(get_configuration, request) @pytest.fixture() diff --git a/tests/integration/test_fim/test_files/test_ambiguous_confs/test_ignore_works_over_restrict.py b/tests/integration/test_fim/test_files/test_ambiguous_confs/test_ignore_works_over_restrict.py index bc5e168bcf..841ccf842c 100644 --- a/tests/integration/test_fim/test_files/test_ambiguous_confs/test_ignore_works_over_restrict.py +++ b/tests/integration/test_fim/test_files/test_ambiguous_confs/test_ignore_works_over_restrict.py @@ -66,7 +66,7 @@ import pytest from wazuh_testing import logger from wazuh_testing.fim import LOG_FILE_PATH, callback_detect_event, create_file, REGULAR, generate_params -from wazuh_testing.fim_module import CB_IGNORING_DUE_TO_SREGEX, CB_IGNORING_DUE_TO_PATTERN +from wazuh_testing.modules.fim.event_monitor import CB_IGNORING_DUE_TO_SREGEX, CB_IGNORING_DUE_TO_PATTERN from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback diff --git a/tests/integration/test_fim/test_files/test_basic_usage/test_basic_usage_entries_match_path_count.py b/tests/integration/test_fim/test_files/test_basic_usage/test_basic_usage_entries_match_path_count.py index 5fa47ba094..62412bfc69 100644 --- a/tests/integration/test_fim/test_files/test_basic_usage/test_basic_usage_entries_match_path_count.py +++ b/tests/integration/test_fim/test_files/test_basic_usage/test_basic_usage_entries_match_path_count.py @@ -75,7 +75,7 @@ from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing.fim_module.event_monitor import callback_entries_path_count +from wazuh_testing.modules.fim.event_monitor import callback_entries_path_count # Marks diff --git a/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf.yaml b/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf.yaml index ccdf0e0a48..e79be5bb4f 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf.yaml +++ b/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf.yaml @@ -1,98 +1,96 @@ ---- # conf 1 - tags: - - no_file_limit + - no_file_limit apply_to_modules: - - test_file_limit_no_limit + - test_file_limit_no_limit sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - file_limit: - elements: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - file_limit: + elements: + - enabled: + value: 'no' + - entries: + value: 10 + - section: sca + elements: - enabled: value: 'no' - - entries: - value: '10' - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: active-response - elements: - - disabled: - value: 'yes' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: + value: 'yes' # conf 2 - tags: - - file_limit_default + - file_limit_default apply_to_modules: - - test_file_limit_default + - test_file_limit_default sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: active-response - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: + value: 'yes' # conf 3 - tags: - - file_limit_conf + - file_limit_conf apply_to_modules: - - test_file_limit_full - - test_file_limit_values - - test_file_limit_capacity_alerts + - test_file_limit_full + - test_file_limit_values + - test_file_limit_capacity_alerts sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - frequency: - value: 10 - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - file_limit: - elements: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 10 + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - file_limit: + elements: + - enabled: + value: 'yes' + - entries: + value: FILE_LIMIT + - section: sca + elements: - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: value: 'yes' - - entries: - value: FILE_LIMIT - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: active-response - elements: - - disabled: - value: 'yes' - diff --git a/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf_delete_full.yaml b/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf_delete_full.yaml index 2d617d5803..3b4b0346b0 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf_delete_full.yaml +++ b/tests/integration/test_fim/test_files/test_file_limit/data/wazuh_conf_delete_full.yaml @@ -1,34 +1,31 @@ ---- -# conf 1 - tags: - - tags_delete_full + - tags_delete_full apply_to_modules: - - test_file_limit_delete_full + - test_file_limit_delete_full sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - file_limit: - elements: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - file_limit: + elements: + - enabled: + value: 'yes' + - entries: + value: LIMIT + - section: sca + elements: - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: value: 'yes' - - entries: - value: LIMIT - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: active-response - elements: - - disabled: - value: 'yes' - diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_capacity_alerts.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_capacity_alerts.py index 24cc918594..673d82460f 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_capacity_alerts.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_capacity_alerts.py @@ -51,6 +51,7 @@ pytest_args: - fim_mode: + scheduled: Monitoring is done after a configured interval realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. whodata: Implies real-time monitoring but adding the 'who-data' information. - tier: @@ -65,23 +66,26 @@ import sys import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, generate_params, create_file, REGULAR, delete_file, wait_for_scheduled_scan) + +from wazuh_testing import LOG_FILE_PATH, REGULAR, global_parameters from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file, delete_file from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import (CB_FILE_LIMIT_CAPACITY, ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT, - ERR_MSG_WRONG_CAPACITY_LOG_DB_LIMIT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, ERR_MSG_WRONG_INODE_PATH_COUNT, - CB_FILE_LIMIT_BACK_TO_NORMAL, ERR_MSG_DB_BACK_TO_NORMAL, ERR_MSG_FIM_INODE_ENTRIES) -from wazuh_testing.fim_module.event_monitor import callback_entries_path_count +from wazuh_testing.modules import TIER1 +from wazuh_testing.modules.fim import SCHEDULED_MODE, FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS +from wazuh_testing.modules.fim.event_monitor import (callback_entries_path_count, CB_FILE_LIMIT_CAPACITY, + ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT, ERR_MSG_FIM_INODE_ENTRIES, + ERR_MSG_WRONG_CAPACITY_LOG_DB_LIMIT, + ERR_MSG_WRONG_NUMBER_OF_ENTRIES, ERR_MSG_WRONG_INODE_PATH_COUNT) +from wazuh_testing.modules.fim.utils import generate_params, wait_for_scheduled_scan # Marks - -pytestmark = [pytest.mark.tier(level=1)] +pytestmark = [TIER1] # Variables +local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS test_directories = [os.path.join(PREFIX, 'testdir1')] - directory_str = ','.join(test_directories) wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') @@ -95,8 +99,9 @@ file_limit_list = ['100'] conf_params = {'TEST_DIRECTORIES': testdir1} -params, metadata = generate_params(extra_params=conf_params, modes=['scheduled'], - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list)) +params, metadata = generate_params(extra_params=conf_params, modes=[SCHEDULED_MODE], + apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem + in file_limit_list)) configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) @@ -113,9 +118,9 @@ def get_configuration(request): # Tests -@pytest.mark.parametrize('percentage', [(80), (90), (0)]) -def test_file_limit_capacity_alert(percentage, get_configuration, configure_environment, restart_syscheckd, - wait_for_fim_start): +@pytest.mark.parametrize('percentage', [(0), (80), (90)]) +def test_file_limit_capacity_alert(percentage, configure_local_internal_options_module, get_configuration, + configure_environment, restart_syscheckd, wait_for_fim_start): ''' description: Check if the 'wazuh-syscheckd' daemon generates events for different capacity thresholds limits when using the 'schedule' monitoring mode. For this purpose, the test will monitor a directory in which @@ -124,7 +129,7 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi the total and when the number is less than that percentage. Finally, the test will verify that on the FIM event, inodes and monitored files number match. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 @@ -132,6 +137,9 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi - percentage: type: int brief: Percentage of testing files to be created. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -156,7 +164,7 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi expected_output: - r'.*Sending FIM event: (.+)$' ('added' event if the testing directory is not ignored) - - r'.*Sending DB * full alert.' + - r'.*File database is * full.' - r'.*Sending DB back to normal alert.' - r'.*Fim inode entries*, path count' - r'.*Fim entries' (on Windows systems) @@ -169,28 +177,26 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi if percentage == 0: NUM_FILES = 0 - # Create files up to desired database percentage to generate alerts + + # Create files up to desired database percentage to generate alerts if percentage >= 80: # Percentages 80 and 90 for i in range(NUM_FILES): create_file(REGULAR, testdir1, f'test{i}') - #Delete files to empty DB and return it to normal levels + + # Delete files to empty DB and return it to normal levels else: # Database back to normal for i in range(91): - delete_file(testdir1, f'test{i}') + delete_file(os.path.join(testdir1, f'test{i}')) wait_for_scheduled_scan(True, interval=scan_delay, monitor=wazuh_log_monitor) - #Look for file_limit percentage alert configure value and check it matches with the expected percentage - if percentage >= 80: + + # Look for file_limit percentage alert configure value and check it matches with the expected percentage + if percentage >= 80: file_limit_capacity = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=generate_monitoring_callback(CB_FILE_LIMIT_CAPACITY), error_message=ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT).result() assert file_limit_capacity == str(percentage), ERR_MSG_WRONG_CAPACITY_LOG_DB_LIMIT - # Check the is back on normal levels - else: - event_found = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_FILE_LIMIT_BACK_TO_NORMAL), - error_message=ERR_MSG_DB_BACK_TO_NORMAL).result() # Get entries and path counts and check they match the expected values entries, path_count = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_default.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_default.py index 9df545a221..ecc5d41912 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_default.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_default.py @@ -64,12 +64,14 @@ import sys import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params +from wazuh_testing import global_parameters, LOG_FILE_PATH from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import ERR_MSG_FILE_LIMIT_VALUES, CB_FILE_LIMIT_VALUE, ERR_MSG_WRONG_FILE_LIMIT_VALUE +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (ERR_MSG_FILE_LIMIT_VALUES, CB_FILE_LIMIT_VALUE, + ERR_MSG_WRONG_FILE_LIMIT_VALUE) +from wazuh_testing.modules.fim.utils import generate_params # Marks @@ -77,7 +79,6 @@ # Variables test_directories = [os.path.join(PREFIX, 'testdir1')] - directory_str = ','.join(test_directories) wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') @@ -102,20 +103,22 @@ def get_configuration(request): # Tests - -@pytest.mark.skipif(sys.platform == 'win32', reason="Blocked by wazuh/wazuh#11819") -def test_file_limit_default(get_configuration, configure_environment, restart_syscheckd): +def test_file_limit_default(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' description: Check if the maximum number of files monitored by the 'wazuh-syscheckd' daemon is set to default when the 'file_limit' tag is missing in the configuration. For this purpose, the test will monitor a directory and wait for FIM to start and generate an event indicating the maximum number of files to monitor. Finally, the test will verify that this number matches the default value (100000). - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -135,14 +138,14 @@ def test_file_limit_default(get_configuration, configure_environment, restart_sy combined with the testing directory to be monitored defined in this module. expected_output: - - r'.*Maximum number of entries to be monitored' + - r'.*Maximum number of files to be monitored' tags: - scheduled - realtime - who_data ''' - #Check the file limit configured and that it matches expected value (100000) + # Check the file limit configured and that it matches expected value (100000) file_limit_value = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=generate_monitoring_callback(CB_FILE_LIMIT_VALUE), error_message=ERR_MSG_FILE_LIMIT_VALUES).result() diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_delete_full.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_delete_full.py index 9913c9f13f..eae5370c61 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_delete_full.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_delete_full.py @@ -64,16 +64,18 @@ from time import sleep import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, delete_file, generate_params, create_file, REGULAR +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file, delete_file from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import (ERR_MSG_DATABASE_FULL_ALERT_EVENT, CB_FILE_LIMIT_CAPACITY, - ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL, ERR_MSG_NO_EVENTS_EXPECTED, ERR_MSG_DELETED_EVENT_NOT_RECIEVED) -from wazuh_testing.fim_module.event_monitor import callback_detect_event -# Marks +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (callback_detect_event, ERR_MSG_DATABASE_FULL_ALERT_EVENT, + CB_FILE_LIMIT_CAPACITY, ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL, + ERR_MSG_NO_EVENTS_EXPECTED, ERR_MSG_DELETED_EVENT_NOT_RECIEVED) +from wazuh_testing.modules.fim.utils import generate_params +# Marks pytestmark = [pytest.mark.tier(level=1)] # Variables @@ -123,7 +125,8 @@ def extra_configuration_before_yield(): @pytest.mark.parametrize('folder, file_name', [(testdir1, f'{base_file_name}{1}')]) -def test_file_limit_delete_full(folder, file_name, get_configuration, configure_environment, restart_syscheckd): +def test_file_limit_delete_full(folder, file_name, configure_local_internal_options_module, get_configuration, + configure_environment, restart_syscheckd): ''' description: Check a specific case. If a testing file ('test_file1') is not inserted in the FIM database (because the maximum number of files to be monitored has already been reached), and another @@ -134,7 +137,7 @@ def test_file_limit_delete_full(folder, file_name, get_configuration, configure_ no FIM events to be generated (file limit reached). Finally, it will delete 'test_file10' and verify that the 'deleted' FIM event matches that file. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 @@ -145,6 +148,9 @@ def test_file_limit_delete_full(folder, file_name, get_configuration, configure_ - file_name: type: str brief: Name of the testing file to be created. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -168,14 +174,14 @@ def test_file_limit_delete_full(folder, file_name, get_configuration, configure_ the testing directory to be monitored defined in this module. expected_output: - - r'.*Sending DB * full alert.' + - r'.*File database is (\\d+)% full' - r'.*Sending FIM event: (.+)$' ('deleted' event) tags: - realtime - who_data ''' - #Check that database is full and assert database usage percentage is 100% + # Check that database is full and assert database usage percentage is 100% database_state = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=generate_monitoring_callback(CB_FILE_LIMIT_CAPACITY), error_message=ERR_MSG_DATABASE_FULL_ALERT_EVENT).result() @@ -186,7 +192,7 @@ def test_file_limit_delete_full(folder, file_name, get_configuration, configure_ create_file(REGULAR, testdir1, file_name) sleep(sleep_time) # Delete the file created - Should not generate events - delete_file(folder, file_name) + delete_file(os.path.join(folder, file_name)) # Check no Creation or Deleted event has been generated with pytest.raises(TimeoutError): @@ -195,9 +201,9 @@ def test_file_limit_delete_full(folder, file_name, get_configuration, configure_ assert event is None, ERR_MSG_NO_EVENTS_EXPECTED # Delete the first file that was created (It is included in DB) - delete_file(folder, f'{file_name}{0}') + delete_file(os.path.join(folder, f'{file_name}{0}')) - #Get that the file deleted generetes an event and assert the event data path. + # Get that the file deleted generetes an event and assert the event data path. event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message=ERR_MSG_DELETED_EVENT_NOT_RECIEVED).result() diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_full.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_full.py index 479d0f800b..a47ab6aa7a 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_full.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_full.py @@ -65,18 +65,20 @@ import sys import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params, create_file, REGULAR +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import(CB_FILE_LIMIT_CAPACITY, ERR_MSG_DATABASE_FULL_ALERT_EVENT, - ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL, CB_DATABASE_FULL_COULD_NOT_INSERT, ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT, - ERR_MSG_FIM_INODE_ENTRIES, ERR_MSG_WRONG_INODE_PATH_COUNT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES) -from wazuh_testing.fim_module.event_monitor import callback_entries_path_count +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (callback_entries_path_count, CB_FILE_LIMIT_CAPACITY, + ERR_MSG_DATABASE_FULL_ALERT_EVENT, ERR_MSG_FIM_INODE_ENTRIES, + ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL, + ERR_MSG_WRONG_INODE_PATH_COUNT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES) +from wazuh_testing.modules.fim.utils import generate_params -# Marks +# Marks pytestmark = [pytest.mark.tier(level=1)] # Variables @@ -95,7 +97,8 @@ conf_params = {'TEST_DIRECTORIES': testdir1} params, metadata = generate_params(extra_params=conf_params, - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list)) + apply_to_all=({'FILE_LIMIT': file_limit_elem} for + file_limit_elem in file_limit_list)) configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) @@ -119,8 +122,8 @@ def extra_configuration_before_yield(): # Tests - -def test_file_limit_full( get_configuration, configure_environment, restart_syscheckd): +def test_file_limit_full(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon generates proper events while the FIM database is in 'full database alert' mode for reaching the limit of files to monitor set in the 'file_limit' tag. @@ -129,14 +132,14 @@ def test_file_limit_full( get_configuration, configure_environment, restart_sysc when a new testing file is added to the monitored directory. Finally, the test will verify that on the FIM event, inodes and monitored files number match. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: - - tags_to_apply: - type: set - brief: Run test if matches with a configuration identifier, skip otherwise. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -157,7 +160,7 @@ def test_file_limit_full( get_configuration, configure_environment, restart_sysc combined with the testing directory to be monitored defined in this module. expected_output: - - r'.*Sending DB * full alert.' + - r'.*File database is (\\d+)% full' - r'.*The DB is full.*' - r'.*Fim inode entries*, path count' - r'.*Fim entries' (on Windows systems) @@ -167,19 +170,15 @@ def test_file_limit_full( get_configuration, configure_environment, restart_sysc - who_data - realtime ''' - #Check that database is full and assert database usage percentage is 100% + # Check that database is full and assert database usage percentage is 100% database_state = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=generate_monitoring_callback(CB_FILE_LIMIT_CAPACITY), error_message=ERR_MSG_DATABASE_FULL_ALERT_EVENT).result() assert database_state == '100', ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL - + # Create a file with the database being full - Should not generate events create_file(REGULAR, testdir1, 'file_full', content='content') - # Check new file could not be added to DB - wazuh_log_monitor.start(timeout=monitor_timeout, callback=generate_monitoring_callback(CB_DATABASE_FULL_COULD_NOT_INSERT), - error_message=ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT) - # Check number of entries and paths in DB and assert the value matches the expected count entries, path_count = wazuh_log_monitor.start(timeout=monitor_timeout, callback=callback_entries_path_count, error_message=ERR_MSG_FIM_INODE_ENTRIES).result() diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_no_limit.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_no_limit.py index 09111633ed..267ebd3172 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_no_limit.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_no_limit.py @@ -76,16 +76,18 @@ import sys import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params + +from wazuh_testing import global_parameters, LOG_FILE_PATH from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import (ERR_MSG_FILE_LIMIT_DISABLED, CB_FILE_LIMIT_DISABLED) +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_FILE_LIMIT_DISABLED, CB_FILE_LIMIT_DISABLED +from wazuh_testing.modules import TIER1 +from wazuh_testing.modules.fim.utils import generate_params # Marks - -pytestmark = [pytest.mark.tier(level=1)] +pytestmark = [TIER1] # Variables test_directories = [os.path.join(PREFIX, 'testdir1')] @@ -114,19 +116,21 @@ def get_configuration(request): # Tests - -@pytest.mark.skipif(sys.platform == 'win32', reason="Blocked by wazuh/wazuh #11162") -def test_file_limit_no_limit(get_configuration, configure_environment, restart_syscheckd): +def test_file_limit_no_limit(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon detects that the 'file_limit' feature of FIM is disabled. For this purpose, the test will monitor a testing directory, and finally, it will verify that the FIM event 'no limit' is generated. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. diff --git a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_values.py b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_values.py index cd7ad659b7..833a15e1d3 100644 --- a/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_values.py +++ b/tests/integration/test_fim/test_files/test_file_limit/test_file_limit_values.py @@ -65,28 +65,31 @@ import sys import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params, create_file, REGULAR + +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module import (ERR_MSG_FILE_LIMIT_VALUES, CB_FILE_LIMIT_VALUE, ERR_MSG_WRONG_FILE_LIMIT_VALUE, - ERR_MSG_FIM_INODE_ENTRIES, ERR_MSG_WRONG_INODE_PATH_COUNT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES) -from wazuh_testing.fim_module.event_monitor import callback_entries_path_count +from wazuh_testing.modules import TIER1 +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (ERR_MSG_FILE_LIMIT_VALUES, CB_FILE_LIMIT_VALUE, + ERR_MSG_WRONG_FILE_LIMIT_VALUE, ERR_MSG_FIM_INODE_ENTRIES, + ERR_MSG_WRONG_INODE_PATH_COUNT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, + callback_entries_path_count) +from wazuh_testing.modules.fim.utils import generate_params # Marks - -pytestmark = [pytest.mark.tier(level=1)] +pytestmark = [TIER1] # Variables test_directories = [os.path.join(PREFIX, 'testdir1')] - directory_str = ','.join(test_directories) wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') testdir1 = test_directories[0] -monitor_timeout= 40 +monitor_timeout = 40 # Configurations @@ -94,7 +97,8 @@ conf_params = {'TEST_DIRECTORIES': testdir1} params, metadata = generate_params(extra_params=conf_params, - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list)) + apply_to_all=({'FILE_LIMIT': file_limit_elem} for + file_limit_elem in file_limit_list)) configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) @@ -118,9 +122,8 @@ def extra_configuration_before_yield(): # Tests - -@pytest.mark.skipif(sys.platform == 'win32', reason="Blocked by wazuh/wazuh #11819") -def test_file_limit_values(get_configuration, configure_environment, restart_syscheckd): +def test_file_limit_values(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon detects that the value of the 'entries' tag, which corresponds to the maximum number of files to monitor from the 'file_limit' feature of FIM. For this purpose, @@ -128,11 +131,14 @@ def test_file_limit_values(get_configuration, configure_environment, restart_sys is generated and has the correct value. Finally, the test will verify that on the FIM event, inodes and monitored files number match. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -164,13 +170,12 @@ def test_file_limit_values(get_configuration, configure_environment, restart_sys # assert it matches the expected value assert file_limit_value == get_configuration['metadata']['file_limit'], ERR_MSG_WRONG_FILE_LIMIT_VALUE - # Check number of entries and paths in DB and assert the value matches the expected count entries, path_count = wazuh_log_monitor.start(timeout=monitor_timeout, callback=callback_entries_path_count, error_message=ERR_MSG_FIM_INODE_ENTRIES).result() if sys.platform != 'win32': assert (entries == get_configuration['metadata']['file_limit'] and - path_count == get_configuration['metadata']['file_limit']), ERR_MSG_WRONG_INODE_PATH_COUNT + path_count == get_configuration['metadata']['file_limit']), ERR_MSG_WRONG_INODE_PATH_COUNT else: assert entries == str(get_configuration['metadata']['file_limit']), ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_conf.yaml b/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_conf.yaml index 105eb0e197..ae55625ae5 100644 --- a/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_conf.yaml +++ b/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_conf.yaml @@ -1,22 +1,33 @@ - ---- -# conf 1 - tags: - - max_eps + - apply_to_modules: - - MODULE_NAME + - test_max_eps sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - max_eps: - value: MAX_EPS - - synchronization: - elements: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - max_eps: + value: MAX_EPS + - synchronization: + elements: + - enabled: + value: 'no' + - section: sca + elements: - enabled: value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_sync_conf_max_eps.yaml b/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_sync_conf_max_eps.yaml index fd04113b64..4b42afc901 100644 --- a/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_sync_conf_max_eps.yaml +++ b/tests/integration/test_fim/test_files/test_max_eps/data/wazuh_sync_conf_max_eps.yaml @@ -1,32 +1,32 @@ -# Configuration for sync max eps enabled -- tags: - - max_eps_synchronization - apply_to_modules: - - test_max_eps_synchronization - sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - synchronization: - elements: - - max_eps: - value: MAX_EPS - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' +# Configuration for sync max eps enabled +- tags: + - + apply_to_modules: + - test_sync_max_eps_scheduled + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - synchronization: + elements: + - max_eps: + value: MAX_EPS + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_files/test_max_eps/test_max_eps.py b/tests/integration/test_fim/test_files/test_max_eps/test_max_eps.py index 9adf4b256c..d473c6c71d 100644 --- a/tests/integration/test_fim/test_files/test_max_eps/test_max_eps.py +++ b/tests/integration/test_fim/test_files/test_max_eps/test_max_eps.py @@ -60,37 +60,41 @@ - fim_max_eps ''' import os -from collections import Counter - +import sys import pytest -from wazuh_testing.fim import LOG_FILE_PATH, REGULAR, create_file, generate_params, callback_event_message, \ - check_time_travel +import time + +from collections import Counter +from wazuh_testing import logger, LOG_FILE_PATH from wazuh_testing.tools import PREFIX -from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test -from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.tools.file import write_file +from wazuh_testing.modules.fim import TEST_DIR_1, REALTIME_MODE, WHODATA_MODE +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (ERR_MSG_MULTIPLE_FILES_CREATION, callback_integrity_message, + CB_PATH_MONITORED_REALTIME, ERR_MSG_MONITORING_PATH, + CB_PATH_MONITORED_WHODATA, CB_PATH_MONITORED_WHODATA_WINDOWS) +from wazuh_testing.modules.fim.utils import generate_params -# Marks +# Marks pytestmark = pytest.mark.tier(level=1) # Variables -test_directories = [os.path.join(PREFIX, 'testdir1')] - -directory_str = ','.join(test_directories) - wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') -testdir1 = os.path.join(PREFIX, 'testdir1') +test_directories = [os.path.join(PREFIX, TEST_DIR_1)] +TIMEOUT = 180 # Configurations -conf_params = {'TEST_DIRECTORIES': directory_str, - 'MODULE_NAME': __name__} +conf_params = {'TEST_DIRECTORIES': test_directories[0]} eps_values = ['50', '10'] p, m = generate_params(extra_params=conf_params, apply_to_all=({'MAX_EPS': eps_value} for eps_value in eps_values), - modes=['scheduled']) + modes=[REALTIME_MODE, WHODATA_MODE]) configurations = load_wazuh_configurations(configurations_path, __name__, params=p, metadata=m) @@ -102,7 +106,21 @@ def get_configuration(request): return request.param -def test_max_eps(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): +def create_multiple_files(get_configuration): + """Create multiple files of a specific type.""" + max_eps = get_configuration['metadata']['max_eps'] + mode = get_configuration['metadata']['fim_mode'] + try: + for i in range(int(max_eps) * 4): + file_name = f'file{i}_to_max_eps_{max_eps}_{mode}_mode{time.time()}' + path = os.path.join(test_directories[0], file_name) + write_file(path) + except OSError: + logger.info(ERR_MSG_MULTIPLE_FILES_CREATION) + + +@pytest.mark.skip("This test is affected by Issue #15844, when it is fixed it should be enabled again.") +def test_max_eps(configure_local_internal_options_module, get_configuration, configure_environment, restart_wazuh): ''' description: Check if the 'wazuh-syscheckd' daemon applies the limit set in the 'max_eps' tag when a lot of 'syscheck' events are generated. For this purpose, the test will monitor a folder, @@ -111,7 +129,7 @@ def test_max_eps(get_configuration, configure_environment, restart_syscheckd, wa the testing files created. Finally, it will verify the limit of events per second (eps) is not exceeded by checking the creation time of the testing files. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 @@ -141,29 +159,27 @@ def test_max_eps(get_configuration, configure_environment, restart_syscheckd, wa - r'.*Sending FIM event: (.+)$' ('added' events) tags: - - realtime - scheduled ''' - check_apply_test({'max_eps'}, get_configuration['tags']) - max_eps = int(get_configuration['metadata']['max_eps']) mode = get_configuration['metadata']['fim_mode'] - + if sys.platform == 'win32': + monitoring_regex = CB_PATH_MONITORED_REALTIME if mode == 'realtime' else CB_PATH_MONITORED_WHODATA_WINDOWS + else: + monitoring_regex = CB_PATH_MONITORED_REALTIME if mode == 'realtime' else CB_PATH_MONITORED_WHODATA + + result = wazuh_log_monitor.start(timeout=TIMEOUT, + callback=generate_monitoring_callback(monitoring_regex), + error_message=ERR_MSG_MONITORING_PATH).result() + create_multiple_files(get_configuration) # Create files to read max_eps files with added events - for i in range(int(max_eps) * 5): - create_file(REGULAR, testdir1, f'test{i}_{mode}_{max_eps}', content='') - - check_time_travel(mode == "scheduled") - n_results = max_eps * 5 - - result = wazuh_log_monitor.start(timeout=(n_results / max_eps) * 6, + n_results = max_eps * 3 + result = wazuh_log_monitor.start(timeout=TIMEOUT, accum_results=n_results, - callback=callback_event_message, + callback=callback_integrity_message, error_message=f'Received less results than expected ({n_results})').result() counter = Counter([date_time for date_time, _ in result]) - error_margin = (max_eps * 0.1) for _, n_occurrences in counter.items(): - assert n_occurrences <= round( - max_eps + error_margin), f'Sent {n_occurrences} but a maximum of {max_eps} was set' + assert n_occurrences <= max_eps, f'Sent {n_occurrences} but a maximum of {max_eps} was set' diff --git a/tests/integration/test_fim/test_files/test_max_eps/test_max_eps_synchronization.py b/tests/integration/test_fim/test_files/test_max_eps/test_sync_max_eps_scheduled.py similarity index 81% rename from tests/integration/test_fim/test_files/test_max_eps/test_max_eps_synchronization.py rename to tests/integration/test_fim/test_files/test_max_eps/test_sync_max_eps_scheduled.py index 68739fc4dc..c95a0ec595 100644 --- a/tests/integration/test_fim/test_files/test_max_eps/test_max_eps_synchronization.py +++ b/tests/integration/test_fim/test_files/test_max_eps/test_sync_max_eps_scheduled.py @@ -48,8 +48,6 @@ pytest_args: - fim_mode: - realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. - whodata: Implies real-time monitoring but adding the 'who-data' information. scheduled: Implies scheduled scan - tier: @@ -62,20 +60,21 @@ ''' import os import pytest +import time from collections import Counter from wazuh_testing import logger -from wazuh_testing.tools import PREFIX -from wazuh_testing.fim import LOG_FILE_PATH, generate_params +from wazuh_testing.tools import PREFIX, LOG_FILE_PATH from wazuh_testing.tools.monitoring import FileMonitor from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.modules import DATA, TIER1, AGENT, WINDOWS, LINUX -from wazuh_testing.modules.fim import (TEST_DIR_1, TEST_DIRECTORIES, YAML_CONF_MAX_EPS_SYNC, - ERR_MSG_AGENT_DISCONNECT, ERR_MSG_INTEGRITY_CONTROL_MSG, - SCHEDULE_MODE, REALTIME_MODE, WHODATA_MODE) +from wazuh_testing.modules.fim import TEST_DIR_1, TEST_DIRECTORIES, YAML_CONF_MAX_EPS_SYNC, SCHEDULED_MODE from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options -from wazuh_testing.modules.fim.event_monitor import callback_integrity_message, callback_connection_message +from wazuh_testing.modules.fim.event_monitor import (callback_integrity_message, ERR_MSG_INTEGRITY_CONTROL_MSG, + ERR_MSG_MULTIPLE_FILES_CREATION) from wazuh_testing.tools.file import delete_path_recursively, write_file +from wazuh_testing.modules.fim.utils import generate_params + # Marks pytestmark = [TIER1, AGENT, WINDOWS, LINUX] @@ -89,9 +88,7 @@ test_directory = os.path.join(PREFIX, TEST_DIR_1) conf_params = {TEST_DIRECTORIES: test_directory} -ERR_MSG_MULTIPLE_FILES_CREATION = 'Multiple files could not be created.' -TIMEOUT_CHECK_AGENT_CONNECT = 10 TIMEOUT_CHECK_INTEGRATY_START = 30 TIMEOUT_CHECK_EACH_INTEGRITY_MSG = 90 @@ -101,13 +98,13 @@ eps_values = ['1', '100'] parameters, metadata = generate_params(extra_params=conf_params, - modes=[SCHEDULE_MODE, REALTIME_MODE, WHODATA_MODE], + modes=[SCHEDULED_MODE], apply_to_all=({'MAX_EPS': eps_value} for eps_value in eps_values)) configurations = load_wazuh_configurations(configurations_path, __name__, params=parameters, metadata=metadata) configuration_ids = [f"{x['fim_mode']}_mode_{x['max_eps']}_max_eps" for x in metadata] -# Fixtures +# Fixtures @pytest.fixture(scope='module', params=configurations, ids=configuration_ids) def get_configuration(request): """Get configurations from the module.""" @@ -122,12 +119,13 @@ def create_multiple_files(get_configuration): os.makedirs(test_directory, exist_ok=True, mode=0o777) try: for i in range(int(max_eps) + 5): - file_name = f'file{i}_to_max_eps_{max_eps}_{mode}_mode' + file_name = f'file{i}_to_max_eps_{max_eps}_{mode}_mode{time.time()}' path = os.path.join(test_directory, file_name) write_file(path) except OSError: logger.info(ERR_MSG_MULTIPLE_FILES_CREATION) + # Tests def test_max_eps_sync_valid_within_range(configure_local_internal_options_module, get_configuration, create_multiple_files, configure_environment, restart_wazuh): @@ -161,9 +159,6 @@ def test_max_eps_sync_valid_within_range(configure_local_internal_options_module - restart_wazuh: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. - - delete_files: - type: fixture - brief: Delete the testing files when the test ends. assertions: - Verify that FIM 'integrity' events are generated for each testing file created. @@ -174,7 +169,6 @@ def test_max_eps_sync_valid_within_range(configure_local_internal_options_module the 'wazuh-syscheckd' daemon and, these are combined with the testing directories to be monitored defined in the module. expected_output: - - r'.* Connected to the server .*' - r'.*Sending integrity control message' tags: @@ -185,11 +179,6 @@ def test_max_eps_sync_valid_within_range(configure_local_internal_options_module try: max_eps = int(get_configuration['metadata']['max_eps']) - # Wait until the agent connects to the manager. - wazuh_log_monitor.start(timeout=TIMEOUT_CHECK_AGENT_CONNECT, - callback=callback_connection_message, - error_message=ERR_MSG_AGENT_DISCONNECT).result() - # Find integrity start before attempting to read max_eps. wazuh_log_monitor.start(timeout=TIMEOUT_CHECK_INTEGRATY_START, callback=callback_integrity_message, @@ -197,11 +186,10 @@ def test_max_eps_sync_valid_within_range(configure_local_internal_options_module # Find integrity message for each file created after read max_eps. total_file_created = max_eps + 5 - result = wazuh_log_monitor.start(timeout=TIMEOUT_CHECK_EACH_INTEGRITY_MSG, - accum_results=total_file_created, - callback=callback_integrity_message, - error_message=f'Received less results than expected ({total_file_created})').result() - + result = wazuh_log_monitor.start(timeout=TIMEOUT_CHECK_EACH_INTEGRITY_MSG, accum_results=total_file_created, + callback=callback_integrity_message, + error_message=f'Received less results than expected\ + ({total_file_created})').result() # Collect by time received the messages. counter = Counter([date_time for date_time, _ in result]) diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_configured.py b/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_configured.py index 7328c52e3d..5474e54fb8 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_configured.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_configured.py @@ -74,11 +74,11 @@ from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.modules.fim import (TEST_DIR_1, DIFF_LIMIT_VALUE, DIFF_SIZE_LIMIT, FILE_SIZE_LIMIT, - DISK_QUOTA_ENABLED, DISK_QUOTA_LIMIT, FILE_SIZE_ENABLED, CB_MAXIMUM_FILE_SIZE, - REPORT_CHANGES, TEST_DIRECTORIES, ERR_MSG_MAXIMUM_FILE_SIZE, - ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE) from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim import (TEST_DIR_1, REPORT_CHANGES, TEST_DIRECTORIES, DIFF_LIMIT_VALUE, FILE_SIZE_LIMIT, + DIFF_SIZE_LIMIT, DISK_QUOTA_ENABLED, DISK_QUOTA_LIMIT, FILE_SIZE_ENABLED) +from wazuh_testing.modules.fim.event_monitor import (CB_MAXIMUM_FILE_SIZE, ERR_MSG_MAXIMUM_FILE_SIZE, + ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE) from wazuh_testing.modules.fim.utils import generate_params diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_default.py b/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_default.py index ca9bc40617..8aea598431 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_default.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_diff_size_limit_default.py @@ -70,15 +70,15 @@ import os import pytest -from wazuh_testing import global_parameters, DATA, LOG_FILE_PATH, SYSCHECK_DEBUG, VERBOSE_DEBUG_OUTPUT +from wazuh_testing import global_parameters, DATA, LOG_FILE_PATH from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.modules.fim import (DIFF_DEFAULT_LIMIT_VALUE, CB_MAXIMUM_FILE_SIZE, REPORT_CHANGES, TEST_DIR_1, - TEST_DIRECTORIES, ERR_MSG_MAXIMUM_FILE_SIZE, - ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE) -from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim import DIFF_DEFAULT_LIMIT_VALUE, REPORT_CHANGES, TEST_DIR_1, TEST_DIRECTORIES +from wazuh_testing.modules.fim.event_monitor import (CB_MAXIMUM_FILE_SIZE, ERR_MSG_MAXIMUM_FILE_SIZE, + ERR_MSG_WRONG_VALUE_MAXIMUM_FILE_SIZE) from wazuh_testing.modules.fim.utils import generate_params +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options # Marks pytestmark = [pytest.mark.tier(level=1)] @@ -97,7 +97,6 @@ TEST_DIRECTORIES: test_directory}) configurations = load_wazuh_configurations(configurations_path, __name__, params=parameters, metadata=metadata) -local_internal_options = {SYSCHECK_DEBUG: VERBOSE_DEBUG_OUTPUT} # Fixtures diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_default.py b/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_default.py index 18dd717418..101bf75634 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_default.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_default.py @@ -67,7 +67,8 @@ from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.modules import fim +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import CB_DISK_QUOTA_LIMIT_CONFIGURED_VALUE, ERR_MSG_DISK_QUOTA_LIMIT from wazuh_testing.modules.fim.utils import generate_params @@ -76,7 +77,6 @@ pytestmark = [pytest.mark.tier(level=1)] # Variables -local_internal_options = fim.FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_directories = [os.path.join(PREFIX, 'testdir1')] directory_str = ','.join(test_directories) @@ -149,8 +149,8 @@ def test_disk_quota_default(get_configuration, configure_environment, disk_quota_value = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(fim.CB_DISK_QUOTA_LIMIT_CONFIGURED_VALUE), - error_message=fim.ERR_MSG_DISK_QUOTA_LIMIT).result() + callback=generate_monitoring_callback(CB_DISK_QUOTA_LIMIT_CONFIGURED_VALUE), + error_message=ERR_MSG_DISK_QUOTA_LIMIT).result() if disk_quota_value: assert disk_quota_value == str(DEFAULT_SIZE), 'Wrong value for disk_quota' diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_disabled.py b/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_disabled.py index 4688ecf3f7..883964128b 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_disabled.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_disk_quota_disabled.py @@ -67,7 +67,7 @@ from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing.modules import fim +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options from wazuh_testing.modules.fim.event_monitor import callback_disk_quota_limit_reached from wazuh_testing.modules.fim.utils import generate_params, create_file from test_fim.common import generate_string @@ -77,7 +77,6 @@ pytestmark = [pytest.mark.tier(level=1)] # Variables -local_internal_options = fim.FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_directories = [os.path.join(PREFIX, 'testdir1')] directory_str = ','.join(test_directories) diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_default.py b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_default.py index b1946563ab..8739367819 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_default.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_default.py @@ -69,9 +69,9 @@ from wazuh_testing.tools.file import create_file, modify_file_content from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.modules.fim import (CB_FILE_SIZE_LIMIT_REACHED, FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS, - ERR_MSG_FIM_EVENT_NOT_DETECTED, ERR_MSG_FILE_LIMIT_REACHED) -from wazuh_testing.modules.fim.event_monitor import callback_detect_event +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (callback_detect_event, CB_FILE_SIZE_LIMIT_REACHED, + ERR_MSG_FIM_EVENT_NOT_DETECTED, ERR_MSG_FILE_LIMIT_REACHED) from wazuh_testing.modules.fim.utils import generate_params @@ -80,7 +80,6 @@ pytestmark = [pytest.mark.tier(level=1)] # Variables -local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_directories = [os.path.join(PREFIX, 'testdir1')] directory_str = ','.join(test_directories) diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_disabled.py b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_disabled.py index 362d1fd6d8..14256b783b 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_disabled.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_disabled.py @@ -67,7 +67,8 @@ from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR -from wazuh_testing.modules.fim import CB_FILE_SIZE_LIMIT_REACHED, FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import CB_FILE_SIZE_LIMIT_REACHED from wazuh_testing.modules.fim.utils import generate_params, create_file from test_fim.common import generate_string @@ -77,7 +78,6 @@ # Variables -local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) test_directories = [os.path.join(PREFIX, 'testdir1')] directory_str = ','.join(test_directories) diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_values.py b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_values.py index 5274ec7bc5..adacce9eac 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_file_size_values.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_file_size_values.py @@ -68,11 +68,10 @@ from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.file import create_file, modify_file_content from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.modules.fim import (CB_FILE_SIZE_LIMIT_REACHED, CB_DIFF_FOLDER_DELETED, - ERR_MSG_FIM_EVENT_NOT_DETECTED, ERR_MSG_FILE_LIMIT_REACHED, - ERR_MSG_FOLDER_DELETED) +from wazuh_testing.modules.fim.event_monitor import (CB_FILE_SIZE_LIMIT_REACHED, CB_DIFF_FOLDER_DELETED, + ERR_MSG_FIM_EVENT_NOT_DETECTED, ERR_MSG_FILE_LIMIT_REACHED, + ERR_MSG_FOLDER_DELETED, callback_detect_event) from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options -from wazuh_testing.modules.fim.event_monitor import callback_detect_event from wazuh_testing.modules.fim.utils import generate_params from test_fim.common import (generate_string, translate_size, disable_file_max_size, restore_file_max_size, make_diff_file_path, disable_rt_delay, restore_rt_delay) diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_report_changes_and_diff.py b/tests/integration/test_fim/test_files/test_report_changes/test_report_changes_and_diff.py index ba4fbe271d..97226ce6bb 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_report_changes_and_diff.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_report_changes_and_diff.py @@ -112,7 +112,7 @@ @pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) def test_reports_file_and_nodiff(configuration, metadata, set_wazuh_configuration, configure_local_internal_options_function, restart_syscheck_function, - create_monitored_folders_module, wait_fim_start_function): + create_monitored_folders_module, wait_syscheck_start): ''' description: Check if the 'wazuh-syscheckd' daemon reports the file changes (or truncates if required) in the generated events using the 'nodiff' tag and vice versa. For this purpose, the test @@ -145,7 +145,7 @@ def test_reports_file_and_nodiff(configuration, metadata, set_wazuh_configuratio - create_monitored_folders_module type: fixture brief: Create folders to be monitored, delete after test. - - wait_for_fim_start_function: + - wait_syscheck_start: type: fixture brief: check that the starting fim scan is detected. diff --git a/tests/integration/test_fim/test_files/test_report_changes/test_report_deleted_diff.py b/tests/integration/test_fim/test_files/test_report_changes/test_report_deleted_diff.py index f257619c3c..7c2d25a2e7 100644 --- a/tests/integration/test_fim/test_files/test_report_changes/test_report_deleted_diff.py +++ b/tests/integration/test_fim/test_files/test_report_changes/test_report_deleted_diff.py @@ -249,6 +249,9 @@ def test_report_when_deleted_directories(path, get_configuration, configure_envi diff_dir = create_file_and_check_diff(FILE_NAME, path, fim_mode) shutil.rmtree(path, ignore_errors=True) wait_for_event(fim_mode) + # Wait a second so diff path is deleted + if 'scheduled' not in fim_mode: + time.sleep(2) assert not os.path.exists(diff_dir), f'{diff_dir} exists' diff --git a/tests/integration/test_fim/test_files/test_restrict/data/wazuh_conf.yaml b/tests/integration/test_fim/test_files/test_restrict/data/wazuh_conf.yaml index 62f163497e..cca1d31b2f 100644 --- a/tests/integration/test_fim/test_files/test_restrict/data/wazuh_conf.yaml +++ b/tests/integration/test_fim/test_files/test_restrict/data/wazuh_conf.yaml @@ -1,189 +1,200 @@ ---- # conf 1 - tags: - - valid_empty + - valid_empty apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: "" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: "" + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' # conf 2 - tags: - - valid_regex - - valid_regex1 + - valid_regex + - valid_regex1 apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: ".restricted$" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: .restricted$ + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' # conf 3 - tags: - - valid_regex - - valid_regex2 + - valid_regex + - valid_regex2 apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: "^restricted" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: ^restricted + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' # conf 4 - tags: - - valid_regex - - valid_regex3 + - valid_regex + - valid_regex3 apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: "filerestricted|other_restricted$" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: filerestricted|other_restricted$ + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' # conf 5 - tags: - - valid_regex_incomplete_unix + - valid_regex_incomplete_unix apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: "^/testdir1/f|^/testdir1/subdir/f|^/testdir2/f|^/testdir2/subdir/f" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: ^/testdir1/f|^/testdir1/subdir/f + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' # conf 6 - tags: - - valid_regex_incomplete_win + - valid_regex_incomplete_win apply_to_modules: - - test_restrict_valid + - test_restrict_valid sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - check_all: 'yes' - - FIM_MODE - - restrict: "^c:\\testdir1\\f|^c:\\testdir1\\subdir\\f|^c:\\testdir2\\f|^c:\\testdir2\\subdir\\f" - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 2 + - directories: + value: TEST_DIRECTORIES + attributes: + - check_all: 'yes' + - FIM_MODE + - restrict: ^c:\testdir1\f|^c:\testdir1\subdir\f + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_files/test_restrict/test_restrict_valid.py b/tests/integration/test_fim/test_files/test_restrict/test_restrict_valid.py index 5e7aad61b6..9bbc21105e 100644 --- a/tests/integration/test_fim/test_files/test_restrict/test_restrict_valid.py +++ b/tests/integration/test_fim/test_files/test_restrict/test_restrict_valid.py @@ -61,46 +61,35 @@ ''' import os import sys - import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, callback_detect_event, callback_restricted, create_file, \ - REGULAR, generate_params, check_time_travel +from time import sleep + +from wazuh_testing import global_parameters, REGULAR, LOG_FILE_PATH from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.tools.file import create_file +from wazuh_testing.modules.fim.event_monitor import callback_detect_file_added_event, callback_restricted +from wazuh_testing.modules.fim.utils import generate_params -# Marks +# Marks pytestmark = pytest.mark.tier(level=1) -# variables - +# Variables test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') test_directories = [os.path.join(PREFIX, 'testdir1'), - os.path.join(PREFIX, 'testdir1', 'subdir'), - os.path.join(PREFIX, 'testdir2'), - os.path.join(PREFIX, 'testdir2', 'subdir') + os.path.join(PREFIX, 'testdir1', 'subdir') ] -testdir1, testdir1_sub, testdir2, testdir2_sub = test_directories - -directory_str = ','.join([os.path.join(PREFIX, 'testdir1'), os.path.join(PREFIX, 'testdir2')]) - wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) -# configurations - -conf_params, conf_metadata = generate_params(extra_params={'TEST_DIRECTORIES': directory_str}) - -configurations = load_wazuh_configurations(configurations_path, __name__, - params=conf_params, - metadata=conf_metadata - ) +# Configurations +conf_params, conf_metadata = generate_params(extra_params={'TEST_DIRECTORIES': test_directories[0]}) +configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_metadata) -# fixtures - +# Fixtures @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -122,12 +111,10 @@ def get_configuration(request): {f'valid_regex_incomplete_{"win" if sys.platform == "win32" else "unix"}'}), ('fileinfolder1', 'wb', b"Sample content", True, {f'valid_regex_incomplete_{"win" if sys.platform == "win32" else "unix"}'}), - ('testing_regex', 'w', "", False, - {f'valid_regex_incomplete_{"win" if sys.platform == "win32" else "unix"}'}), + ('testing_regex', 'w', "", False, {f'valid_regex_incomplete_{"win" if sys.platform == "win32" else "unix"}'}), ]) -def test_restrict(folder, filename, mode, content, triggers_event, tags_to_apply, - get_configuration, configure_environment, restart_syscheckd, - wait_for_fim_start): +def test_restrict(folder, filename, mode, content, triggers_event, tags_to_apply, get_configuration, + configure_environment, restart_syscheckd, wait_for_fim_start): ''' description: Check if the 'wazuh-syscheckd' daemon detects or ignores events in monitored files depending on the value set in the 'restrict' attribute. This attribute limit checks to files that match @@ -188,21 +175,19 @@ def test_restrict(folder, filename, mode, content, triggers_event, tags_to_apply tags: - scheduled - - time_travel ''' check_apply_test(tags_to_apply, get_configuration['tags']) # Create text files create_file(REGULAR, folder, filename, content=content) - scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' # Go ahead in time to let syscheck perform a new scan - check_time_travel(scheduled, monitor=wazuh_log_monitor) + if get_configuration['metadata']['fim_mode'] == 'scheduled': + sleep(3) if triggers_event: event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=callback_detect_event).result() - assert event['data']['type'] == 'added', f'Event type not equal' + callback=callback_detect_file_added_event).result() assert event['data']['path'] == os.path.join(folder, filename), f'Event path not equal' else: while True: diff --git a/tests/integration/test_fim/test_files/test_whodata_policy_change/data/test_cases/cases_whodata_policy_change.yaml b/tests/integration/test_fim/test_files/test_whodata_policy_change/data/test_cases/cases_whodata_policy_change.yaml index d711a0d6c1..a10eaeadeb 100644 --- a/tests/integration/test_fim/test_files/test_whodata_policy_change/data/test_cases/cases_whodata_policy_change.yaml +++ b/tests/integration/test_fim/test_files/test_whodata_policy_change/data/test_cases/cases_whodata_policy_change.yaml @@ -5,6 +5,7 @@ metadata: check_event: false disabling_file: policy_disable.csv + fim_mode: whodata - name: audit_policy_change_event_4719 description: Check when receiving event 4719 for audit policies change, fim changes to realtime mode @@ -13,3 +14,4 @@ metadata: check_event: true disabling_file: policy_success_removed.csv + fim_mode: whodata diff --git a/tests/integration/test_fim/test_files/test_whodata_policy_change/test_whodata_policy_change.py b/tests/integration/test_fim/test_files/test_whodata_policy_change/test_whodata_policy_change.py index a13c7ee58f..f4ac47a8f2 100644 --- a/tests/integration/test_fim/test_files/test_whodata_policy_change/test_whodata_policy_change.py +++ b/tests/integration/test_fim/test_files/test_whodata_policy_change/test_whodata_policy_change.py @@ -91,7 +91,7 @@ @pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) def test_whodata_policy_change(configuration, metadata, set_wazuh_configuration, create_monitored_folders_module, configure_local_internal_options_function, policies_file, restore_win_whodata_policies, - restart_syscheck_function, wait_fim_start_function): + restart_syscheck_function, wait_syscheck_start): ''' description: Check if the 'wazuh-syscheckd' is monitoring a in whodata mode in Windows, and the Audit Policies are changed, the monitoring changes to realtime and works on the monitored files. @@ -180,7 +180,7 @@ def test_whodata_policy_change(configuration, metadata, set_wazuh_configuration, # Check monitoring changes to realtime if metadata['check_event']: - evm.check_fim_event(timeout=T_20, callback=fim.CB_RECIEVED_EVENT_4719) + evm.check_fim_event(timeout=T_20, callback=evm.CB_RECIEVED_EVENT_4719) evm.detect_windows_whodata_mode_change(wazuh_log_monitor) # Create/Update/Delete file and check events diff --git a/tests/integration/test_fim/test_files/test_windows_system_folder_redirection/test_windows_system_folder_redirection.py b/tests/integration/test_fim/test_files/test_windows_system_folder_redirection/test_windows_system_folder_redirection.py index 78c9c78536..a11639368d 100644 --- a/tests/integration/test_fim/test_files/test_windows_system_folder_redirection/test_windows_system_folder_redirection.py +++ b/tests/integration/test_fim/test_files/test_windows_system_folder_redirection/test_windows_system_folder_redirection.py @@ -88,7 +88,7 @@ @pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) def test_windows_system_monitoring(configuration, metadata, test_folders, set_wazuh_configuration, create_monitored_folders_module, configure_local_internal_options_function, - restart_syscheck_function, wait_fim_start_function): + restart_syscheck_function, wait_syscheck_start): ''' description: Check if the 'wazuh-syscheckd' monitors the windows system folders (System32 and SysWOW64) properly, and that monitoring for Sysnative folder is redirected to System32 and works properly. @@ -132,7 +132,7 @@ def test_windows_system_monitoring(configuration, metadata, test_folders, set_wa - restart_syscheck_function: type: fixture brief: restart syscheckd daemon, and truncate the ossec.log. - - wait_for_fim_start_function: + - wait_syscheck_start: type: fixture brief: check that the starting FIM scan is detected. diff --git a/tests/integration/test_fim/test_registry/conftest.py b/tests/integration/test_fim/test_registry/conftest.py index 86eacd881f..72934c965e 100644 --- a/tests/integration/test_fim/test_registry/conftest.py +++ b/tests/integration/test_fim/test_registry/conftest.py @@ -4,10 +4,11 @@ import pytest -from wazuh_testing.fim import LOG_FILE_PATH, detect_initial_scan, detect_realtime_start, detect_whodata_start +from wazuh_testing import LOG_FILE_PATH from wazuh_testing.tools.file import truncate_file from wazuh_testing.tools.monitoring import FileMonitor from wazuh_testing.tools.services import control_service +from wazuh_testing.modules.fim.event_monitor import detect_initial_scan, detect_realtime_start, detect_whodata_start @pytest.fixture(scope='module') diff --git a/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_delete_registry.py b/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_delete_registry.py index e27ac02123..2af11d8747 100644 --- a/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_delete_registry.py +++ b/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_delete_registry.py @@ -176,8 +176,8 @@ def test_delete_registry(key, subkey, arch, value_list, check_time_travel(scheduled, monitor=wazuh_log_monitor) events = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_value_event, - accum_results=len(value_list), error_message='Did not receive expected ' - '"Sending FIM event: ..." event').result() + accum_results=len(value_list), + error_message='Did not receive expected "Sending FIM event: ..." event').result() for ev in events: validate_registry_value_event(ev, mode=mode) diff --git a/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_registry_duplicated_entries.py b/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_registry_duplicated_entries.py index 2b80916843..dcea9e48e6 100644 --- a/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_registry_duplicated_entries.py +++ b/tests/integration/test_fim/test_registry/test_registry_basic_usage/test_basic_usage_registry_duplicated_entries.py @@ -6,8 +6,8 @@ from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.utils import get_version -# Helper functions +# Helper functions def extra_configuration_after_yield(): fim.delete_registry(fim.registry_parser[key], sub_key_2, fim.KEY_WOW64_64KEY) @@ -23,11 +23,9 @@ def check_event_type_and_path(fim_event, monitored_registry): # Marks - pytestmark = [pytest.mark.win32, pytest.mark.tier(level=0)] # Variables - key = 'HKEY_LOCAL_MACHINE' classes_subkey = os.path.join('SOFTWARE', 'Classes') diff --git a/tests/integration/test_fim/test_registry/test_registry_file_limit/data/wazuh_conf.yaml b/tests/integration/test_fim/test_registry/test_registry_file_limit/data/wazuh_conf.yaml deleted file mode 100644 index 2347b3f284..0000000000 --- a/tests/integration/test_fim/test_registry/test_registry_file_limit/data/wazuh_conf.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -#conf 1 -- tags: - - file_limit_registry_conf - apply_to_modules: - - test_registry_limit_capacity_alerts - - test_registry_limit_full - - test_registry_limit_values - sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - frequency: - value: 5 - - windows_registry: - value: WINDOWS_REGISTRY - attributes: - - arch: '64bit' - - file_limit: - elements: - - enabled: - value: 'yes' - - entries: - value: FILE_LIMIT - - section: sca - elements: - - enabled: - value: 'no' - - section: rootcheck - elements: - - disabled: - value: 'yes' - - section: active-response - elements: - - disabled: - value: 'yes' - - section: wodle - attributes: - - name: 'syscollector' - elements: - - disabled: - value: 'yes' diff --git a/tests/integration/test_fim/test_registry/test_registry_limit/data/wazuh_conf.yaml b/tests/integration/test_fim/test_registry/test_registry_limit/data/wazuh_conf.yaml new file mode 100644 index 0000000000..a2dcec0394 --- /dev/null +++ b/tests/integration/test_fim/test_registry/test_registry_limit/data/wazuh_conf.yaml @@ -0,0 +1,136 @@ +# conf 1 +- tags: + - fim_registry_limit + apply_to_modules: + - test_registry_limit_capacity_alerts + - test_registry_value_limit_full + - test_registry_limit_values + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 5 + - windows_registry: + value: WINDOWS_REGISTRY + attributes: + - arch: 64bit + - registry_limit: + elements: + - enabled: + value: 'yes' + - entries: + value: REGISTRIES + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' + +# conf 2 +- tags: + - fim_registry_limit + apply_to_modules: + - test_registry_key_limit_full + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 5 + - windows_registry: + value: WINDOWS_REGISTRY_1 + attributes: + - arch: 64bit + - windows_registry: + value: WINDOWS_REGISTRY_2 + attributes: + - arch: 64bit + - registry_limit: + elements: + - enabled: + value: 'yes' + - entries: + value: REGISTRIES + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' + +# conf 2 +- tags: + - fim_registry_limit + apply_to_modules: + - test_registry_key_limit_values + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 5 + - windows_registry: + value: WINDOWS_REGISTRY_1 + attributes: + - arch: 64bit + - windows_registry: + value: WINDOWS_REGISTRY_2 + attributes: + - arch: 64bit + - windows_registry: + value: WINDOWS_REGISTRY_3 + attributes: + - arch: 64bit + - registry_limit: + elements: + - enabled: + value: 'yes' + - entries: + value: REGISTRIES + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: active-response + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_full.py b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_full.py new file mode 100644 index 0000000000..eba5425348 --- /dev/null +++ b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_full.py @@ -0,0 +1,179 @@ +''' +copyright: Copyright (C) 2015-2022, Wazuh Inc. + + Created by Wazuh, Inc. . + + This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +type: integration + +brief: File Integrity Monitoring (FIM) system watches selected files and triggering alerts + when these files are modified. Specifically, these tests will check if FIM events are + generated while the database is in 'full database alert' mode for reaching the limit + of entries to monitor set in the 'registry_limit'-'registries' tag. + The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks + configured files for changes to the checksums, permissions, and ownership. + +tier: 1 + +modules: + - fim + +components: + - agent + +daemons: + - wazuh-syscheckd + +os_platform: + - windows + +os_version: + - Windows 10 + - Windows 8 + - Windows 7 + - Windows Server 2019 + - Windows Server 2016 + - Windows Server 2012 + - Windows Server 2003 + - Windows XP + +references: + - https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html + - https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/syscheck.html#file-limit + +pytest_args: + - fim_mode: + scheduled: file/registry changes are monitored only at the configured interval + - tier: + 0: Only level 0 tests are performed, they check basic functionalities and are quick to perform. + 1: Only level 1 tests are performed, they check functionalities of medium complexity. + 2: Only level 2 tests are performed, they check advanced functionalities and are slow to perform. + +tags: + - fim_registry_limit +''' +import os +import pytest + +from wazuh_testing import global_parameters +from wazuh_testing.tools import LOG_FILE_PATH +from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules import WINDOWS, TIER1 +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, registry_parser, + KEY_WOW64_64KEY, KEY_ALL_ACCESS, RegOpenKeyEx, RegCloseKey) +from wazuh_testing.modules.fim.event_monitor import (CB_REGISTRY_LIMIT_CAPACITY, ERR_MSG_DATABASE_FULL_ALERT, + ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT, CB_COUNT_REGISTRY_ENTRIES, + CB_DATABASE_FULL_COULD_NOT_INSERT_KEY, + ERR_MSG_FIM_REGISTRY_ENTRIES, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, + ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL) +from wazuh_testing.modules.fim.utils import generate_params, create_registry + +# Marks +pytestmark = [WINDOWS, TIER1] + + +# Variables +test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), + os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2)] +test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) +NUM_REGS = 2 +EXPECTED_DB_STATE = "100" +monitor_timeout = 40 + + +# Configurations +registry_limit_list = ['2'] +conf_params = {'WINDOWS_REGISTRY_1': test_regs[0], 'WINDOWS_REGISTRY_2': test_regs[1]} +params, metadata = generate_params(extra_params=conf_params, + apply_to_all=({'REGISTRIES': registry_limit_elem} for registry_limit_elem in + registry_limit_list), modes=['scheduled']) +configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') +configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) + + +# Fixtures +@pytest.fixture(scope='module', params=configurations) +def get_configuration(request): + """Get configurations from the module.""" + return request.param + + +# Functions +def extra_configuration_before_yield(): + """Generate registry entries to fill database""" + for key in (MONITORED_KEY, MONITORED_KEY_2): + reg_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], key, KEY_WOW64_64KEY) + reg_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], key, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) + RegCloseKey(reg_handle) + + +# Tests +def test_registry_key_limit_full(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): + ''' + description: Check if the 'wazuh-syscheckd' daemon generates proper events while the FIM database is in + 'full database alert' mode for reaching the limit of entries to monitor set in the 'registries' option + of the 'registry_limit' tag. + For this purpose, the test will set the a limit of keys to monitor, and will monitor a series of keys. + Then, it will try to add a new key and it will check if the FIM event 'full' is generated. Finally, the + test will verify that, in the FIM 'entries' event, the number of entries and monitored values match. + + wazuh_min_version: 4.5.0 + + parameters: + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. + - get_configuration: + type: fixture + brief: Get configurations from the module. + - configure_environment: + type: fixture + brief: Configure a custom environment for testing. + - restart_syscheckd: + type: fixture + brief: Clear the Wazuh logs file and start a new monitor. + + assertions: + - Verify that the FIM database is in 'full database alert' mode + when the maximum number of values to monitor has been reached. + - Verify that proper FIM events are generated while the database + is in 'full database alert' mode. + + input_description: A test case (fim_registry_limit) is contained in external YAML file (wazuh_conf.yaml) + which includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined + with the testing registry key to be monitored defined in this module. + + expected_output: + - r'.*Registry database is (\\d+)% full.' + - r'.*Couldn't insert ('.*') entry into DB. The DB is full.*' + - r'.*Fim registry entries count:.*' + + tags: + - scheduled + ''' + database_state = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_REGISTRY_LIMIT_CAPACITY), + error_message=ERR_MSG_DATABASE_FULL_ALERT).result() + + assert database_state == EXPECTED_DB_STATE, ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL + + reg_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY+'\\DB_FULL', + KEY_WOW64_64KEY) + reg_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY+'\\DB_FULL', 0, + KEY_ALL_ACCESS | KEY_WOW64_64KEY) + + RegCloseKey(reg_handle) + + wazuh_log_monitor.start(timeout=monitor_timeout, error_message=ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT, + callback=generate_monitoring_callback(CB_DATABASE_FULL_COULD_NOT_INSERT_KEY)) + + key_entries = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_COUNT_REGISTRY_ENTRIES), + error_message=ERR_MSG_FIM_REGISTRY_ENTRIES).result() + + assert key_entries == str(get_configuration['metadata']['registries']), ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_values.py b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_values.py new file mode 100644 index 0000000000..23ebd3c025 --- /dev/null +++ b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_key_limit_values.py @@ -0,0 +1,179 @@ +''' +copyright: Copyright (C) 2015-2022, Wazuh Inc. + + + Created by Wazuh, Inc. . + + This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +type: integration + +brief: File Integrity Monitoring (FIM) system watches selected files and triggering alerts + when these files are modified. Specifically, these tests will check if the FIM event + 'maximum number of entries' has the correct value for the monitored entries limit of + the 'registries' option. + The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks configured + files for changes to the checksums, permissions, and ownership. + +tier: 1 + +modules: + - fim + +components: + - agent + +daemons: + - wazuh-syscheckd + +os_platform: + - windows + +os_version: + - Windows 10 + - Windows 8 + - Windows 7 + - Windows Server 2019 + - Windows Server 2016 + - Windows Server 2012 + - Windows Server 2003 + - Windows XP + +references: + - https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html + - https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/syscheck.html#file-limit + +pytest_args: + - fim_mode: + scheduled: implies a scheduled scan + - tier: + 0: Only level 0 tests are performed, they check basic functionalities and are quick to perform. + 1: Only level 1 tests are performed, they check functionalities of medium complexity. + 2: Only level 2 tests are performed, they check advanced functionalities and are slow to perform. + +tags: + - fim_registry_limit +''' +import os +import pytest +from wazuh_testing import LOG_FILE_PATH, global_parameters +from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules import WINDOWS, TIER1 +from wazuh_testing.modules.fim import (registry_parser, KEY_WOW64_64KEY, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, + MONITORED_KEY_2, MONITORED_KEY_3, REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, + RegCloseKey) +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (CB_REGISTRY_LIMIT_VALUE, ERR_MSG_REGISTRY_LIMIT_VALUES, + CB_COUNT_REGISTRY_ENTRIES, ERR_MSG_FIM_REGISTRY_ENTRIES, + ERR_MSG_WRONG_NUMBER_OF_ENTRIES, ERR_MSG_FIM_REGISTRY_ENTRIES, + ERR_MSG_WRONG_REGISTRY_LIMIT_VALUE, CB_COUNT_REGISTRY_ENTRIES) +from wazuh_testing.modules.fim.utils import generate_params, create_registry, modify_registry_value + + +# Marks +pytestmark = [WINDOWS, TIER1] + + +# Variables +test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), + os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2), + os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_3)] +test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) +monitor_timeout = 40 + + +# Configurations +registry_limit_list = ['1', '2', '3'] +conf_params = {'WINDOWS_REGISTRY_1': test_regs[0], + 'WINDOWS_REGISTRY_2': test_regs[1], + 'WINDOWS_REGISTRY_3': test_regs[2]} +params, metadata = generate_params(extra_params=conf_params, + apply_to_all=({'REGISTRIES': registry_limit_elem} for registry_limit_elem + in registry_limit_list), modes=['scheduled']) + +configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') +configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) + + +# Fixtures +@pytest.fixture(scope='module', params=configurations) +def get_configuration(request): + """Get configurations from the module.""" + return request.param + + +# Functions +def extra_configuration_before_yield(): + """Generate registry entries to fill database""" + for key in (MONITORED_KEY, MONITORED_KEY_2, MONITORED_KEY_3): + reg_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], key, KEY_WOW64_64KEY) + reg_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], key, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) + RegCloseKey(reg_handle) + + +# Tests +def test_registry_limit_values(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): + ''' + description: Check if the 'wazuh-syscheckd' daemon detects the value of the 'registries' tag, which corresponds to + the maximum number of entries to monitor from the 'db_entries_limit' option of FIM. For this purpose, + the test will monitor three keys, and the limit for registries to monitor, will change. Then it will + check that the FIM event 'maximum number of entries' generated has the correct value of registries. + Finally, the test will verify that, in the FIM 'entries' event, the number of entries and monitored + values match. + + wazuh_min_version: 4.4.0 + + parameters: + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. + - get_configuration: + type: fixture + brief: Get configurations from the module. + - configure_environment: + type: fixture + brief: Configure a custom environment for testing. + - restart_syscheckd: + type: fixture + brief: Clear the Wazuh logs file and start a new monitor. + + assertions: + - Verify that the FIM event 'maximum number of entries' has the correct value + for the monitored entries limit of the 'registries' option. + + input_description: A test case (fim_registry_limit) is contained in external YAML file (wazuh_conf.yaml) + which includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined + with the limits and the testing registry key to be monitored defined in this module. + + expected_output: + - r".Maximum number of registry values to be monitored: '(\\d+)'" + - r".*Fim registry entries count: '(\\d+)'" + + tags: + - scheduled + ''' + registry_limit = get_configuration['metadata']['registries'] + + for key in (MONITORED_KEY, MONITORED_KEY_2, MONITORED_KEY_3): + reg_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], key, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) + # Add values to registry plus 1 values over the registry limit + for i in range(0, int(registry_limit) + 1): + modify_registry_value(reg_handle, f'value_{i}', REG_SZ, 'added') + + # Look for the file limit value has been configured + registry_limit_value = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_REGISTRY_LIMIT_VALUE), + error_message=ERR_MSG_REGISTRY_LIMIT_VALUES).result() + + # Compare that the value configured is correct + assert registry_limit_value == registry_limit, ERR_MSG_WRONG_REGISTRY_LIMIT_VALUE + + # Get the ammount of entries monitored and assert they are the same as the limit and not over + key_entries = wazuh_log_monitor.start(timeout=monitor_timeout, + callback=generate_monitoring_callback(CB_COUNT_REGISTRY_ENTRIES), + error_message=ERR_MSG_FIM_REGISTRY_ENTRIES).result() + + assert key_entries == registry_limit, ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_capacity_alerts.py b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_capacity_alerts.py similarity index 66% rename from tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_capacity_alerts.py rename to tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_capacity_alerts.py index 718ddbc389..7afb314608 100644 --- a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_capacity_alerts.py +++ b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_capacity_alerts.py @@ -8,9 +8,10 @@ type: integration brief: File Integrity Monitoring (FIM) system watches selected files and triggering alerts - when these files are modified. Specifically, these tests will check if the threshold - set in the 'file_limit' tag generates FIM events when the number of monitored entries - approaches this value. + when these files are modified. Specifically, these tests will check if FIM events are + generated while the database is close to reaching the limit of entries to monitor set + in the 'registry_limit'-'entries' tag. + The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks configured files for changes to the checksums, permissions, and ownership. @@ -44,58 +45,58 @@ pytest_args: - fim_mode: - realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. - whodata: Implies real-time monitoring but adding the 'who-data' information. + scheduled: implies a scheduled scan - tier: 0: Only level 0 tests are performed, they check basic functionalities and are quick to perform. 1: Only level 1 tests are performed, they check functionalities of medium complexity. 2: Only level 2 tests are performed, they check advanced functionalities and are slow to perform. tags: - - fim_registry_file_limit + - fim_registry_limit ''' import os from sys import platform import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params, modify_registry_value, wait_for_scheduled_scan, \ - delete_registry_value, registry_parser, KEY_WOW64_64KEY, callback_detect_end_scan, REG_SZ, KEY_ALL_ACCESS, \ - RegOpenKeyEx, RegCloseKey -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, CB_FILE_LIMIT_CAPACITY, - ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT, ERR_MSG_FIM_INODE_ENTRIES, CB_FILE_LIMIT_BACK_TO_NORMAL, - ERR_MSG_DB_BACK_TO_NORMAL, CB_COUNT_REGISTRY_FIM_ENTRIES, ERR_MSG_WRONG_NUMBER_OF_ENTRIES) +from wazuh_testing import global_parameters, LOG_FILE_PATH +from wazuh_testing.modules.fim import (registry_parser, KEY_WOW64_64KEY, REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, + RegCloseKey, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY) +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (callback_detect_end_scan, CB_REGISTRY_LIMIT_CAPACITY, + ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT, ERR_MSG_DB_BACK_TO_NORMAL, + ERR_MSG_FIM_REGISTRY_ENTRIES, CB_REGISTRY_DB_BACK_TO_NORMAL, + CB_COUNT_REGISTRY_VALUE_ENTRIES, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, + ERR_MSG_SCHEDULED_SCAN_ENDED) +from wazuh_testing.modules import WINDOWS, TIER1 from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules.fim.utils import (generate_params, modify_registry_value, wait_for_scheduled_scan, + delete_registry_value) if platform == 'win32': import pywintypes + # Marks +pytestmark = [WINDOWS, TIER1] -pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # Variables - test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY)] test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) scan_delay = 5 -# Configurations - -file_limit_list = ['100'] +# Configurations +registry_limit_list = ['100'] conf_params = {'WINDOWS_REGISTRY': test_regs[0]} params, metadata = generate_params(extra_params=conf_params, - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list), - modes=['scheduled']) - + apply_to_all=({'REGISTRIES': registry_limit_elem} for registry_limit_elem + in registry_limit_list), modes=['scheduled']) configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) # Fixtures - - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -103,11 +104,9 @@ def get_configuration(request): # Tests - - @pytest.mark.parametrize('percentage', [(80), (90), (0)]) -def test_file_limit_capacity_alert(percentage, get_configuration, configure_environment, restart_syscheckd, - wait_for_fim_start): +def test_registry_limit_capacity_alert(percentage, get_configuration, configure_local_internal_options_module, + configure_environment, restart_syscheckd, wait_for_fim_start): ''' description: Check if the 'wazuh-syscheckd' daemon generates events for different capacity thresholds limits when using the 'schedule' monitoring mode. For this purpose, the test will monitor a key in which @@ -116,7 +115,7 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi the total and when the number is less than that percentage. Finally, the test will verify that, in the FIM 'entries' event, the entries number is one unit more than the number of monitored values. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 @@ -124,12 +123,12 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi - percentage: type: int brief: Percentage of testing values to be created. - - tags_to_apply: - type: set - brief: Run test if matches with a configuration identifier, skip otherwise. - get_configuration: type: fixture brief: Get configurations from the module. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - configure_environment: type: fixture brief: Configure a custom environment for testing. @@ -145,28 +144,28 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi exceeds the established threshold and viceversa. - Verify that FIM 'entries' events contain one unit more than the number of monitored values. - input_description: A test case (file_limit_registry_conf) is contained in external YAML file (wazuh_conf.yaml) + input_description: A test case (fim_registry_limit) is contained in external YAML file (wazuh_conf.yaml) which includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined with the percentages and the testing registry key to be monitored defined in this module. expected_output: - - r'.*Sending FIM event: (.+)$' ('added' events) - - r'.*Sending DB .* full alert.' - - r'.*Sending DB back to normal alert.' - - r'.*Fim registry entries' + - r".*Registry database is (\\d+)% full." + - r".*(The registry database status returns to normal)." + - r".*Fim registry value entries count: '(\\d+)'" tags: - scheduled ''' - limit = int(get_configuration['metadata']['file_limit']) + limit = int(get_configuration['metadata']['registries']) NUM_REGS = int(limit * (percentage / 100)) + 1 if percentage == 0: NUM_REGS = 0 - reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) - + reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | + KEY_WOW64_64KEY) + # Add registry values to fill the database up to alert generating percentage if percentage >= 80: # Percentages 80 and 90 for i in range(NUM_REGS): @@ -179,7 +178,7 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_end_scan, - error_message=ERR_MSG_FIM_INODE_ENTRIES) + error_message=ERR_MSG_SCHEDULED_SCAN_ENDED) for i in range(limit): try: @@ -195,17 +194,17 @@ def test_file_limit_capacity_alert(percentage, get_configuration, configure_envi if percentage >= 80: # Percentages 80 and 90 wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_FILE_LIMIT_CAPACITY), + callback=generate_monitoring_callback(CB_REGISTRY_LIMIT_CAPACITY), error_message=ERR_MSG_DATABASE_PERCENTAGE_FULL_ALERT).result() else: # Database back to normal wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_FILE_LIMIT_BACK_TO_NORMAL), + callback=generate_monitoring_callback(CB_REGISTRY_DB_BACK_TO_NORMAL), error_message=ERR_MSG_DB_BACK_TO_NORMAL).result() - entries = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_COUNT_REGISTRY_FIM_ENTRIES), - error_message=ERR_MSG_FIM_INODE_ENTRIES).result() + value_entries = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_COUNT_REGISTRY_VALUE_ENTRIES), + error_message=ERR_MSG_FIM_REGISTRY_ENTRIES).result() - # We add 1 because of the key created to hold the values - assert entries == str(NUM_REGS + 1), ERR_MSG_WRONG_NUMBER_OF_ENTRIES + # Assert the number of value_entries matches the ammount that was generated. + assert value_entries == str(NUM_REGS), ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_values.py b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_values.py similarity index 50% rename from tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_values.py rename to tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_values.py index 211cc0326e..bd27a86b32 100644 --- a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_values.py +++ b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_limit_values.py @@ -8,11 +8,12 @@ type: integration brief: File Integrity Monitoring (FIM) system watches selected files and triggering alerts - when these files are modified. Specifically, these tests will check if the FIM event - 'maximum number of entries' has the correct value for the monitored entries limit of - the 'file_limit' option. - The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks configured - files for changes to the checksums, permissions, and ownership. + when these files are modified. Specifically, these tests will check that after having a + limit configured for the 'entries' option for 'registry_limit' of syscheck, it will + only monitor values up to the specified limit and any excess will not be monitored. + + The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks + configured files for changes to the checksums, permissions, and ownership. components: - fim @@ -44,54 +45,55 @@ pytest_args: - fim_mode: - realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. - whodata: Implies real-time monitoring but adding the 'who-data' information. + scheduled: implies a scheduled scan - tier: 0: Only level 0 tests are performed, they check basic functionalities and are quick to perform. 1: Only level 1 tests are performed, they check functionalities of medium complexity. 2: Only level 2 tests are performed, they check advanced functionalities and are slow to perform. tags: - - fim_registry_file_limit + - fim_registry_limit ''' -import os, sys + +import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, generate_params, modify_registry_value, registry_parser, KEY_WOW64_64KEY, - REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, RegCloseKey, create_registry) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, CB_FILE_LIMIT_VALUE, - ERR_MSG_FILE_LIMIT_VALUES, CB_COUNT_REGISTRY_FIM_ENTRIES, - ERR_MSG_FIM_INODE_ENTRIES, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, - ERR_MSG_WRONG_FILE_LIMIT_VALUE) + +from wazuh_testing import global_parameters, LOG_FILE_PATH from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules import WINDOWS, TIER1 +from wazuh_testing.fim import (generate_params, modify_registry_value, create_registry) +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, registry_parser, KEY_WOW64_64KEY, + REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, RegCloseKey) +from wazuh_testing.modules.fim.event_monitor import (CB_REGISTRY_LIMIT_VALUE, ERR_MSG_FIM_REGISTRY_VALUE_ENTRIES, + ERR_MSG_REGISTRY_LIMIT_VALUES, CB_COUNT_REGISTRY_VALUE_ENTRIES, + ERR_MSG_WRONG_NUMBER_OF_ENTRIES, ERR_MSG_WRONG_FILE_LIMIT_VALUE) + # Marks +pytestmark = [WINDOWS, TIER1] -pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # Variables - test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY)] test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) monitor_timeout = 40 -# Configurations -file_limit_list = ['1', '1000'] +# Configurations +registry_limit_list = [10] conf_params = {'WINDOWS_REGISTRY': test_regs[0]} params, metadata = generate_params(extra_params=conf_params, - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list), - modes=['scheduled']) - + apply_to_all=({'REGISTRIES': registry_elem} for registry_elem + in registry_limit_list), modes=['scheduled']) configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) # Fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -99,32 +101,35 @@ def get_configuration(request): # Functions - def extra_configuration_before_yield(): """Generate registry entries to fill database""" - reg1_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, KEY_WOW64_64KEY) - - RegCloseKey(reg1_handle) + reg_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, KEY_WOW64_64KEY) + reg_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | + KEY_WOW64_64KEY) + # Add values to registry plus 1 values over the registry limit + for i in range(0, registry_limit_list[0] + 1): + modify_registry_value(reg_handle, f'value_{i}', REG_SZ, 'added') + RegCloseKey(reg_handle) # Tests -@pytest.mark.skip(reason="Blocked by issue wazuh/wazuh #11819") -def test_file_limit_values(get_configuration, configure_environment, restart_syscheckd): +def test_registry_limit_values(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' - description: Check if the 'wazuh-syscheckd' daemon detects the value of the 'entries' tag, which corresponds to - the maximum number of entries to monitor from the 'file_limit' option of FIM. For this purpose, + description: Check if the 'wazuh-syscheckd' daemon detects the value of the 'registries' tag, which corresponds to + the maximum number of entries to monitor from the 'registry_limit' option of FIM. For this purpose, the test will monitor a key in which multiple testing values will be added. Then, it will check if the FIM event 'maximum number of entries' is generated and has the correct value. Finally, the test - will verify that, in the FIM 'entries' event, the number of entries and monitored values match. + will verify that, in the FIM 'values entries' event, the number of entries and monitored values match. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: - - tags_to_apply: - type: set - brief: Run test if matches with a configuration identifier, skip otherwise. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -137,35 +142,31 @@ def test_file_limit_values(get_configuration, configure_environment, restart_sys assertions: - Verify that the FIM event 'maximum number of entries' has the correct value - for the monitored entries limit of the 'file_limit' option. + for the monitored entries limit of the 'registries' option. - input_description: A test case (file_limit_registry_conf) is contained in external YAML file (wazuh_conf.yaml) + input_description: A test case (fim_registry_limit) is contained in external YAML file (wazuh_conf.yaml) which includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined with the limits and the testing registry key to be monitored defined in this module. expected_output: - - r'.*Maximum number of entries to be monitored' - - r'.*Fim registry entries' + - r".*Maximum number of registry values to be monitored: '(\\d+)'" + - r".*Fim registry values entries count: '(\\d+)'" tags: - scheduled ''' - file_limit = get_configuration['metadata']['file_limit'] - reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) - # Add values to registry plus 10 values over the file limit - for i in range(0, int(file_limit) + 10): - modify_registry_value(reg1_handle, f'value_{i}', REG_SZ, 'added') - + registry_limit = get_configuration['metadata']['registries'] + # Look for the file limit value has been configured - file_limit_value = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_FILE_LIMIT_VALUE), - error_message=ERR_MSG_FILE_LIMIT_VALUES).result() + registry_limit_value = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_REGISTRY_LIMIT_VALUE), + error_message=ERR_MSG_REGISTRY_LIMIT_VALUES).result() # Compare that the value configured is correct - assert file_limit_value == get_configuration['metadata']['file_limit'], ERR_MSG_WRONG_FILE_LIMIT_VALUE + assert registry_limit_value == str(registry_limit), ERR_MSG_WRONG_FILE_LIMIT_VALUE # Get the ammount of entries monitored and assert they are the same as the limit and not over - entries = wazuh_log_monitor.start(timeout=monitor_timeout, - callback=generate_monitoring_callback(CB_COUNT_REGISTRY_FIM_ENTRIES), - error_message=ERR_MSG_FIM_INODE_ENTRIES).result() + value_entries = wazuh_log_monitor.start(timeout=monitor_timeout, + callback=generate_monitoring_callback(CB_COUNT_REGISTRY_VALUE_ENTRIES), + error_message=ERR_MSG_FIM_REGISTRY_VALUE_ENTRIES).result() - assert entries == str(get_configuration['metadata']['file_limit']), ERR_MSG_WRONG_NUMBER_OF_ENTRIES + assert value_entries == str(registry_limit), ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_full.py b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_value_limit_full.py similarity index 62% rename from tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_full.py rename to tests/integration/test_fim/test_registry/test_registry_limit/test_registry_value_limit_full.py index c06a425d0e..e3620d9f0a 100644 --- a/tests/integration/test_fim/test_registry/test_registry_file_limit/test_registry_limit_full.py +++ b/tests/integration/test_fim/test_registry/test_registry_limit/test_registry_value_limit_full.py @@ -10,7 +10,7 @@ brief: File Integrity Monitoring (FIM) system watches selected files and triggering alerts when these files are modified. Specifically, these tests will check if FIM events are generated while the database is in 'full database alert' mode for reaching the limit - of entries to monitor set in the 'file_limit' tag. + of entries to monitor set in the 'registry_limit'-'entries' tag. The FIM capability is managed by the 'wazuh-syscheckd' daemon, which checks configured files for changes to the checksums, permissions, and ownership. @@ -51,23 +51,28 @@ 2: Only level 2 tests are performed, they check advanced functionalities and are slow to perform. tags: - - fim_registry_file_limit + - fim_registry_limit ''' import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, generate_params, modify_registry_value, registry_parser, KEY_WOW64_64KEY, \ - REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, RegCloseKey, create_registry -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, CB_FILE_LIMIT_CAPACITY, - ERR_MSG_DATABASE_FULL_ALERT_EVENT, ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT, CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE, - CB_COUNT_REGISTRY_FIM_ENTRIES, ERR_MSG_FIM_INODE_ENTRIES, ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL, - ERR_MSG_WRONG_NUMBER_OF_ENTRIES) +from wazuh_testing import LOG_FILE_PATH, global_parameters from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules import WINDOWS, TIER1 +from wazuh_testing.modules.fim import (registry_parser, KEY_WOW64_64KEY, REG_SZ, KEY_ALL_ACCESS, RegOpenKeyEx, + RegCloseKey, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY) +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options +from wazuh_testing.modules.fim.event_monitor import (CB_REGISTRY_LIMIT_CAPACITY, CB_COUNT_REGISTRY_VALUE_ENTRIES, + CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE, + ERR_MSG_DATABASE_FULL_ALERT, ERR_MSG_WRONG_NUMBER_OF_ENTRIES, + ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT, + ERR_MSG_FIM_REGISTRY_VALUE_ENTRIES, + ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL) +from wazuh_testing.modules.fim.utils import generate_params, modify_registry_value, create_registry # Marks +pytestmark = [WINDOWS, TIER1] -pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # Variables test_reg = os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY) @@ -77,20 +82,18 @@ EXPECTED_DATABES_STATE = "100" monitor_timeout = 40 -# Configurations -file_limit_list = ['10'] +# Configurations +registry_limit_list = ['10'] conf_params = {'WINDOWS_REGISTRY': test_reg} params, metadata = generate_params(extra_params=conf_params, - apply_to_all=({'FILE_LIMIT': file_limit_elem} for file_limit_elem in file_limit_list), - modes=['scheduled']) - + apply_to_all=({'REGISTRIES': registry_limit_elem} for registry_limit_elem + in registry_limit_list), modes=['scheduled']) configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) # Fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -98,11 +101,11 @@ def get_configuration(request): # Functions - def extra_configuration_before_yield(): """Generate registry entries to fill database""" reg1_handle = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, KEY_WOW64_64KEY) - reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) + reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | + KEY_WOW64_64KEY) for i in range(0, NUM_REGS): modify_registry_value(reg1_handle, f'value_{i}', REG_SZ, 'added') @@ -111,23 +114,25 @@ def extra_configuration_before_yield(): # Tests -def test_file_limit_full(get_configuration, configure_environment, restart_syscheckd): +def test_registry_value_limit_full(configure_local_internal_options_module, get_configuration, configure_environment, + restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon generates proper events while the FIM database is in - 'full database alert' mode for reaching the limit of entries to monitor set in the 'file_limit' tag. + 'full database alert' mode for reaching the limit of entries to monitor set in the 'entries' option + of the 'registry_limit' tag. For this purpose, the test will monitor a key in which several testing values will be created until the entry monitoring limit is reached. Then, it will check if the FIM event 'full' is generated when a new testing value is added to the monitored key. Finally, the test will verify that, in the FIM 'entries' event, the number of entries and monitored values match. - wazuh_min_version: 4.2.0 + wazuh_min_version: 4.5.0 tier: 1 parameters: - - tags_to_apply: - type: set - brief: Run test if matches with a configuration identifier, skip otherwise. + - configure_local_internal_options_module: + type: fixture + brief: Set the local_internal_options for the test. - get_configuration: type: fixture brief: Get configurations from the module. @@ -144,35 +149,37 @@ def test_file_limit_full(get_configuration, configure_environment, restart_sysch - Verify that proper FIM events are generated while the database is in 'full database alert' mode. - input_description: A test case (file_limit_registry_conf) is contained in external YAML file (wazuh_conf.yaml) + input_description: A test case (fim_registry_limit) is contained in external YAML file (wazuh_conf.yaml) which includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined with the testing registry key to be monitored defined in this module. expected_output: - - r'.*Sending DB .* full alert.' - - r'.*The DB is full.*' - - r'.*Fim registry entries' + - r".*Registry database is (\\d+)% full." + - r".*Couldn't insert ('.*') entry into DB. The DB is full.*" + - r".*Fim registry values entries count: '(\\d+)'" tags: - scheduled ''' database_state = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_FILE_LIMIT_CAPACITY), - error_message=ERR_MSG_DATABASE_FULL_ALERT_EVENT).result() + callback=generate_monitoring_callback(CB_REGISTRY_LIMIT_CAPACITY), + error_message=ERR_MSG_DATABASE_FULL_ALERT).result() assert database_state == EXPECTED_DATABES_STATE, ERR_MSG_WRONG_VALUE_FOR_DATABASE_FULL - reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) + reg1_handle = RegOpenKeyEx(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], MONITORED_KEY, 0, + KEY_ALL_ACCESS | KEY_WOW64_64KEY) modify_registry_value(reg1_handle, 'value_full', REG_SZ, 'added') RegCloseKey(reg1_handle) - wazuh_log_monitor.start(timeout=monitor_timeout, callback=generate_monitoring_callback(CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE), + wazuh_log_monitor.start(timeout=monitor_timeout, + callback=generate_monitoring_callback(CB_DATABASE_FULL_COULD_NOT_INSERT_VALUE), error_message=ERR_MSG_DATABASE_FULL_COULD_NOT_INSERT) - entries = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=generate_monitoring_callback(CB_COUNT_REGISTRY_FIM_ENTRIES), - error_message=ERR_MSG_FIM_INODE_ENTRIES).result() + value_entries = wazuh_log_monitor.start(timeout=monitor_timeout, + callback=generate_monitoring_callback(CB_COUNT_REGISTRY_VALUE_ENTRIES), + error_message=ERR_MSG_FIM_REGISTRY_VALUE_ENTRIES).result() - assert entries == str(get_configuration['metadata']['file_limit']), ERR_MSG_WRONG_NUMBER_OF_ENTRIES \ No newline at end of file + assert value_entries == str(get_configuration['metadata']['registries']), ERR_MSG_WRONG_NUMBER_OF_ENTRIES diff --git a/tests/integration/test_fim/test_registry/test_registry_multiple_registries/common.py b/tests/integration/test_fim/test_registry/test_registry_multiple_registries/common.py index 5593d274fd..9887bf6576 100644 --- a/tests/integration/test_fim/test_registry/test_registry_multiple_registries/common.py +++ b/tests/integration/test_fim/test_registry/test_registry_multiple_registries/common.py @@ -1,12 +1,14 @@ -# Copyright (C) 2015-2021, Wazuh Inc. +# Copyright (C) 2015-2023, Wazuh Inc. # Created by Wazuh, Inc. . # This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 import os -from wazuh_testing.fim import create_registry, registry_parser, check_time_travel, modify_registry, delete_registry, \ - callback_detect_event, validate_registry_key_event, KEY_WOW64_32KEY, modify_registry_value, delete_registry_value, \ - validate_registry_value_event, callback_value_event, REG_SZ, RegCloseKey +from wazuh_testing.modules.fim import registry_parser, KEY_WOW64_32KEY, REG_SZ, RegCloseKey +from wazuh_testing.modules.fim.classes import validate_registry_event +from wazuh_testing.modules.fim.event_monitor import callback_detect_event, callback_value_event +from wazuh_testing.modules.fim.utils import (create_registry, check_time_travel, modify_registry, delete_registry, + modify_registry_value, delete_registry_value) def multiple_keys_and_entries_keys(num_entries, subkeys, log_monitor, root_key, timeout=10): @@ -39,7 +41,7 @@ def perform_and_validate_events(func): error_message='Did not receive expected "Sending FIM event: ..." event').result() for ev in events: - validate_registry_key_event(ev) + validate_registry_event(ev, is_key=True) perform_and_validate_events(create_registry) perform_and_validate_events(modify_registry) @@ -81,7 +83,7 @@ def perform_and_validate_events(func, content='added', is_delete=False): error_message='Did not receive expected "Sending FIM event: ..." event').result() for ev in events: - validate_registry_value_event(ev) + validate_registry_event(ev, is_key=False) perform_and_validate_events(modify_registry_value) # Create perform_and_validate_events(modify_registry_value, content='modified') # Modify diff --git a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_bigger_file_limit.py b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_bigger_file_limit.py index 1ae893e0e7..d75f059776 100644 --- a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_bigger_file_limit.py +++ b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_bigger_file_limit.py @@ -57,13 +57,12 @@ import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, KEY_WOW64_32KEY, KEY_WOW64_64KEY, generate_params, - calculate_registry_diff_paths, registry_value_create, registry_value_update, - registry_value_delete, registry_parser, create_values_content) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, - SIZE_LIMIT_CONFIGURED_VALUE, ERR_MSG_CONTENT_CHANGES_EMPTY, - ERR_MSG_CONTENT_CHANGES_NOT_EMPTY) +from wazuh_testing import LOG_FILE_PATH, global_parameters +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, KEY_WOW64_32KEY, + KEY_WOW64_64KEY, SIZE_LIMIT_CONFIGURED_VALUE) +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_CONTENT_CHANGES_EMPTY, ERR_MSG_CONTENT_CHANGES_NOT_EMPTY +from wazuh_testing.modules.fim.utils import (generate_params, calculate_registry_diff_paths, registry_value_create, + registry_value_update, registry_value_delete, create_values_content) from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor @@ -73,7 +72,7 @@ # Variables -test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), +test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2)] test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) @@ -93,8 +92,6 @@ configurations_path = os.path.join(test_data_path, "wazuh_registry_report_changes_limits_quota.yaml") configurations = load_wazuh_configurations(configurations_path, __name__, params=params, metadata=metadata) - - # Fixtures @@ -104,15 +101,11 @@ def get_configuration(request): return request.param - @pytest.mark.parametrize("size", [(8192), (32768)]) @pytest.mark.parametrize("key, subkey, arch, value_name", - [ - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_64KEY, "some_value"), - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_32KEY, "some_value"), - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2, KEY_WOW64_64KEY, "some_value"), - ], -) + [(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_64KEY, "some_value"), + (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_32KEY, "some_value"), + (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2, KEY_WOW64_64KEY, "some_value"), ],) def test_disk_quota_values(key, subkey, arch, value_name, size, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ diff --git a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_values.py b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_values.py index 22c9c306fe..cf100fe75e 100644 --- a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_values.py +++ b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_disk_quota/test_registry_disk_quota_values.py @@ -57,15 +57,15 @@ import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, KEY_WOW64_32KEY, KEY_WOW64_64KEY, generate_params, - calculate_registry_diff_paths, registry_value_create, registry_value_update, - registry_value_delete, registry_parser, create_values_content) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, - SIZE_LIMIT_CONFIGURED_VALUE, ERR_MSG_CONTENT_CHANGES_EMPTY, - ERR_MSG_CONTENT_CHANGES_NOT_EMPTY) +from wazuh_testing import LOG_FILE_PATH, global_parameters from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, + SIZE_LIMIT_CONFIGURED_VALUE, KEY_WOW64_32KEY, KEY_WOW64_64KEY) +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_CONTENT_CHANGES_EMPTY, ERR_MSG_CONTENT_CHANGES_NOT_EMPTY +from wazuh_testing.modules.fim.utils import (generate_params, calculate_registry_diff_paths, registry_value_create, + registry_value_update, registry_value_delete, create_values_content) + # Marks @@ -73,7 +73,7 @@ # Variables -test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), +test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2)] test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) @@ -105,12 +105,11 @@ def get_configuration(request): @pytest.mark.parametrize("size", [(4096), (32768)]) @pytest.mark.parametrize("key, subkey, arch, value_name", - [ - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_64KEY, "some_value"), - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_32KEY, "some_value"), - (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2, KEY_WOW64_64KEY, "some_value"), - ], -) + [ + (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_64KEY, "some_value"), + (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, KEY_WOW64_32KEY, "some_value"), + (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY_2, KEY_WOW64_64KEY, "some_value"), + ]) def test_disk_quota_values(key, subkey, arch, value_name, size, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ @@ -120,7 +119,7 @@ def test_disk_quota_values(key, subkey, arch, value_name, size, get_configuratio limit, and increase its size on each test case. Finally, the test will verify that the compressed file has been created, and the related FIM event includes the 'content_changes' field if the value size does not exceed the specified limit and viceversa. - - Case 1, small file - when compressed it will be less than the disk_quota. The file is generated + - Case 1, small file - when compressed it will be less than the disk_quota. The file is generated and the logs have content_changes data. - Case 2, big size - when compressed the file would be bigger than the disk_quota. The file is not generated and the logs should not have content_changes data. diff --git a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_all_limits_disabled.py b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_all_limits_disabled.py index c66437fbf2..9e500ffc94 100644 --- a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_all_limits_disabled.py +++ b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_all_limits_disabled.py @@ -58,14 +58,14 @@ import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, registry_value_create, registry_value_update, registry_value_delete, - KEY_WOW64_32KEY, KEY_WOW64_64KEY, generate_params, calculate_registry_diff_paths, - create_values_content) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, - SIZE_LIMIT_CONFIGURED_VALUE, ERR_MSG_CONTENT_CHANGES_EMPTY) +from wazuh_testing import LOG_FILE_PATH, global_parameters from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, KEY_WOW64_32KEY, + KEY_WOW64_64KEY) +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_CONTENT_CHANGES_EMPTY +from wazuh_testing.modules.fim.utils import (generate_params, calculate_registry_diff_paths, create_values_content, + registry_value_create, registry_value_update, registry_value_delete) # Marks @@ -83,11 +83,11 @@ # Configurations params, metadata = generate_params(modes=['scheduled'], extra_params={'WINDOWS_REGISTRY_1': test_regs[0], - 'WINDOWS_REGISTRY_2': test_regs[1], - 'FILE_SIZE_ENABLED': 'no', - 'FILE_SIZE_LIMIT': '10KB', - 'DISK_QUOTA_ENABLED': 'no', - 'DISK_QUOTA_LIMIT': '4KB'}) + 'WINDOWS_REGISTRY_2': test_regs[1], + 'FILE_SIZE_ENABLED': 'no', + 'FILE_SIZE_LIMIT': '10KB', + 'DISK_QUOTA_ENABLED': 'no', + 'DISK_QUOTA_LIMIT': '4KB'}) configurations_path = os.path.join(test_data_path, 'wazuh_registry_report_changes_limits_quota.yaml') diff --git a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_diff_size_limit_values.py b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_diff_size_limit_values.py index 98f41e2391..1379b1f72a 100644 --- a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_diff_size_limit_values.py +++ b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_diff_size_limit_values.py @@ -57,13 +57,12 @@ import os import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import (LOG_FILE_PATH, registry_value_create, registry_value_update, registry_value_delete, - KEY_WOW64_32KEY, KEY_WOW64_64KEY, generate_params, calculate_registry_diff_paths, - create_values_content) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, - SIZE_LIMIT_CONFIGURED_VALUE, ERR_MSG_CONTENT_CHANGES_EMPTY, - ERR_MSG_CONTENT_CHANGES_NOT_EMPTY) +from wazuh_testing import LOG_FILE_PATH, global_parameters +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, + KEY_WOW64_32KEY, KEY_WOW64_64KEY, SIZE_LIMIT_CONFIGURED_VALUE) +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_CONTENT_CHANGES_EMPTY, ERR_MSG_CONTENT_CHANGES_NOT_EMPTY +from wazuh_testing.modules.fim.utils import (registry_value_create, registry_value_update, registry_value_delete, + generate_params, calculate_registry_diff_paths, create_values_content) from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor diff --git a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_file_size_values.py b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_file_size_values.py index ea41ef7b0e..3cb4d60755 100644 --- a/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_file_size_values.py +++ b/tests/integration/test_fim/test_registry/test_registry_report_changes/test_registry_file_size_values.py @@ -61,15 +61,16 @@ from wazuh_testing.fim import (LOG_FILE_PATH, registry_value_create, registry_value_update, registry_value_delete, KEY_WOW64_32KEY, KEY_WOW64_64KEY, generate_params, calculate_registry_diff_paths, create_values_content) -from wazuh_testing.fim_module import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, - SIZE_LIMIT_CONFIGURED_VALUE, ERR_MSG_CONTENT_CHANGES_EMPTY, - ERR_MSG_CONTENT_CHANGES_NOT_EMPTY) +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, MONITORED_KEY_2, + SIZE_LIMIT_CONFIGURED_VALUE) +from wazuh_testing.modules.fim.event_monitor import ERR_MSG_CONTENT_CHANGES_EMPTY, ERR_MSG_CONTENT_CHANGES_NOT_EMPTY from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.modules import WINDOWS, TIER1 # Marks -pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] +pytestmark = [WINDOWS, TIER1] # Variables @@ -82,10 +83,9 @@ # Configurations params, metadata = generate_params(modes=['scheduled'], extra_params={'WINDOWS_REGISTRY_1': test_regs[0], - 'WINDOWS_REGISTRY_2': test_regs[1], - 'FILE_SIZE_ENABLED': 'yes', - 'FILE_SIZE_LIMIT': '10KB' - }) + 'WINDOWS_REGISTRY_2': test_regs[1], + 'FILE_SIZE_ENABLED': 'yes', + 'FILE_SIZE_LIMIT': '10KB'}) configurations_path = os.path.join(test_data_path, 'wazuh_registry_file_size_values.yaml') @@ -115,9 +115,9 @@ def test_file_size_values(key, subkey, arch, value_name, size, get_configuration its size on each test case. Finally, the test will verify that the compressed 'diff' file has been created, and the related FIM event includes the 'content_changes' field if the value size does not exceed the specified limit and vice versa. - - Case 1, small size - The file is smaller than the file_limit configured, the diff_file is + - Case 1, small size - The file is smaller than the file_limit configured, the diff_file is generated and there is content_changes information - - Case 2, big size - The file is smaller than the file_limit configured,sp the diff_file is + - Case 2, big size - The file is smaller than the file_limit configured, so the diff_file is not generated and the logs should not have content_changes data. wazuh_min_version: 4.2.0 @@ -189,7 +189,7 @@ def report_changes_validator_diff(event): callback_test = report_changes_validator_no_diff else: callback_test = report_changes_validator_diff - + # Create the value inside the key - we do it here because it key or arch is not known before the test launches registry_value_create(key, subkey, wazuh_log_monitor, arch=arch, value_list=values, wait_for_scan=True, scan_delay=scan_delay, min_timeout=global_parameters.default_timeout, triggers_event=True) diff --git a/tests/integration/test_fim/test_synchronization/conftest.py b/tests/integration/test_fim/test_synchronization/conftest.py index 5782984fa5..c8838dbd40 100644 --- a/tests/integration/test_fim/test_synchronization/conftest.py +++ b/tests/integration/test_fim/test_synchronization/conftest.py @@ -1,52 +1,51 @@ -# Copyright (C) 2015-2021, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -import pytest - -from wazuh_testing.fim import LOG_FILE_PATH, detect_initial_scan, detect_realtime_start, detect_whodata_start -from wazuh_testing.tools.file import truncate_file -from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing.tools.services import control_service - - -@pytest.fixture(scope='module') -def restart_syscheckd(get_configuration, request): - """ - Reset ossec.log and start a new monitor. - """ - control_service('stop', daemon='wazuh-syscheckd') - truncate_file(LOG_FILE_PATH) - file_monitor = FileMonitor(LOG_FILE_PATH) - setattr(request.module, 'wazuh_log_monitor', file_monitor) - control_service('start', daemon='wazuh-syscheckd') - - -@pytest.fixture(scope='module') -def wait_for_fim_start(get_configuration, request): - """ - Wait for realtime start, whodata start or end of initial FIM scan. - """ - file_monitor = getattr(request.module, 'wazuh_log_monitor') - mode_key = 'fim_mode' if 'fim_mode2' not in get_configuration['metadata'] else 'fim_mode2' - - try: - if get_configuration['metadata'][mode_key] == 'realtime': - detect_realtime_start(file_monitor) - elif get_configuration['metadata'][mode_key] == 'whodata': - detect_whodata_start(file_monitor) - else: # scheduled - detect_initial_scan(file_monitor) - except KeyError: - detect_initial_scan(file_monitor) - - -@pytest.fixture(scope='module') -def wait_for_fim_start_sync_disabled(request): - """ - Wait for en of initial FIM scan. - - If detect_realtime_start is used, the synchronization event is skipped and the test fails. - """ - file_monitor = getattr(request.module, 'wazuh_log_monitor') - detect_initial_scan(file_monitor) +# Copyright (C) 2015-2022, Wazuh Inc. + +# Created by Wazuh, Inc. . +# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +import pytest + +from wazuh_testing.fim import LOG_FILE_PATH, detect_initial_scan, detect_realtime_start, detect_whodata_start +from wazuh_testing.tools.file import truncate_file +from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.tools.services import control_service + + +@pytest.fixture(scope='module') +def restart_syscheckd(get_configuration, request): + """ + Reset ossec.log and start a new monitor. + """ + control_service('stop', daemon='wazuh-syscheckd') + truncate_file(LOG_FILE_PATH) + file_monitor = FileMonitor(LOG_FILE_PATH) + setattr(request.module, 'wazuh_log_monitor', file_monitor) + control_service('start', daemon='wazuh-syscheckd') + + +@pytest.fixture(scope='module') +def wait_for_fim_start(get_configuration, request): + """ + Wait for realtime start, whodata start or end of initial FIM scan. + """ + file_monitor = getattr(request.module, 'wazuh_log_monitor') + mode_key = 'fim_mode' if 'fim_mode2' not in get_configuration['metadata'] else 'fim_mode2' + + try: + if get_configuration['metadata'][mode_key] == 'realtime': + detect_realtime_start(file_monitor) + elif get_configuration['metadata'][mode_key] == 'whodata': + detect_whodata_start(file_monitor) + else: # scheduled + detect_initial_scan(file_monitor) + except KeyError: + detect_initial_scan(file_monitor) + + +@pytest.fixture(scope='module') +def wait_for_fim_start_sync(request): + """ + Wait for the sync initial FIM scan. + """ + file_monitor = getattr(request.module, 'wazuh_log_monitor') + detect_initial_scan(file_monitor) diff --git a/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_overlap.yaml b/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_overlap.yaml new file mode 100644 index 0000000000..10d7e317f2 --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_overlap.yaml @@ -0,0 +1,38 @@ +- sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 20 + - directories: + value: MONITORED_DIR + attributes: + - check_all: 'yes' + - synchronization: + elements: + - interval: + value: INTERVAL + - response_timeout: + value: RESPONSE_TIMEOUT + - max_interval: + value: MAX_INTERVAL + - max_eps: + value: 1 + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_time.yaml b/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_time.yaml new file mode 100644 index 0000000000..10d7e317f2 --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/data/configuration_template/configuration_sync_time.yaml @@ -0,0 +1,38 @@ +- sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 20 + - directories: + value: MONITORED_DIR + attributes: + - check_all: 'yes' + - synchronization: + elements: + - interval: + value: INTERVAL + - response_timeout: + value: RESPONSE_TIMEOUT + - max_interval: + value: MAX_INTERVAL + - max_eps: + value: 1 + + - section: sca + elements: + - enabled: + value: 'no' + + - section: rootcheck + elements: + - disabled: + value: 'yes' + + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_overlap.yaml b/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_overlap.yaml new file mode 100644 index 0000000000..9ece9baffd --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_overlap.yaml @@ -0,0 +1,111 @@ +- name: Doubled sync_interval smaller than max_interval + description: Detect that sync_interval is doubled when a new sync tries to start before sync has ended + configuration_parameters: + INTERVAL: 3 + RESPONSE_TIMEOUT: 3 + MAX_INTERVAL: 20 + metadata: + interval: 3 + response_timeout: 3 + doubled_times: 1 + max_interval: 20 + files: 5 + lower: false + +- name: Doubled sync_interval capped at max_interval + description: Detect that when doubled sync_interval will not exceed max_interval + configuration_parameters: + INTERVAL: 5 + RESPONSE_TIMEOUT: 5 + MAX_INTERVAL: 8 + metadata: + interval: 5 + response_timeout: 5 + doubled_times: 1 + max_interval: 8 + files: 10 + lower: false + +- name: response_timeout lower than interval + description: Detect behavior when response_timeout is lower than interval + configuration_parameters: + INTERVAL: 5 + RESPONSE_TIMEOUT: 3 + MAX_INTERVAL: 8 + metadata: + interval: 5 + response_timeout: 3 + doubled_times: 1 + max_interval: 8 + files: 10 + lower: false + +- name: Invalid response_timeout value + description: Check behavior when invalid (string) value is configured for response_timeout + configuration_parameters: + INTERVAL: 3 + RESPONSE_TIMEOUT: invalid + MAX_INTERVAL: 20 + metadata: + interval: 3 + response_timeout: invalid + doubled_times: 3 + max_interval: 20 + files: 5 + lower: false + +- name: Invalid response_timeout value (negative) + description: Check behavior when invalid (negative) value is configured for response_timeout + configuration_parameters: + INTERVAL: 3 + RESPONSE_TIMEOUT: -1 + MAX_INTERVAL: 20 + metadata: + interval: 3 + response_timeout: -1 + doubled_times: 3 + max_interval: 20 + files: 5 + lower: false + +- name: Invalid max_interval value (String) + description: Check behavior when invalid (string) value is configured for max_interval + configuration_parameters: + INTERVAL: 3 + RESPONSE_TIMEOUT: 5 + MAX_INTERVAL: invalid + metadata: + interval: 3 + response_timeout: 5 + doubled_times: 1 + max_interval: invalid + files: 5 + lower: false + +- name: Invalid max_interval value (Lower than interval) + description: Detect when max_interval is lower than interval, the value is set to be equal to interval + configuration_parameters: + INTERVAL: 5 + RESPONSE_TIMEOUT: 3 + MAX_INTERVAL: 3 + metadata: + interval: 5 + response_timeout: 3 + doubled_times: 1 + max_interval: 3 + files: 5 + lower: true + +- name: Invalid max_interval value (negative value) + description: Detect when max_interval is negative, max interval is not set + configuration_parameters: + INTERVAL: 5 + RESPONSE_TIMEOUT: 3 + MAX_INTERVAL: -1 + metadata: + interval: 5 + response_timeout: 3 + doubled_times: 1 + max_interval: invalid + files: 5 + lower: false diff --git a/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_time.yaml b/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_time.yaml new file mode 100644 index 0000000000..de3e90660a --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/data/test_cases/cases_sync_time.yaml @@ -0,0 +1,11 @@ +- name: Short sync + description: Check behavior when sync is shorter than interval and max_interval + configuration_parameters: + INTERVAL: 10 + RESPONSE_TIMEOUT: 5 + MAX_INTERVAL: 10 + metadata: + interval: 10 + response_timeout: 5 + max_interval: 10 + files: 3 diff --git a/tests/integration/test_fim/test_synchronization/data/wazuh_conf_integrity_scan_win32.yaml b/tests/integration/test_fim/test_synchronization/data/wazuh_conf_integrity_scan_win32.yaml index 0d18d85e38..061a59341f 100644 --- a/tests/integration/test_fim/test_synchronization/data/wazuh_conf_integrity_scan_win32.yaml +++ b/tests/integration/test_fim/test_synchronization/data/wazuh_conf_integrity_scan_win32.yaml @@ -1,19 +1,33 @@ ---- -# conf 1 - tags: - - synchronize_events_conf + - apply_to_modules: - - test_synchronize_integrity_win32 + - test_synchronize_integrity_win32 sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - windows_registry: - value: TEST_REGS - attributes: - - arch: "both" + - section: syscheck + elements: + - disabled: + value: 'no' + - frequency: + value: 40 + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - windows_registry: + value: TEST_REGS + attributes: + - arch: both + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_synchronization/data/wazuh_conf_registry_responses_win32.yaml b/tests/integration/test_fim/test_synchronization/data/wazuh_conf_registry_responses_win32.yaml index 4f97ae7ef4..25c437caea 100644 --- a/tests/integration/test_fim/test_synchronization/data/wazuh_conf_registry_responses_win32.yaml +++ b/tests/integration/test_fim/test_synchronization/data/wazuh_conf_registry_responses_win32.yaml @@ -1,22 +1,35 @@ ---- # conf 1 - tags: - - registry_sync_responses + - registry_sync_responses apply_to_modules: - - test_registry_responses_win32 + - test_registry_responses_win32 sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - windows_registry: - value: WINDOWS_REGISTRY - attributes: - - check_mtime: 'no' - - arch: '64bit' - - synchronization: - elements: - - interval: - value: SYNC_INTERVAL - - max_interval: - value: SYNC_INTERVAL + - section: syscheck + elements: + - disabled: + value: 'no' + - windows_registry: + value: WINDOWS_REGISTRY + attributes: + - check_mtime: 'no' + - arch: 64bit + - synchronization: + elements: + - interval: + value: SYNC_INTERVAL + - max_interval: + value: SYNC_INTERVAL + - section: sca + elements: + - enabled: + value: 'no' + - section: rootcheck + elements: + - disabled: + value: 'yes' + - section: wodle + attributes: + - name: syscollector + elements: + - disabled: + value: 'yes' diff --git a/tests/integration/test_fim/test_synchronization/data/wazuh_sync_conf_win32.yaml b/tests/integration/test_fim/test_synchronization/data/wazuh_sync_conf_win32.yaml index 16f5c5b221..b083453bde 100644 --- a/tests/integration/test_fim/test_synchronization/data/wazuh_sync_conf_win32.yaml +++ b/tests/integration/test_fim/test_synchronization/data/wazuh_sync_conf_win32.yaml @@ -1,27 +1,26 @@ - # Configuration for sync disabled - tags: - - sync_disabled + - sync_disabled apply_to_modules: - - test_sync_disabled_win32 - - test_sync_enabled_win32 - - test_sync_registry_enabled_win32 + - test_sync_disabled_win32 + - test_sync_enabled_win32 + - test_sync_registry_enabled_win32 sections: - - section: syscheck - elements: - - disabled: - value: 'no' - - synchronization: - elements: - - enabled: - value: SYNCHRONIZATION_ENABLED - - registry_enabled: - value: SYNCHRONIZATION_REGISTRY_ENABLED - - directories: - value: TEST_DIRECTORIES - attributes: - - FIM_MODE - - windows_registry: - value: TEST_REGISTRIES - attributes: - - arch: "both" \ No newline at end of file + - section: syscheck + elements: + - disabled: + value: 'no' + - synchronization: + elements: + - enabled: + value: SYNCHRONIZATION_ENABLED + - registry_enabled: + value: SYNCHRONIZATION_REGISTRY_ENABLED + - directories: + value: TEST_DIRECTORIES + attributes: + - FIM_MODE + - windows_registry: + value: TEST_REGISTRIES + attributes: + - arch: both diff --git a/tests/integration/test_fim/test_synchronization/test_registry_responses_win32.py b/tests/integration/test_fim/test_synchronization/test_registry_responses_win32.py index ad8a1ec3bf..d4254cd359 100644 --- a/tests/integration/test_fim/test_synchronization/test_registry_responses_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_registry_responses_win32.py @@ -56,20 +56,18 @@ ''' import os import pytest -from wazuh_testing import DATA, WAZUH_SERVICES_START -from wazuh_testing.fim import (generate_params, create_registry, modify_registry_value, registry_parser, - KEY_WOW64_64KEY, REG_SZ) +from wazuh_testing import LOG_FILE_PATH, DATA, WAZUH_SERVICES_START from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.monitoring import FileMonitor from wazuh_testing.tools.services import control_service -from wazuh_testing.fim_module.fim_synchronization import find_value_in_event_list, get_sync_msgs -from wazuh_testing.fim_module.fim_variables import (SCHEDULE_MODE, WINDOWS_REGISTRY, SYNC_INTERVAL, - SYNC_INTERVAL_VALUE, YAML_CONF_REGISTRY_RESPONSE, - WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY) -from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options - +from wazuh_testing.modules.fim.utils import (find_value_in_event_list, get_sync_msgs, generate_params, create_registry, + modify_registry_value) +from wazuh_testing.modules.fim import (FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS, SCHEDULED_MODE, WINDOWS_REGISTRY, + SYNC_INTERVAL, SYNC_INTERVAL_VALUE, YAML_CONF_REGISTRY_RESPONSE, REG_SZ, + WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, registry_parser, KEY_WOW64_64KEY) +from wazuh_testing.modules.fim.event_monitor import detect_initial_scan # Marks - pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] @@ -77,16 +75,16 @@ test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), DATA) configurations_path = os.path.join(test_data_path, YAML_CONF_REGISTRY_RESPONSE) conf_params = {WINDOWS_REGISTRY: os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY), - SYNC_INTERVAL: SYNC_INTERVAL_VALUE} + SYNC_INTERVAL: 10} # configurations -conf_params, conf_metadata = generate_params(extra_params=conf_params, modes=[SCHEDULE_MODE]) +conf_params, conf_metadata = generate_params(extra_params=conf_params, modes=[SCHEDULED_MODE]) configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_metadata) +local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS # fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -94,8 +92,6 @@ def get_configuration(request): # tests - - @pytest.mark.parametrize('key_name', [':subkey1', 'subkey2:', ':subkey3:']) @pytest.mark.parametrize('value_name', [':value1', 'value2:', ':value3:']) def test_registry_sync_after_restart(key_name, value_name, configure_local_internal_options_module, @@ -147,7 +143,6 @@ def test_registry_sync_after_restart(key_name, value_name, configure_local_inter tags: - scheduled - - time_travel ''' key_path = os.path.join(MONITORED_KEY, key_name) value_path = os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, key_path, value_name) @@ -157,9 +152,9 @@ def test_registry_sync_after_restart(key_name, value_name, configure_local_inter modify_registry_value(key_handle, value_name, REG_SZ, 'This is a test with syscheckd down.') control_service(WAZUH_SERVICES_START) + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + detect_initial_scan(wazuh_log_monitor) + events = get_sync_msgs(timeout=SYNC_INTERVAL_VALUE) - events = get_sync_msgs(SYNC_INTERVAL_VALUE) - - assert find_value_in_event_list( - os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, key_path), value_name, - events) is not None, f"No sync event was found for {value_path}" + assert find_value_in_event_list(os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, key_path), value_name, + events) is not None, f"No sync event was found for {value_path}" diff --git a/tests/integration/test_fim/test_synchronization/test_sync_disabled.py b/tests/integration/test_fim/test_synchronization/test_sync_disabled.py index 3ee4205612..b5589ef636 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_disabled.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_disabled.py @@ -94,7 +94,7 @@ def get_configuration(request): # Tests -def test_sync_disabled(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): +def test_sync_disabled(get_configuration, configure_environment, install_audit, restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon uses the value of the 'enabled' tag to disable the file synchronization. For this purpose, the test will monitor a testing directory, @@ -112,12 +112,12 @@ def test_sync_disabled(get_configuration, configure_environment, restart_syschec - configure_environment: type: fixture brief: Configure a custom environment for testing. + - install_audit: + type: fixture + brief: install audit to check whodata. - restart_syscheckd: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. - - wait_for_fim_start: - type: fixture - brief: Wait for realtime start, whodata start, or end of initial FIM scan. assertions: - Verify that no FIM 'integrity' event is generated when the value diff --git a/tests/integration/test_fim/test_synchronization/test_sync_disabled_win32.py b/tests/integration/test_fim/test_synchronization/test_sync_disabled_win32.py index 33910aa42c..f8d4d82ac5 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_disabled_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_disabled_win32.py @@ -57,17 +57,18 @@ import os import pytest -from wazuh_testing import global_parameters, DATA -from wazuh_testing.fim import LOG_FILE_PATH, generate_params +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR, DATA from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module.fim_variables import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, - YAML_CONF_SYNC_WIN32, TEST_DIRECTORIES, TEST_REGISTRIES, - SYNCHRONIZATION_ENABLED, CB_INTEGRITY_CONTROL_MESSAGE, - SYNCHRONIZATION_REGISTRY_ENABLED) -# Marks +from wazuh_testing.modules.fim import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, TEST_DIRECTORIES, + YAML_CONF_SYNC_WIN32, TEST_REGISTRIES, SYNCHRONIZATION_ENABLED, + SYNCHRONIZATION_REGISTRY_ENABLED) +from wazuh_testing.modules.fim.event_monitor import CB_INTEGRITY_CONTROL_MESSAGE +from wazuh_testing.modules.fim.utils import generate_params +# Marks pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # variables @@ -94,16 +95,21 @@ # fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" return request.param -# Tests +@pytest.fixture(scope='module') +def create_a_file(get_configuration): + """Create a file previous to restart syscheckd""" + create_file(REGULAR, test_directories[0], 'test_file.txt') + -def test_sync_disabled(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start_sync_disabled): +# Tests +def test_sync_disabled(get_configuration, configure_environment, create_a_file, restart_syscheckd, + wait_for_fim_start_sync): ''' description: Check if the 'wazuh-syscheckd' daemon uses the value of the 'enabled' tag to start/stop the file/registry synchronization. For this purpose, the test will monitor a directory/key. @@ -124,7 +130,7 @@ def test_sync_disabled(get_configuration, configure_environment, restart_syschec - restart_syscheckd: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. - - wait_for_fim_start_sync_disabled: + - wait_for_fim_start_sync: type: fixture brief: Wait for end of initial FIM scan. assertions: diff --git a/tests/integration/test_fim/test_synchronization/test_sync_enabled_win32.py b/tests/integration/test_fim/test_synchronization/test_sync_enabled_win32.py index 13fba328cd..280a2c6045 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_enabled_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_enabled_win32.py @@ -58,14 +58,18 @@ import os import pytest -from wazuh_testing import global_parameters, DATA -from wazuh_testing.fim import LOG_FILE_PATH, generate_params, callback_detect_integrity_event +from wazuh_testing import global_parameters, DATA, LOG_FILE_PATH, REGULAR from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing.fim_module.fim_variables import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, - YAML_CONF_SYNC_WIN32, TEST_DIRECTORIES, TEST_REGISTRIES, - SYNCHRONIZATION_ENABLED, SYNCHRONIZATION_REGISTRY_ENABLED) +from wazuh_testing.modules.fim.utils import generate_params +from wazuh_testing.modules.fim import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, + YAML_CONF_SYNC_WIN32, TEST_DIRECTORIES, TEST_REGISTRIES, + SYNCHRONIZATION_ENABLED, SYNCHRONIZATION_REGISTRY_ENABLED) +from wazuh_testing.modules.fim.event_monitor import (callback_detect_registry_integrity_event, + callback_detect_file_integrity_event) + # Marks pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] @@ -94,16 +98,21 @@ # fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" return request.param -# Tests +@pytest.fixture(scope='module') +def create_a_file(get_configuration): + """Create a file previous to restart syscheckd""" + create_file(REGULAR, test_directories[0], 'testfile') -def test_sync_disabled(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start_sync_disabled): + +# Tests +def test_sync_enabled(get_configuration, configure_environment, create_a_file, restart_syscheckd, + wait_for_fim_start_sync): ''' description: Check if the 'wazuh-syscheckd' daemon uses the value of the 'enabled' tag to start/stop the file/registry synchronization. For this purpose, the test will monitor a directory/key. @@ -121,10 +130,13 @@ def test_sync_disabled(get_configuration, configure_environment, restart_syschec - configure_environment: type: fixture brief: Configure a custom environment for testing. + - create_a_file: + type: fixture + brief: It creates a file. It verifies that also appear the files created when is enabled. - restart_syscheckd: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. - - wait_for_fim_start_sync_disabled: + - wait_for_fim_start_sync: type: fixture brief: Wait for end of initial FIM scan. @@ -141,18 +153,15 @@ def test_sync_disabled(get_configuration, configure_environment, restart_syschec tags: - scheduled - - time_travel - - realtime - - who_data ''' # The file synchronization event should be triggered event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, - callback=callback_detect_integrity_event, update_position=True).result() + callback=callback_detect_file_integrity_event, update_position=True).result() - assert event['component'] == 'fim_file', 'Wrong event component' + assert event['component'] == 'fim_file', 'Did not recieve the expected "fim_file" event' # The registry synchronization event should be triggered event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, update_position=True, - callback=callback_detect_integrity_event).result() + callback=callback_detect_registry_integrity_event).result() - assert event['component'] == 'fim_registry', 'Wrong event component' + assert event['component'] == 'fim_registry_key', 'Did not recieve the expected "fim_registry_key" event' diff --git a/tests/integration/test_fim/test_synchronization/test_sync_interval.py b/tests/integration/test_fim/test_synchronization/test_sync_interval.py index a3a1b92c8e..90448e4523 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_interval.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_interval.py @@ -94,7 +94,7 @@ def get_configuration(request): # Tests - +@pytest.mark.skip(reason="It will be blocked by #2174, when it was solve we can enable again this test") def test_sync_interval(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): ''' description: Check if the 'wazuh-syscheckd' daemon performs the file synchronization at the intervals diff --git a/tests/integration/test_fim/test_synchronization/test_sync_interval_win32.py b/tests/integration/test_fim/test_synchronization/test_sync_interval_win32.py index 60ce6ff030..80a41801f1 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_interval_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_interval_win32.py @@ -155,7 +155,7 @@ def test_sync_interval(get_configuration, configure_environment, restart_syschec # This should fail as we are only advancing half the time needed for synchronization to occur except TimeoutError: - pytest.xfail("Expected fail due to issue: https://github.com/wazuh/wazuh-qa/issues/947 ") + pytest.skip("Expected fail due to issue: https://github.com/wazuh/wazuh-qa/issues/947 ") check_time_travel(True, interval=interval / 2) try: diff --git a/tests/integration/test_fim/test_synchronization/test_sync_overlap.py b/tests/integration/test_fim/test_synchronization/test_sync_overlap.py new file mode 100644 index 0000000000..97ffbd0423 --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/test_sync_overlap.py @@ -0,0 +1,208 @@ +''' +copyright: Copyright (C) 2015-2022, Wazuh Inc. + + Created by Wazuh, Inc. . + + This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +type: integration + +brief: Check if the 'wazuh-syscheckd' daemon is performing a synchronization at the intervals specified in the + configuration, using the 'interval' tag, if a new synchronization is fired, and the last sync message has been + recieved in less time than 'response_timeout, the sync interval is doubled. + The new value for interval cannot be higher than max_interval option. After a new sync interval is tried and the + last message was recieved in a time that is higher than response_timeout, the sync interval value is returned to + the configured value. + +components: + - fim + +suite: synchronization + +targets: + - agent + - manager + +daemons: + - wazuh-syscheckd + +os_platform: + - linux + - windows + +os_version: + - Arch Linux + - Amazon Linux 2 + - Amazon Linux 1 + - CentOS 8 + - CentOS 7 + - Debian Buster + - Red Hat 8 + - Ubuntu Focal + - Ubuntu Bionic + - Windows Server 2019 + +references: + - https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html + - https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/syscheck.html#synchronization + +pytest_args: + - fim_mode: + scheduled: monitoring is done at a preconfigured interval. + realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. + whodata: Implies real-time monitoring but adding the 'who-data' information. + - tier: + 0: Basic functionalities and quick to perform. + 1: Functionalities of medium complexity. + 2: Advanced functionalities and are slow to perform. + +tags: + - fim_synchronization +''' +import os +import pytest + +from wazuh_testing import global_parameters +from wazuh_testing.tools import LOG_FILE_PATH, configuration +from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback +from wazuh_testing.modules import TIER1, AGENT, SERVER +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS, MONITORED_DIR_1 +from wazuh_testing.modules.fim.event_monitor import (callback_detect_synchronization, CB_INVALID_CONFIG_VALUE, + ERR_MSG_INVALID_CONFIG_VALUE, ERR_MSG_FIM_SYNC_NOT_DETECTED, + CB_SYNC_SKIPPED, ERR_MSG_SYNC_SKIPPED_EVENT, + CB_SYNC_INTERVAL_RESET, ERR_MSG_SYNC_INTERVAL_RESET_EVENT) + +# Marks +pytestmark = [AGENT, SERVER, TIER1] + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +test_cases_path = os.path.join(TEST_CASES_PATH, 'cases_sync_overlap.yaml') +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_sync_overlap.yaml') + +# Test configurations +configuration_parameters, configuration_metadata, test_case_ids = configuration.get_test_cases_data(test_cases_path) +# This assigns the monitored dir during runtime depending on the OS, cannot be added to yaml +for count, value in enumerate(configuration_parameters): + configuration_parameters[count]['MONITORED_DIR'] = MONITORED_DIR_1 +configurations = configuration.load_configuration_template(configurations_path, configuration_parameters, + configuration_metadata) + +# Variables +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) +local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS + + +# Tests +@pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) +@pytest.mark.parametrize('files_number', [configuration_metadata[0]['files']]) +def test_sync_overlap(configuration, metadata, set_wazuh_configuration, configure_local_internal_options_function, + create_files_in_folder, restart_syscheck_function, wait_fim_start): + ''' + description: Check if the 'wazuh-syscheckd' daemon is performing a synchronization at the interval specified in the + configuration, using the 'interval' tag, if a new synchronization is fired, and the last sync message + has been recieved in less time than 'response_timeout, the sync interval is doubled. + The new value for interval cannot be higher than max_interval option. After a new sync interval is + tried and the last message was recieved in a time that is higher than response_timeout, the sync + interval value is returned to the configured value. + + test_phases: + - Create a folder with a number of files inside. + - Restart syscheckd. + - Check that a sync interval started. + - Check that next sync is skipped and interval value is doubled + - Check that interval value is returned to configured value after successful sync + + wazuh_min_version: 4.5.0 + + tier: 1 + + parameters: + - configuration: + type: dict + brief: Configuration values for ossec.conf. + - metadata: + type: dict + brief: Test case data. + - set_wazuh_configuration: + type: fixture + brief: Set ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Set local_internal_options.conf file. + - create_files_in_folder: + type: fixture + brief: create files in monitored folder, and delete them after the test. + - restart_syscheck_function: + type: fixture + brief: restart syscheckd daemon, and truncate the ossec.log. + - wait_for_fim_start_function: + type: fixture + brief: check that the starting fim scan is detected. + + assertions: + - Verify that the new value for interval when doubled is equal or lower to max_interval. + + input_description: A test case (sync_interval) is contained in external YAML file (cases_sync_overlap.yaml) which + includes configuration settings for the 'wazuh-syscheckd' daemon. That is combined with + the interval periods and the testing directory to be monitored defined in this module. + + expected_output: + - r'Initializing FIM Integrity Synchronization check' + - r"*Sync still in progress. Skipped next sync and increased interval.*'(\\d+)s'" + - r".*Previous sync was successful. Sync interval is reset to: '(\\d+)s'" + + tags: + - scheduled + ''' + + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + # If config is invalid, check that invalid config value message appers + if metadata['response_timeout'] == 'invalid' or metadata['max_interval'] == 'invalid': + wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=generate_monitoring_callback(CB_INVALID_CONFIG_VALUE), + error_message=ERR_MSG_INVALID_CONFIG_VALUE, + update_position=True).result() + + # Wait for new sync + wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_synchronization, + error_message=ERR_MSG_FIM_SYNC_NOT_DETECTED, update_position=True).result() + + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + # Check if response_timeout has elapsed, and sync is still running, the sync interval is doubled + interval = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*5, + callback=generate_monitoring_callback(CB_SYNC_SKIPPED), + accum_results=metadata['doubled_times'], + error_message=ERR_MSG_SYNC_SKIPPED_EVENT, update_position=True).result() + + if metadata['doubled_times'] > 1: + new_interval = interval[-1] + else: + new_interval = interval + + # Check interval when doubled is not higher than max interval, if max_interval is higher than configured interval + # Check interval when doubled is equal than configured interval, if max_interval is lower than configured interval + if metadata['max_interval'] != 'invalid': + if not metadata['lower']: + assert int(new_interval) <= int(metadata['max_interval']), f"Invalid value for interval: {new_interval},\ + cannot be more than MAX_INTERVAL:\ + {metadata['max_interval']}" + else: + assert int(new_interval) <= int(metadata['interval']), f"Invalid value for interval {new_interval}, cannot\ + be more than interval: {metadata['interval']}" + + # Check when sync ends sync_interval is returned to normal after response_timeout since last message. + if not metadata['lower']: + result = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*10, + callback=generate_monitoring_callback(CB_SYNC_INTERVAL_RESET), + error_message=ERR_MSG_SYNC_INTERVAL_RESET_EVENT, + update_position=True).result() + + assert int(result) == int(metadata['interval']), f"Invalid value for interval: {result}, it should be reset to\ + interval: {metadata['interval']}" diff --git a/tests/integration/test_fim/test_synchronization/test_sync_registry_enabled_win32.py b/tests/integration/test_fim/test_synchronization/test_sync_registry_enabled_win32.py index 29800e62e4..c566cbfaeb 100644 --- a/tests/integration/test_fim/test_synchronization/test_sync_registry_enabled_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_sync_registry_enabled_win32.py @@ -58,17 +58,18 @@ import os import pytest -from wazuh_testing import global_parameters, DATA -from wazuh_testing.fim import LOG_FILE_PATH, generate_params +from wazuh_testing import global_parameters, DATA, LOG_FILE_PATH from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor, generate_monitoring_callback -from wazuh_testing.fim_module.fim_variables import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, - YAML_CONF_SYNC_WIN32, TEST_DIRECTORIES, TEST_REGISTRIES, - SYNCHRONIZATION_ENABLED, CB_INTEGRITY_CONTROL_MESSAGE, - SYNCHRONIZATION_REGISTRY_ENABLED) -# Marks +from wazuh_testing.modules.fim import (TEST_DIR_1, WINDOWS_HKEY_LOCAL_MACHINE, MONITORED_KEY, YAML_CONF_SYNC_WIN32, + TEST_DIRECTORIES, TEST_REGISTRIES, SYNCHRONIZATION_ENABLED, + SYNCHRONIZATION_REGISTRY_ENABLED) +from wazuh_testing.modules.fim.event_monitor import CB_INTEGRITY_CONTROL_MESSAGE +from wazuh_testing.modules.fim.utils import generate_params + +# Marks pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # variables @@ -104,7 +105,7 @@ def get_configuration(request): # Tests -def test_sync_disabled(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start_sync_disabled): +def test_sync_disabled(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start_sync): ''' description: Check if the 'wazuh-syscheckd' daemon uses the value of the 'enabled' tag to start/stop the file/registry synchronization. For this purpose, the test will monitor a directory/key. @@ -125,7 +126,7 @@ def test_sync_disabled(get_configuration, configure_environment, restart_syschec - restart_syscheckd: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. - - wait_for_fim_start_sync_disabled: + - wait_for_fim_start_sync: type: fixture brief: Wait for end of initial FIM scan. assertions: diff --git a/tests/integration/test_fim/test_synchronization/test_sync_time.py b/tests/integration/test_fim/test_synchronization/test_sync_time.py new file mode 100644 index 0000000000..4a424fc518 --- /dev/null +++ b/tests/integration/test_fim/test_synchronization/test_sync_time.py @@ -0,0 +1,174 @@ +''' +copyright: Copyright (C) 2015-2022, Wazuh Inc. + + Created by Wazuh, Inc. . + + This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 + +type: integration + +brief: Check when the 'wazuh-syscheckd' daemon is performing a synchronization, a normal synchronization will end +before the configured `interval` and `max_interval`. + +components: + - fim + +suite: synchronization + +targets: + - agent + - manager + +daemons: + - wazuh-syscheckd + +os_platform: + - linux + - windows + +os_version: + - Arch Linux + - Amazon Linux 2 + - Amazon Linux 1 + - CentOS 8 + - CentOS 7 + - Debian Buster + - Red Hat 8 + - Ubuntu Focal + - Ubuntu Bionic + - Windows Server 2019 + + +references: + - https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/index.html + - https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/syscheck.html#synchronization + +pytest_args: + - fim_mode: + scheduled: monitoring is done at a preconfigured interval. + realtime: Enable real-time monitoring on Linux (using the 'inotify' system calls) and Windows systems. + whodata: Implies real-time monitoring but adding the 'who-data' information. + - tier: + 0: Basic functionalities and quick to perform. + 1: Functionalities of medium complexity. + 2: Advanced functionalities and are slow to perform. + +tags: + - fim_synchronization +''' +import os +import pytest + + +from wazuh_testing import global_parameters +from wazuh_testing.tools import LOG_FILE_PATH, configuration +from wazuh_testing.tools.monitoring import FileMonitor +from wazuh_testing.modules import TIER1, AGENT, SERVER +from wazuh_testing.modules.fim import MONITORED_DIR_1, FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS +from wazuh_testing.modules.fim import event_monitor as evm + +# Marks +pytestmark = [AGENT, SERVER, TIER1] + +local_internal_options = FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS + +# Reference paths +TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template') +TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases') + +# Configuration and cases data +test_cases_path = os.path.join(TEST_CASES_PATH, 'cases_sync_time.yaml') +configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_sync_time.yaml') + +# Test configurations +configuration_parameters, configuration_metadata, test_case_ids = configuration.get_test_cases_data(test_cases_path) +# This assigns the monitored_dir during runtime depending on the OS, cannot be added to yaml +for count, value in enumerate(configuration_parameters): + configuration_parameters[count]['MONITORED_DIR'] = MONITORED_DIR_1 +configurations = configuration.load_configuration_template(configurations_path, configuration_parameters, + configuration_metadata) + +# Variables +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# Tests +@pytest.mark.parametrize('configuration, metadata', zip(configurations, configuration_metadata), ids=test_case_ids) +@pytest.mark.parametrize('files_number', [configuration_metadata[0]['files']]) +def test_sync_time(configuration, metadata, set_wazuh_configuration, configure_local_internal_options_function, + create_files_in_folder, restart_syscheck_function, wait_fim_start): + ''' + description: Check when the 'wazuh-syscheckd' daemon is performing a synchronization, a normal synchronization + will end before the configured `interval` and `max_interval`. + + test_phases: + - Create a folder with a number of files inside. + - Restart syscheckd. + - Check that a sync interval started, and get the time it starts + - Get all the integrity state events time. + - Assert that the time it took for the sync to complete was less than the configured interval and max_interval. + + wazuh_min_version: 4.5.0 + + tier: 2 + + parameters: + - configuration: + type: dict + brief: Configuration values for ossec.conf. + - metadata: + type: dict + brief: Test case data. + - set_wazuh_configuration: + type: fixture + brief: Set ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Set local_internal_options.conf file. + - create_files_in_folder: + type: fixture + brief: create files in monitored folder, and delete them after the test. + - restart_syscheck_function: + type: fixture + brief: restart syscheckd daemon, and truncate the ossec.log. + - wait_for_fim_start_function: + type: fixture + brief: check that the starting fim scan is detected. + + assertions: + - Assert sync time delta is smaller than interval + - Assert sync time delta is smaller than max_interval + + input_description: A test case is contained in external YAML file (cases_sync_interval.yaml) which includes + configuration settings for the 'wazuh-syscheckd' daemon. That is combined with the interval + periods and the testing directory to be monitored defined in this module. + + expected_output: + - r'Initializing FIM Integrity Synchronization check' + - r".*Executing FIM sync" + - r".*Sending integrity control message.*" + + tags: + - scheduled + ''' + + wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + # Wait for new sync and get start time + sync_time = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=evm.callback_sync_start_time, + error_message=evm.ERR_MSG_FIM_SYNC_NOT_DETECTED, update_position=True).result() + + # Get the time of all the sync state events for the created files + results = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, + callback=evm.callback_state_event_time, accum_results=3, + error_message=evm.ERR_MSG_FIM_SYNC_NOT_DETECTED, update_position=True).result() + + # Calculate timedelta between start of sync and last message. + # Add 1 second to take into account the first second from the scan + delta = (results[-1] - sync_time).total_seconds() + 1 + + # Assert that sync took less time that interval and max_interval + assert delta <= metadata['interval'], f"Error: Sync took longer than interval: {metadata['interval']}" + assert delta <= metadata['max_interval'], f"Error: Sync took longer than max_interval: {metadata['max_interval']}" diff --git a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_scan.py b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_scan.py index 676ac6fce3..6702e6dda0 100644 --- a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_scan.py +++ b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_scan.py @@ -60,7 +60,7 @@ import pytest from wazuh_testing import global_parameters from wazuh_testing.fim import LOG_FILE_PATH, generate_params, create_file, REGULAR, \ - callback_detect_event, callback_real_time_whodata_started + callback_detect_event, callback_real_time_whodata_started, callback_detect_synchronization from wazuh_testing.tools import PREFIX from wazuh_testing.tools.configuration import load_wazuh_configurations from wazuh_testing.tools.monitoring import FileMonitor @@ -107,14 +107,8 @@ def extra_configuration_before_yield(): create_file(REGULAR, testdir, file, content='Sample content') -def callback_integrity_synchronization_check(line): - if 'Initializing FIM Integrity Synchronization check' in line: - return line - return None - - def callback_integrity_or_whodata(line): - if callback_integrity_synchronization_check(line): + if callback_detect_synchronization(line): return 1 elif callback_real_time_whodata_started(line): return 2 @@ -124,7 +118,8 @@ def callback_integrity_or_whodata(line): @pytest.mark.parametrize('tags_to_apply', [ {'synchronize_events_conf'} ]) -def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): +def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure_environment, install_audit, + restart_syscheckd): ''' description: Check if the 'wazuh-syscheckd' daemon detects events while the synchronization is performed simultaneously. For this purpose, the test will monitor a testing directory. Then, it @@ -145,6 +140,9 @@ def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure - configure_environment: type: fixture brief: Configure a custom environment for testing. + - install_audit: + type: fixture + brief: install audit to check whodata. - restart_syscheckd: type: fixture brief: Clear the 'ossec.log' file and start a new monitor. @@ -176,20 +174,20 @@ def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure value_1 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 2, callback=callback_integrity_or_whodata, error_message='Did not receive expected "File integrity monitoring ' - 'real-time Whodata engine started" or "Initializing ' - 'FIM Integrity Synchronization check"').result() + 'real-time Whodata engine started" or ' + '"Executing FIM sync"').result() value_2 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 2, callback=callback_integrity_or_whodata, error_message='Did not receive expected "File integrity monitoring ' - 'real-time Whodata engine started" or "Initializing FIM ' - 'Integrity Synchronization check"').result() + 'real-time Whodata engine started" or ' + '"Executing FIM sync"').result() assert value_1 != value_2, "callback_integrity_or_whodata detected the same message twice" else: # Check the integrity scan has begun wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 3, - callback=callback_integrity_synchronization_check, + callback=callback_detect_synchronization, error_message='Did not receive expected ' '"Initializing FIM Integrity Synchronization check" event') diff --git a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py index e7e4064337..f150053880 100644 --- a/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py +++ b/tests/integration/test_fim/test_synchronization/test_synchronize_integrity_win32.py @@ -54,34 +54,37 @@ - fim_synchronization ''' import os -from datetime import timedelta - +import time import pytest -from wazuh_testing import global_parameters -from wazuh_testing.fim import LOG_FILE_PATH, create_registry, generate_params, \ - create_file, modify_registry_value, REGULAR, callback_detect_event, callback_real_time_whodata_started, \ - KEY_WOW64_64KEY, registry_parser, REG_SZ + +from wazuh_testing import global_parameters, LOG_FILE_PATH, REGULAR from wazuh_testing.tools import PREFIX -from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test +from wazuh_testing.tools.configuration import load_wazuh_configurations +from wazuh_testing.tools.file import create_file from wazuh_testing.tools.monitoring import FileMonitor -from wazuh_testing.tools.time import TimeMachine - +from wazuh_testing.modules import TIER2, WINDOWS +from wazuh_testing.modules.fim import (WINDOWS_HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY, registry_parser, + REG_SZ, MONITORED_KEY) +from wazuh_testing.modules.fim.event_monitor import (callback_detect_event, callback_real_time_whodata_started, + callback_detect_synchronization, ERR_MSG_FIM_EVENT_NOT_RECIEVED, + ERR_MSG_INTEGRITY_OR_WHODATA_NOT_STARTED, + ERR_MSG_INTEGRITY_CHECK_EVENT) +from wazuh_testing.modules.fim.utils import create_registry, generate_params, modify_registry_value +from wazuh_testing.modules.fim import FIM_DEFAULT_LOCAL_INTERNAL_OPTIONS as local_internal_options # Marks +pytestmark = [WINDOWS, TIER2] -pytestmark = [pytest.mark.win32, pytest.mark.tier(level=1)] # variables -key = "HKEY_LOCAL_MACHINE" -subkey = "SOFTWARE\\test_key" +subkey = MONITORED_KEY test_directories = [os.path.join(PREFIX, 'testdir1'), os.path.join(PREFIX, 'testdir2')] -test_regs = [os.path.join(key, subkey)] +test_regs = [os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, subkey)] directory_str = ','.join(test_directories) test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') configurations_path = os.path.join(test_data_path, 'wazuh_conf_integrity_scan_win32.yaml') -testdir1, testdir2 = test_directories conf_params = {'TEST_DIRECTORIES': test_directories, - 'TEST_REGS': os.path.join(key, subkey)} + 'TEST_REGS': os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, subkey)} file_list = [] subkey_list = [] @@ -99,7 +102,6 @@ # fixtures - @pytest.fixture(scope='module', params=configurations) def get_configuration(request): """Get configurations from the module.""" @@ -111,27 +113,19 @@ def extra_configuration_before_yield(): for testdir in test_directories: for file, reg in zip(file_list, subkey_list): create_file(REGULAR, testdir, file, content='Sample content') - create_registry(registry_parser[key], os.path.join(key, 'SOFTWARE', reg), KEY_WOW64_64KEY) - - -def callback_integrity_synchronization_check(line): - if 'Initializing FIM Integrity Synchronization check' in line: - return line - return None + create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], os.path.join(subkey, reg), KEY_WOW64_64KEY) def callback_integrity_or_whodata(line): - if callback_integrity_synchronization_check(line): + if callback_detect_synchronization(line): return 1 elif callback_real_time_whodata_started(line): return 2 # tests -@pytest.mark.parametrize('tags_to_apply', [ - {'synchronize_events_conf'} -]) -def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): +def test_events_while_integrity_scan(get_configuration, configure_environment, restart_syscheckd, + configure_local_internal_options_module): ''' description: Check if the 'wazuh-syscheckd' daemon detects events while the synchronization is performed simultaneously. For this purpose, the test will monitor a testing directory and registry key. @@ -176,47 +170,39 @@ def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure - realtime - who_data ''' - check_apply_test(tags_to_apply, get_configuration['tags']) - folder = testdir1 if get_configuration['metadata']['fim_mode'] == 'realtime' else testdir2 - key_h = create_registry(registry_parser[key], subkey, KEY_WOW64_64KEY) + folder = test_directories[0] if get_configuration['metadata']['fim_mode'] == 'realtime' else test_directories[1] + key_h = create_registry(registry_parser[WINDOWS_HKEY_LOCAL_MACHINE], subkey, KEY_WOW64_64KEY) # Wait for whodata to start and the synchronization check. Since they are different threads, we cannot expect # them to come in order every time if get_configuration['metadata']['fim_mode'] == 'whodata': - value_1 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 2, + value_1 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 3, callback=callback_integrity_or_whodata, - error_message='Did not receive expected "File integrity monitoring ' - 'real-time Whodata engine started" or "Initializing ' - 'FIM Integrity Synchronization check"').result() + error_message=ERR_MSG_INTEGRITY_OR_WHODATA_NOT_STARTED).result() - value_2 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 2, + value_2 = wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 3, callback=callback_integrity_or_whodata, - error_message='Did not receive expected "File integrity monitoring ' - 'real-time Whodata engine started" or "Initializing FIM ' - 'Integrity Synchronization check"').result() + error_message=ERR_MSG_INTEGRITY_OR_WHODATA_NOT_STARTED).result() assert value_1 != value_2, "callback_integrity_or_whodata detected the same message twice" else: # Check the integrity scan has begun wazuh_log_monitor.start(timeout=global_parameters.default_timeout * 3, - callback=callback_integrity_synchronization_check, - error_message='Did not receive expected ' - '"Initializing FIM Integrity Synchronization check" event') + callback=callback_detect_synchronization, + error_message=ERR_MSG_INTEGRITY_CHECK_EVENT) # Create a file and a registry value. Assert syscheckd detects it while doing the integrity scan file_name = 'file' create_file(REGULAR, folder, file_name, content='') modify_registry_value(key_h, "test_value", REG_SZ, 'added') - sending_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*3, callback=callback_detect_event, - error_message='Did not receive expected ' - '"Sending FIM event: ..." event').result() + sending_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*5, callback=callback_detect_event, + error_message=ERR_MSG_FIM_EVENT_NOT_RECIEVED).result() assert sending_event['data']['path'] == os.path.join(folder, file_name) - TimeMachine.travel_to_future(timedelta(hours=13)) - sending_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*3, callback=callback_detect_event, - error_message='Did not receive expected ' - '"Sending FIM event: ..." event').result() - assert sending_event['data']['path'] == os.path.join(key, subkey) + time.sleep(global_parameters.default_timeout) + sending_event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout*5, callback=callback_detect_event, + error_message=ERR_MSG_FIM_EVENT_NOT_RECIEVED).result() + assert sending_event['data']['path'] == os.path.join(WINDOWS_HKEY_LOCAL_MACHINE, subkey) assert sending_event['data']['arch'] == '[x64]' diff --git a/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yaml b/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yaml new file mode 100644 index 0000000000..a106bcc5a8 --- /dev/null +++ b/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yaml @@ -0,0 +1,4 @@ +wazuh-agent1: + - regex: .*Finished FIM sync. + path: /var/ossec/logs/ossec.log + timeout: 60 diff --git a/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yml b/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yml deleted file mode 100644 index d5e627e9ef..0000000000 --- a/tests/system/test_fim/test_synchronization/data/agent_initializing_synchronization.yml +++ /dev/null @@ -1,4 +0,0 @@ -wazuh-agent1: - - regex: ".*Initializing FIM Integrity Synchronization check. (.+)$" - path: "/var/ossec/logs/ossec.log" - timeout: 60 \ No newline at end of file diff --git a/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yaml b/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yaml new file mode 100644 index 0000000000..3ea9f7ddbd --- /dev/null +++ b/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yaml @@ -0,0 +1,4 @@ +wazuh-manager: + - regex: .*Finished FIM sync. + path: /var/ossec/logs/ossec.log + timeout: 60 diff --git a/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yml b/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yml deleted file mode 100644 index 804ea2a01d..0000000000 --- a/tests/system/test_fim/test_synchronization/data/manager_initializing_synchronization.yml +++ /dev/null @@ -1,4 +0,0 @@ -wazuh-manager: - - regex: ".*Initializing FIM Integrity Synchronization check. (.+)$" - path: "/var/ossec/logs/ossec.log" - timeout: 60 \ No newline at end of file diff --git a/tests/system/test_fim/test_synchronization/test_synchronization.py b/tests/system/test_fim/test_synchronization/test_synchronization.py index 58eb6e9ee5..c3ad8c7220 100644 --- a/tests/system/test_fim/test_synchronization/test_synchronization.py +++ b/tests/system/test_fim/test_synchronization/test_synchronization.py @@ -60,8 +60,8 @@ messages_path = [os.path.join(local_path, 'data/messages.yml'), os.path.join(local_path, 'data/delete_message.yml'), os.path.join(local_path, 'data/wait_fim_scan.yml'), - os.path.join(local_path, 'data/agent_initializing_synchronization.yml'), - os.path.join(local_path, 'data/manager_initializing_synchronization.yml') + os.path.join(local_path, 'data/agent_initializing_synchronization.yaml'), + os.path.join(local_path, 'data/manager_initializing_synchronization.yaml') ] tmp_path = os.path.join(local_path, 'tmp') scheduled_mode = 'testdir1' @@ -101,7 +101,7 @@ def test_synchronization(folder_path, case, host): expected_output: - Different test cases are contained in external YAML file - (agent_initializing_synchronization.yml and manager_initializing_synchronization.yml) + (agent_initializing_synchronization.yml and manager_initializing_synchronization.yaml) tags: - fim_basic_usage - scheduled