Wazuh + OpenCTI = Integration?

Разворачиваем OpenCTI с интеграцией Wazuh

Дефендеры и прочие blue-team, а вы обогащаете данные в своем Wazuh?

Разумеется, Wazuh используют не везде, но в силу бюджетов его можно встретить даже в крупном бизнесе.
Сравнительно удобно, бесплатно и можно запихать в Docker.

Так вот, переходим к теме.
Представим, что правила у нас написаны, алерты настроены и от вечного внедрения уже можно перейти к добавлению функционала.
Например, алерты при обнаружении IoC. А для этого нам нужна какая-то Threat Intelligence платформа.
В голову приходят только MISP и OpenCTI, последний мы и будем использовать.

Типы событий / группы правил возможные для отработки с OpenCTI API

Event typemetadataRationale
sysmon event1win.eventdata.hashesCheck existing IoC in process image file hash
sysmon event3win.eventdata.hashesCheck existing IoC in in destination IP
sysmon event6win.eventdata.hashesCheck existing IoC in in loaded driver file hash
sysmon event7win.eventdata.hashesCheck existing IoC in loaded DLL file hash
sysmon event 15win.eventdata.hashesCheck existing IoC in downloaded file hash
sysmon event 22win.eventdata.queryNameCheck existing IoC in queried hostname
sysmon event 23win.eventdata.hashesCheck existing IoC in deleted file hash
sysmon event 24win.eventdata.hashesCheck existing IoC in clipboard content file hash
sysmon event 25win.eventdata.hashesCheck existing IoC in process file hash
sysmon process-anomalieswin.eventdata.hashes
idsdest_ip, src_ip
osquery, osquery_fileosquery.columns.sha256

Тестовое развертывание

Для теста потребуется:

  1. API-ключ Alienvault OTX
  2. Wazuh
  3. OpenCTI
  4. Интеграция OpenCTI с Wazuh
  5. Windows машина с sysmon и wazuh-agent

Получаем API-ключ Alienvault OTX

Разворачиваем OpenCTI

  • Клонируем репозиторий
1
2
git clone https://github.com/OpenCTI-Platform/docker.git
cd docker
  • Настраиваем переменные:
    Устанавливаем jq:
1
sudo apt install -y jq

Добавляем переменные в .env:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cd ~/docker
(cat << EOF
OPENCTI_ADMIN_EMAIL=admin@opencti.io
OPENCTI_ADMIN_PASSWORD=CHANGE_ME
OPENCTI_ADMIN_TOKEN=GENERATE_UUID
OPENCTI_BASE_URL=http://localhost:8080
MINIO_ROOT_USER=opencti
MINIO_ROOT_PASSWORD=CHANGE_ME
RABBITMQ_DEFAULT_USER=opencti
RABBITMQ_DEFAULT_PASS=CHANGE_ME
CONNECTOR_EXPORT_FILE_STIX_ID=dd817c8b-abae-460a-9ebc-97b1551e70e6
CONNECTOR_EXPORT_FILE_CSV_ID=7ba187fb-fde8-4063-92b5-c3da34060dd7
CONNECTOR_EXPORT_FILE_TXT_ID=ca715d9c-bd64-4351-91db-33a8d728a58b
CONNECTOR_IMPORT_FILE_STIX_ID=72327164-0b35-482b-b5d6-a5a3f76b845f
CONNECTOR_IMPORT_DOCUMENT_ID=c3970f8a-ce4b-4497-a381-20b7256f56f0
SMTP_HOSTNAME=localhost
ELASTIC_MEMORY_SIZE=4G
ALIENVAULT_API_KEY=API_KEY
ALIENVAULT_CONNECTOR_ID=GENERATE_UUID
EOF
 ) > .env

В полученный файл необходимо добавить свои переменные, будь это API-токен, почта или что-то ещё. Можно указать прямо в файле, но лучше, если сами переменные хранятся в глобальном окружении.

Так же не забываем заменить GENERATE_UUID на валидные UUID, которые можно сгенерировать либо с помощью утилиты uuidgen или онлайн-генератором uuidgenerator.net.

  • Добавлю сразу, что помимо самого OpenCTI и интеграции в Wazuh нам необходимы т.н. external-import connectors, и для примера будем использовать коннектор от alienvault
  • Чтобы не плодить множество compose-файлов, забираем отсюда часть от connector-alienvault: до restart: always, так же добавляем часть в конец
