Kurt Seifried, [email protected]
Passive OS detection is an increasingly useful technique. People want to generate statistics on who's connecting to their machines, and administrators want to determine what is attacking them. The beauty of passive OS detection is that avoiding or faking it out takes a reasonable amount of work and expertise, and most won't bother. There are a variety of packet fields that can be used to identify the remote OS; TTL field, window size, don't fragment and so on. This is largely due to the fact that while TCP/IP stacks are interoperable, there are major variations in the way they handle various details that are set in the packet headers.
Last week I covered Linux, and more specifically its default behavior in relation to the ports it uses for the source of outgoing connections. This raised an interesting question: Can I reliably detect what the remote OS is, based solely on the source port of the connection?
The default behavior of Linux with respect to local ports is extremely predictable. Within the kernel there is a setting for the local port range:
/usr/src/linux/net/ipv4/tcp_ipv4.c/* * This array holds the first and last local port number. * For high-usage systems, use sysctl to change this to * 32768-61000 */ int sysctl_local_port_range[2] = { 1024, 4999 };
If you wish to change this behavior, you can change the kernel source code, or modify the local port range via the proc interface:
echo 6000 8000 > /proc/sys/net/ipv4/ip_local_port_range
It increments by one for each outgoing connection. IP-MASQ'ed connections are handled similarly, starting at 61000, and incrementing steadily.
Windows 9x and NT 4.0 behave very similarly, starting connections with port 1024 and steadily incrementing it by one for each outgoing connection. I was not able to find anything in the registry or the MS knowledge base, so I assume - to assume is all I can do - that it is hard coded into the OS somewhere. As far as I can tell there is no way to modify this. (If there is, I would love to know about it.) Solaris 8.0 on an Ultrasparc seems to start around port 32860. I suspect it starts somewhere around half of 65535 (hard to nail down exactly), and it steadily increments by one.
If you get a connection from a port near 1024 (your average client won't initiate more than a few hundred connections an hour), you cannot be sure if it is Linux or a Microsoft platform, or can you? You can drastically increase the confidence of your tests by observing other portions of the packet. According to a page by Lance Spitzner, Windows sets the TTL on packets to 32 or 128, and Linux uses 64. Considering how few people modify this default behavior, it is a reasonably sure way to tell the difference between Linux and Windows. Also, if you look at the window size - the sliding TCP/IP window - Windows 9x and NT use the second smallest window size on average (HP Jet Direct uses a smaller window). Linux uses a much larger window size. With all the various differences between TCP/IP stacks, you can be near 100% of what OS a packet originated from - assuming the remote machine hasn't been significantly modified. And doing so is relatively inexpensive, computationally.
Additionally, you can use active OS detection techniques. The way in which operating systems respond to various IP packet options, ICMP packets and so on, results in an almost guaranteed correct identification of the remote end. As an extension of passive fingerprinting, for TCP connections, you would be able to send arbitrary packets to the remote end, which would most likely not be firewalled, since they appear to be part of a legitimate connection. What is more, these packets could be injected by a machine other than the server handling the connection. (Although tricky, this wouldn't be impossible.)
So, what does this mean for administrators trying to defend their networks? Well, if you want to, you can reliably identify the OS that is connecting to your machines, without the remote end knowing that this is happening. This will allow for an extra layer of defenses. By allowing only Windows-based machines to connect to your exchange server, for example, you would potentially block attackers using Unix platforms, as is common nowadays. There doesn't even need to be any integration on the host server. Using various "features" - flaws, depending on your point of view - there are several tools that can be used to kill TCP connections on a local LAN. Perhaps something for the Snort/Arachnids people to work on (using Sniffit or HUNT).
Network security is constantly evolving, and new nooks and crannies are being discovered every day. Sometimes these "features" can be used in new and unintended ways, and while I wouldn't recommend betting the farm on securing your network with passive OS fingerprinting and TCP connection killing, it might be a useful security addition for some networks. That, and using things in unintended ways, can result in unexpected problems; on the other hand, it can also be fun.
Reference links:
http://www.enteract.com/~lspitz/finger.html - Passive Fingerprinting
http://www.subterrain.net/projects/siphon/ - Siphon
http://siden.sourceforge.net/ - Siden lets you simulate network probes and is useful for testing
http://lin.fsid.cvut.cz/~kra/index.html - HUNT Project - kill local TCP connections and more
http://www.snort.org/ - A great packet sniffer/Network Intrusion Detection System
http://whitehats.com/ids/ids.html - Arachnids, a set of IDS signatures for use in conjunction with Snort
Last updated 9/10/2001
Copyright Kurt Seifried 2001