Beispiel #1
0
def test_providers_no_os(clean_vuln_tables, get_configuration, configure_environment):
    """
    Check if modulesd downloads the feeds without specifing the os version.
    """
    check_apply_test({'test_providers_no_os'}, get_configuration['tags'])
    provider_name = get_configuration['metadata']['provider_name']

    # Those providers that aren't expected to work without the <os> tag.
    try:
        control_service('restart')
    except ValueError:
        assert 'error' in get_configuration['metadata']

    if 'error' in get_configuration['metadata']:
        wazuh_log_monitor.start(timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
                                callback=vd.make_vuln_callback(r".* \(\d+\): Configuration error at.*",
                                                               prefix='.*wazuh-modulesd.*'),
                                error_message=f"Error log 'Configuration error at '/var/ossec/etc/ossec.conf'.' "
                                              f"not found")
    else:
        for os in get_configuration['metadata']['os']:
            if os != '':
                os_name = f"{provider_name} {os}"
            else:
                os_name = f"JSON {provider_name}" if 'Red Hat' in provider_name else f"{provider_name}"

            wazuh_log_monitor.start(
                timeout=80 if 'Red Hat' in os_name else VULN_DETECTOR_GLOBAL_TIMEOUT,
                callback=make_vuln_callback(f"Starting '{os_name}' database update"),
                error_message=f"Could not find {os_name} update starting log",
            )
Beispiel #2
0
def test_vulnerabilities_report(get_configuration, configure_environment,
                                restart_modulesd, check_cve_db, mock_agent,
                                mock_vulnerability_scan):
    """
    Check if a missing patch triggers a vulnerability(only windows).
    """
    hotfixes = mock_vulnerability_scan['hotfixes']
    dep = vulnerabilities['dependencies']

    for cve, item in vulnerabilities['vulnerabilities'].items():
        installed, hotfix = is_hotfix_installed(item[0]['patch'], dep,
                                                hotfixes)
        if installed:
            wazuh_log_monitor.start(
                timeout=vd.VULN_DETECTOR_SCAN_TIMEOUT,
                update_position=False,
                callback=vd.make_vuln_callback(
                    f"Agent '{mock_agent}' has installed '{hotfix}' that corrects the vulnerability '{cve}'"
                ),
                error_message=
                f"Could not find the report which says that the patch {hotfix} solves {cve}"
            )
        else:
            wazuh_log_monitor.start(
                timeout=vd.VULN_DETECTOR_SCAN_TIMEOUT,
                update_position=False,
                callback=vd.make_vuln_callback(
                    f"Agent '{mock_agent}' is vulnerable to '{cve}'. Condition: 'KB{hotfix} patch is not installed'"
                ),
                error_message=
                f"Could not find the report which says that the system" +
                f" is vulnerable to {cve} due to missing {hotfix}")

    vd.check_if_modulesd_is_running()
def test_vulnerabilities_report(get_configuration, configure_environment, restart_modulesd, check_cve_db,
                                mock_vulnerability_scan):
    """
    Check if inserted vulnerable packages are reported by vulnerability detector
    """
    vulnerabilities_number = mock_vulnerability_scan["vulnerabilities_number"]

    if mock_vulnerability_scan['format'] == 'pkg' and mock_vulnerability_scan['version'] == 'Wazuh v4.0':
        version = mock_vulnerability_scan['version']
        wazuh_log_monitor.start(
            timeout=SCAN_TIMEOUT,
            update_position=False,
            callback=vd.make_vuln_callback(fr"Agent .* has an unsupported Wazuh version: '{version}'"),
            error_message="The expected event 'Agent .* has an unsupported Wazuh version' not found"
        )

        return

    # Check the vulnerabilities of inserted packages
    try:
        for item in nvd_vulnerabilities['vulnerabilities_nvd']:
            vd.check_vulnerability_scan_event(wazuh_log_monitor, item['package']['name'], item['cve']['cveid'])
    except TimeoutError:
        check_time_travel(time_travel=True, interval=timedelta(seconds=300))
        for item in nvd_vulnerabilities['vulnerabilities_nvd']:
            vd.check_vulnerability_scan_event(wazuh_log_monitor, item['package']['name'], item['cve']['cveid'])

    # Check that the number of NVD vulnerabilities is the expected
    if mock_vulnerability_scan["format"] != "win":
        vd.check_detected_vulnerabilities_number(wazuh_log_monitor=wazuh_log_monitor,
                                                 expected_vulnerabilities_number=vulnerabilities_number,
                                                 feed_source='NVD', timeout=vd.VULN_DETECTOR_SCAN_TIMEOUT)

    vd.check_if_modulesd_is_running()