1
2
    depends_on:
      - opencti 

Что у нас должно получиться (GIST):

Click to view the spoiler

  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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
version: '3'
services:
  redis:
    image: redis:7.0.9
    restart: always
    volumes:
      - redisdata:/data
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.6.2
    volumes:
      - esdata:/usr/share/elasticsearch/data
    environment:
      # Comment out the line below for single-node
      - discovery.type=single-node
      # Uncomment line below below for a cluster of multiple nodes
      # - cluster.name=docker-cluster
      - xpack.ml.enabled=false
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms${ELASTIC_MEMORY_SIZE} -Xmx${ELASTIC_MEMORY_SIZE}"
    restart: always
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
  minio:
    image: minio/minio:RELEASE.2023-02-27T18-10-45Z
    volumes:
      - s3data:/data
    ports:
      - "9000:9000"
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}    
    command: server /data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3
    restart: always
  rabbitmq:
    image: rabbitmq:3.11-management
    environment:
      - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}
    volumes:
      - amqpdata:/var/lib/rabbitmq
    restart: always
  opencti:
    image: opencti/platform:5.7.1
    environment:
      - NODE_OPTIONS=--max-old-space-size=8096
      - APP__PORT=8080
      - APP__BASE_URL=${OPENCTI_BASE_URL}
      - APP__ADMIN__EMAIL=${OPENCTI_ADMIN_EMAIL}
      - APP__ADMIN__PASSWORD=${OPENCTI_ADMIN_PASSWORD}
      - APP__ADMIN__TOKEN=${OPENCTI_ADMIN_TOKEN}
      - APP__APP_LOGS__LOGS_LEVEL=error
      - REDIS__HOSTNAME=redis
      - REDIS__PORT=6379
      - ELASTICSEARCH__URL=http://elasticsearch:9200
      - MINIO__ENDPOINT=minio
      - MINIO__PORT=9000
      - MINIO__USE_SSL=false
      - MINIO__ACCESS_KEY=${MINIO_ROOT_USER}
      - MINIO__SECRET_KEY=${MINIO_ROOT_PASSWORD}
      - RABBITMQ__HOSTNAME=rabbitmq
      - RABBITMQ__PORT=5672
      - RABBITMQ__PORT_MANAGEMENT=15672
      - RABBITMQ__MANAGEMENT_SSL=false
      - RABBITMQ__USERNAME=${RABBITMQ_DEFAULT_USER}
      - RABBITMQ__PASSWORD=${RABBITMQ_DEFAULT_PASS}
      - SMTP__HOSTNAME=${SMTP_HOSTNAME}
      - SMTP__PORT=25
      - PROVIDERS__LOCAL__STRATEGY=LocalStrategy
    ports:
      - "8080:8080"
    depends_on:
      - redis
      - elasticsearch
      - minio
      - rabbitmq
    restart: always
  worker:
    image: opencti/worker:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - WORKER_LOG_LEVEL=info
    depends_on:
      - opencti
    deploy:
      mode: replicated
      replicas: 3
    restart: always
  connector-export-file-stix:
    image: opencti/connector-export-file-stix:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${CONNECTOR_EXPORT_FILE_STIX_ID} # Valid UUIDv4
      - CONNECTOR_TYPE=INTERNAL_EXPORT_FILE
      - CONNECTOR_NAME=ExportFileStix2
      - CONNECTOR_SCOPE=application/json
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_LOG_LEVEL=info
    restart: always
    depends_on:
      - opencti
  connector-export-file-csv:
    image: opencti/connector-export-file-csv:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${CONNECTOR_EXPORT_FILE_CSV_ID} # Valid UUIDv4
      - CONNECTOR_TYPE=INTERNAL_EXPORT_FILE
      - CONNECTOR_NAME=ExportFileCsv
      - CONNECTOR_SCOPE=text/csv
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_LOG_LEVEL=info
    restart: always
    depends_on:
      - opencti
  connector-export-file-txt:
    image: opencti/connector-export-file-txt:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${CONNECTOR_EXPORT_FILE_TXT_ID} # Valid UUIDv4
      - CONNECTOR_TYPE=INTERNAL_EXPORT_FILE
      - CONNECTOR_NAME=ExportFileTxt
      - CONNECTOR_SCOPE=text/plain
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_LOG_LEVEL=info
    restart: always
    depends_on:
      - opencti
  connector-import-file-stix:
    image: opencti/connector-import-file-stix:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${CONNECTOR_IMPORT_FILE_STIX_ID} # Valid UUIDv4
      - CONNECTOR_TYPE=INTERNAL_IMPORT_FILE
      - CONNECTOR_NAME=ImportFileStix
      - CONNECTOR_VALIDATE_BEFORE_IMPORT=true # Validate any bundle before import
      - CONNECTOR_SCOPE=application/json,text/xml
      - CONNECTOR_AUTO=true # Enable/disable auto-import of file
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_LOG_LEVEL=info
    restart: always
    depends_on:
      - opencti
  connector-import-document:
    image: opencti/connector-import-document:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${CONNECTOR_IMPORT_DOCUMENT_ID} # Valid UUIDv4
      - CONNECTOR_TYPE=INTERNAL_IMPORT_FILE
      - CONNECTOR_NAME=ImportDocument
      - CONNECTOR_VALIDATE_BEFORE_IMPORT=true # Validate any bundle before import
      - CONNECTOR_SCOPE=application/pdf,text/plain,text/html
      - CONNECTOR_AUTO=true # Enable/disable auto-import of file
      - CONNECTOR_ONLY_CONTEXTUAL=false # Only extract data related to an entity (a report, a threat actor, etc.)
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_LOG_LEVEL=info
      - IMPORT_DOCUMENT_CREATE_INDICATOR=true
    restart: always
    depends_on:
      - opencti
  connector-alienvault:
    image: opencti/connector-alienvault:5.7.1
    environment:
      - OPENCTI_URL=http://opencti:8080
      - OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
      - CONNECTOR_ID=${ALIENVAULT_CONNECTOR_ID}
      - CONNECTOR_TYPE=EXTERNAL_IMPORT
      - CONNECTOR_NAME=AlienVault
      - CONNECTOR_SCOPE=alienvault
      - CONNECTOR_CONFIDENCE_LEVEL=15 # From 0 (Unknown) to 100 (Fully trusted)
      - CONNECTOR_UPDATE_EXISTING_DATA=false
      - CONNECTOR_LOG_LEVEL=info
      - ALIENVAULT_BASE_URL=https://otx.alienvault.com
      - ALIENVAULT_API_KEY=${ALIENVAULT_API_KEY}
      - ALIENVAULT_TLP=White
      - ALIENVAULT_CREATE_OBSERVABLES=true
      - ALIENVAULT_CREATE_INDICATORS=true
      - ALIENVAULT_PULSE_START_TIMESTAMP=2020-05-01T00:00:00                  # BEWARE! Could be a lot of pulses!
      - ALIENVAULT_REPORT_TYPE=threat-report
      - ALIENVAULT_REPORT_STATUS=New
      - ALIENVAULT_GUESS_MALWARE=false                                        # Use tags to guess malware.
      - ALIENVAULT_GUESS_CVE=false                                            # Use tags to guess CVE.
      - ALIENVAULT_EXCLUDED_PULSE_INDICATOR_TYPES=FileHash-MD5,FileHash-SHA1  # Excluded Pulse indicator types.
      - ALIENVAULT_ENABLE_RELATIONSHIPS=true                                  # Enable/Disable relationship creation between SDOs.
      - ALIENVAULT_ENABLE_ATTACK_PATTERNS_INDICATES=true                      # Enable/Disable "indicates" relationships between indicators and attack patterns
      - ALIENVAULT_INTERVAL_SEC=1800
    restart: always
    depends_on:
      - opencti  

