def test_report_changes_after_restart(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check if diff directories are removed after disabling report_changes and Wazuh is restarted. """ check_apply_test({'test_delete_after_restart'}, get_configuration['tags']) value_name = 'random_value' folder_path_key1, diff_file_key_1 = calculate_registry_diff_paths( key, sub_key_1, KEY_WOW64_64KEY, value_name) folder_path_key2, diff_file_key_2 = calculate_registry_diff_paths( key, sub_key_1, KEY_WOW64_64KEY, value_name) # Open key key1_h = create_registry(registry_parser[key], sub_key_1, KEY_WOW64_64KEY) key2_h = create_registry(registry_parser[key], sub_key_2, KEY_WOW64_64KEY) # Modify the registry modify_registry_value(key1_h, value_name, REG_SZ, "some_content") modify_registry_value(key2_h, value_name, REG_SZ, "some_content") # Travel to future check_time_travel(True, monitor=wazuh_log_monitor) assert os.path.exists( diff_file_key_1), f'{diff_file_key_1} does not exists' assert os.path.exists( diff_file_key_2), f'{diff_file_key_2} does not exists' reload_new_conf('no', test_regs[0], test_regs[1]) assert not os.path.exists( folder_path_key1), f'{folder_path_key1} does exists' assert not os.path.exists( folder_path_key2), f'{folder_path_key2} does exists'
def extra_configuration_before_yield(): # Create 3000 files before restarting Wazuh to make sure the integrity scan will not finish before testing 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 test_disk_quota_values(key, subkey, arch, value_name, tags_to_apply, size, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check that no events are sent when the disk_quota exceeded Parameters ---------- key : str Root key (HKEY_*) subkey : str path of the registry. arch : str Architecture of the registry. value_name : str Name of the value that will be created tags_to_apply : set Run test if match with a configuration identifier, skip otherwise. size : int Size of the content to write in value """ check_apply_test(tags_to_apply, get_configuration['tags']) value_content = generate_string(size, '0') values = {value_name: value_content} _, diff_file = calculate_registry_diff_paths(key, subkey, arch, value_name) def report_changes_validator_no_diff(event): """Validate content_changes attribute exists in the event""" assert event['data'].get( 'content_changes') is None, 'content_changes isn\'t empty' def report_changes_validator_diff(event): """Validate content_changes attribute exists in the event""" assert os.path.exists(diff_file), '{diff_file} does not exist' assert event['data'].get( 'content_changes') is not None, 'content_changes is empty' if size > size_limit_configured: callback_test = report_changes_validator_no_diff else: callback_test = report_changes_validator_diff create_registry(registry_parser[key], subkey, arch) registry_value_cud( key, subkey, wazuh_log_monitor, arch=arch, value_list=values, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled', min_timeout=global_parameters.default_timeout, triggers_event=True, validators_after_update=[callback_test]) delete_registry(registry_parser[key], subkey, arch) check_time_travel(True, monitor=wazuh_log_monitor)
def extra_configuration_before_yield(): key_h = create_registry(registry_parser[key], sub_key_1, arch) modify_registry_value(key_h, "value1", REG_SZ, "some content") modify_registry_value(key_h, "value2", REG_MULTI_SZ, "some content\0second string\0") modify_registry_value(key_h, "value3", REG_DWORD, 1234)
def test_new_key(get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check that a new monitored key generates events after the next scheduled scan. """ create_registry(registry_parser[key], sub_key_1, arch) check_time_travel(True, monitor=wazuh_log_monitor) registry_value_cud( key, sub_key_1, wazuh_log_monitor, arch=arch, time_travel=get_configuration['metadata']['fim_mode'] == 'scheduled', min_timeout=global_parameters.default_timeout, triggers_event=True)
def extra_configuration_before_yield(): """Generate registry entries to fill database""" reg1_handle = create_registry(registry_parser[KEY], sub_key_1, KEY_WOW64_64KEY) reg1_handle = RegOpenKeyEx(registry_parser[KEY], sub_key_1, 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') RegCloseKey(reg1_handle)
def test_events_while_integrity_scan(tags_to_apply, get_configuration, configure_environment, restart_syscheckd): """Check that events are being generated while a synchronization is being performed simultaneously. """ 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) # 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, 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() 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() 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') # 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, callback=callback_detect_event, error_message='Did not receive expected ' '"Sending FIM event: ..." event').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, 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) assert sending_event['data']['arch'] == '[x64]'
def test_file_size_default(key, subkey, arch, value_name, tags_to_apply, get_configuration, configure_environment, restart_syscheckd_each_time): """ Check that no events are sent when the disk_quota exceeded Parameters ---------- key : str Root key (HKEY_*) subkey : str path of the registry. arch : str Architecture of the registry. value_name : str Name of the value that will be created tags_to_apply : set Run test if match with a configuration identifier, skip otherwise. size : int Size of the content to write in value """ check_apply_test(tags_to_apply, get_configuration['tags']) mode = get_configuration['metadata']['fim_mode'] file_size_values = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_diff_size_limit_value, accum_results=3, error_message='Did not receive expected ' '"Maximum file size limit to generate diff information ' 'configured to \'... KB\'..." event').result() for value in file_size_values: if value: assert value == str(DEFAULT_SIZE), 'Wrong value for file_size' else: raise AssertionError('Wrong value for file_size') key_h = create_registry(registry_parser[key], subkey, arch) modify_registry_value(key_h, "some_value", REG_SZ, "some content") check_time_travel(True, monitor=wazuh_log_monitor) events = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=2, error_message='Did not receive expected ' '"Sending FIM event: ..." event').result() for ev in events: validate_registry_value_event(ev, mode=mode)
def test_wait_until_baseline(key, subkey, arch, value_type, content, get_configuration, configure_environment, restart_syscheckd_each_time): """ Check if events are appearing after the baseline The message 'File integrity monitoring scan ended' informs about the end of the first scan, which generates the baseline """ key_handle = create_registry(registry_parser[key], subkey, arch) modify_registry_value(key_handle, "value_name", value_type, content) wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event_before_end_scan, error_message='Did not receive expected event before end the scan')
def perform_and_validate_events(func, content='added', is_delete=False): for reg in subkeys: key_handle = create_registry(registry_parser[root_key], reg, KEY_WOW64_32KEY) if not is_delete: func(key_handle, 'test_value', REG_SZ, content) else: func(key_handle, 'test_value') RegCloseKey(key_handle) check_time_travel(True, monitor=log_monitor) events = log_monitor.start( timeout=timeout, callback=callback_value_event, accum_results=num_entries, error_message= 'Did not receive expected "Sending FIM event: ..." event').result( ) for ev in events: validate_registry_value_event(ev)
def test_registry_sync_after_restart(key_name, value_name, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Test to check that FIM synchronizes the registry DB when a modification is performed while the agent is down. Params: key_name (str): Name of the subkey that will be created in the test. value_name (str): Name of the value that will be created in the test. If 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 a path or value are not in the sync event. """ check_apply_test(tags_to_apply, get_configuration['tags']) key_path = os.path.join(subkey, key_name) value_path = os.path.join(key, key_path, value_name) # wait until the sync is done. get_sync_msgs(sync_interval) # stops syscheckd control_service('stop') key_handle = fim.create_registry(fim.registry_parser[key], key_path, fim.KEY_WOW64_64KEY) fim.modify_registry_value(key_handle, value_name, fim.REG_SZ, 'This is a test with syscheckd down.') control_service('start') events = get_sync_msgs(sync_interval + 15) assert find_value_in_event_list( os.path.join(key, key_path), value_name, events) is not None, f"No sync event was found for {value_path}"
def configure_syscheck_environment(time_sleep): # Create every needed directory for n in range(n_windows_registry): t_dir = f'{testreg}{n}' create_registry(registry_parser[KEY], f'{testreg}{n}', KEY_WOW64_64KEY) reg_list.append(t_dir) control_service('restart') logger.debug('Waiting 15 seconds for syscheckd to start.') time.sleep(15) reg_key = 'reg_key' reg_value = 'value_name' logger.debug( f'Waiting {str(time_sleep)} seconds. Execute `generate_windows_yaml.py` now.' ) time.sleep(time_sleep) logger.debug(f'Waiting {SCAN_WAIT} seconds for baseline scan to finish.') time.sleep(120) logger.debug('Creating registries...') for registry in reg_list: key_h = create_registry(registry_parser[KEY], os.path.join(registry, reg_key), KEY_WOW64_64KEY) modify_registry_value(key_h, reg_value, REG_SZ, 'added') TimeMachine.travel_to_future(timedelta(hours=13)) logger.debug(f'Waiting {SCAN_WAIT} seconds for scan to finish.') time.sleep(SCAN_WAIT) logger.debug('Modifying registries...') for registry in reg_list: modify_key_perms( registry_parser[KEY], os.path.join(registry, reg_key), KEY_WOW64_64KEY, LookupAccountName(None, f"{platform.node()}\\{os.getlogin()}")[0]) modify_registry_owner( registry_parser[KEY], os.path.join(registry, reg_key), KEY_WOW64_64KEY, LookupAccountName(None, f"{platform.node()}\\{os.getlogin()}")[0]) key_h = RegOpenKeyEx(registry_parser[KEY], os.path.join(registry, reg_key), 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY) modify_registry_value(key_h, reg_value, REG_SZ, 'modified') TimeMachine.travel_to_future(timedelta(hours=13)) logger.debug(f'Waiting {SCAN_WAIT} seconds for scan to finish.') time.sleep(SCAN_WAIT) logger.debug('Deleting registries...') for registry in reg_list: delete_registry(registry_parser[KEY], os.path.join(registry, reg_key), KEY_WOW64_64KEY) TimeMachine.travel_to_future(timedelta(hours=13)) logger.debug(f'Waiting {SCAN_WAIT} seconds for scan to finish.') time.sleep(SCAN_WAIT)
def test_restrict_value(key, subkey, arch, value_name, triggers_event, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check the only registry values detected are those matching the restrict regex Parameters ---------- key : str Root key (HKEY_*) subkey : str path of the registry. arch : str Architecture of the registry. value_name : str Name of the value that will be created triggers_event : bool True if an event must be generated, False otherwise. tags_to_apply : set Run test if match with a configuration identifier, skip otherwise. """ check_apply_test(tags_to_apply, get_configuration['tags']) # This shouldn't create an alert because the key is already created key_h = create_registry(registry_parser[key], subkey, arch) # Create values modify_registry_value(key_h, value_name, REG_SZ, "added") # Go ahead in time to let syscheck perform a new scan check_time_travel(get_configuration['metadata']['fim_mode'] == 'scheduled', monitor=wazuh_log_monitor) event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=2 if triggers_event else 1).result() if triggers_event: assert event[0]['data']['type'] == 'modified', 'Key event not modified' assert event[0]['data']['path'] == os.path.join( key, subkey), 'Key event wrong path' assert event[0]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Key event arch not equal' assert event[1]['data']['type'] == 'added', 'Event type not equal' assert event[1]['data']['path'] == os.path.join( key, subkey), 'Event path not equal' assert event[1]['data'][ 'value_name'] == value_name, 'Value name not equal' assert event[1]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Value event arch not equal' else: assert event['data']['type'] == 'modified', 'Key event not modified' assert event['data']['path'] == os.path.join( key, subkey), 'Key event wrong path' assert event['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Key event arch not equal' while True: ignored_value = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_restricted, error_message='Did not receive expected ' '"Sending FIM event: ..." event').result() if ignored_value == value_name: break delete_registry_value(key_h, value_name) # Go ahead in time to let syscheck perform a new scan check_time_travel(get_configuration['metadata']['fim_mode'] == 'scheduled', monitor=wazuh_log_monitor) event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=2 if triggers_event else 1).result() if triggers_event: assert event[0]['data']['type'] == 'modified', 'Key event not modified' assert event[0]['data']['path'] == os.path.join( key, subkey), 'Key event wrong path' assert event[0]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Key event arch not equal' assert event[1]['data']['type'] == 'deleted', 'Event type not equal' assert event[1]['data']['path'] == os.path.join( key, subkey), 'Event path not equal' assert event[1]['data'][ 'value_name'] == value_name, 'Value name not equal' assert event[1]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Value event arch not equal' else: # After deleting the value, we don't expect any message of the value because it's not in the DB assert event['data']['type'] == 'modified', 'Key event not modified' assert event['data']['path'] == os.path.join( key, subkey), 'Key event wrong path' assert event['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Key event arch not equal'
def test_restrict_key(key, subkey, test_subkey, arch, triggers_event, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check the only registry keys detected are those matching the restrict regex Parameters ---------- key : str Root key (HKEY_*) subkey : str Path of the registry. test_subkey : str Name of the key that will be used for the test arch : str Architecture of the registry. triggers_event : bool True if an event must be generated, False otherwise. tags_to_apply : set Run test if match with a configuration identifier, skip otherwise. """ check_apply_test(tags_to_apply, get_configuration['tags']) test_key = os.path.join(subkey, test_subkey) create_registry(registry_parser[key], test_key, arch) # Go ahead in time to let syscheck perform a new scan check_time_travel(get_configuration['metadata']['fim_mode'] == 'scheduled', monitor=wazuh_log_monitor) if triggers_event: event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=1).result() assert event['data']['type'] == 'added', 'Event type not equal' assert event['data']['path'] == os.path.join( key, test_key), 'Event path not equal' assert event['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Arch not equal' else: while True: ignored_key = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_restricted, error_message='Did not receive expected ' '"Sending FIM event: ..." event').result() if ignored_key == os.path.join(key, subkey): break delete_registry(registry_parser[key], test_key, arch) # Go ahead in time to let syscheck perform a new scan check_time_travel(get_configuration['metadata']['fim_mode'] == 'scheduled', monitor=wazuh_log_monitor) if triggers_event: event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=1).result() assert event['data']['type'] == 'deleted', 'key event not equal' assert event['data']['path'] == os.path.join( key, test_key), 'Key event wrong path' assert event['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Key arch not equal'
def test_windows_registry(arch_list, tag, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_initial_scan): """Check the correct monitoring of Windows Registries. This test creates a new registry in windows, adds a value, modifies it and then deletes the registry. It verifies that syscheck correctly monitors certain events while applying different settings. Parameters ---------- arch_list : list Selected architectures. tag : str Name of the tag to look for in 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']) # Check that configuration is applying to the correct test if ((tag and 'tags' not in get_configuration['metadata']['attribute'].keys()) or (len(arch_list) > 1 and 'arch' not in get_configuration['metadata']['attribute'].keys())): pytest.skip("Does not apply to this config file") # Check that windows_registry does not trigger alerts for new keys create_registry(winreg.HKEY_LOCAL_MACHINE, sub_key, winreg.KEY_WOW64_32KEY | winreg.KEY_WRITE) check_time_travel(time_travel=True, interval=timedelta(seconds=frequency), monitor=wazuh_log_monitor) with pytest.raises(TimeoutError): wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message= 'Did not receive expected "Sending FIM event: ..." event', accum_results=len(arch_list)) # Check that windows_registry trigger alerts when adding an entry modify_registry(winreg.HKEY_LOCAL_MACHINE, sub_key, 'test_add') check_time_travel(time_travel=True, interval=timedelta(seconds=frequency), 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', accum_results=len(arch_list)).result() if not isinstance(event, list): event = [event] for i, arch in enumerate(arch_list): assert event[i]['data']['type'] == 'added', f'Event type not equal' # Check that windows_registry trigger alerts when modifying existing entries # and check arch and tag values match with the ones in event modify_registry(winreg.HKEY_LOCAL_MACHINE, sub_key, 'test_modify') check_time_travel(time_travel=True, interval=timedelta(seconds=frequency), 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', accum_results=len(arch_list)).result() if not isinstance(event, list): event = [event] for i, arch in enumerate(arch_list): assert event[i]['data']['type'] == 'modified', f'Event type not equal' if arch: assert arch in event[i]['data'][ 'path'], f'Architecture is not correct' if tag: assert event[i]['data']['tags'] == tag, f'{tag} not found in event' # Check that windows_registry trigger alerts when deleting a key delete_registry(winreg.HKEY_LOCAL_MACHINE, sub_key, winreg.KEY_WOW64_32KEY) check_time_travel(time_travel=True, interval=timedelta(seconds=frequency), 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', accum_results=len(arch_list)).result() if not isinstance(event, list): event = [event] for i, arch in enumerate(arch_list): assert event[i]['data'][ 'type'] == 'deleted', f'{event[i]["data"]["type"]} type not equal to deleted'
def test_ignore_registry_key(root_key, registry, arch, subkey, triggers_event, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check registry keys are ignored according to configuration. Parameters ---------- root_key : str Root key (HKEY_*) registry : str path of the registry where the test will be executed. arch : str Architecture of the registry. subkey : str Name of the key that will be created. triggers_event : bool True if an event must be generated, False otherwise. tags_to_apply : set Run test if match with a configuration identifier, skip otherwise. """ check_apply_test(tags_to_apply, get_configuration['tags']) scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled' # Create registry create_registry(registry_parser[root_key], os.path.join(registry, subkey), arch) # Go ahead in time to let syscheck perform a new scan check_time_travel(scheduled, monitor=wazuh_log_monitor) if triggers_event: event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message='Did not receive expected ' '"Sending FIM event: ..." event', accum_results=2).result() assert event[0]['data']['type'] == 'added', 'Wrong event type.' assert event[0]['data']['path'] == os.path.join( root_key, registry, subkey), 'Wrong key path.' assert event[0]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Wrong key arch.' assert event[1]['data'][ 'type'] == 'modified', 'Parent key event type not equal' assert event[1]['data']['path'] == os.path.join( root_key, registry), 'Wrong parent key path.' assert event[1]['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Parent key arch not equal.' else: # The ignore event is generated before the event of the parent key. while True: # Look for the ignore event of the created key ignored_key = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_ignore).result() if ignored_key == "{} {}".format( '[x64]' if arch == KEY_WOW64_64KEY else '[x32]', os.path.join(root_key, registry, subkey)): break event = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message='Did not receive expected ' '"Sending FIM event: ..." event', accum_results=1).result() assert event['data'][ 'type'] == 'modified', 'Parent key event type not equal' assert event['data']['path'] == os.path.join( root_key, registry), 'Wrong parent key path.' assert event['data'][ 'arch'] == '[x32]' if arch == KEY_WOW64_32KEY else '[x64]', 'Parent key arch not equal.'
def configure_environment(get_configuration, request): """Configure a custom environment for testing. Restart Wazuh is needed for applying the configuration.""" # Save current configuration backup_config = conf.get_wazuh_conf() # Configuration for testing test_config = conf.set_section_wazuh_conf(get_configuration.get('sections')) # Create test directories if hasattr(request.module, 'test_directories'): test_directories = getattr(request.module, 'test_directories') for test_dir in test_directories: os.makedirs(test_dir, exist_ok=True, mode=0o777) # Create test registry keys if sys.platform == 'win32': if hasattr(request.module, 'test_regs'): test_regs = getattr(request.module, 'test_regs') for reg in test_regs: match = re.match(r"(^HKEY_[a-zA-Z_]+)\\+(.+$)", reg) create_registry(registry_parser[match.group(1)], match.group(2), KEY_WOW64_32KEY) create_registry(registry_parser[match.group(1)], match.group(2), KEY_WOW64_64KEY) # Set new configuration conf.write_wazuh_conf(test_config) # Change Windows Date format to ensure TimeMachine will work properly if sys.platform == 'win32': subprocess.call('reg add "HKCU\\Control Panel\\International" /f /v sShortDate /t REG_SZ /d "dd/MM/yyyy" >nul', shell=True) # Call extra functions before yield if hasattr(request.module, 'extra_configuration_before_yield'): func = getattr(request.module, 'extra_configuration_before_yield') func() # Set current configuration global_parameters.current_configuration = get_configuration yield TimeMachine.time_rollback() # Remove created folders (parents) if sys.platform == 'win32' and not hasattr(request.module, 'no_restart_windows_after_configuration_set'): control_service('stop') if hasattr(request.module, 'test_directories'): for test_dir in test_directories: shutil.rmtree(test_dir, ignore_errors=True) if sys.platform == 'win32': if hasattr(request.module, 'test_regs'): for reg in test_regs: match = re.match(r"(^HKEY_[a-zA-Z_]+)\\+(.+$)", reg) delete_registry(registry_parser[match.group(1)], match.group(2), KEY_WOW64_32KEY) delete_registry(registry_parser[match.group(1)], match.group(2), KEY_WOW64_64KEY) if sys.platform == 'win32' and not hasattr(request.module, 'no_restart_windows_after_configuration_set'): control_service('start') # Restore previous configuration conf.write_wazuh_conf(backup_config) # Call extra functions after yield if hasattr(request.module, 'extra_configuration_after_yield'): func = getattr(request.module, 'extra_configuration_after_yield') func() if hasattr(request.module, 'force_restart_after_restoring'): if getattr(request.module, 'force_restart_after_restoring'): control_service('restart')
def test_registry_responses(key_name, value_name, tags_to_apply, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """Test to check that the fields in synchronization events are decoded properly by the agent. Params: key_name (str): Name of the subkey that will be created in the test. value_name (str): Name of the value that will be created in the test. If 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 a path or value are not in the sync event. """ if key_name is None and value_name is None: pytest.skip('key_name and value_name are None. Skipping') check_apply_test(tags_to_apply, get_configuration['tags']) # Wait for subkey sync messages only when it's expected if key_name is not None: fim.create_registry(fim.registry_parser[key], os.path.join(subkey, key_name), fim.KEY_WOW64_64KEY) fim.check_time_travel(True, monitor=wazuh_log_monitor) wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=fim.callback_detect_end_scan, error_message='Did not receive expected "end_scan" event').result( ) events = get_sync_msgs(sync_interval + 15) # Parent key sync event assert find_path_in_event_list( test_regs[0], events) is not None, f"No sync event was found for {test_regs[0]}" # Subkey sync event subkey_path = os.path.join(test_regs[0], key_name) assert find_path_in_event_list( subkey_path, events) is not None, f'No sync event was found for {subkey_path}' if value_name is not None: if key_name is not None: key_path = os.path.join(subkey, key_name) else: key_path = subkey value_path = os.path.join(key, key_path, value_name) key_handle = fim.RegOpenKeyEx(fim.registry_parser[key], key_path, 0, fim.KEY_ALL_ACCESS | fim.KEY_WOW64_64KEY) fim.modify_registry_value(key_handle, value_name, fim.REG_SZ, 'This is a test') fim.check_time_travel(True, monitor=wazuh_log_monitor) wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=fim.callback_detect_end_scan, error_message='Did not receive expected "end_scan" event').result( ) events = get_sync_msgs(sync_interval + 15) assert find_value_in_event_list( os.path.join(key, key_path), value_name, events) is not None, f"No sync event was found for {value_path}"
def extra_configuration_before_yield(): create_registry(registry_parser[key], sub_key_1, arch)
def test_delete_registry(key, subkey, arch, value_list, get_configuration, configure_environment, restart_syscheckd, wait_for_fim_start): """ Check if syscheckd detects 'deleted' events from the values contained in a registry key that is being deleted. Parameters ---------- key : str Root key where the sub key will be created (HKEY_LOCAL_MACHINE, etc) subkey : str Path of the registry subkey arch : int Arch of the registry subkey value_list : list Names of the values. """ mode = get_configuration['metadata']['fim_mode'] scheduled = mode == 'scheduled' key_h = create_registry(registry_parser[key], subkey, arch) # Create values inside subkey modify_registry_value(key_h, value_list[0], REG_SZ, "some content") modify_registry_value(key_h, value_list[1], REG_MULTI_SZ, "some content\0second string\0") modify_registry_value(key_h, value_list[2], REG_DWORD, 1234) check_time_travel(scheduled, monitor=wazuh_log_monitor) events = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, accum_results=len(value_list) + 1, error_message='Did not receive expected ' '"Sending FIM event: ..." event').result() for ev in events: validate_registry_value_event(ev, mode=mode) # Remove registry delete_registry(registry_parser[key], subkey, arch) check_time_travel(scheduled, monitor=wazuh_log_monitor) # Expect deleted events event_list = wazuh_log_monitor.start( timeout=global_parameters.default_timeout, callback=callback_detect_event, error_message='Did not receive expected ' '"Sending FIM event: ..." event', accum_results=len(value_list) + 1).result() counter_type = Counter([event['data']['type'] for event in event_list]) for ev in events: validate_registry_value_event(ev, mode=mode) assert counter_type['deleted'] == len( value_list ) + 1, f'Number of "deleted" events should be {len(value_list) + 1}' name_list = set([event['data']['value_name'] for event in event_list[1:]]) for value in value_list: assert value in name_list, f'Value {value} not found within the events'
def extra_configuration_before_yield(): for reg, rl in rl_dict.items(): path = str(reg) for n in range(int(rl)): path = os.path.join(path, '' + str(n + 1)) create_registry(registry_parser[key], path, KEY_WOW64_64KEY)