Enumerating Local Services via mDNS PCAP Multicast Record Analysis and Host Fingerprinting
Theory
Why This Matters
mDNS is the zero-configuration naming protocol used by Apple Bonjour, Avahi on Linux, and Windows mDNS to make devices discoverable on local networks without a DNS server. In CTF challenges and real-world investigations, mDNS traffic in a PCAP reveals the complete local network topology: device hostnames, service types, IP addresses, and metadata encoded in TXT records — all broadcast in cleartext. Attackers and penetration testers use mDNS enumeration (via tools like avahi-browse or Responder) to identify high-value targets before any active scanning. Forensic analysts use the same traffic to reconstruct what devices were present and what services they advertised.
Core Concept
mDNS operates on UDP port 5353 to the multicast address 224.0.0.251 (IPv4) or ff02::fb (IPv6). It uses the standard DNS message format but with link-local multicast instead of unicast to a DNS server. A device can resolve hostnames and discover services without any infrastructure.
DNS-SD (DNS Service Discovery) rides on top of mDNS to advertise and discover services. The discovery process uses three record types:
- PTR records: map service type to instance name. E.g.,
_http._tcp.local PTR MyWebServer._http._tcp.local. A PTR query to_services._dns-sd._udp.localreturns all advertised service types. - SRV records: map service instance to hostname and port. E.g.,
MyWebServer._http._tcp.local SRV 0 0 80 mydevice.local. - TXT records: carry key=value metadata for the service instance. E.g.,
path=/index.html,version=1.0,admin=true.
From mDNS traffic alone, an analyst can enumerate: device hostnames (A/AAAA records), IP addresses, service types running on each device, port numbers, and service-specific metadata in TXT records.
Technical Deep-Dive
# Display all mDNS traffic from a PCAP
tshark -r capture.pcap -Y "mdns"
-T fields
-e frame.number -e frame.time_relative
-e ip.src -e dns.qry.name -e dns.resp.name
-e dns.ptr.domain_name -e dns.srv.name
-e dns.a -e dns.txt
-E header=y
# Filter mDNS to multicast destination only (announcements)
tshark -r capture.pcap
-Y "udp.dstport == 5353 and ip.dst == 224.0.0.251"
-T fields
-e frame.time_relative -e ip.src
-e dns.resp.type -e dns.resp.name -e dns.a
-e dns.ptr.domain_name -e dns.srv.target
-E header=y
# Extract all PTR records (service type → instance name mappings)
tshark -r capture.pcap -Y "mdns and dns.ptr.domain_name"
-T fields -e ip.src -e dns.resp.name -e dns.ptr.domain_name
| sort -u
# Extract all SRV records (instance → host + port)
tshark -r capture.pcap -Y "mdns and dns.srv.target"
-T fields
-e ip.src -e dns.resp.name
-e dns.srv.target -e dns.srv.port
| sort -u
# Extract TXT record key=value metadata
tshark -r capture.pcap -Y "mdns and dns.txt"
-T fields -e ip.src -e dns.resp.name -e dns.txt
| sort -u
#!/usr/bin/env python3
"""
Parse mDNS PCAP and build a per-host service inventory.
Requires: pip install scapy
"""
from scapy.all import rdpcap, DNS, DNSRR, DNSRRSRV, DNSRRTXT, UDP
from collections import defaultdict
packets = rdpcap("capture.pcap")
hosts = defaultdict(lambda: {"services": [], "ips": set(), "txt": []})
for pkt in packets:
if not (pkt.haslayer(UDP) and pkt[UDP].dport == 5353 and pkt.haslayer(DNS)):
continue
dns = pkt[DNS]
src_ip = pkt["IP"].src if "IP" in pkt else "?"
# Walk answer, authority, and additional records
for section in (dns.an, dns.ns, dns.ar):
rr = section
while rr and rr.type != 0:
name = rr.rrname.decode(errors="replace").rstrip(".")
if rr.type == 12: # PTR
ptr = rr.rdata.decode(errors="replace").rstrip(".")
hosts[src_ip]["services"].append(f"PTR: {name} -> {ptr}")
elif rr.type == 33: # SRV
hosts[src_ip]["services"].append(
f"SRV: {name} -> {rr.target.decode(errors='replace')}:{rr.port}")
elif rr.type == 1: # A
hosts[src_ip]["ips"].add(rr.rdata)
elif rr.type == 16: # TXT
for s in rr.rdata:
hosts[src_ip]["txt"].append(s.decode(errors="replace"))
try:
rr = rr.payload
except Exception:
break
for src, info in sorted(hosts.items()):
print(f"
[{src}]")
for ip in sorted(info["ips"]):
print(f" A: {ip}")
for svc in sorted(set(info["services"])):
print(f" {svc}")
for txt in sorted(set(info["txt"])):
print(f" TXT: {txt}")
# Live enumeration reference (for understanding what tools generate these captures):
# avahi-browse -a -t # enumerate all services on the local network
# dns-sd -B _services._dns-sd._udp local # macOS service discovery
# python3 -m zeroconf # Python zeroconf library discovery
Analytical Methodology
- Apply Wireshark filter
mdnsorudp.port == 5353. Count the number of unique source IPs to estimate the number of active devices on the local segment during the capture window. - For each source IP, examine the PTR records it announces. PTR records with names ending in
._tcp.localor._udp.localreveal service types. Compile a list:_http._tcp,_smb._tcp,_afpovertcp._tcp,_ssh._tcp, etc. - For each service instance (PTR target), locate the corresponding SRV record to obtain the canonical hostname and TCP/UDP port number. The hostname resolves to an IP via the A/AAAA record in the same mDNS response.
- Examine TXT records for each service instance. TXT records carry service-specific metadata: web root path, version numbers, authentication requirements, device model, and sometimes credentials or access tokens in IoT devices.
- Build a host inventory table: source IP, mDNS hostname (.local name), resolved IP (from A record), advertised service types, ports, and TXT metadata. This is the network topology derived from passive mDNS observation.
- Identify Apple Bonjour publishers by service types
_airplay._tcp,_raop._tcp,_homekit._tcp,_afpovertcp._tcp. Identify Avahi (Linux) by_workstation._tcp. Identify Windows mDNS by_smb._tcpand_microsoft-ds._tcp. - Look for mDNS probing conflicts — two hosts sending mDNS probes (questions, not answers) for the same hostname. This occurs when two devices attempt to claim the same .local name and indicates hostname collision, possibly suggesting a rogue device.
- Correlate hostnames and IPs discovered via mDNS with other traffic in the PCAP (HTTP, SMB, SSH sessions) to confirm which services were actually used versus merely advertised.
Common Analytical Errors
- Missing IPv6 mDNS: mDNS uses
ff02::fbfor IPv6 multicast. If the capture includes IPv6 traffic, filterudp.dstport == 5353rather than relying on themdnsdisplay filter, which may not match IPv6 mDNS in all Wireshark versions. - Confusing mDNS queries with responses: mDNS uses the QR bit in the DNS header: 0 = query (device looking for services), 1 = response (device announcing services). Responses are the data source for enumeration; queries reveal what services a device is looking for.
- Overlooking "goodbye" packets: When a device leaves the network, it sends a final mDNS announcement with TTL=0 (a "goodbye" packet) to withdraw its records. These packets indicate a device went offline — relevant for timeline reconstruction.
- Assuming .local hostnames are unique: mDNS hostname conflicts are common in enterprise networks. Multiple devices may claim similar hostnames, and the A records associated with the same hostname may change over the capture window. Always correlate hostname with the source IP of the announcement, not just the hostname string.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0046 | Knowledge of intrusion detection systems and methodologies | mDNS enumeration is a passive reconnaissance technique detectable by monitoring multicast traffic |
| K0093 | Knowledge of network protocols | mDNS and DNS-SD protocol structure: PTR, SRV, TXT record semantics and multicast addressing |
| K0221 | Knowledge of OSI model and network layers | mDNS operates at layer 7 (DNS format) over UDP layer 4 using link-local multicast at layer 3 |
| S0046 | Skill in performing packet-level analysis | Parsing mDNS PTR/SRV/TXT records from PCAP to construct a host-service inventory |
| T0023 | Collect intrusion artifacts for use in forensic analysis | mDNS-derived device inventory is a forensic artifact establishing what hosts were present on the network segment |
Further Reading
- RFC 6762: Multicast DNS — complete mDNS specification
- RFC 6763: DNS-Based Service Discovery — DNS-SD PTR/SRV/TXT protocol details
- Apple Bonjour technology overview (developer.apple.com) — service type registry
- Avahi project documentation (avahi.org) — Linux mDNS implementation reference
- Responder tool documentation — attacker mDNS/LLMNR poisoning to understand what anomalous mDNS traffic looks like
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.