This is a follow-up to our second blog on hunting using the publicly available Newly Registered Domains (NRD) threat intel lists. In this blog, we will explore a hands-on example of infection traffic and review one of three possible detection and investigation techniques that can unearth malicious behavior.
It is important to note that NRDs are not necessarily bad by default, and an NRD alone is not enough of an IoC/match to determine whether or not it is malicious. We need to combine context with the detection itself to make that determination. But what information can help us come to our conclusion? This blog post should help give you a baseline of what to look for.
This blog post is one of five blogs introducing Open NRD and sharing various ways it can be used with Suricata for threat hunting and investigation. To skip to the other blog posts in the series, click on one of the following links:
Before beginning, there are some tools you need to ensure you can follow along:
Before we look into the actual hunting example, we must understand three major Suricata hunting concepts. They are as follows:
One of the many powerful features of Suricata is that it can create protocol and transaction logs even in the absence of alerts. These logs include flow records, anomalies, alerts, protocol transactions, and file transaction logs, plus file extraction and packet capture (PCAP).
Here is a full list and details of what those logs and transactions look like.
You also might be interested in the many new things available in the recently released Suricata 7.
Suricata produces all relevant network security monitoring logs: protocol, flow, file transaction, and anomaly logs, including the ones related to an alert - but also independent of alerts. In the regular JSON logs that Suricata generates (eve.json), you will find something called “flow_id” that correlates the network protocol data and evidence that Suricata has logged - to an alert event and that alert’s metadata.
The ability to correlate any existing evidence/logs to an alert (“flow_id”) was introduced in 2014 by Suricata lead developer, Victor Julien
https://github.com/OISF/suricata/commit/f1185d051c210ca0daacdddbe865a51af24f4ea3
Suricata can match or highlight on specific simple events, occurrences, anomalies, patterns, or IoCs and also much more complex detection logic either via signature or a lua script – in flows/sessions or cross flows/sessions.
Regardless of what type of match is used we can insert a piece of metadata in all protocol transactions generated by Suricata. This way, multiple different labeling of varying flows can occur that can later be used for detection logic SIEM/DB queries, alerting, and/or automation.
In other words, by using NRD matching all the Suricata protocol records to and from NRD communication that are found in either DNS Query (“event_type”:”dns”), HTTP Hostname (“event_type”:”http”), and TLS SNI (“event_type”:”tls”) will have the flowbit/marker piece of metadata inserted in them as well as any and all corresponding “event_type”:”fileinfo”, “event_type”:”flow”, “event_type”:”anomaly” event logs from those sessions/flows.
Here is an example of a flow in Suricata JSON output:
The above picture has a flow or protocol record labeled (with “stamus.nrd.entropy”) as a Newly Registered Domain communication with high entropy from Stamus’s NRD daily updated lists.
There could even be multiple matches and labeling:
…
{
"flowbits": [
"FBMproto_0",
"stamus.nrd",
"ET.http.binary"
]
}
….
The above record has a flow or protocol record labeled (with “stamus.nrd”) as a Newly Registered Domain communication from Stamus’s NRD daily updated lists.
The visualization above is present in the SN-FLOW dashboard (based on Suricata “event_type”:”flow” log data) as part of free and Open Source
Dashboards are available in GitHub or as part of SELKS:
https://github.com/StamusNetworks/suricata-analytics/tree/main/kibana/7
Now that we have those 3 major points clarified, we can move on with our detection logic.
First, let's clarify what we mean by “detection” here. In this context, detection is simply marking and/or highlighting NRDs in the communication traffic. Then based on our hunting hypothesis we combine that knowledge with the protocol and alert information that Suricata produces. In some cases there could be no alerts, and that’s ok too.
One point that is important to keep in mind is that after the hunt is successful we should check if traces of such traffic or transactions happened in the past. For example, if we find any TLS certificates, file hashes, or domains, we could use Suricata protocol data to check if these occurred previously regardless of alerting.
We are basing this hunt on the hypothesis / idea that the example network traffic might contain traces of beaconing or command and control (C2) communication. Let’s take a closer look.
In this example we will use purely HTTP protocol transaction logging from Suricata.
For a regular Elasticsearch query based only on Suricata HTTP logs (not alerts) we can use the following command (based on “event_type”:”http” logs in Suricata):
event_type:http AND metadata.flowbits:*stamus.nrd*
Which basically says:
We have 3842 such transactions. Now let's break those down to get a better understanding of what type of communication those might represent.
For that purpose we will use one visualization called “SN-ThreatHunt-HTTP-PossibleC2Beacons-BySrcIP”.
This visualization is available in the SN-HTTP dashboard in SELKS. If you do not use SELKS then as long as you have Elasticsearch and Suricata, you can also simply import the freely available /open source dashboards from here. The repository provides 28 dashboards for the Kibana 7.x and Elasticsearch 7.x for use with Suricata IDS/IPS/NSM (Intrusion Detection, Intrusion Prevention, and Network Security Monitoring system).
What we can observe right away on that visualization is revealing by itself:
We have 3764 instances of what seems to be beacon-like communication during the infection from the Newly Registered Domain found in the http hostname. We also have a few (bottom 3 rows) larger transfers to the same IP - 10.10.10.113
That information by itself might be enough to trigger deeper investigation for that specific host.
Here is an actual Suricata HTTP log example containing a lot of information including the full http request/response header information and more:
{
"_index": "logstash-http-2023.10.13",
"_type": "_doc",
"_id": "N1MWSIsB7yuKuyCOuXaF",
"_version": 1,
"_score": 1,
"_source": {
"type": "SELKS",
"host": "2023-10-12-DarkGate-infection-traffic.pcap",
"pcap_cnt": 47000,
"proto": "TCP",
"geoip": {
"country_code2": "US",
"country_code3": "US",
"ip": "172.67.166.185",
"timezone": "America/Chicago",
"continent_code": "NA",
"location": {
"lon": -97.822,
"lat": 37.751
},
"longitude": -97.822,
"country_name": "United States",
"latitude": 37.751
},
"event_type": "http",
"dest_ip": "172.67.166.185",
"path": "/var/log/suricata/eve.json",
"pkt_src": "wire/pcap",
"flow_id": 309144673445905,
"src_port": 52276,
"src_ip": "10.10.10.113",
"community_id": "1:h/JlS42YpA47sHuIREzRgZFf6ao=",
"timestamp": "2023-10-13T00:47:37.780012+0000",
"dest_port": 80,
"metadata": {
"flowbits": [
"ET.DarkGate.1",
"stamus.nrd"
]
},
"tx_id": 0,
"http": {
"hostname": "hgfdytrywq.com",
"http_method": "POST",
"length": 2,
"request_headers": [
{
"name": "Connection",
"value": "keep-alive"
},
{
"name": "Content-Type",
"value": "Application/octet-stream"
},
{
"name": "Content-Length",
"value": "60"
}
],
"url": "/",
"response_headers": [
{
"name": "Date",
"value": "Fri, 13 Oct 2023 00:47:38 GMT"
},
{
"name": "Content-Type",
"value": "text/html; charset=ISO-8859-1"
},
{
"name": "Connection",
"value": "close"
},
{
"name": "Server",
"value": "cloudflare"
}
],
"http_content_type": "text/html",
"protocol": "HTTP/1.0",
"user_agent": {
"os_name": "Other",
"os": "Other",
"name": "Other",
"device": "Other",
"os_full": "Other"
},
"http_user_agent": "Mozilla/4.0 (compatible; Synapse)",
"status": 200
},
"@version": "1",
"@timestamp": "2023-10-13T00:47:37.780Z",
"tags": [
"_geoip_lookup_failure"
]
},
"fields": {
"geoip.country_code2.keyword": [
"US"
],
"http.response_headers.value.raw": [
"Fri, 13 Oct 2023 00:47:38 GMT",
"text/html; charset=ISO-8859-1",
"close",
"cloudflare"
],
"http.url": [
"/"
],
"http.response_headers.name": [
"Date",
"Content-Type",
"Connection",
"Server"
],
"type": [
"SELKS"
],
"proto.raw": [
"TCP"
],
"path": [
"/var/log/suricata/eve.json"
],
"event_type": [
"http"
],
"community_id.raw": [
"1:h/JlS42YpA47sHuIREzRgZFf6ao="
],
"http.user_agent.os_full.raw": [
"Other"
],
"http.protocol.keyword": [
"HTTP/1.0"
],
"EveBox": [
309144673445905
],
"geoip.country_name.raw": [
"United States"
],
"http.user_agent.os_name": [
"Other"
],
"tx_id": [
0
],
"http.request_headers.name.keyword": [
"Connection",
"Content-Type",
"Content-Length"
],
"http.length": [
2
],
"tags": [
"_geoip_lookup_failure"
],
"http.user_agent.device": [
"Other"
],
"http.hostname": [
"hgfdytrywq.com"
],
"metadata.flowbits.raw": [
"ET.DarkGate.1",
"stamus.nrd"
],
"http.user_agent.os_full": [
"Other"
],
"http.request_headers.value": [
"keep-alive",
"Application/octet-stream",
"60"
],
"dest_ip": [
"172.67.166.185"
],
"geoip.latitude": [
37.75
],
"http.http_user_agent.keyword": [
"Mozilla/4.0 (compatible; Synapse)"
],
"http.http_user_agent": [
"Mozilla/4.0 (compatible; Synapse)"
],
"geoip.timezone.raw": [
"America/Chicago"
],
"http.http_method": [
"POST"
],
"http.user_agent.name.raw": [
"Other"
],
"http.http_method.raw": [
"POST"
],
"tags.keyword": [
"_geoip_lookup_failure"
],
"http.request_headers.name.raw": [
"Connection",
"Content-Type",
"Content-Length"
],
"geoip.country_code3.raw": [
"US"
],
"http.hostname.keyword": [
"hgfdytrywq.com"
],
"geoip.ip": [
"172.67.166.185"
],
"http.http_method.keyword": [
"POST"
],
"http.http_user_agent.raw": [
"Mozilla/4.0 (compatible; Synapse)"
],
"geoip.country_name": [
"United States"
],
"http.request_headers.value.raw": [
"keep-alive",
"Application/octet-stream",
"60"
],
"path.raw": [
"/var/log/suricata/eve.json"
],
"timestamp": [
"2023-10-13T00:47:37.780Z"
],
"pcap_cnt": [
47000
],
"http.response_headers.name.raw": [
"Date",
"Content-Type",
"Connection",
"Server"
],
"http.http_content_type.raw": [
"text/html"
],
"pkt_src.raw": [
"wire/pcap"
],
"http.user_agent.os_name.raw": [
"Other"
],
"@timestamp": [
"2023-10-13T00:47:37.780Z"
],
"http.url.keyword": [
"/"
],
"path.keyword": [
"/var/log/suricata/eve.json"
],
"http.response_headers.value": [
"Fri, 13 Oct 2023 00:47:38 GMT",
"text/html; charset=ISO-8859-1",
"close",
"cloudflare"
],
"http.hostname.raw": [
"hgfdytrywq.com"
],
"metadata.flowbits": [
"ET.DarkGate.1",
"stamus.nrd"
],
"geoip.timezone": [
"America/Chicago"
],
"http.url.raw": [
"/"
],
"geoip.country_name.keyword": [
"United States"
],
"http.request_headers.value.keyword": [
"keep-alive",
"Application/octet-stream",
"60"
],
"http.user_agent.os.keyword": [
"Other"
],
"proto.keyword": [
"TCP"
],
"type.keyword": [
"SELKS"
],
"flow_id": [
309144673445905
],
"host": [
"2023-10-12-DarkGate-infection-traffic.pcap"
],
"http.user_agent.name": [
"Other"
],
"geoip.longitude": [
-97.8125
],
"host.keyword": [
"2023-10-12-DarkGate-infection-traffic.pcap"
],
"dest_port": [
80
],
"pkt_src": [
"wire/pcap"
],
"tags.raw": [
"_geoip_lookup_failure"
],
"geoip.continent_code.keyword": [
"NA"
],
"dest_ip.keyword": [
"172.67.166.185"
],
"pkt_src.keyword": [
"wire/pcap"
],
"geoip.continent_code.raw": [
"NA"
],
"proto": [
"TCP"
],
"FPC": [
"ip == 10.10.10.113 && port == 52276 && ip == 172.67.166.185 && port == 80 && protocols == tcp"
],
"http.user_agent.os": [
"Other"
],
"geoip.continent_code": [
"NA"
],
"geoip.country_code2.raw": [
"US"
],
"http.response_headers.value.keyword": [
"Fri, 13 Oct 2023 00:47:38 GMT",
"text/html; charset=ISO-8859-1",
"close",
"cloudflare"
],
"geoip.country_code3.keyword": [
"US"
],
"http.response_headers.name.keyword": [
"Date",
"Content-Type",
"Connection",
"Server"
],
"http.user_agent.name.keyword": [
"Other"
],
"event_type.keyword": [
"http"
],
"http.http_content_type": [
"text/html"
],
"http.user_agent.os_full.keyword": [
"Other"
],
"src_ip": [
"10.10.10.113"
],
"community_id": [
"1:h/JlS42YpA47sHuIREzRgZFf6ao="
],
"http.user_agent.os_name.keyword": [
"Other"
],
"geoip.country_code3": [
"US"
],
"geoip.location": [
{
"coordinates": [
-97.822,
37.751
],
"type": "Point"
}
],
"geoip.country_code2": [
"US"
],
"@version": [
"1"
],
"http.protocol.raw": [
"HTTP/1.0"
],
"src_ip.keyword": [
"10.10.10.113"
],
"host.raw": [
"2023-10-12-DarkGate-infection-traffic.pcap"
],
"community_id.keyword": [
"1:h/JlS42YpA47sHuIREzRgZFf6ao="
],
"metadata.flowbits.keyword": [
"ET.DarkGate.1",
"stamus.nrd"
],
"http.request_headers.name": [
"Connection",
"Content-Type",
"Content-Length"
],
"http.user_agent.device.keyword": [
"Other"
],
"type.raw": [
"SELKS"
],
"http.protocol": [
"HTTP/1.0"
],
"dest_ip.raw": [
"172.67.166.185"
],
"src_port": [
52276
],
"http.user_agent.os.raw": [
"Other"
],
"src_ip.raw": [
"10.10.10.113"
],
"event_type.raw": [
"http"
],
"http.http_content_type.keyword": [
"text/html"
],
"http.user_agent.device.raw": [
"Other"
],
"http.status": [
200
],
"geoip.timezone.keyword": [
"America/Chicago"
]
}
}
Let's discuss how and why exactly the visualization is so useful.
If you look below, you can see the actual visualization creation config. I basically break the HTTP logs produced by Suricata – “event_type”:”http” – into 3 buckets based on the newly registered domains flow labeling:
event_type:http AND metadata.flowbits:*stamus.nrd*
Which gives us 3 groups for easy viewing:
Some people might still consider Suricata a “legacy” intrusion detection system (IDS), but the data produced by Surcata speaks for itself. It is not only a highly capable IDS but has evolved into an impressive tool for gathering NSM data and full protocol, file transaction, flow, and anomaly logs along with file extraction and PCAP logging. And as we’ve shown at Stamus Networks, Suricata is in fact a powerful foundation on which to build a world-class network detection and response (NDR) system.
We hope this article helps to dispel some of these misconceptions and can help users see the many ways to use and optimize Suricata beyond the basic alerts and signatures.
Further reading on this topic can be found in our free book, “Suricata for Analysts.”” the world’s first practical guide to threat detection and hunting using Suricata.
To read part 4 of this series, please visit this link.
Please make sure you check out our free and Open Source contributions to Suricata on our Stamus Labs page.
If you wish to be notified when we publish similar content, please subscribe to the Stamus Networks blog.
Finally, to receive near-real time updates, follow us on Twitter, LinkedIn, and Facebook, or join our Discord.