def test_enabled(get_configuration, configure_environment, restart_modulesd):
    """
    Check if modulesd downloads the feeds from different providers when enabled is set to yes.
    """
    provider_name = get_configuration['metadata']['provider_name']
    if get_configuration['metadata']['enabled'] == 'no':
        with pytest.raises(TimeoutError):
            wazuh_log_monitor.start(
                timeout=VULN_DETECTOR_GLOBAL_TIMEOUT,
                callback=make_vuln_callback("Starting.+database update"))
            raise AttributeError(
                f"Unexpected event {provider_name} database updating")
    else:
        wazuh_log_monitor.start(
            timeout=VULN_DETECTOR_GLOBAL_TIMEOUT,
            callback=make_vuln_callback(
                f"Starting '{provider_name}' database update"),
            error_message=f"Could not find {provider_name} update starting log",
        )
Beispiel #5
0
def test_window_version_indexing(get_configuration, configure_environment,
                                 restart_modulesd, check_cve_db, mock_system):
    wazuh_log_monitor.start(
        timeout=50,
        update_position=False,
        callback=vd.make_vuln_callback(
            rf"The CPE 'o:microsoft:{mock_system['index_name']}:(-|r2|{mock_system['os_release']}):"
            +
            rf"({mock_system['os_release']})?:::::{mock_system['architecture']}:' from the agent '.*' was indexed."
        ),
        error_message=f"{mock_system['os_name']} was not indexed")
Beispiel #6
0
def test_providers(get_configuration, configure_environment, restart_modulesd):
    """
    Check if modulesd downloads the feeds for each os
    """
    check_apply_test({'test_providers_os'}, get_configuration['tags'])

    provider_name = get_configuration['metadata']['provider_name']
    if 'os_warning' in get_configuration['metadata']:
        wazuh_log_monitor.start(
            timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
            callback=vd.make_vuln_callback(
                rf".*Invalid option 'os' for .* provider.*",
                prefix='.*wazuh-modulesd.*'),
            error_message=
            f"Warning log 'Invalid option 'os' for '{provider_name}' "
            f"provider not found")
    wazuh_log_monitor.start(
        timeout=VULN_DETECTOR_GLOBAL_TIMEOUT,
        callback=make_vuln_callback(
            f"Starting '{provider_name}' database update"),
        error_message=f"Could not find {provider_name} update starting log",
    )
def test_ignore_time(get_configuration,
                     configure_environment,
                     restart_modulesd,
                     prepare_agent,
                     custom_callback_vulnerability=vd.make_vuln_callback(
                         callback_string_vulnerability)):
    """
    Check if an alert is not fired during the ignore time  interval
    """

    control_service('stop', daemon='wazuh-modulesd')
    control_service('stop', daemon='wazuh-db')
    vd.update_last_scan(agent=prepare_agent)
    control_service('start', daemon='wazuh-db')
    control_service('start', daemon='wazuh-modulesd')

    ignore_time = get_configuration['metadata']['ignore_time']
    jumps = get_configuration['metadata']['jumps']
    seconds_to_travel = time_to_seconds(ignore_time) / jumps

    # Check for initial alert
    wazuh_log_monitor.start(
        timeout=get_configuration['metadata']['timeout'],
        callback=custom_callback_vulnerability,
        error_message='Alert did not appear at the start of the test')

    # Check if alert does not appear during ignore time
    for _ in range(1, jumps):
        check_time_travel(time_travel=True,
                          interval=timedelta(seconds=seconds_to_travel))
        with pytest.raises(TimeoutError):
            wazuh_log_monitor.start(
                timeout=get_configuration['metadata']['timeout'],
                callback=custom_callback_vulnerability)
            raise AttributeError(
                'Alert appeared before ignore_time was finished')

    # Travel to the time set in ignore time
    check_time_travel(time_travel=True,
                      interval=timedelta(seconds=seconds_to_travel))

    # Check for final alert
    wazuh_log_monitor.start(
        timeout=get_configuration['metadata']['timeout'],
        callback=custom_callback_vulnerability,
        error_message='Alert did not appear at the end of the test')
Beispiel #8
0
def test_download_feeds(clean_vuln_tables, get_configuration,
                        configure_environment, restart_modulesd):
    """
    Check if modulesd downloads successfully the feeds from different providers and os.
    Additionaly, check that the updates are applied only when required. Ex: Outdated local database.
    """
    check_apply_test({'test_download_feeds'}, get_configuration['tags'])

    provider = get_configuration['metadata']['provider_name']
    os = get_configuration['metadata']['os'].capitalize()
    system_log = get_configuration['metadata']['system_log']
    download_timeout = get_configuration['metadata']['download_timeout']
    callback_system_log = system_log

    # If provider configuration has <os> tag
    if os and system_log == provider_info[provider]['system_log']:
        callback_system_log = f"{system_log} {os}"

    try:
        # Check that it starts the feed download
        wazuh_log_monitor.start(
            timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
            callback=vd.make_vuln_callback(
                f"Starting '{callback_system_log}' database update"),
            error_message=
            f"Could not find the provider {callback_system_log} feed download")

        if get_configuration['metadata']['provider_name'] == "debian":
            # Check Debian Security Tracker feed
            wazuh_log_monitor.start(
                timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
                callback=vd.make_vuln_callback(
                    f"Indexing vulnerabilities from the Debian "
                    f"Security Tracker."),
                error_message=
                f"Could not find the Debian Security Tracker feed download")

        # Check that the feed is downloaded successfully
        wazuh_log_monitor.start(
            timeout=download_timeout,
            callback=vd.make_vuln_callback(
                f"The update of the '{callback_system_log}' feed \
                                                                 finished successfully"
            ),
            error_message=
            f"The provider {callback_system_log} download has taken more than \
                                                {download_timeout / 60} minutes"
        )

        # Travels the time set in the update interval parameter
        check_time_travel(time_travel=True, interval=timedelta(seconds=10))

        # Download again the feed.
        # No updates should be applied since the local copy is up-to-date.

        if get_configuration['metadata']['provider_name'] == "nvd":
            # There's no "already up-to-date" message for the nvd.
            year = get_configuration['metadata']['update_from_year']
            with pytest.raises(TimeoutError):
                vd.check_log_event(
                    wazuh_log_monitor=wazuh_log_monitor,
                    log_event=
                    fr"The feed '{callback_system_log} ({year})' is outdated. Fetching the "
                    fr"last version.",
                    update_position=False,
                    timeout=15,
                    prefix=MODULESD_PREFIX)
                raise AttributeError(
                    f'Unexpected outdated feed message for the provider {callback_system_log}'
                )

        else:
            if get_configuration['metadata']['provider_name'] == "arch":
                pytest.xfail(
                    "The expected message doesn't exist for Arch Linux. Issue: "
                    "https://github.com/wazuh/wazuh/issues/8194")
            else:
                wazuh_log_monitor.start(
                    timeout=download_timeout,
                    callback=vd.make_vuln_callback(
                        f"The feed '{callback_system_log}' is in its latest version."
                    ),
                    error_message=
                    f"Could not find the provider {callback_system_log} updated feed "
                    f"log after the interval update")
    finally:
        control_service('stop', daemon='wazuh-db')

        # Clean NVD tables when the download has finished
        vd.clean_vuln_and_sys_programs_tables()

        # Wait for cleaning NVD tables
        sleep(5)

        control_service('start', daemon='wazuh-db')
        'interval': item
    }])

    ids.extend([
        f"Redhat_{item}", f"Canonical_{item}", f"Debian_{item}", f"NVD_{item}",
        f"MSU_{item}", f"Arch_{item}"
    ])

