def test_regular_file_changes(sleep, tags_to_apply, get_configuration, configure_environment, restart_syscheckd,
                              wait_for_initial_scan):
    """
    Check if syscheckd detects regular file changes (add, modify, delete) with a very specific delay between every
    action.

    Parameters
    ----------
    sleep : float
        Delay in seconds between every action.
    """
    threshold = 1.5 if sys.platform == 'win32' else 1.25
    if sleep < threshold and get_configuration['metadata']['fim_mode'] == 'whodata':
        pytest.xfail('Xfailing due to whodata threshold.')
    check_apply_test(tags_to_apply, get_configuration['tags'])

    file = 'regular'
    create_file(REGULAR, path=testdir1, name=file, content='')
    time.sleep(sleep)
    modify_file(path=testdir1, name=file, new_content='Sample')
    time.sleep(sleep)
    delete_file(path=testdir1, name=file)

    events = wazuh_log_monitor.start(timeout=max(sleep * 3, global_parameters.default_timeout), callback=callback_detect_event, accum_results=3,
                                     error_message='Did not receive expected "Sending FIM event: ..." event').result()

    for ev in events:
        validate_event(ev)
示例#2
0
def test_check_all_no(path, checkers, get_configuration, configure_environment,
                      restart_syscheckd, wait_for_initial_scan):
    """
    Test the functionality of `check_all` option when set to no.

    When setting `check_all` to no, only 'type' and 'checksum' attributes should appear in every event. This will
    avoid any modification event.

    Parameters
    ----------
    path : str
        Directory where the file is being created and monitored.
    checkers : dict
        Check options to be used.
    """
    check_apply_test({'test_check_all_no'}, get_configuration['tags'])
    scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled'

    # Create regular file and dont expect any check
    file = 'regular'
    create_file(REGULAR, path, file)
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    create_event = wazuh_log_monitor.start(
        callback=callback_detect_event,
        timeout=15,
        error_message='Did not receive expected '
        '"Sending FIM event: ..." event').result()
    assert create_event['data']['type'] == 'added'
    assert list(
        create_event['data']['attributes'].keys()) == ['type', 'checksum']

    # Delete regular file and dont expect any check. Since it is not using any check, modification events will not
    # be triggered
    modify_file(path, file, 'Sample modification')
    with pytest.raises(TimeoutError):
        event = wazuh_log_monitor.start(callback=callback_detect_event,
                                        timeout=5)
        raise AttributeError(f'Unexpected event {event}')

    delete_file(path, file)
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    delete_event = wazuh_log_monitor.start(
        callback=callback_detect_event,
        timeout=15,
        error_message='Did not receive expected '
        '"Sending FIM event: ..." event').result()
    assert delete_event['data'][
        'type'] == 'deleted', f'Current value is {delete_event["data"]["type"]}'
    assert list(delete_event['data']['attributes'].keys()) == ['type', 'checksum'], \
        f'Current value is {list(delete_event["data"]["attributes"].keys())}'
示例#3
0
def configure_syscheck_environment(time_sleep):
    # Create every needed directory
    for n in range(n_directories):
        t_dir = os.path.join(PREFIX, f'{testdir}{n}')
        os.makedirs(t_dir, exist_ok=True, mode=0o777)
        directories_list.append(t_dir)

    wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)
    control_service('restart')
    logger.debug('Waiting 15 seconds for syscheckd to start.')
    time.sleep(15)

    file = 'regular'

    logger.debug(
        f'Waiting {str(time_sleep)} seconds. Execute `generate_windows_yaml.py` now.'
    )
    time.sleep(time_sleep)

    logger.debug('Creating files...')
    for directory in directories_list:
        create_file(REGULAR, directory, file, content='')
        time.sleep(0.01)
    try:
        while True:
            wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
    except TimeoutError:
        pass

    logger.debug('Modifying files...')
    for directory in directories_list:
        modify_file(directory, file, new_content='Modified')
        time.sleep(0.01)
    try:
        while True:
            wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
    except TimeoutError:
        pass

    logger.debug('Deleting files...')
    for directory in directories_list:
        delete_file(directory, file)
        time.sleep(0.01)
    try:
        while True:
            wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
    except TimeoutError:
        pass
