Alert search
Before the connector can produce any meaningful information to import in OpenCTI, it has to look up entity metadata in Wazuh’s OpenSearch database. A typically use case in an automated setup, is to look up every new File and Artifact hash IoCs imported into OpenCTI. Other common IoCs are domain names and IPv4/IPv6 addresses. The connector has support for looking up all of these, along with many other observables.
It is also possible to look up alerts using less common metadata, like filenames, directory paths and process command lines. This can be helpful in an investigation, if you want to see where files, whose contents varies, has spread across systems, or where a process may have been run. This essentially makes OpenCTI into a search interface for OpenSearch, allowing you to search for alerts without having to craft complicated DSL queries yourself. Be sure to read the usage documentation below before doing so, and beware that “simple” searches may result in a lot of results (sightings), which in turn may create incidents depending your configuration.
Configuration
Use CONNECTOR_SCOPE to
select which entities to search for. Use the various settings in
SearchConfig to determine how searches are
performed.
Observables that have been created by the connector through enrichment are not looked up by default (determined by
label_ignore_list and
enrich_labels). In order to look up these
entities, simply remove the WAZUH_IGNORE label and run the enrichment again.
Supported entities
The function documentation below describes how the various supported entities are looked up. Most observables, along with vulnerabilities and indicators are supported:
- Artifact 
- Directory 
- Domain-Name 
- Email-Addr 
- Hostname 
- IPv4-Addr 
- IPv6-Addr 
- Mac-Addr 
- Network-Traffic 
- Process 
- StixFile 
- Url 
- User-Account 
- User-Agent 
- Windows-Registry-Key 
- Windows-Registry-Value-Type 
- Vulnerability 
- Indicator 
Indicators are special: There is no direct support for searching indicators, but they can be useful to include in the connector scope in the following situation:
- An observable is created in the OpenCTI platform. It is automatically enriched by the connector, but because the configuration requires observables to have indicators based on them (see - require_indicator_for_incidents,- require_indicator_detection,- ignore_revoked_indicatorsand- indicator_score_threshold), sightings/incidents are not created.
- An indicator is later created with a relationship indicating that it is “based on” an observable. The enrichment of the indicator will in turn run on the observable that it is based on, just as if the observable was enriched directly. The search will now produce events, because of the new indicator relationship. 
Even if the indicator and the relationship are created or imported into OpenCTI at the same time as the observable, this information is not available at the time the connector is told to enrich the observable automatically. The separate enrichment of the indicator is therefore necessary.
Automation can be used to automatically create observables from a STIX-only indicator without any based-on relationship. See automatically create obserables from indicators for details.
Note
The indicator pattern is not used at all.
Note
If the indicator is based on more than one observable, only the first relationship is taken into consideration.
- class AlertSearcher.query_file(self, *, entity: dict, stix_entity: dict)
- Search for File/Artifact hashes, filename/paths and/or size - If the file has a hash (SHA-256, MD5 or SHA-1), the hash will looked up in any field with a matching name (*sha256*). 
- If the file also has a name, and if - filesearch_optionscontains- SearchNameAndHash, the name is included in the search
- If the file has no hash, a filename search is performed if - filesearch_optionscontains- SearchFilenameOnly
- If the file does not have hashes, but has a filename and a size, and - filesearch_optionscontains- SearchSize, the search looks for the exact size in syscheck.{size_before,size_after} along with the filenames
- If the file has additional names (x_opencti_additional_names) and - filesearch_optionscontains- SearchAdditionalFilenames, all filenames are included in the search
 - Filenames and paths- When searching for filenames, a number of settings dictate how to deal with paths. The filenames most likely do not contain a path, but if they do, the setting - BasenameOnlyremoves this path before searching for the filename. Otherwise, the path, regardless of whether is is absolute, is included in the search.- If the file has a reference to a parent directory (parent_directory_ref), that directory’s path is included in the search if - filesearch_optionscontains- IncludeParentDirRef. If the filename already contains a path, it is removed and replaced with that of the parent directory.- If - filesearch_optionscontains- RequireAbsPath, the filename (including its parent directory’s path) must be absolute in order to run the search.- Matching- Regular expressions (Regexp) are used as long as - filesearch_optionscontains- AllowRegexp. This allows for flexible searching, like- Searching for filenames regardless of the path in alerts 
- Search for paths with any backslash escaping patterns (\, \\, \\\\ etc.). Wazuh’s syscheck, for instance, uses no extra ecaping, whereas sysmon and most other events uses double escaping. 
- Ignoring case ( - CaseInsensitive)
 - However, regular expressions may be expensive or even disabled in your OpenSearch instance, so when not using Regexp, Match is used instead. This requires an exact match of both the filename and the path. - TODO: Mention IncludeRegValues if not moved to Analyse 