# Configuration data
configurations = load_wazuh_configurations(configurations_path,
                                           __name__,
                                           params=parameters,
                                           metadata=metadata)

# Callbacks
callback_provider_database_updating = make_vuln_callback(
    'Starting .* database update')


# Fixtures
@pytest.fixture(scope='module', params=configurations, ids=ids)
def get_configuration(request):
    """Get configurations from the module."""
    return request.param


def test_update_interval(get_configuration, configure_environment,
                         restart_modulesd):
    """
    Check if the provider database update is triggered after the set interval time has passed
    """
    check_apply_test({'test_providers_update_interval'},
Beispiel #10
0
def test_multiple_providers(clean_vuln_tables, get_configuration,
                            configure_environment, restart_modulesd):
    """

    From now on, Redhat and Debian providers use two feeds to fetch vulnerabilities and CVEs' metadata.
    \<os path=...\> option indicates the local path where the OVAL feed is whereas \<path\> indicates the local path where
    the another feed is. The same goes for \<os url=...\> and \<url\> options.
    This test verifies the path/url and multipath/url options work properly according to the configuration
    and check there are no conflicts when downloading or reading the feeds.
    
    """
    provider = get_configuration['metadata']['provider']

    if provider == 'redhat':
        os_feed = 'https://www.redhat.com/security/data/oval/v2/RHEL8/rhel-8-including-unpatched.oval.xml.bz2'
        feed = 'https://access.redhat.com/labs/securitydataapi/cve.json?after=1999-01-01&per_page=1000&page=1'
    else:
        os_feed = 'https://www.debian.org/security/oval/oval-definitions-buster.xml'
        feed = 'https://security-tracker.debian.org/tracker/data/json'

    try:
        if get_configuration['sections'][0]['elements'][1]['provider'][
                'elements'][1]['os']['attributes']:
            if 'path' in get_configuration['tags'][0]:
                os_feed = get_configuration['metadata']['os_path']
            else:
                os_feed = get_configuration['metadata']['os_url']
    except (KeyError, IndexError):
        pass

    try:
        if get_configuration['sections'][0]['elements'][1]['provider'][
                'elements'][2]:
            path_enable = True
            if 'path' in get_configuration['tags'][0]:
                feed = get_configuration['metadata']['path']
            else:
                feed = get_configuration['metadata']['url']
    except (KeyError, IndexError):
        path_enable = False

    wazuh_log_monitor.start(
        timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
        callback=vd.make_vuln_callback(rf"(Path|Url): ('{os_feed}'|'none').*",
                                       prefix='.*wazuh-modulesd.*'),
        error_message=
        f"OVAL feed {os_feed} from provider {provider} not correctly assigned")

    if path_enable and provider == 'redhat':
        wazuh_log_monitor.start(
            timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
            callback=vd.make_vuln_callback(rf"Multi (path|url): '{feed}'.*",
                                           prefix='.*wazuh-modulesd.*'),
            error_message=
            f"Feed {feed} from provider {provider} was not correctly assigned")

    wazuh_log_monitor.start(
        timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
        callback=vd.make_vuln_callback(
            rf"(Fetching feed from|Downloading) '{os_feed}'.*",
            prefix='.*wazuh-modulesd.*'),
        error_message=
        f"Event 'Fetching or Downloading {os_feed} was not received")

    wazuh_log_monitor.start(
        timeout=vd.VULN_DETECTOR_GLOBAL_TIMEOUT,
        callback=vd.make_vuln_callback(
            f"((Fetching .* from|Downloading) '{feed}'|.*Trying to "
            f"download).*",
            prefix='.*wazuh-modulesd.*'),
        error_message=f"Event 'Trying to download {feed}' was not received")

    vd.clean_vuln_and_sys_programs_tables()
custom_nvd_feed_path = os.path.join(test_data_path, 'feeds', vd.CUSTOM_NVD_FEED)

wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)
scan_timeout = 60

