Zeekurity Zen – Part V: Zeek Intelligence Framework

If you're looking for professional services on this topic or interested in other cybersecurity consulting services, please reach out to me via my Contact page to discuss further.
This is part of the Zeekurity Zen Zeries on building a Zeek (formerly Bro) network sensor.
Overview
In our Zeek journey thus far, we’ve:
- Set up Zeek to monitor some network traffic.
- Used Zeek Package Manager to install packages.
- Configured Zeek to send logs to Splunk for analysis.
- Uncovered notable events through basic threat hunting.
We’ve come a long way and discovered much about our network through our own analysis. Is there a way to leverage curated threat intelligence to elevate our threat hunting game?
We absolutely can with Zeek’s Intelligence Framework. This framework ingests a variety of common indicators and matches them against the rich metadata that Zeek generates. This includes IPs, email addresses, URLs, domain names, and file hashes. We simply need to format our intelligence into a text file and point Zeek to its location. There are countless threat intelligence resources available that we can take advantage of. You’re also highly encouraged to develop your own unique intelligence based on previous incidents or unique threats that target your organization and industry.
To do this, we’ll walkthrough these steps:
- Enable Zeek’s Intelligence Framework to ingest threat intelligence.
- Create a simple intelligence file with one indicator.
- Review intelligence match results.
- Use actionable intelligence sources with automation.
Enable Zeek’s Intelligence Framework
- Edit /opt/zeek/share/zeek/site/local.zeek and add the following lines to the bottom. This enables the Intelligence Framework and tells Zeek to load intelligence from /opt/zeek/intel/zeek_intel.txt.
# Load Zeek Intelligence Framework @load policy/frameworks/intel/seen redef Intel::read_files += { "/opt/zeek/intel/zeek_intel.txt" };
- As the zeek user, create the /opt/zeek/intel directory.
mkdir /opt/zeek/intel
- As the zeek user, stop zeek.
zeekctl stop
- As the zeek user, apply the new settings and start zeek.
zeekctl deploy
Create a simple intelligence file
- As the zeek user, open your favorite file editor to create a text file and save it to /opt/zeek/intel/zeek_intel.txt. This file must be tab delimited, including the #fields header row. The indicator and indicator_type fields are required while the meta headers are optional and can include any additional information you feel would be useful to describe an indicator. For our purposes, we will populate our test file with zeek.org as the indicator and Intel::DOMAIN as the indicator_type. Note that there are several options for indicator_type, depending on the indicator you intend to use.
#fields indicator indicator_type meta.source meta.desc zeek.org Intel::DOMAIN zeek-intel-test Zeek Intelligence Framework Test
Note: If you copy and paste my example above, your file will only have spaces. Given this, you will need to manually ensure that all rows are tab delimited, including the #fields header row.
Note: You can continue adding new indicators to this file without restarting Zeek. A restart is required only if you want to remove an indicator.
Review intelligence match results
- With our newly created intel file, visit zeek.org to see what happens. If all went well, you should now have a newly generated intel.log file in your current log directory. Below is a sample intel.log file in JSON format showing three separate log entries.
{ "ts": 1593537714.074326, "uid": "CNQFv73BiKAd14YY11", "id.orig_h": "10.2.2.23", "id.orig_p": 44425, "id.resp_h": "10.2.2.1", "id.resp_p": 53, "seen.indicator": "zeek.org", "seen.indicator_type": "Intel::DOMAIN", "seen.where": "DNS::IN_REQUEST", "seen.node": "worker-1-2", "matched": [ "Intel::DOMAIN" ], "sources": [ "zeek-intel-test" ] } { "ts": 1593537714.182831, "uid": "CvtoU61JPTygBQUb3c", "id.orig_h": "10.2.2.23", "id.orig_p": 51786, "id.resp_h": "192.0.78.212", "id.resp_p": 443, "seen.indicator": "zeek.org", "seen.indicator_type": "Intel::DOMAIN", "seen.where": "SSL::IN_SERVER_NAME", "seen.node": "worker-1-2", "matched": [ "Intel::DOMAIN" ], "sources": [ "zeek-intel-test" ] } { "ts": 1593537714.182831, "uid": "CvtoU61JPTygBQUb3c", "id.orig_h": "10.2.2.23", "id.orig_p": 51786, "id.resp_h": "192.0.78.212", "id.resp_p": 443, "seen.indicator": "zeek.org", "seen.indicator_type": "Intel::DOMAIN", "seen.where": "X509::IN_CERT", "seen.node": "worker-1-2", "matched": [ "Intel::DOMAIN" ], "sources": [ "zeek-intel-test" ], "fuid": "FWJEqd4JisAzgNZD42", "file_mime_type": "application/x-x509-user-cert", "file_desc": "192.0.78.212:443/tcp" }
- Most of the fields should look familiar, so we’ll focus on the new fields.
- seen.indicator (e.g., zeek.org): The indicator that we told Zeek to look for.
- seen.indicator_type (e.g., Intel::DOMAIN): The indicator’s type.
- seen.where (e.g., DNS::IN_REQUEST, SSL::IN_SERVER_NAME, X509::IN_CERT): Where Zeek detected the indicator. We see that there are three distinct log entries showing that Zeek found “zeek.org” in a DNS request, in a TLS server name, and in a X.509 certificate.
- seen.node (e.g., worker-1-2): The Zeek node that detected the indicator.
- matched (e.g., Intel::DOMAIN): The indicator type that was matched.
- sources (e.g., zeek-intel-test): What we populated for the meta.source field in our zeek_intel.txt file.
Use actionable intelligence sources with automation
We used a simple example above to demonstrate how to use Zeek’s Intelligence Framework to generate a log of intelligence matches. But how do we take this to the next level and instead use large actionable intelligence data sets? How do we also scale our process to automatically consume and generate intelligence files that Zeek can ingest?
To answer these questions, we can leverage the awesome-threat-intelligence list which includes intelligence sources, formats, frameworks and platforms, and tools. It’s a mix of open source and commercial intelligence resources. If you’re brand new to threat intelligence, the list can be overwhelming. If you’re absolutely unsure where to start, I suggest checking out MISP — an open source threat intelligence platform. It supports a wide variety of sources and formats, and can output intelligence to Zeek and other security platforms. Otherwise, read through the descriptions and note any sources or platforms that interest you. When it comes to intelligence sources, you want indicators that are well maintained and not stale (e.g., an IP address that was malicious a year ago, may be recycled and benign today). In terms of frameworks, you’ll want to choose one that can ingest a variety of intelligence sources/formats and can output this data into Zeek-formatted intelligence.
Up Next
In Part VI of this series, we will discuss Zeek’s File Analysis Framework.
If you're looking for professional services on this topic or interested in other cybersecurity consulting services, please reach out to me via my Contact page to discuss further.
intel.log is not generating. could you please help me what i need to check.
Hi Shihab,
Without any additional context on what you’ve already tried, I’d suggest the following:
* Ensure the intel file’s permissions are such that Zeek can access and read the file.
* Confirm that the intel file is tab-delimited.
* Depending on what’s in your intel file, note that you won’t be able to trigger hits on encrypted traffic unless you are actively decrypting already.
Hope that helps!
hello eric
how do you normally configure zeek to send email alerts for these? If we wanted an email to get sent to our exchange email address each time a match occurs in the intel.log or even the notice.log, do you normally configure sendmail or something similar?
If we had an SMTP Server sending us email alerts on our domain already, would we be able to configure zeek to use that SMTP Server and just specify the port and username/password?
any help would be greatly appreciated. thanks!
Great question, Sony!
Honestly, I don’t configure this in my own setup as I have everything sent to a SIEM where I can configure alerts more granularly. I’d recommend doing that as you may not want every email that Zeek sends. That said, yes, you’d need to first configure sendmail on your system to use your preferred mail relay. From there you’d edit /opt/zeek/etc/zeekctl.cfg and add (or modify if it already exists) the following options, replacing the values with your own:
MailTo = user@domain.com
sendmail = /path/to/sendmail
Save the file when you’re done.
For reference, intel hits are automatically written to intel.log and also raise a notice (e.g. alert) in notice.log. Given that, let’s configure Zeek to send these notices to the email we set above. Edit /opt/zeek/share/zeek/site/local.zeek and add the following:
hook Notice::policy(n: Notice::Info)
{
add n$actions[Notice::ACTION\_EMAIL];
}
Stop Zeek (zeekctl stop) and redeploy (zeekctl deploy) and you should start receiving emails.
Hope that helps!