From adc023abaf4beaf3d6e4859f71336c3bb5c53bcd Mon Sep 17 00:00:00 2001 From: jmv74211 Date: Mon, 24 Jan 2022 17:47:12 +0100 Subject: [PATCH] rm: Remove vulnerability detector module #2462 --- .../wazuh_testing/vulnerability_detector.py | 531 ------------------ 1 file changed, 531 deletions(-) delete mode 100644 deps/wazuh_testing/wazuh_testing/vulnerability_detector.py diff --git a/deps/wazuh_testing/wazuh_testing/vulnerability_detector.py b/deps/wazuh_testing/wazuh_testing/vulnerability_detector.py deleted file mode 100644 index e6f7590c29..0000000000 --- a/deps/wazuh_testing/wazuh_testing/vulnerability_detector.py +++ /dev/null @@ -1,531 +0,0 @@ -# Copyright (C) 2015-2021, Wazuh Inc. -# Created by Wazuh, Inc. . -# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2 - -import datetime -import functools -import json -import os -import random -import re -import sqlite3 -from time import time, sleep - -from wazuh_testing.tools import WAZUH_PATH, LOG_FILE_PATH, ALERT_FILE_PATH, GLOBAL_DB_PATH, CLIENT_KEYS_PATH -from wazuh_testing.tools import file -from wazuh_testing.tools.services import control_service, check_if_process_is_running -from wazuh_testing.tools.utils import retry -from wazuh_testing.tools import sqlite -from wazuh_testing.wazuh_db import query_wdb - - -def mock_cve_db(func): - """Decorator used in any function that needs to mock cve.db - - This function will execute `func` after stopping wazuh-modulesd and wazuh-db and cleaning the db. After that, - it will start the daemons again, clean the logs, etc. - - Args: - func (callable): function that will mock the cve.db - - Example: - @vd.mock_cve_db - def mock_vulnerability_scan(request, mock_agent): - """ - - @functools.wraps(func) - def magic(*args, **kwargs): - control_service('stop', daemon='wazuh-modulesd') - - # Clean tables - clean_vd_tables(agent=kwargs['mock_agent']) - - func(*args, **kwargs) - - # Truncate the log file - file.truncate_file(LOG_FILE_PATH) - - # Truncate the alerts log file - file.truncate_file(ALERT_FILE_PATH) - - control_service('start', daemon='wazuh-modulesd') - - yield kwargs['request'].param - - clean_vuln_and_sys_programs_tables(agent=kwargs['mock_agent']) - - return magic - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def check_vuln_detector_event(wazuh_log_monitor, callback, error_message='', update_position=True, - timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT, prefix=VULNERABILITY_DETECTOR_PREFIX): - """Check if a vulnerability event occurs - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - callback (str): log regex to check in Wazuh log - error_message (str): error message to show in case of expected event does not occur - update_position (boolean): filter configuration parameter to search in Wazuh log - timeout (str): timeout to check the event in Wazuh log - prefix (str): log pattern regex - """ - wazuh_log_monitor.start( - timeout=timeout, - update_position=update_position, - callback=make_vuln_callback(callback, prefix), - error_message=error_message - ) - - -def check_vulnerabilities_number(expected_number): - """Check if the number of vulnerabilities inserted in VULNERABILITIES table of CVE DB is the expected. - - Args: - expected_number (int): number of expected vulnerabilities - """ - vulnerabilities_number = get_num_vulnerabilities() - assert vulnerabilities_number == expected_number, f"Number of inserted vulnerabilities is not the expected." \ - f" Expected: {expected_number}, Got: {vulnerabilities_number}" - - -def check_log_event(wazuh_log_monitor, log_event, update_position=False, timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT, - prefix=VULNERABILITY_DETECTOR_PREFIX): - """Check if the vulnerable package has been reported - - Parameters - ---------- - wazuh_log_monitor: FileMonitor - FileMonitor object to monitor the Wazuh log - log_event: str - Log event to find in ossec.log - update_position : boolean - Filter configuration parameter to search in Wazuh log - timeout: str - Timeout to check the event in Wazuh log - prefix: str - Log pattern regex - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, callback=log_event, - error_message=f"Could not find the log event: {log_event}", prefix=prefix - ) - - -def check_feed_imported_successfully(wazuh_log_monitor, log_system_name, expected_vulnerabilities_number, - update_position=False, timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT, - check_vuln_number=True): - """Check that redhat OVAL feeds have been imported successfully - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - log_system_name (str): system name in ossec.log. For instance 'Red Hat Enterprise Linux' - expected_vulnerabilities_number (int): number of expected vulnerabilities imported in the BD - update_position (boolean): filter configuration parameter to search in Wazuh log - timeout (str): timeout to check the event in Wazuh log - check_vuln_number (bool): boolean to enable the check that compares the number of generated alerts with - the number of expected alerts - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, - callback=rf"INFO: \(\d+\): The update of the '{log_system_name}' feed finished successfully.", - error_message=f"Could not find the message: '{log_system_name}' feed finished successfully" - ) - if check_vuln_number: - check_vulnerabilities_number(expected_number=expected_vulnerabilities_number) - - -def check_failure_when_importing_feed(wazuh_log_monitor, expected_vulnerabilities_number=0, update_position=False, - timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT, parser_error=False): - """Check an error message when importing redhat OVAL feeds and checks that the vulnerabilities table is empty - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - expected_vulnerabilities_number (int): number of expected vulnerabilities imported in the BD - update_position (bool): filter configuration parameter to search in Wazuh log - timeout (str): timeout to check the event in Wazuh log - parser_error (bool): check if there is a parser error message - """ - if parser_error: - check_log_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, - log_event=r"ERROR: \(\d+\): The .* feed couldn't be parsed from .* file" - ) - - check_log_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, - log_event=r"ERROR: \(\d+\): CVE database could not be updated." - ) - - check_vulnerabilities_number(expected_number=expected_vulnerabilities_number) - - -def check_detected_vulnerabilities_number(wazuh_log_monitor, expected_vulnerabilities_number, feed_source, agent=None, - update_position=False, timeout=VULN_DETECTOR_GLOBAL_TIMEOUT): - """Check the number of vulnerabilities found by the feed source - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - expected_vulnerabilities_number (int): number of expected vulnerabilities - feed_source (str): OVAL or NVD - agent (str, optional): Agent id - update_position (bool): filter configuration parameter to search in Wazuh log - timeout (str): timeout to check the event in Wazuh log - """ - callback = f"The {feed_source} found a total of '{expected_vulnerabilities_number}' " \ - "potential vulnerabilities for agent .* " - if agent is not None: - callback = f"The {feed_source} found a total of '{expected_vulnerabilities_number}' " \ - f"potential vulnerabilities for agent '{agent}' " - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, - callback=callback, - error_message=f"The expected number of {feed_source} vulnerabilities have not been found" - ) - - - - - -def insert_data_json_feed(data, field_name, field_value, append_data, brackets=True): - """Allow insert key:value pair as string, since otherwise, you could not insert lists or dictionaries as a key - - Args: - data (dict): data dictionary - field_name (str): field name to insert - field_value (str): field value to insert - append_data (dict): additional data to insert - brackets (bool): insert data between brackets - - Returns: - str: JSON string - """ - if type(field_name) is str: - data[field_name] = field_value - raw_data = json.dumps(data, indent=4, ensure_ascii=False) - else: - data['replace_me'] = field_value # This is necessary to make a non-string field - raw_data = json.dumps(data, indent=4, ensure_ascii=False).replace('"replace_me"', f"{field_name}") - - if append_data: - response = f"\n{raw_data},\n{json.dumps(append_data, indent=4, ensure_ascii=False)}\n" - return f"[{response}]" if brackets else response - else: - return f"[\n{raw_data}]" if brackets else f"\n{raw_data}" - - -def check_if_modulesd_is_running(): - """Check if modulesd daemon is running""" - assert check_if_process_is_running('wazuh-modulesd'), 'wazuh-modulesd is not running!' - - -def check_feed_uncompressed_successfully(wazuh_log_monitor, feed, update_position=False, - timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT): - """Check that a feed from path or url have been uncompressed successfully - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - feed (str): path or url where the feed is - update_position (boolean): filter configuration parameter to search in Wazuh log - timeout (str): timeout to check the event in Wazuh log - """ - if feed[-1] == '$': - feed = feed[:-1] - prefix = r'.*wazuh-modulesd.*' - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, update_position=update_position, timeout=timeout, - callback=rf"(The file|File from URL) '{feed}' was successfully uncompressed into .*", - error_message=f"Could not find the message: '{feed}' was successfully uncompressed", - prefix=prefix - ) - - - - - -def check_vulnerability_scan_log(wazuh_log_monitor, package, cve): - """Check if inserted vulnerable packages are reported by vulnerability detector. - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - package (str): Name of custom package to check. Example: 'firefox-0' - cve (str): Package CVE. Example: 'CVE-2019-11764' - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, timeout=VULN_DETECTOR_EXTENDED_GLOBAL_TIMEOUT, update_position=False, - callback=f"The '{package}' package .* from agent .* is vulnerable to '{cve}'", - error_message=f"Could not find the report which says that the package {package} is vulnerable with {cve}", - ) - - -def check_vulnerability_scan_discarded(wazuh_log_monitor, package): - """Check if kernel packages are discarded by vulnerability detector. - - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - package (str): Name of custom kernel package to check. Example: 'linux-image-aws' - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, timeout=VULN_DETECTOR_SCAN_TIMEOUT, update_position=False, - callback=f"Discarded Linux Kernel package '{package}' .*", - error_message=f"Could not find the report which says that the package {package} was discarded", - prefix='.*' - ) - - -def check_vulnerability_scan_alert(wazuh_alert_monitor, package, cve): - """Check if inserted vulnerable packages are reported by vulnerability detector. - Args: - wazuh_alert_monitor (FileMonitor): FileMonitor object to monitor the Wazuh alerts log - package (str): Name of custom package to check. Example: 'firefox-0' - cve (str): Package CVE. Example: 'CVE-2019-11764' - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_alert_monitor, timeout=VULN_DETECTOR_SCAN_TIMEOUT, update_position=False, - callback=f"{cve} affects {package}", - error_message=f"Could not find the report which says that {cve} affects the package {package}", - prefix='.*' - ) - - -def check_vulnerability_scan_remove_log(wazuh_log_monitor, package, cve): - """Check if removed vulnerable packages are reported by vulnerability detector in yhe logs. - Args: - wazuh_log_monitor (FileMonitor): FileMonitor object to monitor the Wazuh log - package (str): Name of custom package to check. Example: 'firefox-0' - cve (str): Package CVE. Example: 'CVE-2019-11764' - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_log_monitor, timeout=VULN_DETECTOR_SCAN_TIMEOUT, update_position=False, - callback=f"The vulnerability '{cve}' affecting '{package}' was eliminated", - error_message=f"Could not find the log which says that the package {package} is no longer vulnerable with {cve}" - ) - - -def check_vulnerability_scan_remove_alerts(wazuh_alerts_monitor, package, cve): - """Check if removed vulnerable packages are reported by vulnerability detector in the alerts. - Args: - wazuh_alerts_monitor (FileMonitor): FileMonitor object to monitor the Wazuh alerts log - package (str): Name of custom package to check. Example: 'firefox-0' - cve (str): Package CVE. Example: 'CVE-2019-11764' - """ - check_vuln_detector_event( - wazuh_log_monitor=wazuh_alerts_monitor, timeout=VULN_DETECTOR_SCAN_TIMEOUT, update_position=False, - callback=f"The {cve} that affected {package} was eliminated due to a package removal/update or a system upgrade", - prefix='.*', - error_message=f"Could not find the alert which says that the package {package} is no longer vulnerable with {cve}" - ) - - -def restart_modulesd(): - """Restart modulesd daemon""" - control_service('restart', daemon='wazuh-modulesd') - sleep(1) - - -def add_client_keys_entry(agent_id, agent_name, agent_ip='any', agent_key=None): - """Add new entry to client keys file. If the agent_id already exists, this will be overwritten. - - Args: - agent_id (str): Agent identifier. - agent_name (str): Agent name. - agent_ip (str): Agent ip. - agent_key (str): Agent key. - """ - registered_client_key_entries_dict = {} - - # Generate new key if necessary - if agent_key is None: - agent_key = ''.join(random.choice('0123456789abcdef') for i in range(64)) - - # Read client keys data - with open(CLIENT_KEYS_PATH, 'r') as client_keys: - registered_client_key_entries_str = client_keys.readlines() - - # Process current client key entries - for client_key_entry in registered_client_key_entries_str: - _agent_id, _agent_name, _agent_ip, _agent_key = client_key_entry.split() - registered_client_key_entries_dict[_agent_id] = f"{_agent_id} {_agent_name} {_agent_ip} {_agent_key}" - - # Add the new client key entry - registered_client_key_entries_dict[agent_id] = f"{agent_id} {agent_name} {agent_ip} {agent_key}" - - # Save new client keys content - with open(CLIENT_KEYS_PATH, 'w') as client_keys: - for _, client_key_entry in registered_client_key_entries_dict.items(): - client_keys.write(f"{client_key_entry}\n") - - -def delete_client_keys_entry(agent_id): - """Delete an entry from client keys file. - - Args: - agent_id (str): Agent identifier. - """ - registered_client_key_entries_dict = {} - - # Read client keys data - with open(CLIENT_KEYS_PATH, 'r') as client_keys: - registered_client_key_entries_str = client_keys.readlines() - - # Process current client key entries - for client_key_entry in registered_client_key_entries_str: - _agent_id, _agent_name, _agent_ip, _agent_key = client_key_entry.split() - registered_client_key_entries_dict[_agent_id] = f"{_agent_id} {_agent_name} {_agent_ip} {_agent_key}" - - # Remove client key entry - registered_client_key_entries_dict.pop(agent_id, None) - - # Save new client keys content - with open(CLIENT_KEYS_PATH, 'w') as client_keys: - for _, client_key_entry in registered_client_key_entries_dict.items(): - client_keys.write(f"{client_key_entry}\n") - - -def check_vulnerability_scan_inventory(agent, package, version, arch, cve, condition, severity='-', cvss2=0, cvss3=0): - """Checks the existence or lack of a vulnerability in the agent's DB - - Args: - agent (str) = Id of the agent. - package (str) = Vulnerable package to look for. - version (str) = Version of the vulnerable package to look for. - arch (str) = Architecture of the vulnerable package to look for. - cve (str) = Vulnerability ID associated to the vulnerable package to look for. - condition (str) = This parameter is used to check if the vulnerability exists ('inserted') or - not ('removed') in the inventory - severity (str,optional) = Severity of the vulnerable package to look for. - cvss2 (str,optional) = CVSS2 score of the vulnerable package to look for. - cvss3 (str,optional) = CVSS3 score of the vulnerable package to look for. - """ - - if condition == 'inserted': - query = f"""agent {agent} sql SELECT CASE WHEN EXISTS - (select 1 FROM vuln_cves WHERE cve = '{cve}' AND name = '{package}' AND version = '{version}' AND architecture = '{arch}' - AND severity = '{severity}' AND cvss2_score = {cvss2} AND cvss3_score = {cvss3}) - THEN 'true' ELSE 'false' END as 'result'""" - elif condition == 'removed': - query = f"""agent {agent} sql SELECT CASE WHEN NOT EXISTS - (select 1 FROM vuln_cves WHERE cve = '{cve}' AND name = '{package}' AND version = '{version}' AND architecture = '{arch}') - THEN 'true' ELSE 'false' END as 'result'""" - else: - raise Exception(f'The "condition" parameter has an unexpected value: {condition}') - - wdb_result = query_wdb(query) - if wdb_result[0]['result'] == 'false': - raise Exception(f'The vulnerability {cve} has not been {condition} as expected') - - -def find_cve_severity_score (cve_array, cve_id): - """It looks for the cve_id in cve_array and returns its severity and score - - Args: - cve_array (str) = The CVE's data read from the NVD feed. - cve_id (str) = The CVE ID to find and return its severity and score. - """ - severity = '-' - cvss2_score = 0 - cvss3_score = 0 - - for cve in cve_array: - if cve['cve']['CVE_data_meta']['ID'] == cve_id: - # The CVSS3 has priority over CVSS2 - if 'baseMetricV2' in cve['impact']: - cvss2_score = cve['impact']['baseMetricV2']['cvssV2']['baseScore'] - severity = calculate_severity_from_score(cvss2_score, 'cvss2') - - if 'baseMetricV3' in cve['impact']: - cvss3_score = cve['impact']['baseMetricV3']['cvssV3']['baseScore'] - severity = calculate_severity_from_score(cvss3_score, 'cvss3') - break - - return severity, cvss2_score, cvss3_score - -def find_rhel_cve_severity_score(cve_nvd_array, cve_rhel_array, cve_id): - """It looks for the cve_id in cve_nvd_array and temporarily stores its - severity and score. Then, if found, the values are overridden by the ones - in the RHEL feed, otherwise it will keep the previous ones. - - Args: - cve_nvd_array (str) = The CVE's data read from the NVD feed. - cve_rhel_array (str) = The CVE's data read from the RHEL feed. - cve_id (str) = The CVE ID to find and return its severity and score. - """ - severity, cvss2_score, cvss3_score = find_cve_severity_score(cve_nvd_array, cve_id) - - for cve in cve_rhel_array: - if cve['CVE'] == cve_id: - # The CVSS3 has priority over CVSS2 - if 'cvss_score' in cve and cve['cvss_score'] is not None: - cvss2_score = float(cve['cvss_score']) - severity = calculate_severity_from_score(cvss2_score, 'cvss2') - if 'cvss3_score' in cve and cve['cvss3_score'] is not None: - cvss3_score = float(cve['cvss3_score']) - severity = calculate_severity_from_score(cvss3_score, 'cvss3') - - return severity, cvss2_score, cvss3_score - - -def calculate_severity_from_score(base_score, cvss): - """It obtains the corresponding severity according to a CVSS2 or CVSS3 score - - Args: - base_score (real) = The base score to get its severity. - cvss (str) = A string to indicate the CVSS scale to use ('cvss2/cvss3'). - """ - severity = '-' - - if cvss == 'cvss2': - if base_score >= 7: - severity = 'High' - elif base_score >= 4: - severity = 'Medium' - else: - severity = 'Low' - - elif cvss == 'cvss3': - if base_score >= 9: - severity = 'Critical' - elif base_score >= 7: - severity = 'High' - elif base_score >= 4: - severity = 'Medium' - elif base_score >= 0.1: - severity = 'Low' - else: - severity = '-' - - return severity