示例#4
0
def test_follow_symbolic_disabled(path, tags_to_apply, get_configuration, configure_environment, restart_syscheckd,
                                  wait_for_fim_start):
    """Check what happens when follow_symbolic_link option is set to "no".

    Ensure that the monitored symbolic link is considered a regular file and it will not follow its target path. It will
    only generate events if it changes somehow, not its target (file or directory)

    Args:
        path (str): Path of the target file or directory
        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 a expected event wasn't triggered.
        AttributeError: If a unexpected event was captured.
    """
    check_apply_test(tags_to_apply, get_configuration['tags'])
    scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled'
    regular_file = 'regular1'
    error_msg = 'A "Sending FIM event: ..." event has been detected. No events should be detected at this time.'

    # If the symlink targets to a directory, create a file in it and ensure no event is raised.
    if tags_to_apply == {'monitored_dir'}:
        fim.create_file(fim.REGULAR, path, regular_file)
        fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
        with pytest.raises(TimeoutError):
            wazuh_log_monitor.start(timeout=5, callback=fim.callback_detect_event)
            logger.error(error_msg)
            raise AttributeError(error_msg)

    # Modify the target file and don't expect any events
    fim.modify_file(path, regular_file, new_content='Modify sample')
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        wazuh_log_monitor.start(timeout=5, callback=fim.callback_detect_event)
        logger.error(error_msg)
        raise AttributeError(error_msg)

    # Delete the target file and don't expect any events
    fim.delete_file(path, regular_file)
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        wazuh_log_monitor.start(timeout=5, callback=fim.callback_detect_event)
        logger.error(error_msg)
        raise AttributeError(error_msg)
def test_follow_symbolic_disabled(path, tags_to_apply, get_configuration,
                                  configure_environment, restart_syscheckd,
                                  wait_for_initial_scan):
    """Check what happens when follow_symbolic_link option is set to "no".

    Ensure that the monitored symbolic link is considered a regular file and it will not follow its target path. It will
    only generate events if it changes somehow, not its target (file or directory)

    Parameters
    ----------
    path : str
        Path of the target file or directory
    """
    check_apply_test(tags_to_apply, get_configuration['tags'])
    scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled'
    regular_file = 'regular1'
    error_msg = 'A "Sending FIM event: ..." event has been detected. No events should be detected at this time.'

    # If the symlink targets to a directory, create a file in it and ensure no event is raised.
    if tags_to_apply == {'monitored_dir'}:
        create_file(REGULAR, path, regular_file)
        check_time_travel(scheduled, monitor=wazuh_log_monitor)
        with pytest.raises(TimeoutError):
            wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
            logger.error(error_msg)
            raise AttributeError(error_msg)

    # Modify the target file and don't expect any events
    modify_file(path, regular_file, new_content='Modify sample')
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
        logger.error(error_msg)
        raise AttributeError(error_msg)

    # Delete the target file and don't expect any events
    delete_file(path, regular_file)
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        wazuh_log_monitor.start(timeout=5, callback=callback_detect_event)
        logger.error(error_msg)
        raise AttributeError(error_msg)
示例#6
0
def test_regular_file_changes(sleep, tags_to_apply, get_configuration,
                              configure_environment, restart_syscheckd,
                              wait_for_initial_scan):
    """
    Check if syscheckd detects regular file changes (add, modify, delete) with a very specific delay between every
    action.

    Parameters
    ----------
    sleep : float
        Delay in seconds between every action.
    """
    check_apply_test(tags_to_apply, get_configuration['tags'])

    file = 'regular'
    create_file(REGULAR, path=testdir1, name=file, content='')
    time.sleep(sleep)
    modify_file(path=testdir1, name=file, new_content='Sample')
    time.sleep(sleep)
    delete_file(path=testdir1, name=file)

    try:
        events = wazuh_log_monitor.start(
            timeout=max(sleep * 3, global_parameters.default_timeout),
            callback=callback_detect_event,
            accum_results=3,
            error_message='Did not receive expected '
            '"Sending FIM event: ..." event').result()
        for ev in events:
            validate_event(ev)
    except TimeoutError as e:
        if get_configuration['metadata']['fim_mode'] == 'whodata':
            pytest.xfail(
                reason=
                'Xfailing due to issue: https://github.com/wazuh/wazuh/issues/4710'
            )
        else:
            raise e
