HackBlue

Tools · Network tools · 13 / 24

Zeek: turn a lab pcap into logs

Zeek reads a capture and writes one log per protocol instead of one line per frame. conn.log, dns.log, and http.log are the three a defender opens first. The uid column is how those files point at the same connection.

15 min read · practice only with authorization

What the command writes

zeek -r /lab/evidence.pcap local reads the lab file and writes logs in the current directory. Run it inside a case folder you created for this ticket, not in a home directory full of unrelated files. -C tells Zeek to ignore checksums. Lab captures often fail checksum validation because the NIC offloaded them. Without -C, Zeek can skip those frames and the logs look quieter than the pcap.

On a normal install, local is the default policy: the base protocol analyzers plus whatever the site added. A sensor's local.zeek may be stricter or noisier than a fresh lab VM. Say which machine ran Zeek when you file the logs. The pcap is unchanged. Zeek does not edit evidence.

  • conn.log is every connection Zeek grouped, TCP, UDP, or ICMP.
  • dns.log is one row per DNS message Zeek parsed.
  • http.log is one row per cleartext HTTP request.
  • ssl.log is handshake metadata for TLS. The application bytes are not a transcript.

Tab-separated by default, JSON when you ask

The default log is tab-separated, with a #fields header that names the columns. Lines starting with # are metadata. zeek-cut strips that metadata and prints selected columns. -m keeps a header on the cut. zeek-cut does not understand JSON.

LogAscii::use_json=T switches the same logs to one JSON object per line. Then jq is the reader. Pick one format per case folder so nobody runs zeek-cut on JSON and reports that the logs were empty.

A worked defensive case

The files-VM pcap is already in the case. You create /lab/zeek, run Zeek with -C, and confirm conn.log, dns.log, and http.log exist. http.log is empty, which matches the tshark result that port 443 had no cleartext HTTP. conn.log has the 10.8.0.20 to 10.8.0.40 session. dns.log has the files.lab.internal lookup.

You keep the logs next to the pcap and write the Zeek version in the ticket. Empty http.log is a finding about the capture, not a broken install. The next hour is spent in conn.log and dns.log, not in recapturing.

Where this is documented

Zeek's log tutorial documents the TSV format, zeek-cut, and LogAscii::use_json. The -C flag is the command-line switch for ignoring checksums. Protocol logs and their record types are in the Zeek script reference.

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

Write default logs from the lab pcap into a case folder
mkdir -p /lab/zeek && cd /lab/zeek && zeek -C -r /lab/evidence.pcap local
Same run as JSON, in its own folder so zeek-cut is not pointed at it
mkdir -p /lab/zeek-json && cd /lab/zeek-json && zeek -C -r /lab/evidence.pcap local LogAscii::use_json=T

Diagram

From one pcap to logs you can join

  1. Folder

    A case directory keeps this run away from other tickets.

  2. Read

    zeek -C -r reads the file and does not rewrite it.

  3. Logs

    conn.log, dns.log, and http.log land in that directory.

  4. Next

    zeek-cut or jq answers a question. Empty http.log is itself an answer.

Check yourself

1. Where does Zeek write conn.log when you run the command in /lab/zeek?

2. Every TCP checksum in the lab pcap is wrong, and the NIC was doing checksum offload. Which flag keeps those frames in the logs?

3. You set LogAscii::use_json=T and then run zeek-cut on conn.log. What went wrong?