def test_readded_rules_on_restart(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the rules are added to Audit when it restarts.""" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) # Restart Audit restart_command = ["service", "auditd", "restart"] p = subprocess.Popen(restart_command) p.wait() wazuh_log_monitor.start( timeout=10, callback=callback_audit_connection, error_message= f'Did not receive expected "connect" event with the command ' f'{" ".join(restart_command)}') events = wazuh_log_monitor.start( timeout=30, callback=callback_audit_reloaded_rule, accum_results=3, error_message=f'Did not receive expected "load" event with the command ' f'{" ".join(restart_command)}').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_readded_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the removed rules are added to Audit rules list. Args: tags_to_apply (set): Run test if matches with a configuration identifier, skip otherwise. get_configuration (fixture): Gets the current configuration of the test. configure_environment (fixture): Configure the environment for the execution of the test. restart_syscheckd (fixture): Restarts syscheck. wait_for_fim_start (fixture): Waits until the first FIM scan is completed. Raises: TimeoutError: If an expected event couldn't be captured. ValueError: If the path of the event is wrong. """ logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) # Remove added rules for dir_ in (testdir1, testdir2, testdir3): command = f"auditctl -W {dir_} -p wa -k wazuh_fim" os.system(command) wazuh_log_monitor.start(timeout=20, callback=fim.callback_audit_rules_manipulation, error_message=f'Did not receive expected "manipulation" event with the ' f'command {command}') events = wazuh_log_monitor.start(timeout=10, callback=fim.callback_audit_added_rule, error_message='Did not receive expected "added" event with the rule ' 'modification').result() assert dir_ in events, f'{dir_} not in {events}'
def test_move_rules_realtime(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the rules are changed to realtime when Audit stops.""" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) # Stop Audit stop_command = ["service", "auditd", "stop"] p = subprocess.Popen(stop_command) p.wait() events = wazuh_log_monitor.start( timeout=30, callback=callback_realtime_added_directory, accum_results=3, error_message= f'Did not receive expected "directory added" for monitoring ' f'with the command {" ".join(stop_command)}').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' # Start Audit p = subprocess.Popen(["service", "auditd", "start"]) p.wait()
def check_events_path(events, folder, file_list=['testfile0'], mode=None): mode = global_parameters.current_configuration['metadata'][ 'fim_mode'] if mode is None else mode audit_path = filter_events( events, ".[].data.audit.path") if mode == "whodata" else None data_path = filter_events(events, ".[].data.path") for file_name in file_list: expected_path = os.path.join(folder, file_name) expected_path = expected_path[:1].lower() + expected_path[1:] if self.encoding is not None: for index, item in enumerate(data_path): data_path[index] = item.encode(encoding=self.encoding) if audit_path: for index, item in enumerate(audit_path): audit_path[index] = item.encode( encoding=self.encoding) if sys.platform == 'darwin' and self.encoding and self.encoding != 'utf-8': logger.info( f'Not asserting {expected_path} in event.data.path. ' f'Reason: using non-utf-8 encoding in darwin.') else: error_msg = f"Expected data path was '{expected_path}' but event data path is '{data_path}'" assert (expected_path in data_path), error_msg if audit_path: error_msg = f"Expected audit path was '{expected_path}' but event audit path is '{audit_path}'" assert (expected_path in audit_path), error_msg
def modify_file_owner(path, name): """ Change the owner of a file. The new owner will be '1'. On Windows, uid will always be 0. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. """ def modify_file_owner_windows(): cmd = f"takeown /S 127.0.0.1 /U {os.getlogin()} /F " + path_to_file subprocess.call(cmd) def modify_file_owner_unix(): os.chown(path_to_file, 1, -1) path_to_file = os.path.join(path, name) logger.info("- Changing owner of " + str(path_to_file)) if sys.platform == 'win32': modify_file_owner_windows() else: modify_file_owner_unix()
def test_readded_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the removed rules are added to Audit rules list.""" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) # Remove added rules for dir_ in (testdir1, testdir2, testdir3): command = f"auditctl -W {dir_} -p wa -k wazuh_fim" os.system(command) wazuh_log_monitor.start( timeout=20, callback=callback_audit_rules_manipulation, error_message= f'Did not receive expected "manipulation" event with the ' f'command {command}') events = wazuh_log_monitor.start( timeout=10, callback=callback_audit_reloaded_rule, error_message= 'Did not receive expected "reload" event with the rule ' 'modification').result() assert dir_ in events, f'{dir_} not in {events}'
def info_collector(agents_dict, agent_id, attempts_info, configuration, actual_n_attempts, actual_n_completions, num_files, state='complete', checksum=None): """Write the stats of the agent during the test. This stats will be written when the agent finish its test process (n_completions(agent_id) > 0). Parameters ---------- agents_dict : dict Dictionary with the start time of every agent. agent_id : str Agent id. attempts_info : shared dict Dictionary with a flag that indicates if the stats collector must start. num_files : str Number of files of this test state : str complete of except_max_attempts: Indicates if the agent took less attempts than the defined limits or not. configuration : str Test configuration checksum : str or None New checksum for files or None if there is no modifications """ if state != 'complete': attempts_info['except_max_attempts'] = True attempts_info['agents_failed'] += 1 if state != 'complete' and checksum: completion = get_files_with_checksum(agent_id, checksum, int(num_files)) elif state != 'complete' and not checksum: completion = 'Case0: no checksums modified' else: completion = None logger.info( f"Info {agent_id} writing: " f"{agent_id},{actual_n_attempts},{actual_n_completions},{agents_dict[agent_id]['start']}," f"{time.time()},{time.time() - agents_dict[agent_id]['start']},{state},{completion}" ) end_time = np.float32(time.time()) lock = Lock() lock.acquire() agents_dict[agent_id]['dataframe'] = { 'configuration': configuration, 'agent_id': agent_id, 'n_attempts': actual_n_attempts, 'n_completions': actual_n_completions, 'start_time': agents_dict[agent_id]['start'], 'end_time': end_time, 'total_time': np.float32(end_time - agents_dict[agent_id]['start']), 'state': str(state), 'complete(%)': str(completion) } lock.release()
def test_added_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the specified folders are added to Audit rules list. Args: tags_to_apply (set): Run test if matches with a configuration identifier, skip otherwise. get_configuration (fixture): Gets the current configuration of the test. configure_environment (fixture): Configure the environment for the execution of the test. restart_syscheckd (fixture): Restarts syscheck. wait_for_fim_start (fixture): Waits until the first FIM scan is completed. Raises: TimeoutError: If an expected event couldn't be captured. ValueError: If the path of the event is wrong. """ logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) logger.info('Checking the event...') events = wazuh_log_monitor.start(timeout=20, callback=fim.callback_audit_added_rule, accum_results=3, error_message='Folders were not added to Audit rules list' ).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 modify_file_win_attributes(path, name): if sys.platform != 'win32': return logger.info("- Changing win attributes of " + str(os.path.join(path, name))) path_to_file = os.path.join(path, name) win32api.SetFileAttributes(path_to_file, win32con.FILE_ATTRIBUTE_HIDDEN)
def test_audit_health_check(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the health check is passed.""" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) wazuh_log_monitor.start(timeout=20, callback=callback_audit_health_check, error_message='Health check failed')
def test_duplicate_entries(get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Check if syscheckd ignores duplicate entries. For instance: - The second entry should prevail over the first one. <directories realtime="yes">/home/user</directories> (IGNORED) <directories whodata="yes">/home/user</directories> OR - Just generate one event. <directories realtime="yes">/home/user,/home/user</directories> """ logger.info('Applying the test configuration') check_apply_test({'ossec_conf_duplicate_simple'}, get_configuration['tags']) file = 'hello' mode2 = get_configuration['metadata']['fim_mode2'] scheduled = mode2 == 'scheduled' mode2 = "real-time" if mode2 == "realtime" else mode2 logger.info(f'Adding file {os.path.join(testdir1, file)}, content: " "') create_file(REGULAR, testdir1, file, content=' ') logger.info(f'Time travel: {scheduled}') check_time_travel(scheduled) logger.info('Checking the event...') event1 = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message=f'Did not receive expected event for file ' f'{os.path.join(testdir1, file)}').result() # Check for a second event event2 = check_event(previous_mode=mode2, previous_event=event1, file=file) assert event2 is None, "Multiple events created"
def test_added_rules(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the specified folders are added to Audit rules list.""" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) logger.info('Checking the event...') events = wazuh_log_monitor.start( timeout=20, callback=callback_audit_added_rule, accum_results=3, error_message='Folders were not added to Audit rules list').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 delete_file(path, name): """ Delete a regular file. Parameters ---------- path : str Path to the file to be deleted. name : str Name of the file to be deleted """ logger.info(f"Removing file {str(os.path.join(path, name))}") regular_path = os.path.join(path, name) if os.path.exists(regular_path): os.remove(regular_path)
def test_restart_audit(tags_to_apply, should_restart, get_configuration, configure_environment, restart_syscheckd): """Check `<restart_audit>` functionality by removing the plugin and monitoring audit to see if it restart and create the file again. Args: tags_to_apply (set): Run test if matches with a configuration identifier, skip otherwise. should_restart (boolean): True if Auditd should restart, False otherwise get_configuration (fixture): Gets the current configuration of the test. configure_environment (fixture): Configure the environment for the execution of the test. restart_syscheckd (fixture): Restarts syscheck. wait_for_fim_start (fixture): Waits until the first FIM scan is completed. Raises: TimeoutError: If an expected event couldn't be captured. ValueError: If the time before the and after the restart are equal when auditd has been restarted or if the time before and after the restart are different when auditd hasn't been restarted """ def get_audit_creation_time(): for proc in psutil.process_iter(attrs=['name']): if proc.name() == "auditd": logger.info(f"auditd detected. PID: {proc.pid}") return proc.create_time() pytest.fail("Auditd is not running") plugin_path = "/etc/audisp/plugins.d/af_wazuh.conf" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) os.remove(plugin_path) time_before_restart = get_audit_creation_time() control_service('restart') try: check_daemon_status(timeout=30) except TimeoutError: pass time_after_restart = get_audit_creation_time() if should_restart: assert time_before_restart != time_after_restart, 'The time before restart audit is equal to ' \ 'the time after restart' else: assert time_before_restart == time_after_restart, 'The time before restart audit is not equal to ' \ 'the time after restart' assert os.path.isfile(plugin_path)
def modify_registry(key, subkey, value): """ Modify the content of REG_SZ in a registry Parameters ---------- key : str The key of the registry (HKEY_* constants) subkey : str The subkey (name) of the registry. value : str The value to be set. """ logger.info("Modifying windows registry.") sys.platform == 'win32' and winreg.SetValue(key, subkey, winreg.REG_SZ, value)
def modify_file_mtime(path, name): """ Change the modification time of a file. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. """ path_to_file = os.path.join(path, name) logger.info("- Changing mtime of " + str(path_to_file)) stat = os.stat(path_to_file) access_time = stat[ST_ATIME] modification_time = stat[ST_MTIME] modification_time = modification_time + 1000 os.utime(path_to_file, (access_time, modification_time))
def modify_database(agent_id, directory, prefix, total_files, modify_file, modify_all, restore_all): """Modify the database files Parameters ---------- agent_id : str Database identifier. directory : str Directory of the file to which we will modify your checksum. prefix : str Prefix of the filename. total_files Total files in the directory. modify_file : bool Flag for modify the checksum of a file. modify_all Flag for modify all checksums in the database. restore_all Flag that indicate if all entries in the fim_entry table should be deleted. """ checksum = None if modify_file: total_files = int(total_files) if total_files == 0: total_files = 1 checksum = 'new_checksum' file = f"{directory}/{prefix}{randrange(total_files)}" db_query( agent_id, f'UPDATE fim_entry SET checksum="{checksum}" WHERE file="{file}"') logger.info(f'Modify checksum of {file}, set to {checksum}') if modify_all: checksum = 'new_checksum2' db_query(agent_id, f'UPDATE fim_entry SET checksum="{checksum}"') logger.info(f'Modify all checksums to {checksum}') if restore_all: db_query(agent_id, 'DELETE FROM fim_entry') db_query(agent_id, 'UPDATE sync_info SET n_attempts=0') db_query(agent_id, 'UPDATE sync_info SET n_completions=0') return checksum
def check_event(previous_mode: str, previous_event: dict, file: str): """Check if a file modification does not trigger an event but its creation did. In case of timeout, checks that the type of the previous event was addition on the correct path and with correct mode. Parameters ---------- previous_mode : str String that contains the mode that the previous event should have previous_event : dict Dict with the previous event file : str String that contains the name of the monitored file Returns ------- dict Dict with the triggered event """ current_event = None try: logger.info('Checking for a second event...') current_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() except TimeoutError: if not isinstance(previous_event["data"]["path"], list): previous_event["data"]["path"] = [previous_event["data"]["path"]] if 'added' not in previous_event['data']['type'] and \ os.path.join(testdir1, file) in list(previous_event['data']['path']) and \ previous_mode in previous_event['data']['mode']: raise AttributeError( f'It was expected that the previous event would be an "added" event, ' f'its type is "{previous_event["data"]["type"]}", ' f'also the "{os.path.join(testdir1, file)}" file would be in ' f'{previous_event["data"]["path"]} and that the "{previous_mode}" mode would be ' f'"{previous_event["data"]["mode"]}"') return current_event
def modify_file_group(path, name): """ Change the group of a file. The new group will be '1'. Available for UNIX. On Windows, gid will always be 0 and the group name will be blank. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. """ if sys.platform == 'win32': return path_to_file = os.path.join(path, name) logger.info("- Changing group of " + str(path_to_file)) os.chown(path_to_file, -1, 1)
def scan_integrity_test(fim_df, string_configuration, configuration, integrity_df, fim_type='scan'): """Get the stats when the scan and integrity is running. Parameters ---------- fim_df : Pandas DataFrame DataFrame that contains the stats. string_configuration: str String with the current configuration configuration : dict Dict with the current configuration integrity_df : Pandas DataFrame, optional DataFrame that contains the integrity stats. fim_type : str, optional scan or integrity. """ time_printing, pause, time_fim = 0, 0, None stats = get_stats(tested_daemon) old_stats = deepcopy(stats) logger.info( f"[SCAN] Test {fim_type} with {str(configuration['path_length'])} path length, {configuration['number_files']}" f" files and {configuration['file_size']} KB file size") while time_fim is None: diff = calculate_stats(old_stats, stats) old_stats = deepcopy(stats) logger.info(diff) if fim_type == 'scan': time_fim = find_ossec_log(r".*during: ([0-9]+\.[0-9]+) sec", "fim_print_info") elif fim_type == 'integrity': time_fim = find_ossec_log(r".*Time: ([0-9]+\.[0-9]+) seconds.", "Finished calculating FIM integrity") else: raise AttributeError(f'Invalid type detected: {fim_type}') fim_df.loc[len(fim_df)] = [string_configuration, str(time_printing), *list(diff.values()), fim_type] if time_fim is not None: db_size, journal_size = get_db_size() integrity_df.loc[len(integrity_df)] = [string_configuration, fim_type, db_size, journal_size, str(time_fim)] break time_printing += 1 time.sleep(1) stats = get_stats(tested_daemon)
def test_restart_audit(tags_to_apply, should_restart, get_configuration, configure_environment, restart_syscheckd): """Check <restart_audit> functionality by removing the plugin and monitoring audit to see if it restart and create the file again. Parameters ---------- tags_to_apply : set Run test if matches with a configuration identifier, skip otherwise should_restart : boolean True if Auditd should restart, False otherwise """ def get_audit_creation_time(): for proc in psutil.process_iter(attrs=['name']): if proc.name() == "auditd": logger.info(f"auditd detected. PID: {proc.pid}") return proc.create_time() pytest.fail("Auditd is not running") plugin_path = "/etc/audisp/plugins.d/af_wazuh.conf" logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) os.remove(plugin_path) time_before_restart = get_audit_creation_time() control_service('restart') try: check_daemon_status(timeout=30) except TimeoutError: pass time_after_restart = get_audit_creation_time() if should_restart: assert time_before_restart != time_after_restart, 'The time before restart audit is equal to ' \ 'the time after restart' else: assert time_before_restart == time_after_restart, 'The time before restart audit is not equal to ' \ 'the time after restart' assert os.path.isfile(plugin_path)
def test_audit_key(audit_key, path, get_configuration, configure_environment, restart_syscheckd): """Check `<audit_key>` functionality by adding a audit rule and checking if alerts with that key are triggered when a file is created. Args: audit_key (str): Name of the audit_key to monitor. tags_to_apply (set): Run test if matches with a configuration identifier, skip otherwise. get_configuration (fixture): Gets the current configuration of the test. configure_environment (fixture): Configure the environment for the execution of the test. restart_syscheckd (fixture): Restarts syscheck. wait_for_fim_start (fixture): Waits until the first FIM scan is completed. Raises: TimeoutError: If an expected event couldn't be captured. ValueError: If the path of the event is wrong. """ logger.info('Applying the test configuration') check_apply_test({audit_key}, get_configuration['tags']) # Add watch rule add_rule_command = "auditctl -w " + path + " -p wa -k " + audit_key os.system(add_rule_command) # Restart and for wazuh control_service('stop') truncate_file(fim.LOG_FILE_PATH) wazuh_log_monitor = FileMonitor(fim.LOG_FILE_PATH) control_service('start') fim.detect_initial_scan(wazuh_log_monitor) # Look for audit_key word fim.create_file(fim.REGULAR, path, "testfile") events = wazuh_log_monitor.start(timeout=30, callback=fim.callback_audit_key, accum_results=1, error_message=f'Did not receive expected "Match audit_key ..." event ' f'with the command {" ".join(add_rule_command)}').result() assert audit_key in events # Remove watch rule os.system("auditctl -W " + path + " -p wa -k " + audit_key)
def modify_file_permission(path, name): """ Change the permision of a file. On UNIX the new permissions will be '666'. On Windows, a list of denied and allowed permissions will be given for each user or group since version 3.8.0. Only works on NTFS partitions on Windows systems. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. """ def modify_file_permission_windows(): import win32security import ntsecuritycon user, domain, account_type = win32security.LookupAccountName( None, f"{platform.node()}\\{os.getlogin()}") sd = win32security.GetFileSecurity( path_to_file, win32security.DACL_SECURITY_INFORMATION) dacl = sd.GetSecurityDescriptorDacl() dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_ALL_ACCESS, user) sd.SetSecurityDescriptorDacl(1, dacl, 0) win32security.SetFileSecurity(path_to_file, win32security.DACL_SECURITY_INFORMATION, sd) def modify_file_permission_unix(): os.chmod(path_to_file, 0o666) path_to_file = os.path.join(path, name) logger.info("- Changing permission of " + str(path_to_file)) if sys.platform == 'win32': modify_file_permission_windows() else: modify_file_permission_unix()
def test_audit_health_check(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check if the health check is passed. Args: tags_to_apply (set): Run test if matches with a configuration identifier, skip otherwise. get_configuration (fixture): Gets the current configuration of the test. configure_environment (fixture): Configure the environment for the execution of the test. restart_syscheckd (fixture): Restarts syscheck. wait_for_fim_start (fixture): Waits until the first FIM scan is completed. Raises: TimeoutError: If an expected event couldn't be captured. """ logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) wazuh_log_monitor.start(timeout=20, callback=fim.callback_audit_health_check, error_message='Health check failed')
def modify_file_content(path, name, new_content=None, is_binary=False): """ Modify the content of a file. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. new_content : str, optional New content to append to the file. Previous content will remain. Default `None` is_binary : boolean, optional True if the file's content is in binary format. False otherwise. Default `False` """ path_to_file = os.path.join(path, name) logger.info("- Changing content of " + str(path_to_file)) content = "1234567890qwertyu" if new_content is None else new_content with open(path_to_file, 'ab' if is_binary else 'a') as f: f.write(content.encode() if is_binary else content)
def modify_file_inode(path, name): """ Change the inode of a file. Parameters ---------- path : str, bytes Path to the file to be modified. name : str, bytes Name of the file to be modified. """ if sys.platform == 'win32': return logger.info("- Changing inode of " + str(os.path.join(path, name))) inode_file = 'inodetmp' path_to_file = os.path.join(path, name) shutil.copy2(path_to_file, os.path.join(tempfile.gettempdir(), inode_file)) os.replace(os.path.join(tempfile.gettempdir(), inode_file), path_to_file)
def test_duplicate_entries_report(get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Check if syscheckd ignores duplicate entries, report changes. For instance: - The second entry should prevail over the first one. <directories report_changes="yes">/home/user</directories> (IGNORED) <directories report_changes="no">/home/user</directories> """ logger.info('Applying the test configuration') check_apply_test({'ossec_conf_duplicate_report'}, get_configuration['tags']) file = 'hello' mode2 = get_configuration['metadata']['fim_mode2'] scheduled = mode2 == 'scheduled' # Check for an event logger.info(f'Adding file {os.path.join(testdir1, file)}, content: " "') create_file(REGULAR, testdir1, file, content=' ') logger.info(f'Time travel: {scheduled}') check_time_travel(scheduled, monitor=wazuh_log_monitor) wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message=f'Did not receive expected event for file ' f'{os.path.join(testdir1, file)}').result() # Check for a second event logger.info(f'Modifying {os.path.join(testdir1, file)} content') modify_file_content(testdir1, file) logger.info(f'Time travel: {scheduled}') check_time_travel(scheduled, monitor=wazuh_log_monitor) wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message=f'Did not receive expected event for file ' f'{os.path.join(testdir1, file)}').result() assert not os.path.exists(os.path.join(WAZUH_PATH, 'queue', 'diff', 'local', testdir1[1:], file)), \ 'Error: Diff file created'
def test_ignore_works_over_restrict(folder, filename, triggers_event, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Check if the ignore tag prevails over the restrict one when using both in the same directory. 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 ---------- folder : str Directory where the file is being created filename : str Name of the file to be created triggers_event : bool True if an event must be generated, False otherwise tags_to_apply : set Run test if it matches with a configuration identifier, skip otherwise """ logger.info('Applying the test configuration') check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' # Create file that must be ignored logger.info(f'Adding file {os.path.join(testdir1, filename)}, content: ""') create_file(REGULAR, folder, filename, content='') # Go ahead in time to let syscheck perform a new scan if mode is scheduled logger.info(f'Time travel: {scheduled}') check_time_travel(scheduled, monitor=wazuh_log_monitor) if triggers_event: logger.info('Checking the event...') event = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message=f'Did not receive expected "Sending FIM event" ' f'event for file {os.path.join(testdir1, filename)}').result() assert event['data']['type'] == 'added', 'Event type not equal' assert event['data']['path'] == os.path.join(folder, filename), 'Event path not equal' else: while True: ignored_file = wazuh_log_monitor.start(timeout=global_parameters.default_timeout, callback=callback_ignore, error_message=f'Did not receive expected ' f'"Ignoring ... due to ..." event for file ' f'{os.path.join(testdir1, filename)}').result() if ignored_file == os.path.join(folder, filename): break
def test_audit_key(audit_key, path, get_configuration, configure_environment, restart_syscheckd): """Check <audit_key> functionality by adding a audit rule and checking if alerts with that key are triggered when a file is created. Parameters ---------- audit_key : str Name of the audit_key to monitor path : str Path of the folder to be monitored """ logger.info('Applying the test configuration') check_apply_test({audit_key}, get_configuration['tags']) # Add watch rule add_rule_command = "auditctl -w " + path + " -p wa -k " + audit_key os.system(add_rule_command) # Restart and for wazuh control_service('stop') truncate_file(LOG_FILE_PATH) wazuh_log_monitor = FileMonitor(LOG_FILE_PATH) control_service('start') 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, error_message=f'Did not receive expected "Match audit_key ..." event ' f'with the command {" ".join(add_rule_command)}').result() assert audit_key in events # Remove watch rule os.system("auditctl -W " + path + " -p wa -k " + audit_key)
def check_time_travel(time_travel: bool, interval: timedelta = timedelta(hours=13), monitor: FileMonitor = None): """ Change date and time of the system depending on a boolean condition. 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. Parameters ---------- time_travel : boolean True if we need to update time. False otherwise. interval : timedelta, optional Time interval that will be added to system clock. Default: 13 hours. 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`. Raises ------ TimeoutError If `monitor` is not `None` and the scan has not ended in the default timeout specified in `global_parameters`. """ if time_travel: before = str(datetime.now()) TimeMachine.travel_to_future(interval) logger.info( f"Changing the system clock from {before} to {str(datetime.now())}" ) if monitor: monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_end_scan, update_position=False, error_message=f'End of scheduled scan not detected after ' f'{global_parameters.default_timeout} seconds')