6.5 Passive OS & Service Fingerprinting
Key Takeaways
- Default initial TTL values are 64 for most Linux and BSD, 128 for Microsoft Windows and 255 for Cisco IOS and legacy Solaris.
- Passive fingerprinting infers the OS from the initial TTL, TCP window size, MSS, Don't Fragment bit and the order of TCP options, none of which requires sending a packet.
- p0f is the reference passive fingerprinting tool and classifies both endpoints of every observed TCP handshake.
- TLS client fingerprints such as JA3 and JA4 hash the ClientHello's version, cipher list, extension list and curve list into a single identifier.
- NAT, load balancers, proxies and normalising firewalls rewrite the very fields passive fingerprinting relies on, so results describe the nearest device, not necessarily the real host.
6.5 Passive OS & Service Fingerprinting
Section 6.3 covered active fingerprinting: Nmap's -O sends crafted probes and compares responses against nmap-os-db. Syllabus item B8 names "active and passive techniques", and the passive half is a distinct discipline with different tooling, different accuracy characteristics and — crucially — a completely different detection profile.
Passive fingerprinting sends nothing. The assessor observes traffic the target is already generating, from a network tap, a SPAN/mirror port, a compromised host on the segment or a captured PCAP, and derives identity from implementation details that every TCP/IP stack leaks by design.
1. Why Stacks Leak Their Identity
RFC 793 and RFC 1122 specify what TCP must do, but leave a great deal to the implementer: the initial TTL to stamp on outbound packets, the default receive window, whether to offer window scaling, the order in which options are placed in the header. Each vendor chose differently, kept those choices for backwards compatibility, and thereby created a durable signature.
The Primary Passive Signals
| Signal | Where it lives | Why it discriminates |
|---|---|---|
| Initial TTL | IPv4 header TTL / IPv6 Hop Limit | Vendors picked different starting values |
| TCP window size | TCP header Window field of the SYN | Default receive buffer differs per stack and per link MTU |
| Maximum Segment Size (MSS) | TCP option in the SYN | Derived from the interface MTU; tunnels and PPPoE change it |
| Don't Fragment (DF) bit | IPv4 flags | Modern stacks set it for PMTUD; some legacy stacks do not |
| TCP options and their order | TCP header options field | e.g. MSS, SACK, Timestamp, NOP, WScale vs MSS, NOP, WScale, NOP, NOP, SACK |
| Window scale factor | WScale option value | Differs by stack and by autotuning policy |
| TCP timestamps | TSval / TSecr | Presence, and the clock tick rate, differ per OS; the value also reveals system uptime |
| IP ID generation | IPv4 Identification field | Sequential, randomised, or per-flow — the same property the idle scan exploits |
Reading the TTL
Because each router hop decrements the TTL by one, the value you observe is the initial TTL minus the hop count. Round the observed value up to the nearest common initial value:
Observed TTL 54 -> initial 64, ~10 hops away -> Linux / *BSD / macOS
Observed TTL 116 -> initial 128, ~12 hops away -> Microsoft Windows
Observed TTL 249 -> initial 255, ~6 hops away -> Cisco IOS / legacy Solaris
| Initial TTL | Typical systems |
|---|---|
| 64 | Linux (all modern kernels), FreeBSD, OpenBSD, macOS, Android, most appliances |
| 128 | Microsoft Windows (all supported versions) |
| 255 | Cisco IOS, Juniper, legacy Solaris, many network appliances |
| 32 | Very old Windows 95/98 and some embedded stacks |
This single heuristic is remarkably robust and is worth knowing cold for the exam.
Combining Signals
TTL alone cannot separate Linux from FreeBSD. Combining fields does:
SYN observed: TTL=64 Window=65535 MSS=1460 DF=1 Opts=[MSS,NOP,WScale,NOP,NOP,TS,SACK-OK]
| | | |
| | | +-- PMTUD in use (modern stack)
| | +---------- 1500-byte Ethernet MTU, no tunnel
| +----------------------- large default receive buffer
+--------------------------------- Unix-like family
=> consistent with a recent FreeBSD or macOS host on plain Ethernet
Note what the MSS tells you independently of the OS: an MSS of 1460 implies a 1500-byte MTU (plain Ethernet); 1380 or 1360 implies a VPN or IPsec tunnel; 1452 implies PPPoE. That is topology intelligence, gathered passively.
2. Tooling
-
p0f— the reference implementation. It reads live traffic or a PCAP and classifies both ends of each TCP handshake against a signature database, reporting OS, distance in hops, uptime, link type and NAT suspicion.p0f -i eth0 -o /tmp/p0f.log # live capture p0f -r capture.pcap # offline analysis of a PCAP.-[ 10.20.31.117/54122 -> 10.20.30.52/445 (syn) ]- | client = 10.20.31.117/54122 | os = Windows 10 or Windows 11 | dist = 0 | params = none | raw_sig = 4:128+0:0:1460:mss*44,8:mss,nop,ws,nop,nop,sok:df,id+:0 `---- -
Zeek(formerly Bro) — a network security monitor that logs software versions, TLS parameters and service banners it observes, producingsoftware.log,ssl.logandconn.logfor later mining. -
NetworkMiner— a GUI forensic tool that reconstructs hosts, sessions, files and credentials from a PCAP and applies its own OS fingerprinting. -
Satori— passive fingerprinting extended beyond TCP to DHCP, HTTP, CDP, SMB and more. -
Wireshark — no automatic OS classification, but every field above is directly readable, and the display filters
ip.ttl,tcp.window_size_valueandtcp.optionsmake manual analysis quick.
3. Passive Application and Service Fingerprinting
The same logic applies above the transport layer, and often yields more precise answers.
- HTTP:
Server:,X-Powered-By:and the order of response headers identify the server and framework. On the client side, theUser-Agent:names the browser and platform, and theAccept-Language:header can indicate the user's locale. - DHCP fingerprinting: the Option 55 Parameter Request List — the specific set of options a client asks for, in the specific order it asks for them — is essentially a device signature. It is how NAC products distinguish a Windows laptop from an iPhone from a printer without any agent.
- TLS fingerprinting (JA3 / JA4): a client's
ClientHellodeclares its supported TLS version, its cipher suite list, its extension list, its supported elliptic curves and its point formats. JA3 concatenates those five fields and takes an MD5 hash; JA4 is the modern successor with a more readable, more resistant format. Because the list contents and ordering come from the TLS library rather than from user configuration, a JA3/JA4 hash identifies the client stack — and therefore distinguishes a real browser from a Pythonrequestsscript or a known malware family, even over encrypted traffic. The server-side equivalents are JA3S and JARM. - SMB, SNMP, CDP/LLDP and mDNS broadcasts: on a local segment these advertise hostnames, OS versions, switch models and device roles with no probing at all.
4. Active vs Passive: Choosing the Right Technique
Active (nmap -O, -sV) | Passive (p0f, Zeek, PCAP review) | |
|---|---|---|
| Packets sent to target | Many, some deliberately malformed | None |
| Detection risk | High — IDS signatures exist for OS probes | Effectively zero from the target's perspective |
| Speed | Seconds per host | Requires waiting for the host to transmit |
| Coverage | Any reachable host, including silent ones | Only hosts that generate observable traffic |
| Accuracy | High when an open and a closed port are available | Good, but degraded by intermediaries |
| Prerequisite | Network reachability to the target | A capture point on the traffic path |
| Risk to target | Small but real — malformed probes can crash fragile stacks | None |
Passive fingerprinting is the technique of choice in three situations the CPSA syllabus cares about: fragile environments (SCADA, medical devices, legacy mainframes) where probing risks an outage; stealth-constrained engagements where the Rules of Engagement require avoiding detection; and post-compromise work, where you have a foothold on a segment and want to map neighbours without generating scan traffic that would draw attention.
5. Limitations and How to Report Them
Passive fingerprinting describes the last device that wrote the fields you observed, which is not always the host you care about:
- NAT rewrites addresses but usually preserves TTL and TCP options, so a p0f result showing several different operating systems behind a single IP address is strong evidence of NAT — which p0f explicitly reports.
- Reverse proxies and load balancers terminate the client's TCP connection entirely. Fingerprinting the "web server" then fingerprints the load balancer, not the back-end. A mismatch between the passive result and an active
-sVbanner is itself a useful finding: it tells you there is an intermediary. - Normalising firewalls (OpenBSD
pf scrub, many next-generation firewalls) deliberately rewrite TTL, clear the IP ID and reorder or strip TCP options specifically to defeat fingerprinting. - Containers and virtual machines share the host kernel's stack in some configurations, so every container on a Linux host fingerprints identically.
- The signature databases age. A result of "Linux 3.11 and newer" means the observed signature has not changed since that kernel, not that the host runs a decade-old kernel.
For these reasons, record passive results as corroborating evidence with a stated confidence, never as the sole basis for a vulnerability claim. Where a finding depends on the operating system or version, confirm it with an active check, a service banner, or authenticated access, and say in the report which method established the fact.
An assessor captures traffic on a SPAN port and observes an inbound SYN packet with TTL 116, a 64240-byte window, MSS 1460, the DF bit set, and TCP options ordered MSS, NOP, WScale, NOP, NOP, SACK-permitted. What is the most defensible conclusion?
A penetration test scope includes a hospital network containing life-critical medical devices, and the Rules of Engagement forbid any probing that could disrupt them. Which fingerprinting approach best satisfies this constraint?
A JA3 fingerprint is computed from a TLS ClientHello. Which property makes it useful to an assessor or defender analysing encrypted traffic?
Passive fingerprinting of a public web address reports several different operating systems over the course of a capture, while an active Nmap service scan of the same address returns a single consistent server banner. What is the most likely explanation?