Network Hunting with zeek & wireshak

Scenario :

The IT Security manager has now tasked you, the only Threat hunter, with hunting for suspicious connections and communications inside the provided PCAP files. Long connections, beaconing activity, abnormal DNS traffic and overly high/low traffic are all considered suspicious.

Hunt for long connections

wireshark sample-200.pcap

click "Statistics" and then "Conversations". Click on the "TCP" tab and sort the results by duration (longest duration first).

From the image above, the longest connection was from 10.55.100.100 to 65.52.108.225 on port 443, which lasted for 86222 seconds (23.95 hours).

Let's switch to the UDP tab and observe that Although it is hard to define a connection 'state' with UDP, some appliances set a time frame of 30 or 60 seconds, where if source and destination IP and Port values are the same, they will be flagged as if they are in the same session. Once switched to the UDP tab, sort again by duration:

Here, the connection with the longest duration is from 192.168.88.2 to 216.229.4.69 on port 123 (NTP). The duration was 86217 seconds (23.95 hours).

An anomaly can be spotted above. The second row shows that although there were only 6 packets ever, the connection lasted for 86209 seconds. Or in other words, each packet's duration was 14383 seconds (nearly 4 hours), which in the UDP world is not a possibility. This tells us that Wireshark's analytics is based on the entire time window of the PCAP file and is not tracking the time between each packet (to have been up to 60 seconds before it assumes the connection was over).

Next, let's analyze the file in Zeek. The zeek logs are located at "/root/Desktop/zeek". To analyze the files, we'll use the "cat" command to read the file and pipe it through "zeek-cut" to extract only certain columns. Those are the original IP and port, the destination IP and port, the protocol used, the service type and finally the duration. Once those fields are extracted, we will use the sort command to sort based on the duration field (which is column 7 after the cut). Finally, we will display top 10 results

cat conn.log | zeek-cut id.orig_h id.orig_p id.resp_h id.resp_p proto service duration | sort -nrk 7 | head -n 10

Another thing to note is that the file conn.log, from which we read the packets, contains all packets captured in TCP, UDP and ICMP. Therefore, to view UDP packets only:

cat conn.log | zeek-cut id.orig_h id.orig_p id.resp_h id.resp_p proto service duration | grep udp | sort -nrk 7 | head -n 10

If you look closely, this output does not match what we saw from Wireshark. The reason for this is because Zeek is actively using a 60 seconds timeout, thus if 2 consecutive UDP connections (from and to the same IP/Port) were to occur with 61 seconds or more time difference, they will not be considered to be within the same "UDP session".

One way that malware can avoid our detection is through multiple short-lived connections (or beaconing as we will see in the next task). To take that into account, we can further extend our "query" by summing up the total duration time for connections that have the same destination IP and Port.

cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p proto duration | awk 'BEGIN{ FS="\t" } { arr[$1 FS $2 FS $3 FS $4] += $5 } END{ for (key in arr) printf "%s%s%s\n", key, FS, arr[key] }' | sort -nrk 5 | head -n 10

Note from the above that now we have a new connection from 10.55.100.111 to 172.217.8.198 on port 443 that we had not seen previously.

let's modify our command to find out how many connections (regardless of the protocol used) in total have contributed to get the sum of duration time

cat conn.log | zeek-cut id.orig_h id.resp_h duration | awk 'BEGIN{ FS="\t" } { arr[$1 FS $2] += $3; count[$1 FS $2] += 1 } END{ for (key in arr) printf "%s%s%s%s%s\n", key, FS, count[key], FS, arr[key] }' | sort -nrk 4 | head -n 10

Hunt for beacons

Let's begin with Wireshark again. Open the pcap file and filter for the IP addresses mentioned in the task description,

Let's see exactly how much is the time difference between those packets. To do that, right click on any of the column names (eg. Protocol) and then click "Column Preferences...". Modify the settings to match the following configuration:

you'll see the time delta as a new column:

Again, it seems that each communication was 1 second apart.

