wazuh-opencti is a Wazuh integration that looks up alert metadata in an OpenCTI threat intel database. If the metadata is found in any STIX indicator, the integration will create a Wazuh alert with plenty of metadata from the OpenCTI observable and indicator.
wazuh-opencti operates on
- SHA256 hashes (typically from files)
- IP addresses (IPv4/IPv6)
- Domain names (like DNS queries)
- Hostnames (like DNS queries)
- URLs (found in arguments in audited commands)
and inspects events from sysmon, syscheck, suricata and osquery. The script can easily be extended to match other types of events as well.
The integration will only inspect events whose rule.groups matches
- sysmon events 1, 3, 6, 7, 15, 22, 23, 24, 25
- ids
- syscheck_file
- osquery
- osquery_file
- audit_command
The logic is as follows:
- The value to look up is queried against observables (stixCyberObservables) and indicators (indicators)
- For every indicator that matches (the indicator has to have pattern_type "stix", and it has to be a single-value (simple) pattern, like [file:hashes.'SHA-256' = '275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f' or [domain-name:value = 'example.org'), an alert of type indicator_pattern_match is created. A maximum of three alerts are created (configurable by modifying the max_ind_alerts variable), and a maximum of 10 indicators are returned by the query for processing and filtering. Indicators are sorted by !revoked, detection, score, confidence and valid_until. If the indicator only matches partially, the event type will be indicator_partial_pattern_match.
- For every observable that matches (either by value or hashes_SHA256, depending on the type of observable), an alert is created if the observable has an indicator related to it. Only one indicator is included, and they are sorted like mentioned above before picking the first one. The alert_type is observable_with_indicator. A maximum of two alerts are created (configurable by modifying the max_obs_alerts variable), and a maximum of 10 observables are returned by the query.
- If the observable is related to other observables (IP addresses and domain names), and those observables have indicators, the related indicator is included in the event. If the observable only has related indicators, the event_type is observable_with_related_indicator.
- An OpenCTI instance (version 5.12.24 or higher) up and running
- Older versions are supported, but you need to revert the changes in #13/#11 and/or #15 in order to support the older graphql filter syntax.
- A read-only OpenCTI API token suitable for querying data (Access knowledge + Access exploration(?))
Copy the two custom-opencti files into your Wazuh manager integrations directory, /var/ossec/integrations. If you're using docker, this will be the root directory in the wazuh_integrations volume.
Modify your manager configuration file, /var/ossec/etc/ossec.conf. If you're
using docker, this will be the file config/wazuh_cluster/wazuh_manager.conf.
Add an entry like the following to an <ossec_config>
block:
<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,audit_command</group>
<alert_format>json</alert_format>
<api_key>REPLACE-ME-WITH-A-VALID-TOKEN</api_key>
<hook_url>https://my.opencti.location/graphql</hook_url>
</integration>
Be sure to replace api_key and hook_url. You should also modify
group to match entries in events' rule.groups that you want to inspect.
You may use <rule_id>
instead of <group>
to match individual rules instead,
but note that you cannot mix both! If you use <rule_id>
, <group>
will
be ignored.
wazuh-opencti looks at events' rule.groups before querying OpenCTI. Currently, it only cares about events related to sysmon, syscheck (file), suricata/packetbeat and osquery. If you look at the configuration example above, you'll notice that sysmon_eidX_detections is used instead of sysmon_eventX. This is because Wazuh (at least as of 4.3.9) doesn't produce any sysmon_eventX events. – Only specific detections events. Also note that 4.3.9 doesn't even have basic rules that cover all of the sysmon events. You may need to add rules for sysmon event 16–25. Event 22–25 is used by this integration.
All monitored directories and files through syscheck will be inspected without further configuration (as long as "syscheck" is part of as described earlier), but DNS queries will have to be manually configured to be logged and subsequently look up by this integration. If you do not already have a rule that logs DNS queries, use the following examples as guidance:
On Windows (sysmon):
<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>
On Linux (using packetbeat):
<group name="packetbeat,ids">
<rule id="101000" level="0">
<decoded_as>json</decoded_as>
<field name="@source">packetbeat</field>
<options>no_full_log</options>
<description>packetbeat messages grouped</description>
</rule>
<rule id="101001" level="3">
<if_sid>101000</if_sid>
<field name="method">QUERY</field>
<mitre>
<id>T1071</id>
</mitre>
<description>DNS query for $(dns.question.name)</description>
<options>no_full_log</options>
</rule>
</group>
In order for Wazuh to create alerts when an IoC is found, a rule is needed. Rules for when the integration fails to operate are also highly recommended. Here is an example rule set (be sure to replace the rule IDs to avoid conflicts in your setup):
<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.event_type">indicator_pattern_match</field>
<description>OpenCTI: IoC found in threat intel: $(opencti.indicator.name)</description>
<options>no_full_log</options>
<group>opencti,opencti_alert,</group>
</rule>
<rule id="100213" level="12">
<if_sid>100210</if_sid>
<field name="opencti.event_type">observable_with_indicator</field>
<description>OpenCTI: IoC found in threat intel: $(opencti.observable_value)</description>
<options>no_full_log</options>
<group>opencti,opencti_alert,</group>
</rule>
<rule id="100214" level="10">
<if_sid>100210</if_sid>
<field name="opencti.event_type">observable_with_related_indicator</field>
<description>OpenCTI: IoC possibly found in threat intel (related): $(opencti.related.indicator.name)</description>
<options>no_full_log</options>
<group>opencti,opencti_alert,</group>
</rule>
<rule id="100215" level="10">
<if_sid>100210</if_sid>
<field name="opencti.event_type">indicator_partial_pattern_match</field>
<description>OpenCTI: IoC possibly found in threat intel: $(opencti.indicator.name)</description>
<options>no_full_log</options>
<group>opencti,opencti_alert,</group>
</rule>
</group>
This integration looks up observables with indicators that are related to an observable. For instance, if a domain name has no indicators, but the IPv4 address it resolves to (if such a relationship exists in OpenCTI) has an indicator, an alert with event_type observable_with_related_indicator is created. This may produce noise depending on your database, so you may want to have a different level on this alert, as in the example above. A connector like google-dns can be enabled to create automatic relationships between addresses and domain name objects.
In order to test that the integration works, create an observable in OpenCTI with a SHA256 hash that matches a file you will later create or move in Windows or Linux. Then create an indicator (wazuh-opencti only creates alerts if an observable has an indicator tied to it). Depending om your syscheck setup, put the file with the matching hash in a monitored directory and wait for the alert to be created. If you don't have a real-time syscheck setup yet, consider setting one up for C:\Users\*\Downloads.
During testing and development, it may be very useful to enable debug output
from the integration. Debug output may be enabled in internal
options.
If you're using docker, add integrator.debug = 1
to
local_internal_options.conf in the wazuh_etc volume. The log is found in
/var/ossec/logs/integrations.log. If you're using docker docker, run
docker-compose exec wazuh.manager tail -f /var/ossec/logs/integrations.log
.
If the log is empty, check the Wazuh manager log and ensure that the
integration doesn't fail and return an exit value of 1.
group name | metadata |
---|---|
sysmon_event1, sysmon_eid1_detections | win.eventdata.hashes |
sysmon_event6, sysmon_eid6_detections | win.eventdata.hashes |
sysmon_event7, sysmon_eid7_detections | win.eventdata.hashes |
sysmon_event_15, sysmon_eid15_detections | win.eventdata.hashes |
sysmon_event_22, sysmon_eid22_detections | win.eventdata.queryName, win.eventdata.queryResults |
sysmon_event_23, sysmon_eid23_detections | win.eventdata.hashes |
sysmon_event_24, sysmon_eid24_detections | win.eventdata.hashes |
sysmon_event_25, sysmon_eid25_detections | win.eventdata.hashes |
sysmon_process-anomalies | win.eventdata.hashes |
ids | dest_ip, destip, src_ip, srcip, dns.question.name, dns.question.answers |
osquery, osquery_file | osquery.columns.sha256 |
audit_command | execve.a0, execve.a1, … |
Feel free to modify custom-opencty.py to suit your needs. It was designed to cover my own needs, but I am sure that there are other events and groups this integration could inspect. I would greatly appreciate if you could provide a pull request to enhance the script if you think others may benefit from your modifications.
Here are some examples of how the events produced are. The data is just for demonstration.
Key | Value |
---|---|
@timestamp | 2023-08-31T10:34:33.222Z |
_id | REDACTED |
agent.id | REDACTED |
agent.ip | REDACTED |
agent.name | REDACTED |
data.integration | opencti |
data.opencti.event_type | indicator_pattern_match |
data.opencti.indicator.confidence | 70 |
data.opencti.indicator.createdBy.id | b975431a-59a9-4982-b75c-cff659801f15 |
data.opencti.indicator.createdBy.identity_class | organization |
data.opencti.indicator.createdBy.name | ThreatFox Abuse.ch |
data.opencti.indicator.createdBy.standard_id | identity--15d97c2e-9367-521e-9306-03a9c99c538d |
data.opencti.indicator.created_at | 2023-08-30T13:39:42.959Z |
data.opencti.indicator.externalReferences | https://attack.mitre.org/software/S0154/ |
data.opencti.indicator.id | 4c14daab-d133-43b6-88ef-e82ec0fd337a |
data.opencti.indicator.indicator_types | malicious-activity |
data.opencti.indicator.labels | malicious-activity |
data.opencti.indicator.name | Cobalt Strike |
data.opencti.indicator.pattern | [ipv4-addr:value = '116.163.24.195'] |
data.opencti.indicator.pattern_type | stix |
data.opencti.indicator.revoked | false |
data.opencti.indicator.updated_at | 2023-08-30T13:39:42.985Z |
data.opencti.indicator.valid_until | 2023-09-29T12:17:03.000Z |
data.opencti.indicator.x_opencti_detection | false |
data.opencti.indicator.x_opencti_score | 50 |
data.opencti.indicator_link | https://REDACTED/dashboard/observations/indicators/4c14daab-d133-43b6-88ef-e82ec0fd337a |
data.opencti.query_key | value |
data.opencti.query_values | [domain-name:value = 'cdn.bootcss.com'];[ipv4-addr:value = '116.172.148.7'];[ipv4-addr:value = '119.188.86.194'];[ipv4-addr:value = '116.153.64.158'];[ipv4-addr:value = '1.62.64.68'];[ipv4-addr:value = '116.163.24.195'];[ipv4-addr:value = '36.248.54.138'];[ipv4-addr:value = '119.167.229.212'];[ipv4-addr:value = '218.12.86.80'];[ipv4-addr:value = '1.62.64.108'] |
data.opencti.source.alert_id | 1693478062.194800757 |
data.opencti.source.image | C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe |
data.opencti.source.queryName | cdn.bootcss.com |
data.opencti.source.queryResults | type: 5 cdn.bootcss.com.cdn.dnsv1.com.cn;type: 5 rpljaw8p.slt.sched.tdnsv8.com;::ffff:116.172.148.7;::ffff:119.188.86.194;::ffff:116.153.64.158;::ffff:1.62.64.68;::ffff:116.163.24.195;::ffff:36.248.54.138;::ffff:119.167.229.212;::ffff:218.12.86.80;::ffff:1.62.64.108; |
decoder.name | json |
id | 1693478073.195158709 |
input.type | log |
location | opencti |
manager.name | wazuh.manager |
rule.description | OpenCTI: IoC found in threat intel: Cobalt Strike |
rule.firedtimes | 3 |
rule.groups | threat_intel, opencti, opencti_alert |
rule.id | 100212 |
rule.level | 12 |
rule.mail | true |
timestamp | 2023-08-31T10:34:33.222+0000 |
The following is an event where the domain name queried matches against an observable with an indicator, and a related observable also with an indicator is included.
Key | Value |
---|---|
@timestamp | 2023-08-09T16:40:02.889Z |
_id | REDACTED |
agent.id | REDACTED |
agent.ip | REDACTED |
agent.name | REDACTED |
data.integration | opencti |
data.opencti.created_at | 2023-08-09T06:22:27.177Z |
data.opencti.entity_type | Domain-Name |
data.opencti.event_type | observable_with_indicator |
data.opencti.id | efcd09cc-8f0d-41f5-8fb2-c197b5459623 |
data.opencti.indicator.confidence | 15 |
data.opencti.indicator.id | 959feeae-2f16-4521-baca-af58a374c845 |
data.opencti.indicator.labels | deleteme |
data.opencti.indicator.name | test3.example.org |
data.opencti.indicator.pattern | [domain-name:value = 'test3.example.org'] |
data.opencti.indicator.pattern_type | stix |
data.opencti.indicator.revoked | false |
data.opencti.indicator.valid_until | 2024-08-08T06:22:27.380Z |
data.opencti.indicator.x_opencti_detection | false |
data.opencti.indicator.x_opencti_score | 50 |
data.opencti.indicator_link | https://REDACTED/dashboard/observations/indicators/959feeae-2f16-4521-baca-af58a374c845 |
data.opencti.labels | deleteme |
data.opencti.multipleIndicators | false |
data.opencti.observable_link | https://REDACTED/dashboard/observations/observables/efcd09cc-8f0d-41f5-8fb2-c197b5459623 |
data.opencti.observable_value | test3.example.org |
data.opencti.query_key | value |
data.opencti.query_values | test3.example.org |
data.opencti.related.id | 7a9f6847-12b1-41f7-bb4a-b41f94808547 |
data.opencti.related.indicator.confidence | 15 |
data.opencti.related.indicator.id | 17384027-a7ff-4802-8576-7af336d4833f |
data.opencti.related.indicator.labels | deleteme |
data.opencti.related.indicator.name | 9dd2:b4b0:ab1d:7c8d:6c26:32c2:af75:93af |
data.opencti.related.indicator.pattern | [ipv6-addr:value = '9dd2:b4b0:ab1d:7c8d:6c26:32c2:af75:93af'] |
data.opencti.related.indicator.pattern_type | stix |
data.opencti.related.indicator.revoked | false |
data.opencti.related.indicator.valid_until | 2023-10-08T13:27:48.365Z |
data.opencti.related.indicator.x_opencti_detection | false |
data.opencti.related.indicator.x_opencti_score | 50 |
data.opencti.related.indicator_link | https://REDACTED/dashboard/observations/indicators/17384027-a7ff-4802-8576-7af336d4833f |
data.opencti.related.multipleIndicators | false |
data.opencti.related.type | IPv6-Addr |
data.opencti.related.value | 9dd2:b4b0:ab1d:7c8d:6c26:32c2:af75:93af |
data.opencti.source.alert_id | 1691599198.370628528 |
data.opencti.source.queryName | test3.example.org |
data.opencti.updated_at | 2023-08-09T06:22:27.246Z |
data.opencti.value | test3.example.org |
data.opencti.x_opencti_description | TEST |
data.opencti.x_opencti_score | 50 |
decoder.name | json |
id | 1691599202.370639246 |
input.type | log |
location | opencti |
manager.name | wazuh.manager |
rule.description | OpenCTI: IoC found in threat intel: test3.example.org |
rule.firedtimes | 1 |
rule.groups | threat_intel, opencti, opencti_alert |
rule.id | 100214 |
rule.level | 12 |
rule.mail | true |
timestamp | 2023-08-09T16:40:02.889+0000 |