示例#7
0
def test_symbolic_monitor_directory_with_symlink(
        monitored_dir, non_monitored_dir1, non_monitored_dir2, sym_target,
        tags_to_apply, get_configuration, configure_environment,
        clean_directories, restart_syscheckd, wait_for_initial_scan):
    """
    Check what happens with a symlink and its target when syscheck monitors a directory with a symlink
    and not the symlink itself.

    When this happens, the symbolic link is considered a regular file and it will not follow its target path.
    It will only generate events if it changes somehow, not its target (file or directory)

    Parameters
    ----------
    monitored_dir : str
        Monitored directory.
    non_monitored_dir1 : str
        Non-monitored directory.
    non_monitored_dir2 : str
        Non-monitored directory.
    """
    check_apply_test(tags_to_apply, get_configuration['tags'])
    name1 = 'regular1'
    name2 = 'regular2'
    sl_name = 'symlink'
    a_path = os.path.join(non_monitored_dir1, name1)
    b_path = os.path.join(
        non_monitored_dir1,
        name2) if sym_target == 'file' else non_monitored_dir2
    sl_path = os.path.join(monitored_dir, sl_name)
    scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled'

    # Create regular files out of the monitored directory and don't expect its event
    create_file(REGULAR, non_monitored_dir1, name1, content='')
    create_file(REGULAR, non_monitored_dir1, name2, content='')
    target = a_path if sym_target == 'file' else non_monitored_dir1
    create_file(SYMLINK, monitored_dir, sl_name, target=target)

    # Create the syslink and expect its event, since it's withing the monitored directory
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    wazuh_log_monitor.start(
        timeout=global_parameters.default_timeout,
        callback=callback_detect_event,
        error_message='Did not receive expected "Sending FIM event: ..." event'
    )

    # Modify the target file and don't expect any event
    modify_file(non_monitored_dir1, name1, new_content='Modify sample')
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        event = wazuh_log_monitor.start(timeout=5,
                                        callback=callback_detect_event)
        logger.error(f'Unexpected event {event.result()}')
        raise AttributeError(f'Unexpected event {event.result()}')

    # Modify the target of the symlink and expect the modify event
    modify_symlink(target=b_path, path=sl_path)
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    result = 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 'modified' in result['data'][
        'type'], f"No 'modified' event when modifying symlink"

    # Remove and restore the target file. Don't expect any events
    delete_file(b_path, name2)
    create_file(REGULAR, non_monitored_dir1, name2, content='')
    check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        event = wazuh_log_monitor.start(timeout=5,
                                        callback=callback_detect_event)
        logger.error(f'Unexpected event {event.result()}')
        raise AttributeError(f'Unexpected event {event.result()}')
示例#8
0
def test_symbolic_monitor_directory_with_symlink(
        monitored_dir, non_monitored_dir1, non_monitored_dir2, sym_target,
        tags_to_apply, get_configuration, configure_environment,
        restart_syscheckd, wait_for_fim_start):
    """Check what happens with a symlink and its target when syscheck monitors a directory with a symlink
    and not the symlink itself.

    When this happens, the symbolic link is considered a regular file and it will not follow its target path.
    It will only generate events if it changes somehow, not its target (file or directory)


    Args:
        monitored_dir (str): Monitored directory.
        non_monitored_dir1 (str): Non-monitored directory.
        non_monitored_dir2 (str): Non-monitored directory.
        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 a expected event wasn't triggered.
        AttributeError: If a unexpected event was captured.
        ValueError: If the event's type and path are not the expected.
    """
    check_apply_test(tags_to_apply, get_configuration['tags'])
    name1 = f'{sym_target}regular1'
    name2 = f'{sym_target}regular2'
    sl_name = f'{sym_target}symlink'
    a_path = os.path.join(non_monitored_dir1, name1)
    b_path = os.path.join(
        non_monitored_dir1,
        name2) if sym_target == 'file' else non_monitored_dir2
    sl_path = os.path.join(monitored_dir, sl_name)
    scheduled = get_configuration['metadata']['fim_mode'] == 'scheduled'

    # Create regular files out of the monitored directory and don't expect its event
    fim.create_file(fim.REGULAR, non_monitored_dir1, name1, content='')
    fim.create_file(fim.REGULAR, non_monitored_dir1, name2, content='')
    target = a_path if sym_target == 'file' else non_monitored_dir1
    fim.create_file(fim.SYMLINK, monitored_dir, sl_name, target=target)

    # Create the syslink and expect its event, since it's withing the monitored directory
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    wazuh_log_monitor.start(
        timeout=global_parameters.default_timeout,
        callback=fim.callback_detect_event,
        error_message='Did not receive expected "Sending FIM event: ..." event'
    )

    # Modify the target file and don't expect any event
    fim.modify_file(non_monitored_dir1, name1, new_content='Modify sample')
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        event = wazuh_log_monitor.start(timeout=5,
                                        callback=fim.callback_detect_event)
        logger.error(f'Unexpected event {event.result()}')
        raise AttributeError(f'Unexpected event {event.result()}')

    # Modify the target of the symlink and expect the modify event
    modify_symlink(target=b_path, path=sl_path)
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    result = wazuh_log_monitor.start(
        timeout=global_parameters.default_timeout,
        callback=fim.callback_detect_event,
        error_message='Did not receive expected '
        '"Sending FIM event: ..." event').result()
    if 'modified' in result['data']['type']:
        logger.info(
            "Received modified event. No more events will be expected.")
    elif 'deleted' in result['data']['type']:
        logger.info(
            "Received deleted event. Now an added event will be expected.")
        result = wazuh_log_monitor.start(
            timeout=global_parameters.default_timeout,
            callback=fim.callback_detect_event,
            error_message='Did not receive expected '
            '"Sending FIM event: ..." event').result()
        assert 'added' in result['data'][
            'type'], f"The event {result} should be of type 'added'"
    else:
        assert False, f"Detected event {result} should be of type 'modified' or 'deleted'"

    # Remove and restore the target file. Don't expect any events
    fim.delete_file(b_path, name2)
    fim.create_file(fim.REGULAR, non_monitored_dir1, name2, content='')
    fim.check_time_travel(scheduled, monitor=wazuh_log_monitor)
    with pytest.raises(TimeoutError):
        event = wazuh_log_monitor.start(timeout=5,
                                        callback=fim.callback_detect_event)
        logger.error(f'Unexpected event {event.result()}')
        raise AttributeError(f'Unexpected event {event.result()}')