config_wildcards_values = [{'RUN_ON_START': 'yes', 'NVD_JSON_PATH': custom_nvd_feed_path},
                           {'RUN_ON_START': 'no', 'NVD_JSON_PATH': custom_nvd_feed_path}]
config_wildcards_metadata = [{'run_on_start': 'yes'}, {'run_on_start': 'no'}]

# Configuration data
configurations = load_wazuh_configurations(configurations_path, __name__,
                                           params=config_wildcards_values,
                                           metadata=config_wildcards_metadata)

# Callbacks
callback_detect_vulnerability_scan_started = make_vuln_callback('Starting vulnerability scan')
callback_detect_vulnerability_scan_finished = make_vuln_callback('Vulnerability scan finished')


# Fixtures
@pytest.fixture(scope='module', params=configurations, ids=["run_on_start_yes", "run_on_start_no"])
def get_configuration(request):
    """Get configurations from the module."""
    return request.param


def test_run_on_start(get_configuration, configure_environment, restart_modulesd):
    """
    Check if modulesd detects the vulnerability detector scan after starting.

    If we have set the parameter run_on_start to 'yes', modulesd will have to report the
def test_vulnerabilities_report(get_configuration, configure_environment,
                                restart_modulesd, check_cve_db,
                                mock_vulnerability_scan):
    """
    Check if inserted vulnerable packages are reported by vulnerability detector
    """
    provider_vulnerabilities_number = mock_vulnerability_scan[
        "provider_vulnerabilities_number"]
    nvd_vulnerabilities_number = mock_vulnerability_scan[
        "nvd_vulnerabilities_number"]

    # Check the vulnerabilities of packages inserted
    try:
        for item in vulnerabilities['vulnerabilities_provider']:
            vd.check_vulnerability_scan_event(wazuh_log_monitor,
                                              item['package']['name'],
                                              item['cve']['cveid'])
    except TimeoutError:
        check_time_travel(time_travel=True, interval=timedelta(seconds=300))
        for item in vulnerabilities['vulnerabilities_provider']:
            vd.check_vulnerability_scan_event(wazuh_log_monitor,
                                              item['package']['name'],
                                              item['cve']['cveid'])

    if mock_vulnerability_scan["format"] != "rpm":
        try:
            for item in vulnerabilities['vulnerabilities_nvd']:
                vd.check_vulnerability_scan_event(wazuh_log_monitor,
                                                  item['package']['name'],
                                                  item['cve']['cveid'])
        except TimeoutError:
            check_time_travel(time_travel=True,
                              interval=timedelta(seconds=300))
            for item in vulnerabilities['vulnerabilities_nvd']:
                vd.check_vulnerability_scan_event(wazuh_log_monitor,
                                                  item['package']['name'],
                                                  item['cve']['cveid'])

    # Check that the number of provider vulnerabilities is the expected
    wazuh_log_monitor.start(
        timeout=SCAN_TIMEOUT,
        update_position=False,
        callback=vd.make_vuln_callback(
            f"A total of '{provider_vulnerabilities_number}' vulnerabilities have been reported for agent '.*' "
            + "thanks to the 'vendor' feed."),
        error_message=
        f"The expected number of vulnerabilities for vendor have not been found",
    )

    # Check that the number of NVD vulnerabilities is the expected
    wazuh_log_monitor.start(
        timeout=SCAN_TIMEOUT,
        update_position=False,
        callback=vd.make_vuln_callback(
            f"A total of '{nvd_vulnerabilities_number}' vulnerabilities have been reported for agent '.*' "
            + "thanks to the 'NVD' feed."),
        error_message=
        f"The expected number of vulnerabilities for NVD have not been found",
    )

    vd.check_if_modulesd_is_running()