Tools · Network tools · 15 / 24
Zeek: what a defender reads in dns.log
dns.log records the name, the type, the response code, and the answers. A defender compares answers to the runbook, watches for a resolver that should not be answering, and treats a burst of strange names from one host as a question about that host.
One DNS message, one row
Each row has the uid of the UDP or TCP connection that carried it, the originator, the query, qtype_name, rcode_name, and answers. qtype_name is A, AAAA, PTR, MX, TXT, or another type. rcode_name is NOERROR, NXDOMAIN, SERVFAIL, and the other DNS results. answers is the set of records in the reply. A dash means Zeek did not have that value, which is normal on a query row before the reply is logged, depending on how the message was seen.
The uid matches a conn.log row whose service is dns and whose responder port is usually 53. One connection can carry more than one query. When you need the bytes, you already know which uid to pull. When you need the name, stay in dns.log.
What is worth a ticket
Compare answers for the lab's own names with the runbook. files.lab.internal answering 10.8.0.77 when the runbook says 10.8.0.40 is a record change, and it explains a later conn.log row to the unexpected address. A reply whose id.resp_h is not the lab resolver is a different ticket: this host accepted DNS from somewhere else.
NXDOMAIN for a name the lab applications use is a broken record. A long run of NXDOMAIN, or query names far longer than the lab's names, from a single originator, is a reason to ask who was on that host and to keep the log. You record the names, the type, the code, and the time. You do not need to interpret the name as a channel, and you do not need any tool beyond the log to escalate the host for review.
- A and AAAA answers are addresses. PTR answers are names for an address.
- TXT on a lab that never uses TXT is a lead, confirmed with the owner.
- query plus answers plus rcode_name is the whole useful triple.
- Filter by id.orig_h when the ticket names one workstation.
A worked defensive case
dns.log shows 10.8.0.20 asking the lab resolver 10.8.0.53 for files.lab.internal, type A, rcode NOERROR, answer 10.8.0.77. The same minute shows 10.8.0.27 asking 10.8.0.53 for a series of lab names that do exist, all NOERROR, answers inside 10.8.0.0/24. One workstation, 10.8.0.31, asks for hundreds of names the lab has never registered, mostly NXDOMAIN, in a short window.
You file the files.lab.internal answer as the wrong-address defect. You file 10.8.0.31 as a host to review with its owner, with the time window and a count of NXDOMAIN, not a paste of every name into chat. The ordinary lookups from 10.8.0.27 stay out of the incident.
Where this is documented
DNS::Info defines query, qtype_name, rcode_name, answers, and uid. Zeek's dns.log write-up shows how the uid ties a DNS row to conn.log.
Use a host-only lab network, or a capture the owner already handed you. These commands read that file or record a single lab host. They are not a scan of the public internet.
Commands
zeek-cut -m ts uid id.orig_h id.resp_h query qtype_name rcode_name answers < /lab/zeek/dns.log
jq -c 'select(.["id.orig_h"] == "10.8.0.31" and .rcode_name == "NXDOMAIN") | {ts, query, qtype_name}' /lab/zeek-json/dns.logDiagram
Three DNS patterns and the note each earns
Same log, different tickets
- Wrong answer
A lab name returns an address the runbook does not list. Fix the record. Point the TCP review at the address that was actually returned.
- Unexpected resolver
Replies arrive from an address that is not the lab resolver. The host accepted DNS from somewhere else.
- Burst of unknown names
One originator asks for many names the lab does not have. Review that host with the owner. Keep the count, the window, and the log.
Check yourself
1. files.lab.internal has qtype_name A, rcode_name NOERROR, and answers 10.8.0.77. The runbook says 10.8.0.40. What do you do next?
2. id.resp_h on a workstation's DNS rows is 10.8.0.99. The only lab resolver is 10.8.0.53. What is the observation?
3. 10.8.0.31 produces hundreds of NXDOMAIN rows in a minute for names the lab does not use. What belongs in the escalation?