tshark -r sample-200.pcap -T fields -e ip.src -e ip.dst -e udp.dstport -e frame.time_delta_displayed 'ip.src==192.168.88.2 && ip.dst==165.227.88.15' | head -10

We see similar output as what Wireshark had reported, again 1 second between packets.

Hunt for suspicious DNS traffic

we'll begin by looking at Zeek logs, specifically the log file "dns.log" and focus on subdomain frequency analysis. The "dns.log" file provides a range of details for each DNS connection, many of which are not directly relevant to us. Therefore, we'll filter for the originating IP, the DNS query, the type of DNS record and the answer. We can do that with the following command:

cat dns.log | zeek-cut -c id.orig_h query qtype_name answers

we already spot a large number of random-looking sub domains.

Let's parse the file and find out how many unique connections

cat dns.log | zeek-cut query | sort | uniq | rev | cut -d '.' -f 1-2 | rev | sort | uniq -c | sort -nr | head -n 10

We can see that a significantly large amount of connections to unique subdomains were performed towards r-1x.com.

cat dns.log | zeek-cut id.orig_h query | grep 'r-1x\.com' | cut -f 1 | sort | uniq -c

This is not ideal for us since it doesn't tell us which was the action machine that initiated the requests. Let's check if any of the answers contain an IP Address in it. We can do that by running:

cat dns.log | zeek-cut query answers | grep 'r-1x\.com' | cut -f 2 | cut -d ' ' -f 3 | egrep '([0-9]{0,3}\.)[0-9]{0,3}' | sort | uniq

We did get a match. Let's see if any internal machines were connecting to that IP address directly

cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p proto service | grep '165.227.88.15' | sort | uniq -c

We do see ICMP and TCP traffic as well.

Another point of interest when doing DNS hunting is to look at the type of records which are being prevalent in the environment

cat dns.log | zeek-cut qtype_name | sort | uniq -c | sort -nr

Note the large number of TXT record queries.

let's perform similar hunt with Tshark to extract the total number of connections to domains based on the unique number of subdomains.

tshark -r sample-200.pcap -T fields -e dns.qry.name udp.dstport==53 | sort | uniq | rev | cut -d '.' -f 1-2 | rev | sort | uniq -c | sort -nr | head -n 10

The result is similar to what we had already observed with Zeek.

let's look at it in Wireshark. Open the PCAP file, and then go to "Statsistics" -> "DNS". If we sort by Count

The reason why numbers here do not match with those from our Zeek commands is because Wireshark does not remove duplicates, while previously we filtered for unique values

Hunt for systems abnormal high or low traffic

cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p proto | awk 'BEGIN{ FS="\t" } { arr[$1 FS $2 FS $3 FS $4] += 1 } END{ for (key in arr) printf "%s%s%s\n", key, FS, arr[key] }' | sort -nrk 5 | head -n 10

We can see that there is a large number of DNS connections from 192.168.88.2 to 165.227.88.15. If we divide the number by 86400 seconds (24 hours, the timespan of capture as indicated in the task), we get than more than 1 connection per second was sent. This is suspicious because DNS gets cached and reused by the local DNS resolver and the operating system's local DNS cache. What also stands out is that the IP address 165.227.88.15 is not an address of a known DNS server.

let's look at the total amount of data transferred.

cat conn.log | zeek-cut id.orig_h id.resp_h orig_bytes | awk 'BEGIN{ FS="\t" } { arr[$1 FS $2] += $3 } END{ for (key in arr) printf "%s%s%s\n", key, FS, arr[key] }' | sort -nrk 3 | head -n 10

We can adjust our command to see the total amount of data sent in both

cat conn.log | zeek-cut id.orig_h id.resp_h orig_bytes resp_bytes | awk 'BEGIN{ FS="\t" } { arr[$1 FS $2] += $3+$4 } END{ for (key in arr) printf "%s%s%s\n", key, FS, arr[key] }' | sort -nrk 3 | head -n 10

we'll look at User Agents

cat http.log | zeek-cut user_agent | sort | uniq -c | sort -n | head -n 10

Last updated