volumes:
  esdata:
  s3data:
  redisdata:
  amqpdata:


Запускаем OpenCTI

Подгружаем переменные:

1
set -a ; source .env

Запускаем контейнеры:

1
docker-compose up -d

Запускаем Wazuh

Если нет Wazuh, то разворачиваем его в Docker

1
2
3
git clone https://github.com/wazuh/wazuh-docker
cd /wazuh-docker/single-node/
docker-compose up

Добавляем интеграцию wazuh-opencti:

  • Из интергации нам потребуются два файла, которые необходимо расположить в /var/ossec/integrations. Если позволяет навык, можно добавить из через отдельный volume, либо забрать напрямую из контейнера в с помощью wget.

Запускаем из контейнера:

1
2
curl https://raw.githubusercontent.com/misje/wazuh-opencti/main/custom-opencti.py -o /var/ossec/integrations/custom-opencti.py
curl https://raw.githubusercontent.com/misje/wazuh-opencti/main/custom-opencti -o /var/ossec/integrations/custom-opencti
  • Добавляем настройки в wazuh-manager:
1
2
3
4
5
6
7
8
  <!-- OpenCTI Integration -->
  <integration>
    <name>custom-opencti</name>
    <group>sysmon_eid1_detections,sysmon_eid3_detections,sysmon_eid7_detections,sysmon_eid22_detections,syscheck_file,osquery_file,ids,sysmon_process-anomalies</group>
    <alert_format>json</alert_format>
    <api_key>YOUR_TOKEN_HERE</api_key>
    <hook_url>http://<YOUR-OPENCTI-HOST>:8080/graphql</hook_url>
  </integration>
  • Добавляем правила обнаружения:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<group name="threat_intel,">
   <rule id="100210" level="10">
      <field name="integration">opencti</field>
      <description>OpenCTI</description>
      <group>opencti,</group>
   </rule>
   <rule id="100211" level="5">
      <if_sid>100210</if_sid>
      <field name="opencti.error">\.+</field>
      <description>OpenCTI: Failed to connect to API</description>
      <options>no_full_log</options>
      <group>opencti,opencti_error,</group>
	</rule>
   <rule id="100212" level="12">
      <if_sid>100210</if_sid>
      <field name="opencti.id">\.+</field>
      <description>OpenCTI: IoC found in threat intel: $(opencti.x_opencti_description)</description>
      <options>no_full_log</options>
      <group>opencti,opencti_alert,</group>
   </rule>
