Identify a TCP connection with p0f

We have talked about how to use nmap to detect the OS of a remote host. Nmap does that by sending probing packets and depending on the responses may or may not be able to identify the remote OS with a certain accuracy. That can work well in many cases, but there are two drawbacks: a) it can be slow, taking several seconds to complete the process b) if the remote host doesn’t respond to the probing packets the identification fails.

Another tool that can do OS identification is p0f. The main difference with nmap is that p0f relies on passively capturing TCP connection information and by fingerprinting it, it manages to identify the OS of the remote host. This has the advantage of being real-time and very fast, but the drawback is that it needs the remote host to initiate a TCP connection to capture the traffic and do the identification. 

Both nmap and p0f may give wrong information, or not be as specific as we’d like it (for example, they may say it’s a Windows remote host without being able to identify between Windows 7 or 10). Both solve the same problem in their own unique way, and you need to decide which one to use depending on the specifics or your problem.

p0f is mainly used when doing forensics or security scans, and it’s a well known tool to infosec and a standard package for Kali Linux, the Linux distributions tailored to security engineers.

Let’s see how p0f is used and what information provides.

p0f Installation

Installing p0f on Debian based Linux can be done with:

apt-get install p0f

Usage

To get a list of all available interfaces on your system use the following:

netbeez.net$ sudo p0f -L
--- p0f 3.09b by Michal Zalewski <lcamtuf@coredump.cx> ---


-- Available interfaces --

  0: Name        : eth0
     Description : -
     IP address  : 172.31.0.69

  1: Name        : wlan0
     Description : -
     IP address  : 192.168.1.81

  2: Name        : any
     Description : Pseudo-device that captures on all interfaces
     IP address  : (none)

  3: Name        : lo
     Description : -
     IP address  : 127.0.0.1

  4: Name        : bluetooth0
     Description : Bluetooth adapter number 0
     IP address  : (none)

  5: Name        : nflog
     Description : Linux netfilter log (NFLOG) interface
     IP address  : (none)

  6: Name        : nfqueue
     Description : Linux netfilter queue (NFQUEUE) interface
     IP address  : (none)

  7: Name        : usbmon1
     Description : USB bus number 1
     IP address  : (none)

As you may have guessed the interfaces I can readily use are “eth0” and “wlan0”.

Let’s capture traffic on interface eth0 and identify the OS the remote hosts:

netbeez.net$ sudo p0f -i eth0
--- p0f 3.09b by Michal Zalewski <lcamtuf@coredump.cx> ---

[+] Closed 1 file descriptor.
[+] Loaded 322 signatures from '/etc/p0f/p0f.fp'.
[+] Intercepting traffic on interface 'eth0'.
[+] Default packet filtering configured [+VLAN].
[+] Entered main event loop.

.-[ 172.31.0.222/7079 -> 172.31.0.69/22 (syn) ]-
|
| client   = 172.31.0.222/7079
| os       = Windows NT kernel
| dist     = 0
| params   = generic
| raw_sig  = 4:128+0:0:1460:mss*44,8:mss,nop,ws,nop,nop,sok:df,id+:0
|
`----

.-[ 172.31.0.222/7079 -> 172.31.0.69/22 (mtu) ]-
|
| client   = 172.31.0.222/7079
| link     = Ethernet or modem
| raw_mtu  = 1500
|
`----

.-[ 172.31.0.222/7079 -> 172.31.0.69/22 (syn+ack) ]-
|
| server   = 172.31.0.69/22
| os       = ???
| dist     = 0
| params   = none
| raw_sig  = 4:64+0:0:1460:mss*20,7:mss,nop,nop,sok,nop,ws:df:0
|
`----

.-[ 172.31.0.222/7079 -> 172.31.0.69/22 (mtu) ]-
|
| server   = 172.31.0.69/22
| link     = Ethernet or modem
| raw_mtu  = 1500
|
`----

Once you start p0f you won’t see any output unless a remote host tries to initiate a connection. To get the previous output, I started an ssh connection with ssh 172.21.0.69 from my Windows 10 machine. As you can see p0f identified that my machine is running “Windows NT kernel.” Not as accurate as I would like it to be, but it looks like p0f has no way to identify between the different Windows distributions at the time being.

In addition, it gives the ports used on the two ends of the connection, the MTU (“raw_mtu  = 1500”), the type of connection (“link = Ethernet or modem”), and the number of hops between the two hosts (“dist = 0”). The “raw_sig” field is the signature encoding used by p0f in it’s fingerprint library.

You can get similar results by opening a browser and typing 172.31.0.69 in the address bar. Even if there is no HTTP server running on 172.31.0.69, the HTTP request generates TCP traffic which is enough to identify the OS.

The good thing is that if a new way comes up to differentiate between Windows distributions, you can update the p0f fingerprint library (/etc/p0f/p0f.fp) and improve p0f’s accuracy. You can also give your own fingerprint library with (-f file_path) option.

Going back to the difference between nmap and p0f, I tried ( nmap -O 172.31.0.222) (172.31.0.222 is my Windows 10 machine) and I didn’t get a response because Windows doesn’t respond to nmap’s probe requests. 

p0f is simple to use and has a few more options, such as running  as a daemon on the background (-d), logging the output in a file (-o), or getting input from a pcap file instead of an interface (-r). 

It is a specialized tool, and for what it does is pretty good at it. Comparing it directly to nmap is a bit of apples-vs.-oranges comparison because nmap does so much more, but nmap is the closet tool I know off. All said and done, I think it’s the clear choice if you are looking to do OS identification of incoming connections on a host.

decoration image

Get your free trial now

Monitor your network from the user perspective

You can share

Twitter Linkedin Facebook

Let's keep in touch

decoration image