top of page
Writer's pictureotw

Operating System (OS) Fingerprinting with p0F

Updated: Dec 31, 2022


I have said it many times before and I will say it again, good reconnaissance is crucial to successful hacking! Without it thorough reconnaissance, you are probably wasting tour time. There have been many cases where hackers have spent days and weeks doing reconnaissance before they even beginning to try to hack/exploit a system or network. That's because you might only get one attempt, and if it fails, you are done.

Probably the most basic information we need before hacking is the operating system (OS). I hope it goes without saying that a Linux exploit won't work on a Windows system and likely won't work on a Apple's OS X. Furthermore, a Windows XP exploit won't likely work on Windows 10. Exploits are very specific and you need to have good information before choosing your approach to the hack.

In this tutorial, we will use an approach to get reliable results as to the operating system of the target. It is a passive approach relying upon the differences in each operating system's implementation of the TCP/IP stack. If we understand these differences, we can decipher what OS sent each packet travelling across the internet.

When using nmap, we know that we could use the -O switch with nmap to have that tool provide us an OS "guess". If you had a chance to use nmap much, you found out that it's not very accurate. Not only does it often "guess" incorrectly, but it also can be fooled by routers, switches and load balancers.

In this lesson, we will look at a tool known as p0f. The name is an acronym for passive operating system fingerprinting. Unlike nmap and some other operating system fingerprinters that send packets at the target and gauge their response, p0f is passive. It relies upon an understanding how each of the operating system TCP/IP stacks implement and build their packets to determine the OS of the sender. In this way, it is totally passive. We don't need to touch the target system with packets or anything else. This allows us to remain stealthy and undetected, while determining the target operating system.

TCP/IP Stack Implementation

There are many ways to determine the operating system of a target. For instance, certain ports and services will only be open on Windows systems (1433, SQL Server and 137,NetBios) and some ports only on Linux systems (631,IPP). This kind of fingerprinting will at least divide the world into those two broad camps, but it is a pretty limited method. First, some Windows systems don't have those ports open and some Linux systems don't have that port open. Second, sometimes knowing what broad camp the OS is in is not enough information. We need a more refined understanding of the OS version, sometimes down to the service pack level.

There are some tools like xprobe2 that will throw many probes at the system and then gauge the response to determine the operating system. These tools are very noisy and not very stealthy, but in general, work well if their fingerprints are up-to-date. What if we wanted to determine the OS without ever touching the system and risking being detected. Can we do that?

The answer is a definitive "Yes"! A few years back, Michal Zalewski developed the tool p0F or the passive operating system fingerprinting.

p0F and other passive fingerprinting tools rely upon the fact that different operating systems have different TCP/IP stacks and therefore create their packets slightly differently. This means that we can take any packet travelling around the Internet and if we know what we are looking for, determine what operating system that sent it.

The four key fields of the TCP/IP headers that are crucial for OS identification are;

  • TOS

  • TTL

  • DF

  • Window size

In the diagram below, I have circled these fields in the IP header (TOS, TTL, and DF) and in the TCP header (Window Size).

Let's take a look at each of these fields.

First, the Type of Service in the IP header or TOS. That field can have four (4) different values;

  • Minimize Delay

  • Maximize Throughput

  • Maximize Reliability

  • Minimize Monetary Cost

Second, the Flags field. This shouldn't be confused with the TCP flags (S,A,F,U,P,R). This flag is set as either D or M, don't fragment or more fragments. This is the way that IP signals to the receiver whether more packets fragments are on the way. If it gets packets with the M flag set, the receiver can hold the packets and reassemble them into a complete packet.

Third, TTL or Time to Live. This field indicates how many hops the packet should make before it expires. Windows systems usually have this set to 32 and Linux systems to 64, although, it does vary.

Finally, Window or window size. This defines how much buffer the TCP stack has to buffer packets. Remember that one of beauties of TCP is that is has flow control. If one side is sending packets to quickly for the other to process, the sender can buffer the packets. Window size defines the size of that buffer. This field alone, carries more information than any other field in either header as to the identity of the sender. Nearly every operating system has a different window size.

Now that we understand what p0f does, let's put it to work on some packets.

p0F

p0F is pre-installed in Kali, so no need to download and install it. p0F is not available from the GUI in Kali, but it is built-in and can be accessed via the command line. Since it's binaries are in the /usr/bin directory and /usr/bin is in our PATH variable, we can access it from the command line from anywhere in Kali. Let's take a look at its help file by typing (please note that the middle character is the number zero 0, not the letter o);

kali > p0f -h

As you can see above, p0f has a brief, but complete help file. The first stanza addresses the network interface options, the second stanza the operating mode and the third stanza the performance options.

In its simplest form, you can run p0f by simply typing the command followed by an -i (interface) and then the name of the interface you want p0f to listen on, in this case eth0;

kali > p0f -i eth0

When we start p0f, it begins listening on the designated interface and then decoding the information from each packet as they appear.

Let's try navigating to our Kali system (you may want to start the Apache webserver) from a Windows 7 system with a Firefox browser.

As you can see, first p0f opens, then loads 320 signatures, listens on eth0 and then enters a main event loop . When it sees a packet at the interface, it begins to decode it. First, it tells us what IP address and port it is coming from and the TCP flag that is set(SYN). Next, it tells us what OS fits the fingerprint for this packet (Windows 7 or 8). In the next stanza, it tells us what the link is (Ethernet or modem) and the MTU (1500).

If we scroll down a bit, we see the information above describing the browser we used (Firefox 10.x or newer), the language (English) and its raw signature.

From the same system, if we use Microsoft's Internet Explorer 9 to send packets to our Kali, you can see that p0f is able to fingerprint the browser as "MSIE 8 or newer".

Let's try sending packets from another Kali system. Kali is built on Debian Linux with a Linux kernel. Depending upon what version of Kali you are running, the kernel is either 3.12 or 3.14. If p0f is accurate, it should be able to fingerprint this packet as coming from a Linux system.

As you can see in the screenshot above, p0f was able to determine that the OS was "Linux 3.11 and newer". Pretty accurate, wouldn't you say?

In my tutorial on hping3, I mentioned that TCP has a field that records the "uptime" since the last reboot. With hping3 we are able to grab that field and then convert it into days, hours, minutes and seconds. As you recall, this can be used to determine how long since the system has been patched and therefore we can estimate what exploits the system is vulnerable to.

p0f is capable of grabbing this uptime field as well. If we scan down the output from the Kali decoding, we can see that p0f has determined that the system has been up 6 days, 16 hours and 16 minutes. Very helpful information! We can often determine whether a system has been patched by the uptime. As the patches often require a reboot, any patches that have been provided have not been implemented during the uptime period. This means that new exploits where the vulnerability has been patched will still work!

In addition, p0f also determined the browser from the Kali system (IceWeasel in Kali is built on Firefox) we used as seen below.

p0F is an excellent tool for determined the operating system of a target and is VERY accurate, unlike some of the competing tools in this field. It can also provide us with identification of the target's browser (which may be critical in exploitation) and the target's uptime, which can often tell us when the system was last patched. It is one more invaluable tool in the professional hacker's toolbox.


19,114 views
bottom of page