Темя сегодняшней статьи — настройка Wazuh для работы с API MISP. Основная цель — упростить работу безопасников, избавив их от необходимости вручную соотносить оповещения Wazuh с данными в MISP для IoC (индикатор компрометации). Выглядит моя задумка так: например, какое-то устройство делает DNS-запрос, Wazuh извлекает домен и отправляет его в MISP, чтобы узнать, есть ли этот домен в базе угроз. Если MISP находит совпадение, он возвращает идентификатор события и метаданные о найденном IoC. В случае положительного ответа от MISP, Wazuh генерирует оповещение с сообщением «Найден IoC». Таким образом, SOC-команда сразу получает уведомление с уже готовые данные, а не занимается ручным поиском IoC.
Еще по теме: Использование Wazuh на Raspberry Pi
Настройка правил для Wazuh
Для начала нужно настроить Wazuh, чтобы он знал, когда делать API-запрос к MISP и какие данные передавать. Для этого мы воспользуемся правилами Sysmon, которые собирают массу информации. Очень важно, чтобы на Wazuh были загружены наши кастомные правила Sysmon, а агенты имели корректную конфигурацию Sysmon, иначе интеграция работать не будет.
Вот какие группы событий Sysmon подходят для этой интеграции:
- sysmon_event1
- sysmon_event3
- sysmon_event6
- sysmon_event7
- sysmon_event_15
- sysmon_event_22
- syscheck
Все эти события содержат поля с потенциальными IoC, такими как IP-адреса, домены, хэши и т.д. Например, в событии Sysmon Event 22 фиксируется DNS-запрос, и в Wazuh можно увидеть этот запрос в поле data.win.eventdata.queryName.
Wazuh Manager получает значение opensecure.co и спрашивает MISP, содержится ли это значение в каких-либо базах угроз.
Скрипт на Python для интеграции с MISP
Для того чтобы эта интеграция работала, нам нужно настроить Wazuh для выполнения API-запроса к MISP. Для этого мы будем использовать собственный Python-скрипт. Есть несколько шагов, которые нужно выполнить для успешного запроса.
- Скрипт Custom-MISP.py.
- Настройка пользовательских опций в скрипте.
- Добавление блока интеграции в файл ossec.conf Wazuh.
- Добавление пользовательских правил MISP.
Еще по теме: Использование MISP для защиты от киберугроз
Скрипт Custom-MISP.py
Теперь мы создадим скрипт, который будет отвечать за выполнение API-запроса к MISP. Перейдите в каталог /var/ossec/integrations на вашем Wazuh Manager, и поместите туда наш скрипт custom-misp.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
#!/var/ossec/framework/python/bin/python3 ## Интеграция с API MISP # import sys import os from socket import socket, AF_UNIX, SOCK_DGRAM from datetime import date, datetime, timedelta import time import requests from requests.exceptions import ConnectionError import json import ipaddress import hashlib import re pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) socket_addr = '{0}/queue/sockets/queue'.format(pwd) def send_event(msg, agent = None): if not agent or agent["id"] == "000": string = '1:misp:{0}'.format(json.dumps(msg)) else: string = '1:[{0}] ({1}) {2}->misp:{3}'.format(agent["id"], agent["name"], agent["ip"] if "ip" in agent else "any", json.dumps(msg)) sock = socket(AF_UNIX, SOCK_DGRAM) sock.connect(socket_addr) sock.send(string.encode()) sock.close() false = False # Чтение параметров конфигурации alert_file = open(sys.argv[1]) # Чтение файла оповещения alert = json.loads(alert_file.read()) alert_file.close() # Новый вывод оповещения в случае срабатывания MISP или ошибки вызова API alert_output = {} # Базовый URL сервера MISP misp_base_url = "https://**your misp instance**/attributes/restSearch/" # Ключ авторизации API сервера MISP misp_api_auth_key = "*Your API Key" # API - HTTP заголовки misp_apicall_headers = {"Content-Type":"application/json", "Authorization":f"{misp_api_auth_key}", "Accept":"application/json"} ## Извлечение Sysmon для Windows/Sysmon для Linux и ID события Sysmon event_source = alert["rule"]["groups"][0] event_type = alert["rule"]["groups"][2] ## Регулярное выражение, используемое на основе длины SHA256 (64 символа) regex_file_hash = re.compile('\w{64}') if event_source == 'windows': # ... (код для обработки событий Windows остается без изменений) elif event_source == 'linux': if event_type == 'sysmon_event3' and alert["data"]["eventdata"]["destinationIsIpv6"] == 'false': try: dst_ip = alert["data"]["eventdata"]["DestinationIp"] if ipaddress.ip_address(dst_ip).is_global: wazuh_event_param = dst_ip misp_search_value = "value:"f"{wazuh_event_param}" misp_search_url = ''.join([misp_base_url, misp_search_value]) try: misp_api_response = requests.get(misp_search_url, headers=misp_apicall_headers, verify=False) except ConnectionError: alert_output["misp"] = {} alert_output["integration"] = "misp" alert_output["misp"]["error"] = 'Ошибка подключения к API MISP' send_event(alert_output, alert["agent"]) else: misp_api_response = misp_api_response.json() # Проверка, включает ли ответ Атрибуты (IoCs) if (misp_api_response["response"]["Attribute"]): # Генерация вывода оповещения из ответа MISP alert_output["misp"] = {} alert_output["misp"]["event_id"] = misp_api_response["response"]["Attribute"][0]["event_id"] alert_output["misp"]["category"] = misp_api_response["response"]["Attribute"][0]["category"] alert_output["misp"]["value"] = misp_api_response["response"]["Attribute"][0]["value"] alert_output["misp"]["type"] = misp_api_response["response"]["Attribute"][0]["type"] send_event(alert_output, alert["agent"]) else: sys.exit() except IndexError: sys.exit() else: sys.exit() elif event_source == 'ossec' and event_type == "syscheck_entry_added": try: wazuh_event_param = alert["syscheck"]["sha256_after"] except IndexError: sys.exit() misp_search_value = "value:"f"{wazuh_event_param}" misp_search_url = ''.join([misp_base_url, misp_search_value]) try: misp_api_response = requests.get(misp_search_url, headers=misp_apicall_headers, verify=false) except ConnectionError: alert_output["misp"] = {} alert_output["integration"] = "misp" alert_output["misp"]["error"] = 'Ошибка подключения к API MISP' send_event(alert_output, alert["agent"]) else: misp_api_response = misp_api_response.json() # Проверка, включает ли ответ Атрибуты (IoCs) if (misp_api_response["response"]["Attribute"]): # Генерация вывода оповещения из ответа MISP alert_output["misp"] = {} alert_output["misp"]["event_id"] = misp_api_response["response"]["Attribute"][0]["event_id"] alert_output["misp"]["category"] = misp_api_response["response"]["Attribute"][0]["category"] alert_output["misp"]["value"] = misp_api_response["response"]["Attribute"][0]["value"] alert_output["misp"]["type"] = misp_api_response["response"]["Attribute"][0]["type"] send_event(alert_output, alert["agent"]) else: sys.exit() |
Настройка пользовательских опций
Так как урл и API-токен MISP могут отличаться в разных средах, нам нужно внести соответствующие изменения в скрипт custom-misp.py. Для этого нужно изменить переменные misp_base_url и misp_api_auth_key, так, чтобы они соответствовали вашему урлу MISP и API-ключу.
Добавление блока интеграции в ossec.conf
Теперь нужно настроить Wazuh так, чтобы он запускал скрипт custom-misp.py при срабатывании определенных событий. Для этого добавляем новый блок интеграции в файл ossec.conf:
1 2 3 4 5 |
<integration> <name>custom-misp.py</name> <group>sysmon_event1,sysmon_event3,sysmon_event6,sysmon_event7,sysmon_event_15,sysmon_event_22,syscheck</group> <alert_format>json</alert_format> </integration> |
Обратите внимание, что Manager будет запускать скрипт только при срабатывании одной из групп событий Sysmon.
После этого перезагрузите Wazuh Manager.
Добавление кастомных правил MISP
Теперь нужно создать кастомные правила для Wazuh, чтобы он мог генерировать оповещения при положительном ответе от MISP.
Для этого создайте файл misp.xml с правилами и добавьте следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<group name="misp,"> <rule id="100620" level="10"> <field name="integration">misp</field> <match>misp</match> <description>MISP Events</description> <options>no_full_log</options> </rule> <rule id="100621" level="5"> <if_sid>100620</if_sid> <field name="misp.error">\.+</field> <description>MISP - Error connecting to API</description> <options>no_full_log</options> <group>misp_error,</group> </rule> <rule id="100622" level="12"> <field name="misp.category">\.+</field> <description>MISP - IoC found in Threat Intel - Category: $(misp.category), Attribute: $(misp.value)</description> <options>no_full_log</options> <group>misp_alert,</group> </rule> </group> |
Если MISP возвращает положительный ответ, сработает правило с id 100622.
Пример работы Wazuh с MISP
Давайте рассмотрим живой пример. На тестовом устройстве я выполню команду ping по домену, который уже существует в MISP. Это вызовет событие Sysmon Event 22, которое затем заставит Manager сделать API-запрос к MISP. MISP вернет положительный результат, и Wazuh сгенерирует оповещение.
Мы увидим, что в Wazuh пришло оповещение от Sysmon Event 22 о DNS-запросе. Далее Wazuh получит от MISP оповещение о положительном результате.
Затем мы видим, что менеджер Wazuh получает положительное оповещение от MISP.
В оповещении будет указано несколько полей MISP, включая идентификатор события, оригинальное оповещение и найденное значение (например, домен tikonam.com).
Данная интеграция значительно упрощает работу SOC-команды, так как им больше не нужно вручную искать IoC в оповещениях и MISP. Весь процесс теперь автоматизирован, что снижает риск пропуска IoC и ускоряет время реагирования. Оставшиеся шаги включают настройку оповещений через Elastalert или Shuffle, чтобы тикеты автоматически создавались при срабатывании правила MISP.
ПОЛЕЗНЫЕ ССЫЛКИ:
- Как установить OpenCTI в Docker
- Защита сетевого оборудования Cisco
- Лучшие платформы Threat Intelligence для SOC