Detecting threats and enriching investigations with native threat intelligence in Enterprise Security 8.5
After threat intel feeds are flowing into the Splunk Enterprise Security (ES) Threat Intelligence Framework (TIF), the next step is putting that data to work — surfacing matches against your environment's events, alerting analysts when an IOC is spotted, and ensuring those IOCs end up as observables in the resulting investigations.
This article picks up where Configuring native threat intelligence sources in Enterprise Security 8.5 leaves off. It assumes you already have a prepackaged source (such as PhishTank) activated and/or a custom feed (such as Malware Bazaar) downloading file hashes into the file_intel collection. If you haven't set those up yet, start with the configuration article first.
Solution overview
The Threat Intelligence Framework moves data through five stages. The first two stages are covered in the configuration article; the remaining stages are covered in this article.
- Adding threat intel sources — a threat list is downloaded from a configured source (prepackaged or custom) and parsed using source-specific directives.
- Verifying the download and routing — processed records are written to a dedicated KV store collection (one of nine
*_intelcollections), with routing determined by the fields the parser extracts. - Seeing threat matching in action — granular
threatintel_by_*collections derived from the*_intelcollections are used by scheduled threat matching searches to surface IOC matches against your environment's events, with findings written to thethreat_activityindex when an IOC match is detected. - Generating alerts from threat findings — threat detections such as Threat Activity Detected alert on findings, and the Threat findings dashboard surfaces them for analysts.
- Enriching investigations with threat intel observables — event-based detections can be edited to capture IOCs as observables, surfacing them in the Investigation Intelligence tab.
Seeing threat matching in action
After following the steps in the configuration article to get threat data in place, the next step is threat matching. A good candidate for a file_hash match can be drawn from the Malware Bazaar list. The following raw event originates from a Cisco firewall log. It records a Malware Cloud Lookup action against a downloaded file and includes a SHA256 hash identifying the file.

To test threat matching and detection, you can create a synthetic event mimicking this log entry, with a file hash borrowed from the file_intel collection. You can also replace the src IP with a suspicious IP from one of the prepackaged IP blocklists saved to ip_intel. This produces an event spiked with potential red flags that ES will recognize, thanks to their presence in the threat intel collections.
Use | makeresults with | collect index=main to inject the event:

Generating alerts from threat findings
Understanding how threat matching searches work
The power of TIF lies in fully automated threat detection through pre-defined threat matching searches. These searches run as backend scheduled processes, and you won't find them among knowledge objects in Content Management. They monitor various data models' fields of interest for matching IOCs from the *_intel collections. By "fields of interest," this means those most likely to store IOCs, such as Processes.process_hash, Web.dest, and Registry.registry_path, among others.
For example, the synthetic finding injected into index=main in the previous step has been normalized to the Malware.Malware_Attacks dataset. As a result, the Malware Bazaar hash is stored in the Malware_Attacks.file_hash field. That same field is one of the match fields the dedicated file_hash threat matching search inspects for matching hashes originating from the file_intel collection.

The file_hash threat matching search is complex, but it can be deconstructed by focusing on the excerpt that concerns the Malware_Attacks case. At its core, each threat matching search is composed of several consecutive data model queries that share the same structure and function, so the logic below applies to virtually any other threat matching search. It's also worth noting that you can customize threat matching searches to enrich the findings they produce, for example by including additional dataset fields for extraction.
The following is the Malware.Malware_Attacks search block excerpted from the file_hash threat matching search:

The first half is part of the broader multisearch that runs on each data model relevant to the type of IOC being searched, just as Malware.Malware_Attacks is relevant to file_hash. The focal point of this part of the search is the threatintel_by_* lookup, which extracts hash values from the collection for a match against the hash values from Malware.Malware_Attacks. The hash values are then filtered out if they aren't found in the threatintel_by_* collection.
At this point you might be wondering where this threatintel_by_* lookup has come from. While *_intel collections serve as intel repositories, they aren't the target of threat matching searches. Instead, the threatintel_by_* collections, derived from the *_intel collections, serve that purpose. They are more granular in design, further dividing the downloaded threat intel into groups based on various intel attributes, which makes them leaner and well suited for threat matching searches. For that reason, custom searches targeting threat intel should be directed against the threatintel_by_* collections.
Returning to the search: the second half is largely post-processing, with additional fields being added from relevant threat intel collections. The extracted and evaluated fields are grouped on the matching IOC and output as a threat finding. In this example, the search returns a single threat finding—a match for the test hash.
The output of a threat matching search is a finding in its own right, but it doesn't land in the notable index. Like any other match found by threat matching searches, it is saved to the threat_activity index instead. The source field indicates the threat matching search that produced the finding, for example source = threatmatch://file_hash.

The next link in the threat detection chain is the Threat Intelligence data model, which provides an accelerated view of the threat findings written to the threat_activity index.

This is where event-based detections come into play. Detections that target the Threat Intelligence data model or threat_activity index are designed to alert on the threat findings generated by threat matching searches. You can write your own, but one of the event-based detections that ship with ES that's fit for purpose here is Threat Activity Detected.

Back in the Analyst Queue, the Threat Activity Detected alert is triggered by the malware threat finding. There's more context in the side panel, but the description alone reveals:
- The IOC type (
Malware_Attacks.file_hash). - The IOC value (
$threat_match_value$in brackets, which resolves to the hash). - Which
*_intelcollection the IOC was found in.

The small spike in threat findings (+1) caused by the test event injection is also recorded in the Analytics > Security intelligence > Threat intelligence > Threat findings dashboard. The dashboard tells you, among other things, when the threat finding was saved to the threat_activity index, which threat intel collection the IOC match was found in, and the threat_key that attributes it to the exact source feed.

Enriching investigations with threat intel observables
The steps below assume you can view the Intelligence tab in investigations, for which you need to activate at least one TIM Cloud source and create at least one threatlist.
The event-based detection that alerted on the Cisco firewall raw event in the previous example sits outside the threat matching pipeline analyzed above, because it doesn't query the Threat Intelligence data model. In the context of investigation enrichment with threat intel data, the issue with that detection is that it doesn't extract the hash. As a result, opening an investigation on the finding it produced won't surface the hash among the investigated observables. The same applies to the source IP field.
To remedy that, edit the event-based detection search to include two additional Malware.Malware_Attacks data model fields you want to capture as observables: file_hash and src. In the test event, after it's scoped by the data model, these two fields store the Malware Bazaar hash and the IP blocklist IP.

Because the default time window for the search hasn't been extended, the event must be re-injected to index=main for the new version of the detection to see it. After the event lands in main, run a couple of manual checks using the hash filter as a unique identifier:
- Against the Malware data model the event is expected to be normalized to.

- Using the detection search before it runs on schedule, to confirm the event will be picked up.

- Against
index=notable, to verify the detection has captured the finding.
Open an Investigation on the finding to reach the list of observables in the Intelligence tab. Both observables—the src IP and the file hash—appear there, matched against the indicators of compromise from the native threat intel collections.

Next steps
With threat matching, alerting, and investigation enrichment all working off the native Threat Intelligence Framework, you've now seen how ES surfaces and enriches threats from native sources end-to-end. To extend these capabilities further, Enriching threat intelligence with cloud-based sources in Enterprise Security 8.5 covers Splunk Threat Intelligence Management (TIM Cloud), which adds cloud-based aggregation and enrichment from a wide range of open source and premium threat intel providers.
In addition, these resources might help you understand and implement this guidance:

