diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/common.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/common.py index 751220ff00..90c587003f 100644 --- a/tests/integration/test_fim/test_files/test_follow_symbolic_link/common.py +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/common.py @@ -13,8 +13,8 @@ configurations_path = os.path.join(test_data_path, 'wazuh_conf.yaml') test_directories = [os.path.join(PREFIX, 'testdir_link'), os.path.join(PREFIX, 'testdir1'), os.path.join(PREFIX, 'testdir2'), os.path.join(PREFIX, 'testdir_target'), - os.path.join(PREFIX, 'testdir_not_target')] -testdir_link, testdir1, testdir2, testdir_target, testdir_not_target = test_directories + os.path.join(PREFIX, 'testdir_not_target'), os.path.join(PREFIX, 'testdir1', 'subdir')] +testdir_link, testdir1, testdir2, testdir_target, testdir_not_target, test_subdir = test_directories symlink_interval = 20 @@ -74,10 +74,14 @@ def extra_configuration_before_yield(): create_file(REGULAR, testdir1, 'regular2', content='') create_file(REGULAR, testdir2, 'regular1', content='') create_file(REGULAR, testdir2, 'regular2', content='') + create_file(REGULAR, test_subdir, 'regular1', content='') + create_file(REGULAR, test_subdir, 'regular2', content='') # Symlink pointing to /testdir1/regular1 create_file(SYMLINK, symlinkdir, 'symlink', target=os.path.join(testdir1, 'regular1')) # Symlink pointing to /testdir_target/ create_file(SYMLINK, symlinkdir, 'symlink2', target=testdir_target) + # Symlink pointing to /testdir1 + create_file(SYMLINK, symlinkdir, 'symlink3', target=testdir1) # Set symlink_scan_interval to a given value change_internal_options(param='syscheck.symlink_scan_interval', value=symlink_interval) diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/data/wazuh_conf.yaml b/tests/integration/test_fim/test_files/test_follow_symbolic_link/data/wazuh_conf.yaml index 04ad4b3db2..4b6ea0888b 100644 --- a/tests/integration/test_fim/test_files/test_follow_symbolic_link/data/wazuh_conf.yaml +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/data/wazuh_conf.yaml @@ -60,3 +60,98 @@ attributes: - FIM_MODE - follow_symbolic_link: FOLLOW_MODE +# conf 4 +- tags: + - replace_with_directory + apply_to_modules: + - test_symlink_to_dir_between_scans + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: '/testdir_link' + attributes: + - FIM_MODE + - follow_symbolic_link: FOLLOW_MODE +# conf 5 +- tags: + - symlink_within_directory + apply_to_modules: + - test_symlink_within_dir + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: '/testdir' + attributes: + - FIM_MODE + - check_all: 'yes' + - directories: + value: '/testdir/testdir_link' + attributes: + - FIM_MODE + - follow_symbolic_link: FOLLOW_MODE + - check_size: 'no' +# conf 6 +- tags: + - symlink_dir_inside_monitored_dir + apply_to_modules: + - test_symlink_dir_inside_monitored_dir + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: '/testdir' + attributes: + - FIM_MODE + - check_all: 'yes' + - directories: + value: '/testdir_link' + attributes: + - FIM_MODE + - follow_symbolic_link: FOLLOW_MODE + - check_size: 'no' +# conf 8 +- tags: + - symlink_and_dir + apply_to_modules: + - test_symlink_and_dir + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: '/testdir' + attributes: + - FIM_MODE + - directories: + value: '/testdir_link' + attributes: + - FIM_MODE + - follow_symbolic_link: FOLLOW_MODE +# conf 9 +- tags: + - nested_dir + apply_to_modules: + - test_change_target_with_nested_directory + sections: + - section: syscheck + elements: + - disabled: + value: 'no' + - directories: + value: '/testdir1/subdir' + attributes: + - FIM_MODE + - directories: + value: '/testdir_link/symlink3' + attributes: + - FIM_MODE + - follow_symbolic_link: FOLLOW_MODE diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_change_target_with_nested_directory.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_change_target_with_nested_directory.py new file mode 100644 index 0000000000..35a60b9629 --- /dev/null +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_change_target_with_nested_directory.py @@ -0,0 +1,85 @@ +# Copyright (C) 2015-2020, 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 pytest +from test_fim.test_files.test_follow_symbolic_link.common import configurations_path, testdir1, \ + modify_symlink, testdir_link, wait_for_symlink_check, wait_for_audit, testdir2 +# noinspection PyUnresolvedReferences +from test_fim.test_files.test_follow_symbolic_link.common import test_directories, extra_configuration_before_yield, \ + extra_configuration_after_yield + +from wazuh_testing import logger, global_parameters +from wazuh_testing.fim import (generate_params, create_file, REGULAR, callback_detect_event, + check_time_travel, LOG_FILE_PATH) +from wazuh_testing.tools.configuration import load_wazuh_configurations, check_apply_test +from wazuh_testing.tools.monitoring import FileMonitor + +# Marks + +pytestmark = [pytest.mark.linux, pytest.mark.sunos5, pytest.mark.darwin, pytest.mark.tier(level=1)] + +# configurations + +conf_params, conf_metadata = generate_params(extra_params={'FOLLOW_MODE': 'yes'}, + modes=['scheduled']) +configurations = load_wazuh_configurations(configurations_path, __name__, + params=conf_params, + metadata=conf_metadata + ) + +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# fixtures + +@pytest.fixture(scope='module', params=configurations) +def get_configuration(request): + """Get configurations from the module.""" + return request.param + + +# tests + +@pytest.mark.parametrize('tags_to_apply, previous_target, new_target', [ + ({'nested_dir'}, testdir1, testdir2) +]) +def test_symbolic_change_target_inside_folder(tags_to_apply, previous_target, new_target, get_configuration, + configure_environment, restart_syscheckd, wait_for_fim_start): + """ + Check if syscheck stops detecting events from previous target when pointing to a new folder + + CHECK: Having a symbolic link pointing to a folder which contains another monitored directory. Changing the target + should not trigger 'added' events for the monitored subdirectory on the next scan. + + Parameters + ---------- + previous_target : str + Previous symlink target (path) + new_target : str + New symlink target (path). + """ + check_apply_test(tags_to_apply, get_configuration['tags']) + scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' + whodata = get_configuration['metadata']['fim_mode'] == 'whodata' + file1 = 'new_file' + symlink = 'symlink3' + + # Check create event + create_file(REGULAR, previous_target, file1, content='') + check_time_travel(scheduled, monitor=wazuh_log_monitor) + wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event, + error_message='Did not receive expected "Sending FIM event: ..." event') + + # Change the target to another file and wait the symcheck to update the link information + modify_symlink(new_target, os.path.join(testdir_link, symlink)) + wait_for_symlink_check(wazuh_log_monitor) + wait_for_audit(whodata, wazuh_log_monitor) + + # Verify that no events are generated + check_time_travel(scheduled, monitor=wazuh_log_monitor) + with pytest.raises(TimeoutError): + event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event) + logger.error(f'Unexpected event {event.result()}') + raise AttributeError(f'Unexpected event {event.result()}') diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_and_dir.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_and_dir.py new file mode 100644 index 0000000000..7d1f608ca3 --- /dev/null +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_and_dir.py @@ -0,0 +1,108 @@ +# Copyright (C) 2015-2020, 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 pytest + +from wazuh_testing import global_parameters, logger +from wazuh_testing.fim import SYMLINK, REGULAR, LOG_FILE_PATH, generate_params, create_file, change_internal_options, \ + callback_detect_event, check_time_travel +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 test_fim.test_files.test_follow_symbolic_link.common import wait_for_symlink_check, wait_for_audit, symlink_interval, \ + modify_symlink + + +# Marks + +pytestmark = [pytest.mark.linux, pytest.mark.sunos5, pytest.mark.darwin, pytest.mark.tier(level=1)] + + +# Variables + +test_directories = [os.path.join(PREFIX, 'testdir'), os.path.join(PREFIX, 'testdir_target')] +testdir = test_directories[0] +testdir_link = os.path.join(PREFIX, 'testdir_link') +testdir_target = test_directories[1] +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') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# Configurations + +conf_params, conf_metadata = generate_params(extra_params={'FOLLOW_MODE': 'yes'}) +configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_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(): + """Create files and symlinks""" + create_file(REGULAR, testdir_target, 'regular1') + create_file(SYMLINK, PREFIX, 'testdir_link', target=testdir) + # Set symlink_scan_interval to a given value + change_internal_options(param='syscheck.symlink_scan_interval', value=symlink_interval) + + +def extra_configuration_after_yield(): + """Set symlink_scan_interval to default value and remove symbolic link""" + os.remove(testdir_link) + change_internal_options(param='syscheck.symlink_scan_interval', value=600) + + +# Tests + +@pytest.mark.parametrize('tags_to_apply', [ + {'symlink_and_dir'}, +]) +def test_symlink_dir_inside_monitored_dir(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, + wait_for_fim_start): + """ + Monitor a directory and a symbolic link to it, change the target of the symbolic link. + + The directory must be scanned silently, preventing events from triggering until it has finished. + + Parameters + ---------- + tags_to_apply : set + Run test if matches with a configuration identifier, skip otherwise. + """ + check_apply_test(tags_to_apply, get_configuration['tags']) + scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' + whodata = get_configuration['metadata']['fim_mode'] == 'whodata' + + # Modify the symbolic link and expect no events + modify_symlink(testdir_target, testdir_link) + + # Wait for both audit and the symlink check to run + wait_for_symlink_check(wazuh_log_monitor) + wait_for_audit(whodata, wazuh_log_monitor) + + check_time_travel(scheduled, monitor=wazuh_log_monitor) + + with pytest.raises(TimeoutError): + event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event) + logger.error(f'Unexpected event {event.result()}') + raise AttributeError(f'Unexpected event {event.result()}') + + # Create a file in the pointed folder and expect events + create_file(REGULAR, testdir_link, 'regular2') + + check_time_travel(scheduled, monitor=wazuh_log_monitor) + + wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event, + error_message='Did not receive expected ' + '"Sending FIM event: ..." event') diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_dir_inside_monitored_dir.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_dir_inside_monitored_dir.py new file mode 100644 index 0000000000..6d1b79417d --- /dev/null +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_dir_inside_monitored_dir.py @@ -0,0 +1,88 @@ +# Copyright (C) 2015-2020, 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 pytest + +from wazuh_testing import global_parameters +from wazuh_testing.fim import SYMLINK, REGULAR, LOG_FILE_PATH, generate_params, create_file, \ + REQUIRED_ATTRIBUTES, CHECK_ALL, CHECK_SIZE, regular_file_cud +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 + + +# Marks + +pytestmark = [pytest.mark.linux, pytest.mark.sunos5, pytest.mark.darwin, pytest.mark.tier(level=1)] + + +# Variables + +test_directories = [os.path.join(PREFIX, 'testdir')] +testdir = test_directories[0] +testdir_link = os.path.join(PREFIX, 'testdir_link') +testdir_target = os.path.join(testdir, 'testdir_target') +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') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# Configurations + +conf_params, conf_metadata = generate_params(extra_params={'FOLLOW_MODE': 'yes'}) +configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_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(): + """Create files and symlinks""" + os.makedirs(testdir_target, exist_ok=True, mode=0o777) + create_file(REGULAR, testdir_target, 'regular1') + create_file(SYMLINK, PREFIX, 'testdir_link', target=testdir_target) + + +def extra_configuration_after_yield(): + """Set symlink_scan_interval to default value""" + os.remove(testdir_link) + + +# Tests + +@pytest.mark.parametrize('tags_to_apply, checkers', [ + ({'symlink_dir_inside_monitored_dir'}, REQUIRED_ATTRIBUTES[CHECK_ALL] - {CHECK_SIZE}), +]) +def test_symlink_dir_inside_monitored_dir(tags_to_apply, checkers, get_configuration, configure_environment, + restart_syscheckd, wait_for_fim_start): + """ + Monitor a directory within a directory monitored through a symbolic link with `follow_symbolic_link` enabled. + + The monitored directory configuration should prevail over the configuration of the symbolic link (checks, + follow_symbolic_link, etc...) + + Parameters + ---------- + tags_to_apply : set + Run test if matches with a configuration identifier, skip otherwise. + checkers : dict + Check options to be used. + """ + check_apply_test(tags_to_apply, get_configuration['tags']) + scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' + + # Alerts from the pointed directory should have all checks except size + regular_file_cud(testdir_target, wazuh_log_monitor, min_timeout=global_parameters.default_timeout, options=checkers, + time_travel=scheduled) + # Alerts from the main directory should have all checks + regular_file_cud(testdir, wazuh_log_monitor, min_timeout=global_parameters.default_timeout, time_travel=scheduled) diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_to_dir_between_scans.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_to_dir_between_scans.py new file mode 100644 index 0000000000..97d0add1fd --- /dev/null +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_to_dir_between_scans.py @@ -0,0 +1,103 @@ +# Copyright (C) 2015-2020, 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 shutil import rmtree + +import pytest + +from wazuh_testing import global_parameters +from wazuh_testing.fim import SYMLINK, REGULAR, LOG_FILE_PATH, generate_params, create_file, change_internal_options,\ + check_time_travel, callback_detect_event +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 test_fim.test_files.test_follow_symbolic_link.common import wait_for_symlink_check, symlink_interval, testdir_link, \ + testdir_target + + +# Marks + +pytestmark = [pytest.mark.linux, pytest.mark.sunos5, pytest.mark.darwin, pytest.mark.tier(level=1)] + + +# 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') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# Configurations + +conf_params, conf_metadata = generate_params(extra_params={'FOLLOW_MODE': 'yes'}, modes=['scheduled']) +configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_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(): + """Create files and symlinks""" + symlinkdir = testdir_link + + os.makedirs(testdir_target, exist_ok=True, mode=0o777) + create_file(REGULAR, testdir_target, 'regular1') + create_file(SYMLINK, PREFIX, symlinkdir, target=testdir_target) + # Set symlink_scan_interval to a given value + change_internal_options(param='syscheck.symlink_scan_interval', value=symlink_interval) + + +def extra_configuration_after_yield(): + """Set symlink_scan_interval to default value""" + rmtree(testdir_link, ignore_errors=True) + rmtree(testdir_target, ignore_errors=True) + change_internal_options(param='syscheck.symlink_scan_interval', value=600) + + +# Tests + +@pytest.mark.parametrize('tags_to_apply', [ + {'replace_with_directory'}, +]) +def test_symlink_to_dir_between_scans(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, + wait_for_fim_start): + """ + Replace a link with a directory between scans. + + This test monitors a link with `follow_symblic_link` enabled. After the first scan, it is replaced with a directory, + the new directory should send alerts during a second scan. + + Parameters + ---------- + tags_to_apply : set + Run test if matches with a configuration identifier, skip otherwise. + """ + check_apply_test(tags_to_apply, get_configuration['tags']) + scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' + regular2 = 'regular2' + + # Delete symbolic link and create a folder with the same name + os.remove(testdir_link) + os.makedirs(testdir_link, exist_ok=True, mode=0o777) + create_file(REGULAR, testdir_link, regular2) + + # Wait for both audit and the symlink check to run + wait_for_symlink_check(wazuh_log_monitor) + check_time_travel(scheduled, monitor=wazuh_log_monitor) + + event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event, + error_message='Did not receive expected ' + '"Sending FIM event: ..." event').result() + + assert 'added' in event['data']['type'] and regular2 in event['data']['path'], \ + f'"added" event not matching for {event}' diff --git a/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_within_dir.py b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_within_dir.py new file mode 100644 index 0000000000..8f6cd90763 --- /dev/null +++ b/tests/integration/test_fim/test_files/test_follow_symbolic_link/test_symlink_within_dir.py @@ -0,0 +1,88 @@ +# Copyright (C) 2015-2020, 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 shutil import rmtree + +import pytest + +from wazuh_testing import global_parameters +from wazuh_testing.fim import SYMLINK, REGULAR, LOG_FILE_PATH, generate_params, create_file, \ + REQUIRED_ATTRIBUTES, CHECK_ALL, CHECK_SIZE, regular_file_cud +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 + + +# Marks + +pytestmark = [pytest.mark.linux, pytest.mark.sunos5, pytest.mark.darwin, pytest.mark.tier(level=1)] + + +# Variables + +test_directories = [os.path.join(PREFIX, 'testdir')] +testdir = test_directories[0] +testdir_link = os.path.join(testdir, 'testdir_link') +testdir_target = os.path.join(PREFIX, 'testdir_target') +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') +wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) + + +# Configurations + +conf_params, conf_metadata = generate_params(extra_params={'FOLLOW_MODE': 'yes'}) +configurations = load_wazuh_configurations(configurations_path, __name__, params=conf_params, metadata=conf_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(): + """Create files and symlinks""" + os.makedirs(testdir_target, exist_ok=True, mode=0o777) + create_file(REGULAR, testdir_target, 'regular1') + create_file(SYMLINK, testdir, 'testdir_link', target=testdir_target) + + +def extra_configuration_after_yield(): + """Remove symbolic link""" + rmtree(testdir_target, ignore_errors=True) + + +# Tests + +@pytest.mark.parametrize('tags_to_apply, checkers', [ + ({'symlink_within_directory'}, REQUIRED_ATTRIBUTES[CHECK_ALL] - {CHECK_SIZE}), +]) +def test_symlink_within_dir(tags_to_apply, checkers, get_configuration, configure_environment, restart_syscheckd, + wait_for_fim_start): + """ + Monitor a link within a monitored directory. + + The link configuration should prevail over the monitored directory (checks, follow_symbolic_link, etc...). + + Parameters + ---------- + tags_to_apply : set + Run test if matches with a configuration identifier, skip otherwise. + checkers : dict + Check options to be used. + """ + check_apply_test(tags_to_apply, get_configuration['tags']) + scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' + + # Alerts from the pointed directory should have all checks except size + regular_file_cud(testdir_target, wazuh_log_monitor, min_timeout=global_parameters.default_timeout, options=checkers, + time_travel=scheduled) + # Alerts from the main directory should have all checks + regular_file_cud(testdir, wazuh_log_monitor, min_timeout=global_parameters.default_timeout, time_travel=scheduled)