示例#9
0
def generate_analysisd_yaml(n_events, modify_events):
    def parse_events_into_yaml(requests, yaml_file):
        yaml_result = []
        with open(yaml_file, 'a') as y_f:
            id_ev = 0
            for req, event in requests:
                type_ev = event['data']['type']
                stage_ev = type_ev.title()
                mode = None
                agent_id = callback_analysisd_agent_id(req) or '000'

                del event['data']['mode']
                del event['data']['type']
                if 'tags' in event['data']:
                    del event['data']['tags']
                if type_ev == 'added':
                    mode = 'save2'
                    output_ev = json.dumps(event['data'])

                elif type_ev == 'deleted':
                    mode = 'delete'
                    output_ev = json.dumps(event['data']['path']).replace(
                        '"', '')

                elif type_ev == 'modified':
                    mode = 'save2'
                    for field in [
                            'old_attributes', 'changed_attributes',
                            'content_changes'
                    ]:
                        if field in event['data']:
                            del event['data'][field]
                    output_ev = json.dumps(event['data'])

                yaml_result.append({
                    'name':
                    f"{stage_ev}{id_ev}",
                    'test_case': [{
                        'input': f"{req}",
                        'output':
                        f"agent {agent_id} syscheck {mode} {output_ev}",
                        'stage': f"{stage_ev}"
                    }]
                })
                id_ev += 1
            y_f.write(yaml.safe_dump(yaml_result))

    def remove_logs():
        for root, dirs, files in os.walk(WAZUH_LOGS_PATH):
            for file in files:
                os.remove(os.path.join(root, file))

    file = 'regular'

    # Restart syscheckd with the new configuration
    truncate_file(LOG_FILE_PATH)
    file_monitor = FileMonitor(LOG_FILE_PATH)
    control_service('stop')
    check_daemon_status(running=False)
    remove_logs()

    control_service('start', daemon='wazuh-db', debug_mode=True)
    check_daemon_status(running=True, daemon='wazuh-db')

    control_service('start', daemon='wazuh-analysisd', debug_mode=True)
    check_daemon_status(running=True, daemon='wazuh-analysisd')

    mitm_analysisd = ManInTheMiddle(address=analysis_path,
                                    family='AF_UNIX',
                                    connection_protocol='UDP')
    analysis_queue = mitm_analysisd.queue
    mitm_analysisd.start()

    control_service('start', daemon='wazuh-syscheckd', debug_mode=True)
    check_daemon_status(running=True, daemon='wazuh-syscheckd')

    # Wait for initial scan
    detect_initial_scan(file_monitor)

    analysis_monitor = QueueMonitor(analysis_queue)

    for directory in directories_list:
        create_file(REGULAR, directory, file, content='')
        time.sleep(0.01)
    added = analysis_monitor.start(
        timeout=max(0.01 * n_events, 10),
        callback=callback_analysisd_event,
        accum_results=len(directories_list)).result()
    logger.debug('"added" alerts collected.')

    for directory in directories_list:
        modify_file(directory, file, new_content='Modified')
        time.sleep(0.01)
    modified = analysis_monitor.start(timeout=max(0.01 * n_events, 10),
                                      callback=callback_analysisd_event,
                                      accum_results=modify_events).result()
    logger.debug('"modified" alerts collected.')

    for directory in directories_list:
        delete_file(directory, file)
        time.sleep(0.01)
    deleted = analysis_monitor.start(
        timeout=max(0.01 * len(directories_list), 10),
        callback=callback_analysisd_event,
        accum_results=len(directories_list)).result()
    logger.debug('"deleted" alerts collected.')

    # Truncate file
    with open(yaml_file, 'w') as y_f:
        y_f.write(f'---\n')

    for ev_list in [added, modified, deleted]:
        parse_events_into_yaml(ev_list, yaml_file)
    logger.debug(f'YAML done: "{yaml_file}"')

    return mitm_analysisd