</group>

Дополнительно добавим небольшое правило для логирования событий запроса DNS:

1
2
3
4
5
6
<group name="sysmon,sysmon_eid22_detections,windows,">
   <rule id="100140" level="3">
      <if_sid>61650</if_sid>
      <description>DNS query for $(win.eventdata.queryName)</description>
   </rule>
</group>

Особое внимание уделите группам правил, в вашем случае они могут отличаться.

Разворачиваем Windows и ставим sysmon

  • Запускаем powershell от администратора и запускаем установку sysmon:
1
2
3
4
5
6
Set-Location C:\Windows\
Invoke-WebRequest -Uri https://download.sysinternals.com/files/Sysmon.zip -Outfile Sysmon.zip
Expand-Archive Sysmon.zip -force
Write-Host "Unzip Complete."
Invoke-WebRequest -Uri https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml  -OutFile sysmonconfig-export.xml
./Sysmon/sysmon64.exe -accepteula -i sysmonconfig-export.xml
  • Устанавливаем Wazuh Agent
1
Invoke-WebRequest -Uri https://packages.wazuh.com/4.x/windows/wazuh-agent-4.4.1-1.msi -OutFile ${env:tmp}\wazuh-agent.msi; msiexec.exe /i ${env:tmp}\wazuh-agent.msi /q WAZUH_MANAGER='192.168.93.97' WAZUH_REGISTRATION_SERVER='192.168.93.97' WAZUH_AGENT_GROUP='default' WAZUH_AGENT_NAME='test_win' 
  • Добавляем настройки в ossec.conf
1
2
3
4
5
  <!-- Sysmon Config -->
  <localfile>
  <location>Microsoft-Windows-Sysmon/Operational</location>
  <log_format>eventchannel</log_format>
  </localfile>
  • Запускаем wazuh-agent
1
NET START WazuhSvc

Тестирование

Так как у нас есть правила на ICMP запросы, их мы и проверим:

1
ping rad.geewkmy.com

В случае корректной настройки в Security Events мы увидим следующее:

Возможные проблемы:

При развертывании Wazuh в Docker нет python3 и request:

1
2
3
sudo apt update
sudo apt install python3 python3-pip
pip3 install requests

Возможно, для production не лучший выход, но для тестового развертывания подойдет.

Итог

Данная статья не претендует на звание исчерпывающего руководства, и больше преследовалась цель показать, что сравнительно небольших усилиях можно сильно упростить себе жизнь. Разумеется, ICMP-запросами это не ограничивается, но для этого нужно писать правила.


Reference:
OpenCTI Connectors OpenCTI Datasets
OpenCTI Public Knowledge Base
OpenCTI Data Connectors - Add Data Connectors to Your OpenCTI Stack!
Wazuh SIEM — OpenCTI Threat Intel Integration
Github OpenCTI Integration (Not work)
Running OpenCTI using Docker

0%