dhcp.log

Dynamic Host Configuration Protocol is a core protocol found in Internet Protocol (IP) networks. Using the protocol, DHCP servers provide clients with IP addresses and other key information needed to make use of the network. This entry will describe some aspects of Zeek’s dhcp.log that may be of use to network and security personnel.

As with all entries in this document, for full explanation of each field in the log, see DHCP::Info.

DORA via Tcpdump

The method by which a client requests and receives an IP address and other parameters from a DHCP server is represented by the acronym DORA. DORA stands for Discover - Offer - Request - Acknowledge. The following tcpdump output of a complete DORA exchange demonstrates this protocol in action.

$ tcpdump -n -r snort.log.1601610971.bootp.pcap
reading from file snort.log.1601610971.bootp.pcap, link-type EN10MB (Ethernet)

04:14:39.119370 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:58:c2:2f:91:21, length 302
04:14:39.120138 IP 192.168.4.1.67 > 192.168.4.152.68: BOOTP/DHCP, Reply, length 302
04:14:39.158211 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 3c:58:c2:2f:91:21, length 337
04:14:39.456915 IP 192.168.4.1.67 > 192.168.4.152.68: BOOTP/DHCP, Reply, length 302

The default output for tcpdump doesn’t say much, other than showing the IP addresses (or lack thereof, in the case of the 0.0.0.0` source IP addresses). It is helpful to see this “simplified” output, however, before delving into the details. It is slightly deceptive in the “request” and “reply” messages, as strictly speaking these are more detailed and are DORA messages.

DORA via Tcpdump Verbose Mode

We can add the -vvv flag to tcpdump to provide more verbose output, as shown in the examples that follow.

The first datagram shows that a host that does not have an IP address set (i.e., it’s using 0.0.0.0) sends a broadcast to 255.255.255.255 on port 67 UDP. This client has had an IP address before as shown by its request for 192.168.4.152. Note the hostname and the presence of a Microsoft 5.0 vendor class.

This is a DHCP Discover message from a client to any DHCP server listening on the local network:

04:14:39.119370 IP (tos 0x0, ttl 128, id 44414, offset 0, flags [none], proto UDP (17), length 330)
    0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from 3c:58:c2:2f:91:21, length 302, xid 0xfd9859a7, Flags [none] (0x0000)
          Client-Ethernet-Address 3c:58:c2:2f:91:21
          Vendor-rfc1048 Extensions
            Magic Cookie 0x63825363
            DHCP-Message Option 53, length 1: Discover
            Client-ID Option 61, length 7: ether 3c:58:c2:2f:91:21
            Requested-IP Option 50, length 4: 192.168.4.152
            Hostname Option 12, length 15: "3071N0098017422"
            Vendor-Class Option 60, length 8: "MSFT 5.0"
            Parameter-Request Option 55, length 14:
              Subnet-Mask, Default-Gateway, Domain-Name-Server, Domain-Name
              Router-Discovery, Static-Route, Vendor-Option, Netbios-Name-Server
              Netbios-Node, Netbios-Scope, Option 119, Classless-Static-Route
              Classless-Static-Route-Microsoft, Option 252
            END Option 255, length 0

The second datagram is a reply from the local DHCP server running on 192.168.4.1. The server replies directly to 192.168.4.152, which in this case will end up at the system using MAC address 3c:58:c2:2f:91:21, such that the destination IP address is probably not relevant here. Remember that if the client at MAC address 3c:58:c2:2f:91:21 had no IP address to begin with, it would only receive the DHCP offer by virtue of the DHCP offer datagram being addressed to its MAC address. The server is not offering a specified domain name other than “localdomain.”

This is a DHCP Offer message, from the DHCP server to the client:

04:14:39.120138 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 330)
    192.168.4.1.67 > 192.168.4.152.68: [udp sum ok] BOOTP/DHCP, Reply, length 302, xid 0xfd9859a7, Flags [none] (0x0000)
          Your-IP 192.168.4.152
          Client-Ethernet-Address 3c:58:c2:2f:91:21
          Vendor-rfc1048 Extensions
            Magic Cookie 0x63825363
            DHCP-Message Option 53, length 1: Offer
            Server-ID Option 54, length 4: 192.168.4.1
            Lease-Time Option 51, length 4: 86400
            Subnet-Mask Option 1, length 4: 255.255.255.0
            Default-Gateway Option 3, length 4: 192.168.4.1
            Domain-Name-Server Option 6, length 4: 192.168.4.1
            Domain-Name Option 15, length 11: "localdomain"
            T119 Option 119, length 13: 11.108.111.99.97.108.100.111.109.97.105.110.0
            END Option 255, length 0

The third datagram is a reply to the server’s reply. Here the client requests the IP address 192.168.4.152. We also see it provide a fully qualified domain name (FQDN) for itself, belonging to the FCPS educational domain. Again note the client does not include an IP address for itself in the layer 3 header. It uses 0.0.0.0 as in the initial Discover message.

This is a DHCP Request message from the client to the DHCP server:

04:14:39.158211 IP (tos 0x0, ttl 128, id 44415, offset 0, flags [none], proto UDP (17), length 365)
    0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from 3c:58:c2:2f:91:21, length 337, xid 0xfd9859a7, Flags [none] (0x0000)
          Client-Ethernet-Address 3c:58:c2:2f:91:21
          Vendor-rfc1048 Extensions
            Magic Cookie 0x63825363
            DHCP-Message Option 53, length 1: Request
            Client-ID Option 61, length 7: ether 3c:58:c2:2f:91:21
            Requested-IP Option 50, length 4: 192.168.4.152
            Server-ID Option 54, length 4: 192.168.4.1
            Hostname Option 12, length 15: "3071N0098017422"
            FQDN Option 81, length 27: "3071N0098017422.fcps.edu"
            Vendor-Class Option 60, length 8: "MSFT 5.0"
            Parameter-Request Option 55, length 14:
              Subnet-Mask, Default-Gateway, Domain-Name-Server, Domain-Name
              Router-Discovery, Static-Route, Vendor-Option, Netbios-Name-Server
              Netbios-Node, Netbios-Scope, Option 119, Classless-Static-Route
              Classless-Static-Route-Microsoft, Option 252
            END Option 255, length 0

Finally the server sends its last message, essentially confirming the information sent in the DHCP Offer message. Note that tcpdump is unable to make sense of what it renders as T119 Option 119. We will return to that shortly.

This is a DHCP Acknowledgement message, sent from the DHCP server to the client:

04:14:39.456915 IP (tos 0x10, ttl 128, id 0, offset 0, flags [none], proto UDP (17), length 330)
    192.168.4.1.67 > 192.168.4.152.68: [udp sum ok] BOOTP/DHCP, Reply, length 302, xid 0xfd9859a7, Flags [none] (0x0000)
          Your-IP 192.168.4.152
          Client-Ethernet-Address 3c:58:c2:2f:91:21
          Vendor-rfc1048 Extensions
            Magic Cookie 0x63825363
            DHCP-Message Option 53, length 1: ACK
            Server-ID Option 54, length 4: 192.168.4.1
            Lease-Time Option 51, length 4: 86400
            Subnet-Mask Option 1, length 4: 255.255.255.0
            Default-Gateway Option 3, length 4: 192.168.4.1
            Domain-Name-Server Option 6, length 4: 192.168.4.1
            Domain-Name Option 15, length 11: "localdomain"
            T119 Option 119, length 13: 11.108.111.99.97.108.100.111.109.97.105.110.0
            END Option 255, length 0

Acknowledgement via tshark

We could look at the entire trace using tshark (the command line version of Wireshark), but it would largely be redundant. Rather, I would like to look at the Acknowledgment message to explain about the T119 Option that tcpdump could not decode.

To find the datagram of interest, I tell tshark to read the packet capture of interest. I tell it to look for the “bootp” transaction identifier associated with the DORA exchange of interest. (BOOTP refers to Bootstrap, a precursor protocol that Tshark still uses for DHCP filters.) I also tell tshark to look for the specific BOOTP (DHCP) option value (5) associated with the ACK message.

$ tshark -V -n -r snort.log.1601610971.bootp.pcap bootp.id == 0xfd9859a7 and bootp.option.dhcp == 5
Frame 4: 344 bytes on wire (2752 bits), 344 bytes captured (2752 bits) on interface 0
    Interface id: 0 (unknown)
        Interface name: unknown
    Encapsulation type: Ethernet (1)
    Arrival Time: Oct  2, 2020 04:14:39.456915000 UTC
    [Time shift for this packet: 0.000000000 seconds]
    Epoch Time: 1601612079.456915000 seconds
    [Time delta from previous captured frame: 0.298704000 seconds]
    [Time delta from previous displayed frame: 0.000000000 seconds]
    [Time since reference or first frame: 0.337545000 seconds]
    Frame Number: 4
    Frame Length: 344 bytes (2752 bits)
    Capture Length: 344 bytes (2752 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ip:udp:bootp]
Ethernet II, Src: fc:ec:da:49:e0:10, Dst: 3c:58:c2:2f:91:21
    Destination: 3c:58:c2:2f:91:21
        Address: 3c:58:c2:2f:91:21
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Source: fc:ec:da:49:e0:10
        Address: fc:ec:da:49:e0:10
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.4.1, Dst: 192.168.4.152
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x10 (DSCP: Unknown, ECN: Not-ECT)
        0001 00.. = Differentiated Services Codepoint: Unknown (4)
        .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
    Total Length: 330
    Identification: 0x0000 (0)
    Flags: 0x0000
        0... .... .... .... = Reserved bit: Not set
        .0.. .... .... .... = Don't fragment: Not set
        ..0. .... .... .... = More fragments: Not set
        ...0 0000 0000 0000 = Fragment offset: 0
    Time to live: 128
    Protocol: UDP (17)
    Header checksum: 0xafa9 [validation disabled]
    [Header checksum status: Unverified]
    Source: 192.168.4.1
    Destination: 192.168.4.152
User Datagram Protocol, Src Port: 67, Dst Port: 68
    Source Port: 67
    Destination Port: 68
    Length: 310
    Checksum: 0x92db [unverified]
    [Checksum Status: Unverified]
    [Stream index: 1]
Bootstrap Protocol (ACK)
    Message type: Boot Reply (2)
    Hardware type: Ethernet (0x01)
    Hardware address length: 6
    Hops: 0
    Transaction ID: 0xfd9859a7
    Seconds elapsed: 0
    Bootp flags: 0x0000 (Unicast)
        0... .... .... .... = Broadcast flag: Unicast
        .000 0000 0000 0000 = Reserved flags: 0x0000
    Client IP address: 0.0.0.0
    Your (client) IP address: 192.168.4.152
    Next server IP address: 0.0.0.0
    Relay agent IP address: 0.0.0.0
    Client MAC address: 3c:58:c2:2f:91:21
    Client hardware address padding: 00000000000000000000
    Server host name not given
    Boot file name not given
    Magic cookie: DHCP
    Option: (53) DHCP Message Type (ACK)
        Length: 1
        DHCP: ACK (5)
    Option: (54) DHCP Server Identifier
        Length: 4
        DHCP Server Identifier: 192.168.4.1
    Option: (51) IP Address Lease Time
        Length: 4
        IP Address Lease Time: (86400s) 1 day
    Option: (1) Subnet Mask
        Length: 4
        Subnet Mask: 255.255.255.0
    Option: (3) Router
        Length: 4
        Router: 192.168.4.1
    Option: (6) Domain Name Server
        Length: 4
        Domain Name Server: 192.168.4.1
    Option: (15) Domain Name
        Length: 11
        Domain Name: localdomain
    Option: (119) Domain Search
        Length: 13
        FQDN: localdomain
    Option: (255) End
        Option End: 255

This output looks similar to what tcpdump reported, except here we can see the decode for Option 119. It looks like the DHCP server is providing the FQDN of “localdomain.”

Zeek’s Rendition of DORA

With this background, let’s look at Zeek’s depiction of this DHCP exchange.

{
  "ts": "2020-10-02T04:14:39.135304Z",
  "uids": [
    "COoA8M1gbTowuPlVT",
    "CapFoX32zVg3R6TATc"
  ],
  "client_addr": "192.168.4.152",
  "server_addr": "192.168.4.1",
  "mac": "3c:58:c2:2f:91:21",
  "host_name": "3071N0098017422",
  "client_fqdn": "3071N0098017422.fcps.edu",
  "domain": "localdomain",
  "requested_addr": "192.168.4.152",
  "assigned_addr": "192.168.4.152",
  "lease_time": 86400,
  "msg_types": [
    "DISCOVER",
    "OFFER",
    "REQUEST",
    "ACK"
  ],
  "duration": 0.416348934173584
}

As you can see, Zeek has taken the important elements from all four DORA messages and produced a single log entry. Every field is interesting, so I did not highlight them all.

Two UIDs

You might be wondering why there are two UID fields for this single DHCP exchange. Let’s look at the two corresponding conn.log entries.

The first one shows a “conversation” between 0.0.0.0 and 255.255.255.0. This represents the DHCP Discover message, caused by a client not knowing its source IP address, sending its search to the local network for a DHCP server.

{
  "ts": "2020-10-02T04:14:14.443346Z",
  "uid": "COoA8M1gbTowuPlVT",
  "id.orig_h": "0.0.0.0",
  "id.orig_p": 68,
  "id.resp_h": "255.255.255.255",
  "id.resp_p": 67,
  "proto": "udp",
  "service": "dhcp",
  "duration": 63.16645097732544,
  "orig_bytes": 1211,
  "resp_bytes": 0,
  "conn_state": "S0",
  "local_orig": false,
  "local_resp": false,
  "missed_bytes": 0,
  "history": "D",
  "orig_pkts": 4,
  "orig_ip_bytes": 1323,
  "resp_pkts": 0,
  "resp_ip_bytes": 0,
  "sensorname": "so16-enp0s8"
}

Notice that Zeek has tracked 4 “orig packets” here, which does not strictly correspond to the 2 datagrams from 0.0.0.0 to 255.255.255.255. Remember the DORA via tcpdump output?

It’s possible Zeek included other packets involving 0.0.0.0 and 255.255.255.255 when it created this log entry since this is a broadcast and Zeek generally may trouble with that because it doesn’t fit the “connection” abstraction.

The second message shows a conversation between 192.168.4.152, the DHCP client, and 192.168.4.1, the DHCP server.

{
  "ts": "2020-10-02T04:14:39.120138Z",
  "uid": "CapFoX32zVg3R6TATc",
  "id.orig_h": "192.168.4.152",
  "id.orig_p": 68,
  "id.resp_h": "192.168.4.1",
  "id.resp_p": 67,
  "proto": "udp",
  "service": "dhcp",
  "duration": 0.3367769718170166,
  "orig_bytes": 0,
  "resp_bytes": 604,
  "conn_state": "SHR",
  "local_orig": true,
  "local_resp": true,
  "missed_bytes": 0,
  "history": "^d",
  "orig_pkts": 0,
  "orig_ip_bytes": 0,
  "resp_pkts": 2,
  "resp_ip_bytes": 660,
  "sensorname": "so16-enp0s8"
}

Here the count of 2 resp_pkts is correct.

Enumerating DHCP Servers

Analysts can use Zeek’s dhcp.log to enumerate systems providing DHCP services. Consider the output of the following query.

$ find . -name "dhcp**.gz" | while read -r file; do zcat -f "$file"; done | jq -c '[."server_addr"]' | sort | uniq -c | sort -nr | head -10
1337 [null]
 119 ["192.168.4.1"]

Here we see that 192.168.4.1 is providing DHCP services on this network. The null entries refer to DHCP log entries that do not have a server_addr field. One example is Zeek’s log for this DHCP Discover message:

{
  "ts": "2020-10-06T23:59:48.577749Z",
  "uids": [
    "CctZMx18mIK1qj9Vci"
  ],
  "mac": "80:ee:73:52:eb:59",
  "host_name": "ds61",
  "msg_types": [
    "DISCOVER"
  ],
  "duration": 0
}

This log entry does not have a server_addr field, so the query above returns a null result.

Conclusion

DHCP is crucial to the proper operation of any IP network. DHCP logs help analysts map IP addresses to MAC addresses, and may also reveal hostnames. When investigating suspicious or malicious activity, analysts need to know what system was assigned what IP address, as DHCP leases expire. However, depending on the network, systems may retain specific IP addresses for a long time as they may request an old address as was seen in this example. Of course, administrators who have configured DHCP to provide fixed IP addresses based on MAC address will ensure that these machines receive the same IP address, despite relying on the “dynamic” nature of DHCP.