From 31cd9657174227c3a2f0fb2a853e52a238a62d90 Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 27 Jul 2022 12:58:44 +0200 Subject: [PATCH] add: Add new E2E test for FIM events --- .../data/playbooks/configuration.yaml | 61 ++++++++++++ .../data/playbooks/generate_events.yaml | 42 +++++++++ .../test_fim/data/playbooks/teardown.yaml | 44 +++++++++ .../test_fim/data/test_cases/cases_fim.yaml | 92 +++++++++++++++++++ tests/end_to_end/test_fim/test_fim.py | 63 +++++++++++++ 5 files changed, 302 insertions(+) create mode 100644 tests/end_to_end/test_fim/data/playbooks/configuration.yaml create mode 100644 tests/end_to_end/test_fim/data/playbooks/generate_events.yaml create mode 100644 tests/end_to_end/test_fim/data/playbooks/teardown.yaml create mode 100644 tests/end_to_end/test_fim/data/test_cases/cases_fim.yaml create mode 100644 tests/end_to_end/test_fim/test_fim.py diff --git a/tests/end_to_end/test_fim/data/playbooks/configuration.yaml b/tests/end_to_end/test_fim/data/playbooks/configuration.yaml new file mode 100644 index 0000000000..8c3e8df1ed --- /dev/null +++ b/tests/end_to_end/test_fim/data/playbooks/configuration.yaml @@ -0,0 +1,61 @@ +--- +- name: Test case configuration + hosts: agents + tasks: + + - name: Create directory to monitor (Linux) + become: True + file: + path: /tmp/test_demo_fim + state: directory + when: ansible_facts['system'] == "Linux" + + - name: Add directory to syscheck configuration (Linux) + become: True + blockinfile: + path: /var/ossec/etc/ossec.conf + insertafter: + block: | + /tmp/test_demo_fim + marker: + when: ansible_facts['system'] == "Linux" + + - name: Restart Wazuh (Linux) + become: True + systemd: + name: wazuh-agent + state: restarted + when: ansible_facts['system'] == "Linux" + + - name: Create directory to monitor (Windows) + win_file: + path: C:\Test\test_demo_fim + state: directory + when: ansible_facts['os_family'] == "Windows" + + - name: Add directory to syscheck configuration (Windows) + win_lineinfile: + path: C:\Program Files (x86)\ossec-agent\ossec.conf + insertafter: + line: | + C:\\Test\\test_demo_fim + when: ansible_facts['os_family'] == "Windows" + + - name: Truncate ossec.log + win_file: + path: C:\Program Files (x86)\ossec-agent\ossec.log + state: absent + when: ansible_facts['os_family'] == "Windows" + + - name: Restart Wazuh (Windows) + win_shell: | + net stop wazuh + net start wazuh + when: ansible_facts['os_family'] == "Windows" + + - name: Wait for whodata start + win_wait_for: + path: C:\Program Files (x86)\ossec-agent\ossec.log + search_regex: File integrity monitoring real-time Whodata engine started. + timeout: 20 + when: ansible_facts['os_family'] == "Windows" diff --git a/tests/end_to_end/test_fim/data/playbooks/generate_events.yaml b/tests/end_to_end/test_fim/data/playbooks/generate_events.yaml new file mode 100644 index 0000000000..4ddc7c0196 --- /dev/null +++ b/tests/end_to_end/test_fim/data/playbooks/generate_events.yaml @@ -0,0 +1,42 @@ +- name: Clean alerts file + hosts: wazuh-manager + tasks: + + - name: Truncate file + shell: echo "" > /var/ossec/logs/alerts/alerts.json + become: True + +- name: Generate events + hosts: agents + vars: + os: "{{ os }}" + tasks: + + - name: "{{ event_description }}" + become: True + file: + path: "{{ path }}" + state: "{{ state }}" + mode: "{{ mode }}" + when: os == "Linux" + + - name: "{{ event_description }}" + win_file: + path: "{{ path }}" + state: "{{ state }}" + when: os == ansible_facts['os_family'] + +- name: Get alerts + hosts: wazuh-manager + tasks: + + - name: Wait for alert to be generated + wait_for: + timeout: 5 + + - name: Get alerts.json + fetch: + src: /var/ossec/logs/alerts/alerts.json + dest: /tmp/ + flat: true + become: true diff --git a/tests/end_to_end/test_fim/data/playbooks/teardown.yaml b/tests/end_to_end/test_fim/data/playbooks/teardown.yaml new file mode 100644 index 0000000000..584f20e9c3 --- /dev/null +++ b/tests/end_to_end/test_fim/data/playbooks/teardown.yaml @@ -0,0 +1,44 @@ +--- +- name: Cleanup Linux agent environment + hosts: wazuh-agent + become: True + tasks: + + - name: Delete syscheck configuration + blockinfile: + path: /var/ossec/etc/ossec.conf + marker: + block: '' + + - name: Delete folder + file: + path: /tmp/test_demo_fim + state: absent + + - name: Restart wazuh-agent + systemd: + state: restarted + name: wazuh-agent + +- name: Cleanup Windows agent environment + hosts: wazuh-windows + tasks: + + - name: Delete syscheck configuration + win_lineinfile: + path: C:\Program Files (x86)\ossec-agent\ossec.conf + regex: C\:\\\\Test\\\\test_demo_fim + state: absent + when: ansible_facts['os_family'] == "Windows" + + - name: Delete directory to monitor (Windows) + win_file: + path: C:\Test + state: absent + when: ansible_facts['os_family'] == "Windows" + + - name: Restart Wazuh (Windows) + win_shell: | + net stop wazuh + net start wazuh + when: ansible_facts['os_family'] == "Windows" diff --git a/tests/end_to_end/test_fim/data/test_cases/cases_fim.yaml b/tests/end_to_end/test_fim/data/test_cases/cases_fim.yaml new file mode 100644 index 0000000000..aa44555b74 --- /dev/null +++ b/tests/end_to_end/test_fim/data/test_cases/cases_fim.yaml @@ -0,0 +1,92 @@ +- name: create_file_linux + description: Create a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Linux + event_description: Create a file into the monitored folder + path: /tmp/test_demo_fim/monitored_file.txt + state: touch + mode: 0755 + rule.id: 554 + rule.level: 5 + rule.description: File added to the system\. + extra: + syscheck.path: \/tmp\/test_demo_fim\/monitored_file\.txt + +- name: modify_file_linux + description: Modify a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Linux + event_description: Modify a file from the monitored folder + path: /tmp/test_demo_fim/monitored_file.txt + state: file + mode: 0750 + rule.id: 550 + rule.level: 7 + rule.description: Integrity checksum changed\. + extra: + syscheck.path: \/tmp\/test_demo_fim\/monitored_file\.txt + +- name: delete_file_linux + description: Delete a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Linux + event_description: Delete a file from the monitored folder + path: /tmp/test_demo_fim/monitored_file.txt + state: absent + mode: 0755 + rule.id: 553 + rule.level: 7 + rule.description: File deleted\. + extra: + syscheck.path: \/tmp\/test_demo_fim\/monitored_file\.txt + +- name: create_file_windows + description: Create a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Windows + event_description: Create a file into the monitored folder + path: C:\Test\test_demo_fim\monitored_file.txt + state: touch + rule.id: 554 + rule.level: 5 + rule.description: File added to the system\. + extra: + syscheck.path: c:\\\\test\\\\test_demo_fim\\\\monitored_file.txt + +- name: modify_file_windows + description: Modify a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Windows + event_description: Modify a file from the monitored folder + path: C:\Test\test_demo_fim\monitored_file.txt + state: touch + rule.id: 550 + rule.level: 7 + rule.description: Integrity checksum changed\. + extra: + syscheck.path: c:\\\\test\\\\test_demo_fim\\\\monitored_file.txt + +- name: delete_file_windows + description: Delete a file and check generated alerts + configuration_parameters: null + metadata: + extra_vars: + os: Windows + event_description: Delete a file from the monitored folder + path: C:\Test\test_demo_fim\monitored_file.txt + state: absent + rule.id: 553 + rule.level: 7 + rule.description: File deleted\. + extra: + syscheck.path: c:\\\\test\\\\test_demo_fim\\\\monitored_file.txt diff --git a/tests/end_to_end/test_fim/test_fim.py b/tests/end_to_end/test_fim/test_fim.py new file mode 100644 index 0000000000..d46bb6dd33 --- /dev/null +++ b/tests/end_to_end/test_fim/test_fim.py @@ -0,0 +1,63 @@ +import os +import json +import re +import pytest +from tempfile import gettempdir + +from wazuh_testing import end_to_end as e2e +from wazuh_testing import event_monitor as evm +from wazuh_testing.tools import configuration as config + +alerts_json = os.path.join(gettempdir(), 'alerts.json') +test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') +test_cases_file_path = os.path.join(test_data_path, 'test_cases', 'cases_fim.yaml') +configuration_playbooks = ['configuration.yaml'] +events_playbooks = ['generate_events.yaml'] +teardown_playbooks = ['teardown.yaml'] + +configurations, configuration_metadata, cases_ids = config.get_test_cases_data(test_cases_file_path) + + +@pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning') +@pytest.mark.parametrize('metadata', configuration_metadata, ids=cases_ids) +def test_fim(configure_environment, metadata, get_dashboard_credentials, generate_events, clean_alerts_index): + """ + Test to scanning a file using FIM + """ + rule_id = metadata['rule.id'] + rule_level = metadata['rule.level'] + rule_description = metadata['rule.description'] + syscheck_path = metadata['extra']['syscheck.path'] + + expected_alert_json = fr'\{{"timestamp":"(\d+\-\d+\-\w+\:\d+\:\d+\.\d+\+\d+)","rule":{{"level":{rule_level},' \ + fr'"description":"{rule_description}","id":"{rule_id}".*"syscheck":{{"path":' \ + fr'"{syscheck_path}".*\}}' + + expected_indexed_alert = fr'.*"path": "{syscheck_path}".*"rule":.*"level": {rule_level},.*"description": ' \ + fr'"{rule_description}".*"timestamp": "(\d+\-\d+\-\w+\:\d+\:\d+\.\d+\+\d+)".*' + + # Check that alert has been raised and save timestamp + raised_alert = evm.check_event(callback=expected_alert_json, file_to_monitor=alerts_json, + error_message='The alert has not occurred').result() + raised_alert_timestamp = raised_alert.group(1) + + query = e2e.make_query([ + { + "term": { + "rule.id": f"{rule_id}" + } + }, + { + "term": { + "timestamp": f"{raised_alert_timestamp}" + } + } + ]) + + # Check if the alert has been indexed and get its data + response = e2e.get_alert_indexer_api(query=query, credentials=get_dashboard_credentials) + indexed_alert = json.dumps(response.json()) + + # Check that the alert data is the expected one + alert_data = re.search(expected_indexed_alert, indexed_alert) + assert alert_data is not None, 'Alert triggered, but not indexed'