def test_audit_key(audit_key, path, get_configuration, configure_environment, restart_syscheckd): """Checks <audit_key> functionality by adding a audit rule and checking if alerts with that key are triggered when a file is created. This test is intended to be used with valid configurations Parameters ---------- audit_key : str Name of the audit_key to monitor path : str Path of the folder to be monitored """ check_apply_test({audit_key}, get_configuration['tags']) # Add watch rule os.system("auditctl -w " + path + " -p wa -k " + audit_key) # Restart and for wazuh truncate_file(LOG_FILE_PATH) control_service('restart') wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) detect_initial_scan(wazuh_log_monitor) # Look for audit_key word create_file(REGULAR, path, "testfile") events = wazuh_log_monitor.start(timeout=30, callback=callback_audit_key, accum_results=1).result() assert audit_key in events # Remove watch rule os.system("auditctl -W " + path + " -p wa -k " + audit_key)
def test_ambiguous_complex(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Automatic test for each configuration given in the yaml. The main purpose of this test is to check that syscheck will apply different configurations between subdirectories properly. Example: <directories realtime='yes' report_changes='yes' check_all='yes' check_owner='no'> /testdir </directories> <directories realtime='yes' report_changes='no' check_sum='no' check_owner='yes'> /testdir/subdir </directories> * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) # Standard params for each test file_list = ['example.csv'] min_timeout = DEFAULT_TIMEOUT scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' conf_list, check_list = get_dir_and_attributes( get_configuration['elements']) param = (file_list, min_timeout, scheduled) # For every directory, apply each test depending of its attributes. # We assume we've set restrict attribute so it should not expect events # For further functionality with restrict, run ../test_restrict tests for directory, checkers in zip(conf_list, check_list): for path, attributes in directory.items(): trigger = False if 'restrict' in attributes else True apply_test(path, attributes, trigger, checkers, param)
def test_ambiguous_tags(folders, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Checks if syscheck detects the event property 'tags' for each event. This test validates both situations, making sure that if tags='no', there won't be a tags event property. This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. Parameters ---------- folders : list Monitored directories 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' # Check that events inside folder[0] do not contain the key 'tags'. regular_file_cud(folders[0], wazuh_log_monitor, time_travel=scheduled, min_timeout=DEFAULT_TIMEOUT, validators_after_cud=[no_tag_validator]) # Check that events inside folder[1] do contain the key 'tags'. regular_file_cud(folders[1], wazuh_log_monitor, time_travel=scheduled, min_timeout=DEFAULT_TIMEOUT, validators_after_cud=[tag_validator])
def test_max_eps_on_start(get_configuration, configure_environment, restart_syscheckd): """ Checks that max_eps is respected when a big quatity of events are generated Before starting the service, a great number of files is created thanks to function `extra_configuration_before_yield`. After that, syscheck is launched and starts generating as much events as files created. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly and restart the service. """ check_apply_test({'max_eps'}, get_configuration['tags']) result = wazuh_log_monitor.start(timeout=150, accum_results=1000, callback=callback_syscheck_message, update_position=False).result() max_eps = int(get_configuration['metadata']['max_eps']) counter = Counter([date_time for date_time, _ in result]) error_margin = (max_eps * 0.1) for date_time, 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'
def test_scan_time(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if there is a scan at a certain time scan_time option makes sure there is only one scan every 24 hours, at a certain time. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) # Reformat given time to a readable format since it can be writen in several ways in ossec.conf scan_time = reformat_time(get_configuration['metadata']['scan_time']) current_time = datetime.now() # Calculate how much time we need to travel in time to make sure there hasn't been any scan until it is the given # time time_difference = (scan_time - current_time) if (scan_time - current_time).days == 0 else \ ((scan_time - current_time) + timedelta(days=2)) TimeMachine.travel_to_future(time_difference + timedelta(minutes=-30)) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan) TimeMachine.travel_to_future(timedelta(minutes=31)) wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan)
def test_create_file_scheduled(folder, name, filetype, content, checkers, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Checks if a special or regular file creation is detected by syscheck using scheduled monitoring Regular files must be monitored. Special files must not. :param folder: Name of the monitored folder :param name: Name of the file :param filetype: Type of the file :param content: Content of the file :param checkers: Checks that will compared to the ones from the event * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) # Create files create_file(filetype, folder, name, content=content) # Go ahead in time to let syscheck perform a new scan TimeMachine.travel_to_future(timedelta(hours=13)) if filetype == REGULAR: # Wait until event is detected event = wazuh_log_monitor.start( timeout=DEFAULT_TIMEOUT, callback=callback_detect_event).result() validate_event(event, checkers) else: with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_event)
def test_no_report_changes(folder, checkers, delete_dir, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if duplicated directories in diff are deleted when changing report_changes to 'no' or deleting the monitored directories Since report_changes duplicates monitored files, we need to assert that once the original files are deleted, the duplicated ones are deleted too. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. This test will restart with a new configuration throughout its execution as well. """ check_apply_test(tags_to_apply, get_configuration['tags']) filename = 'regularfile' fim_mode = get_configuration['metadata']['fim_mode'] if delete_dir: check_when_deleted_directories(filename, folder, fim_mode) else: new_conf = change_conf(report_value='no') new_ossec_conf = set_section_wazuh_conf(new_conf[0].get('section'), new_conf[0].get('elements')) check_when_no_report_changes(filename, folder, fim_mode, new_ossec_conf)
def test_check_others(path, checkers, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Test the behaviour of several combinations of Check options over the same directory with Check_all disabled to avoid using the default check_all configuration. The order of the checks (including check_all="no") will be different on each case to test the behaviour of check_all="no". Example: check_all: "no" check_size: "yes" check_sum: "yes" check_all: "no" check_md5sum: "yes" check_mtime: "yes" check_group: "yes" check_md5sum: "yes" check_all: "no" check_mtime: "yes" check_group: "yes" ... This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. :param path: Directory where the file is being created and monitored :param checkers: Dict with all the check options to be used """ check_apply_test({'test_check_others'}, get_configuration['tags']) regular_file_cud( path, wazuh_log_monitor, min_timeout=15, options=checkers, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled')
def test_check_others_individually(path, checkers, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Test the behaviour of every Check option individually without using the Check_all option. Check_all option will be set to "no" in order to avoid using the default check_all configuration. Example: check_all="no" check_sum="yes" check_all="no" check_mtime="yes" ... This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. :param path: Directory where the file is being created and monitored :param checkers: Dict with all the check options to be used """ check_apply_test({'test_check_others_individually'}, get_configuration['tags']) regular_file_cud( path, wazuh_log_monitor, min_timeout=15, options=checkers, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled')
def test_events_from_existing_files(filename, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Checks if syscheck generates modified alerts for files that exists when starting the agent """ check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' # Modify file modify_file_content(testdir1, filename, new_content='Sample content') # Expect modified event check_time_travel(scheduled) modified_event = wazuh_log_monitor.start(timeout=timeout, callback=callback_detect_event).result() assert 'modified' in modified_event['data']['type'] and \ os.path.join(testdir1, filename) in modified_event['data']['path'] # Delete file delete_file(testdir1, filename) # Expect deleted event check_time_travel(scheduled) deleted_event = wazuh_log_monitor.start(timeout=timeout, callback=callback_detect_event).result() assert 'deleted' in deleted_event['data']['type'] and \ os.path.join(testdir1, filename) in deleted_event['data']['path']
def test_ambiguous_check(dirname, checkers, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Checks if syscheck detects every check set in the configuration. Checks are read from left to right, overwriting any ambiguous configuration. If we set check_all='yes' and then check_inode='no' for the same directory, syscheck must send an event containing every possible check without inode. This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. Parameters ---------- dirname : string Name of the monitored directory checkers : set Checks to be compared to the actual event check list (the one we get from the event) 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' regular_file_cud(dirname, wazuh_log_monitor, min_timeout=DEFAULT_TIMEOUT, options=checkers, time_travel=scheduled)
def test_scan_day_and_time(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if there is a scan in a certain day and time This test must check both scan params. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) day_of_week = { 'monday': 0, 'tuesday': 1, 'wednesday': 2, 'thursday': 3, 'friday': 4, 'saturday': 5, 'sunday': 6 } current_day = datetime.now() scan_day = day_of_week[get_configuration['metadata']['scan_day']] scan_time = reformat_time(get_configuration['metadata']['scan_time']) day_diff = scan_day - current_day.weekday() scan_today = False if day_diff < 0: day_diff %= 7 elif day_diff == 0: scan_today = True scan_time = replace_date(scan_time, day_diff) if scan_today: if (scan_time - current_day).days == 0: TimeMachine.travel_to_future(scan_time - current_day + timedelta(minutes=1)) wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan) return else: day_diff = 7 if day_diff > 1: TimeMachine.travel_to_future(timedelta(days=day_diff - 1)) current_day = datetime.now() with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan) TimeMachine.travel_to_future(scan_time - current_day - timedelta(minutes=5)) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan) TimeMachine.travel_to_future(timedelta(minutes=6)) wazuh_log_monitor.start(timeout=DEFAULT_TIMEOUT, callback=callback_detect_end_scan)
def test_symbolic_delete_target(tags_to_apply, main_folder, aux_folder, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if syscheck detects events properly when removing a target, have the symlink updated and then recreating the target CHECK: Having a symbolic link pointing to a file/folder, remove that file/folder and check that deleted event is detected. Once symlink_checker runs create the same file. No events should be raised. Wait again for symlink_checker run and modify the file. Modification event must be detected this time. :param main_folder: Directory that is being pointed at or contains the pointed file :param aux_folder: Directory that will be pointed at or will contain the future pointed file * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' whodata = get_configuration['metadata']['fim_mode'] == 'whodata' file1 = 'regular1' # If symlink is pointing to a directory, we need to add files and expect their 'added' event (only if the file # is being created withing the pointed directory. Then, delete the pointed file or directory if tags_to_apply == {'monitored_dir'}: create_file(REGULAR, main_folder, file1, content='') check_time_travel(scheduled) wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) delete_f(main_folder) else: delete_f(main_folder, file1) check_time_travel(scheduled) delete = wazuh_log_monitor.start(timeout=3, callback=callback_detect_event).result() assert 'deleted' in delete['data']['type'] and file1 in delete['data']['path'], \ f"'deleted' event not matching for {file1}" # If syscheck is monitoring with whodata, wait for audit to reload rules wait_for_audit(whodata, wazuh_log_monitor) wait_for_symlink_check(wazuh_log_monitor) # Restore the target and don't expect any event since symlink hasn't updated the link information create_file(REGULAR, main_folder, file1, content='') check_time_travel(scheduled) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) wait_for_symlink_check(wazuh_log_monitor) wait_for_audit(whodata, wazuh_log_monitor) # Modify the files and expect events since symcheck has updated now modify_file_content(main_folder, file1, 'Sample modification') check_time_travel(scheduled) modify = wazuh_log_monitor.start(timeout=3, callback=callback_detect_event).result() assert 'modified' in modify['data']['type'] and file1 in modify['data']['path'], \ f"'modified' event not matching for {file1}"
def test_invalid_sync_response(get_configuration, configure_environment, restart_syscheckd): """Checks if an invalid ignore configuration is detected by catching the warning message displayed on the log. This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly and restart the service. No wait for the initial scan in this case as we need to detect the warning message. """ check_apply_test({'sync_invalid'}, get_configuration['tags']) wazuh_log_monitor.start(timeout=3, callback=callback_configuration_warning)
def test_added_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Checks if the specified folders are added to Audit rules list.""" check_apply_test(tags_to_apply, get_configuration['tags']) events = wazuh_log_monitor.start(timeout=20, callback=callback_audit_added_rule, accum_results=3).result() assert testdir1 in events, f'{testdir1} not detected in scan' assert testdir2 in events, f'{testdir2} not detected in scan' assert testdir3 in events, f'{testdir3} not detected in scan'
def test_invalid(tags_to_apply, get_configuration, configure_environment): """ Checks if an invalid configuration is detected Using invalid configurations with different attributes, expect an error message and syscheck unable to restart. * This test is intended to be used with invalid configurations files. Each execution of this test will fail to configure the environment properly. """ check_apply_test(tags_to_apply, get_configuration['tags']) # Configuration error -> ValueError raised with pytest.raises(ValueError): control_service('restart') wazuh_log_monitor.start(timeout=3, callback=callback_configuration_error)
def test_move_folders_to_realtime(tags_to_apply, get_configuration, uninstall_install_audit, configure_environment, restart_syscheckd): """Check folders monitored with Whodata change to Real-time if auditd is not installed Parameters ---------- tags_to_apply : set Configuration tag to apply """ check_apply_test(tags_to_apply, get_configuration['tags']) wazuh_log_monitor.start(timeout=20, callback=callback_audit_cannot_start)
def test_reports_file_and_nodiff(folder, checkers, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if report_changes events and diff truncated files are correct The report_changes attribute adds a new event property to the 'modified' sent event: 'content_changes' It has information about what changed from the previous content. To do so, it duplicates the file in the diff directory. We call this duplicated file 'diff_file'. :param folder: Directory where the files will be created :param checkers: Dict of syscheck checkers (check_all) * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) file_list = ['regular_file'] is_truncated = folder == testdir_nodiff def report_changes_validator(event): """ Validate content_changes attribute exists in the event """ for file in file_list: diff_file = os.path.join(WAZUH_PATH, 'queue', 'diff', 'local') if sys.platform == 'win32': diff_file = os.path.join(diff_file, 'c') diff_file = os.path.join(diff_file, folder.strip('C:\\'), file) else: diff_file = os.path.join(diff_file, folder.strip('/'), file) assert os.path.exists(diff_file), f'{diff_file} does not exist' assert event['data'].get( 'content_changes') is not None, f'content_changes is empty' def no_diff_validator(event): """ Validate content_changes value is truncated if the file is set to no_diff """ if is_truncated: assert '<Diff truncated because nodiff option>' in event['data'].get('content_changes'), \ f'content_changes is not truncated' else: assert '<Diff truncated because nodiff option>' not in event['data'].get('content_changes'), \ f'content_changes is truncated' regular_file_cud( folder, wazuh_log_monitor, file_list=file_list, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled', min_timeout=DEFAULT_TIMEOUT, triggers_event=True, validators_after_update=[report_changes_validator, no_diff_validator])
def test_process_priority(get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Check if the ossec-syscheckd service priority is updated correctly using <process_priority> tag in ossec.conf. """ check_apply_test({'ossec_conf'}, get_configuration['tags']) priority = int(get_configuration['metadata']['process_priority']) process_name = 'ossec-syscheckd' syscheckd_process = get_process(process_name) assert syscheckd_process is not None, f'Process {process_name} not found' assert syscheckd_process.nice( ) == priority, f'Process {process_name} has not updated its priority.'
def test_no_diff_subdirectory(folder, filename, content, hidden_content, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Checks files are ignored in the subdirectory according to configuration When using the nodiff option for a file in syscheck configuration, every time we get an event from this file, we won't be able to see its content. We'll see 'Diff truncated because nodiff option' instead. :param folder: Directory where the file is being created :param filename: Name of the file to be created :param content: Content to fill the new file :param hidden_content: True if content must be truncated,, False otherwise :param tags_to_apply: Run test if matches with a configuration identifier, skip otherwise * This test is intended to be used with valid nodiff configurations. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) files = {filename: content} def report_changes_validator(event): """ Validate content_changes attribute exists in the event """ for file in files: diff_file = os.path.join(WAZUH_PATH, 'queue', 'diff', 'local', folder.strip(PREFIX), file) assert os.path.exists(diff_file), f'{diff_file} does not exist' assert event['data'].get( 'content_changes') is not None, f'content_changes is empty' def no_diff_validator(event): """ Validate content_changes value is truncated if the file is set to no_diff """ if hidden_content: assert '<Diff truncated because nodiff option>' in event['data'].get('content_changes'), \ f'content_changes is not truncated' else: assert '<Diff truncated because nodiff option>' not in event['data'].get('content_changes'), \ f'content_changes is truncated' regular_file_cud( folder, wazuh_log_monitor, file_list=files, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled', min_timeout=DEFAULT_TIMEOUT, triggers_event=True, validators_after_update=[report_changes_validator, no_diff_validator])
def test_reconnect_to_audit(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Restart auditd and check Wazuh reconnect to auditd Parameters ---------- tags_to_apply : set Configuration tag to apply in the test """ check_apply_test(tags_to_apply, get_configuration['tags']) subprocess.run(["service", "auditd", "restart"], check=True) wazuh_log_monitor.start(timeout=20, callback=callback_audit_connection_close) wazuh_log_monitor.start(timeout=20, callback=callback_audit_connection)
def test_benchmark_regular_files(files, folder, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Checks syscheckd detects a certain volume of file changes (add, modify, delete) :param files: List of regular files to be created :param folder: Monitored directory where files will be created * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) min_timeout = 30 regular_file_cud(folder, wazuh_log_monitor, file_list=files, min_timeout=min_timeout, triggers_event=True)
def test_readded_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Checks if the removed rules are added to Audit rules list.""" check_apply_test(tags_to_apply, get_configuration['tags']) # Remove added rules for dir in (testdir1, testdir2, testdir3): os.system("auditctl -W {0} -p wa -k wazuh_fim".format(dir)) wazuh_log_monitor.start(timeout=20, callback=callback_audit_rules_manipulation) events = wazuh_log_monitor.start( timeout=10, callback=callback_audit_reloaded_rule).result() assert dir in events, f'{dir} not in {events}'
def test_ambiguous_recursion(dirname, recursion_level, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Checks alerts for each level defined in recursion_level Checks if syscheck detects alerts for each level defined in the recursion_level attribute. This overwrites the default value, restricting it. If we set recursion_level=1 and we have this monitored directory /testdir It will only monitor /testdir and /testdir/subdir If we had /testdir/subdir/subdir2, /subdir2 wouldn't be monitored This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. Parameters ---------- dirname : string Name of the monitored directory recursion_level : int Value of the recursion_level attribute 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' recursion_subdir = 'subdir' path = dirname # Iterate from ini to fin and verify that events are generated in the nested directories. path = _test_recursion_cud(ini=0, fin=recursion_level, path=path, recursion_subdir=recursion_subdir, scheduled=scheduled, min_timeout=DEFAULT_TIMEOUT, triggers_event=True) # Iterate from ini to fin and verify that events are NOT generated in nested directories # beyond the established recursion level. _test_recursion_cud(ini=recursion_level, fin=4, path=path, recursion_subdir=recursion_subdir, scheduled=scheduled, min_timeout=DEFAULT_TIMEOUT, triggers_event=False)
def test_ambiguous_recursion_tag(dirnames, recursion_level, triggers_event, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Checks alerts for each level defined in recursion_level with tags Checks if syscheck detects alerts for each level defined in the recursion_level attribute and if it detects the event property 'tags' for each of them. This overwrites the default value, restricting it. This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. Parameters ---------- dirnames : list Monitored directories recursion_level : int Value of the recursion_level attribute triggers_event : bool determine if the event should be raised or not. 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' recursion_subdir = 'subdir' # Iterate from ini to fin and verify that events generated in the nested directories contain the key 'tags'. _test_recursion_cud(ini=0, fin=recursion_level, path=dirnames[0], recursion_subdir=recursion_subdir, scheduled=scheduled, min_timeout=DEFAULT_TIMEOUT, triggers_event=triggers_event, validators_after_cud=[tag_validator]) # Iterate from ini to fin and verify that events generated in the nested directories DO NOT contain the key 'tags'. _test_recursion_cud(ini=0, fin=recursion_level, path=dirnames[1], recursion_subdir=recursion_subdir, scheduled=scheduled, min_timeout=DEFAULT_TIMEOUT, triggers_event=triggers_event, validators_after_cud=[no_tag_validator])
def test_symbolic_delete_symlink(tags_to_apply, main_folder, aux_folder, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if syscheck stops detecting events when deleting the monitored symlink. CHECK: Having a symbolic link pointing to a file/folder, remove that symbolic link file, wait for the symlink checker runs and modify the target file. No events should be detected. Restore the symbolic link and modify the target file again once symlink checker runs. Events should be detected now. :param main_folder: Directory that is being pointed at or contains the pointed file :param aux_folder: Directory that will be pointed at or will contain the future pointed file * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' file1 = 'regular1' if tags_to_apply == {'monitored_dir'}: create_file(REGULAR, main_folder, file1, content='') check_time_travel(scheduled) wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) # Remove symlink and don't expect events symlink = 'symlink' if tags_to_apply == {'monitored_file'} else 'symlink2' delete_f(testdir_link, symlink) wait_for_symlink_check(wazuh_log_monitor) modify_file_content(main_folder, file1, new_content='Sample modification') check_time_travel(scheduled) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) # Restore symlink and modify the target again. Expect events now create_file(SYMLINK, testdir_link, symlink, target=os.path.join(main_folder, file1)) wait_for_symlink_check(wazuh_log_monitor) modify_file_content(main_folder, file1, new_content='Sample modification 2') check_time_travel(scheduled) modify = wazuh_log_monitor.start(timeout=3, callback=callback_detect_event).result() assert 'modified' in modify['data']['type'] and file1 in modify['data']['path'], \ f"'modified' event not matching for {file1}"
def test_symbolic_revert_symlink(tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """ Check if syscheck detects new targets properly CHECK: Having a symbolic link pointing to a file/folder, change its target to a folder. Check that the old file is not being monitored anymore and the new folder is. Revert the target change and ensure the file is being monitored and the folder is not. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ def modify_and_assert(file): modify_file_content(testdir1, file, new_content='Sample modification') check_time_travel(scheduled) ev = wazuh_log_monitor.start(timeout=3, callback=callback_detect_event).result() assert 'modified' in ev['data']['type'] and os.path.join(testdir1, file) in ev['data']['path'], \ f"'modified' event not matching for {testdir1} {file}" check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' whodata = get_configuration['metadata']['fim_mode'] == 'whodata' file1 = 'regular1' file2 = 'regular2' # Don't expect an event since it is not being monitored yet modify_file_content(testdir1, file2, new_content='Sample modification') check_time_travel(scheduled) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) # Change the target to the folder and now expect an event modify_symlink(testdir1, os.path.join(testdir_link, 'symlink')) wait_for_symlink_check(wazuh_log_monitor) wait_for_audit(whodata, wazuh_log_monitor) modify_and_assert(file2) # Modify symlink target, wait for sym_check to update it modify_symlink(os.path.join(testdir1, file1), os.path.join(testdir_link, 'symlink')) wait_for_symlink_check(wazuh_log_monitor) modify_file_content(testdir1, file2, new_content='Sample modification2') check_time_travel(scheduled) with pytest.raises(TimeoutError): wazuh_log_monitor.start(timeout=3, callback=callback_detect_event) modify_and_assert(file1)
def test_readded_rules_on_restart(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Checks if the rules are added to Audit when it restarts.""" check_apply_test(tags_to_apply, get_configuration['tags']) # Restart Audit p = subprocess.Popen(["service", "auditd", "restart"]) p.wait() wazuh_log_monitor.start(timeout=10, callback=callback_audit_connection) events = wazuh_log_monitor.start(timeout=30, callback=callback_audit_loaded_rule, accum_results=3).result() assert testdir1 in events, f'{testdir1} not in {events}' assert testdir2 in events, f'{testdir2} not in {events}' assert testdir3 in events, f'{testdir3} not in {events}'
def test_remove_and_read_folder(tags_to_apply, folder, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Remove folder which is monitored with auditd and then create it again. Parameters ---------- tags_to_apply : set Configuration tag to apply in the test folder : str The folder to remove and readd """ check_apply_test(tags_to_apply, get_configuration['tags']) shutil.rmtree(folder, ignore_errors=True) wazuh_log_monitor.start(timeout=20, callback=callback_audit_removed_rule) os.makedirs(folder, mode=0o777) wazuh_log_monitor.start(timeout=30, callback=callback_audit_reloaded_rule)
def test_entries_match_path_count(get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Checks if FIM entries match the path count It creates two regular files, a symlink and a hard link before the scan begins. After events are logged, we should have 3 inode entries and a path count of 4. * This test is intended to be used with valid configurations files. Each execution of this test will configure the environment properly, restart the service and wait for the initial scan. """ check_apply_test({'ossec_conf'}, get_configuration['tags']) entries, path_count = wazuh_log_monitor.start( timeout=DEFAULT_TIMEOUT, callback=callback_entries_path_count).result() check_time_travel(True) if entries and path_count: assert entries == '3' and path_count == '4', 'Wrong number of inodes and path count' else: raise AssertionError('Wrong number of inodes and path count')