Esempio n. 1
0
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}'
Esempio n. 2
0
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}'
Esempio n. 3
0
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()
Esempio n. 4
0
 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
Esempio n. 5
0
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()
Esempio n. 6
0
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}'
Esempio n. 7
0
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()
Esempio n. 8
0
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'
Esempio n. 9
0
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)
Esempio n. 10
0
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')
Esempio n. 11
0
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"
Esempio n. 12
0
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'
Esempio n. 13
0
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)
Esempio n. 14
0
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)
Esempio n. 15
0
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)
Esempio n. 16
0
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))
Esempio n. 17
0
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
Esempio n. 18
0
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
Esempio n. 19
0
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)
Esempio n. 20
0
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)
Esempio n. 21
0
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)
Esempio n. 22
0
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)
Esempio n. 23
0
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()
Esempio n. 24
0
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')
Esempio n. 25
0
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)
Esempio n. 26
0
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)
Esempio n. 27
0
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
Esempio n. 29
0
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)
Esempio n. 30
0
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')