- class AlertSearcher.query_addr(self, *, entity: dict)
- Search for IPv4/IPv6 addresses - If - lookup_agent_ipis true, Wazuh agents’ IP addresses will also be looked up. This is probably not useful.- If - ignore_private_addrsis true, no search is performed if the IP address is private (IPv4, IPv6).
- class AlertSearcher.query_mac(self, *, entity: dict)
- Search for MAC addresses - If - lookup_mac_variantsis true, various MAC address formats will be looked up. Otherwise, only lower-case, colon-separated MAC addresses will be looked up.
- class AlertSearcher.query_traffic(self, *, stix_entity: dict)
- Search for network traffic SCOs - The following properties in Network-Traffic are considered: - src_ref (MAC/IPv4/IPv6 addresses only, not domain names) 
- src_port 
- dst_ref (MAC/IPv4/IPv6 addresses only, not domain names) 
- dst_port 
- protocol 
 - Support for domain names in sources, as well as support for the other properties are not implemented, because no decoders seem to provide these kinds of fields. - If - lookup_mac_variantsis true, various MAC address formats will be looked up. Otherwise, only lower-case, colon-separated MAC addresses will be looked up.- Note that it is possible to add multiple addresses as sources/destinations in OpenCTI (despite the standard specifying that only one can be specified). However, only one is provided to the connector. The precedence is unknown. 
- class AlertSearcher.query_email(self, *, stix_entity: dict)
- Search for e-mail addresses 
- class AlertSearcher.query_domain(self, *, entity: dict)
- Search for domain names and hostnames - If - lookup_hostnames_in_cmd_lineis enabled, command line alerts will also be searched.
- class AlertSearcher.query_url(self, *, entity: dict)
- Search for URLs - Some alerts, like logs from web servers, only contains the path from URLs (scheme, host etc. are not present). If - lookup_url_without_hostis enabled, these fields can still be matched. This is probably not useful for looking up IoCs unless you’re looking for a malicious requests.- If - lookup_url_ignore_trailing_slashis enabled, trailing slashes in the observable and in alert fields will be ignored.- If none of these settings are enabled, more fields are possibly searched. 
- class AlertSearcher.query_directory(self, *, stix_entity: dict)
- Search for Directory paths - Directory IoCs are most likely very uncommon, but extensive search support is still available. A number of - optionsin- dirsearch_optionsdictate how the search is performed:- MatchSubdirswill match parent directories in paths, like “/foo/bar” in “/foo/bar/baz”.
- SearchFilenameswill look for directories in filename fields as well. If disabled, fields that may contain either directories or absolute filename paths will still be searched.
- CaseInsensitiveignores case when searching
- RequireAbsPathrequires the path in the observable to be absolute in order to perform a search
- NormaliseBackslashessearches for several variations of backslash escaping if- AllowRegexpis disabled. syscheck.path contains minimum exaping, whereas most other fields have twice the amount of backslashes. When regexp is enabled, the number of backslashes in the observable and fields are completely ignored.
- IgnoreTrailingSlashwill ignore trailing slashes in both the observable and fields
 - AllowRegexpmust be enabled for most of the search flexibility to work, and most of the other options requires this option to be set. See- DirSearchOptionfor details.
- class AlertSearcher.query_reg_key(self, *, stix_entity: dict)
- Search for Windows registry keys 
- class AlertSearcher.query_reg_value(self, *, stix_entity: dict)
- Search for Windows registry values - Wazuh’s FIM module only registers registry values’ hashes, not values. Also, it only supports REG_SZ, REG_EXPAND_SZ and REG_BINARY (i.e. not numeric values, like REG_DWORD). - This function will only search for registry values of type REG_{SZ, EXPAND_SZ, BINARY}, and it will only compare SHA-256 values (since that is what Wazuh’s FIM/syscheck module provides). - If the data type is REG_SZ/REG_EXPAND_SZ, a SHA-256 hash is taken from the value (data). If the data type is REG_BINARY, the contents is expected to be a hex string, of which a SHA-256 hash is computed. 
- class AlertSearcher.query_process(self, *, stix_entity: dict)
- Search for process command lines - Command lines are hard to search, because arguments and options may be in any order. This function tries to match all of the words in the SCO’s command_line without being too inaccurate. Only the property command_line is supported. - Matching- First, the string is tokenised into a list of words separated by whitespace. Any sequence of words enclosed in non-escaped quotes are considered as a single token, .e.g.: - foo bar baz becomes [‘foo’, ‘bar’, ‘baz’] 
- foo ‘bar baz’ becomes [‘foo’, ‘bar baz’] 
 - The first token is considered to be the command, and is treated differently: Any path is stripped (basename) in order to match commands both with and without a full path, and this token is searched for in command fields and not argument fields (where applicable). - The remaining tokens are considered arguments. First, any non-escaped quotes are removed from the beginning and end of argument. In case of command line alerts without individual argument fields, a search is performed for each individual argument in command line fields on a non-whitespace boundary, e.g.: - “C:foobar baz ‘qux quux’” will search for “baz” and match “ baz”, ” baz” and “ baz “, but not “bazaar” 
 - For alerts with argument fields, like data.audit.execve, the argument are matched as they are. - Note - Regexp queries are needed to search for process command lines, which may be expensive, and may also be disabled in your OpenSearch installation if search.allow_expensive_queries is set to false. In order to disable regexp searches, disable process searching altogether by not specifying “Process” in the connector scope. 
- class AlertSearcher.query_vulnerability(self, *, stix_entity: dict)
- Search for vulnerabilities - Results will typically contain an event when the vulnerability was first detected, then later when the vulnerability was “resolved” due to a package upgrade. 
- class AlertSearcher.query_account(self, *, stix_entity: dict)
- TODO: document 
- class AlertSearcher.query_user_agent(self, *, stix_entity: dict)
- Search for user agents strings